Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/jinn/src/cli/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
CLAUDE_SKILLS_DIR,
AGENTS_SKILLS_DIR,
} from "../shared/paths.js";
import { initDb } from "../sessions/registry.js";
import { initDb } from "../shared/db.js";
import { getPackageVersion } from "../shared/version.js";
import { deriveTodoIdPrefix } from "../work-items/id.js";
import {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ beforeAll(async () => {
approvals = await import("../../work-items/approvals.js");
registry = await import("../../sessions/registry.js");
approvalAuthority = await import("../approval-authority.js");
registry.initDb();
(await import("../../shared/db.js")).initDb();
});

describe("approval root resolution without an executive employee", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ beforeAll(async () => {
paths = await import("../../shared/paths.js");
reg = await import("../../sessions/registry.js");
files = await import("../files.js");
reg.initDb();
(await import("../../shared/db.js")).initDb();
});

/** Simulate a first-message upload that landed in FILES_DIR before a session existed. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ async function createSessionViaHttp(headers: Record<string, string>): Promise<{
beforeAll(async () => {
api = await import("../api.js");
registry = await import("../../sessions/registry.js");
registry.initDb();
(await import("../../shared/db.js")).initDb();
config = {
gateway: { host: "127.0.0.1", authDisabled: true },
engines: { default: "codex", codex: {}, claude: {} },
Expand Down Expand Up @@ -225,7 +225,7 @@ afterAll(async () => {
await new Promise<void>((resolve, reject) => server.close((error) => error ? reject(error) : resolve()));
// Close the database before removing its directory: Windows refuses to unlink
// a file with an open handle, so the sqlite connection has to go first.
registry.__closeDbForTest();
(await import("../../shared/db.js")).__closeDbForTest();
removeTempDir(testHome);
});

Expand Down
5 changes: 3 additions & 2 deletions packages/jinn/src/gateway/__tests__/budgets.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), "jinn-budgets-"));
process.env.JINN_HOME = tmpHome;
fs.mkdirSync(path.join(tmpHome, "org"), { recursive: true });
for (const n of ["over-cap", "under-cap"]) fs.writeFileSync(path.join(tmpHome, "org", `${n}.yaml`), `name: ${n}\nengine: codex\nmodel: gpt-5.5\npersona: Budget fixture\n`);
const dbModule = await import("../../shared/db.js");
const engineRuns: string[] = [];
const engineStub = { name: "stub", run: async (o: { sessionId?: string }) => { engineRuns.push(String(o.sessionId)); return { result: "ok" }; }, isAlive: () => false, kill: () => {}, killAll: () => {} };
const queueStub = { enqueue: async (_k: string, fn: () => Promise<void>) => { await fn(); }, clearCancelled: () => {}, clearQueue: () => {}, pauseQueue: () => {}, resumeQueue: () => {}, getPendingCount: () => 0, getTransportState: (_k: string, s: string) => s };
Expand All @@ -24,12 +25,12 @@ const apiCtx = {
let api: typeof import("../api.js"), reg: typeof import("../../sessions/registry.js"), budgets: typeof import("../budgets.js");
beforeAll(async () => {
[api, reg, budgets] = await Promise.all([import("../api.js"), import("../../sessions/registry.js"), import("../budgets.js")]);
reg.initDb();
dbModule.initDb();
});
/** Bank prior spend for `employee` inside the current calendar month. */
function seedSpend(employee: string, cost: number) {
const now = new Date().toISOString();
reg.initDb().prepare("INSERT INTO sessions (id, engine, source, source_ref, employee, total_cost, created_at, last_activity) VALUES (?, 'codex', 'web', 'seed', ?, ?, ?, ?)").run(`seed-${employee}`, employee, cost, now, now);
dbModule.initDb().prepare("INSERT INTO sessions (id, engine, source, source_ref, employee, total_cost, created_at, last_activity) VALUES (?, 'codex', 'web', 'seed', ?, ?, ?, ?)").run(`seed-${employee}`, employee, cost, now, now);
}
/** The blocked-turn surface: an ⛔ assistant message on the session. */
const blocked = (id: string) => reg.getMessages(id).some((m) => m.content.startsWith("⛔"));
Expand Down
33 changes: 17 additions & 16 deletions packages/jinn/src/gateway/__tests__/callback-reliability.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type { Engine, EngineRunOpts } from "../../shared/types.js";

const home = fs.mkdtempSync(path.join(os.tmpdir(), "jinn-callback-reliability-"));
process.env.JINN_HOME = home;
const dbModule = await import("../../shared/db.js");

type Api = typeof import("../api.js");
type Registry = typeof import("../../sessions/registry.js");
Expand Down Expand Up @@ -217,11 +218,11 @@ beforeAll(async () => {
queueModule = await import("../../sessions/queue.js");
callbacks = await import("../../sessions/callbacks.js");
workItems = await import("../../work-items/store.js");
registry.initDb();
dbModule.initDb();
});

beforeEach(() => {
registry.initDb().exec(`
dbModule.initDb().exec(`
DELETE FROM work_item_events;
DELETE FROM callback_deliveries;
DELETE FROM queue_items;
Expand Down Expand Up @@ -261,15 +262,15 @@ describe("parent callback reliability", () => {
expect(queue.isRunning(manager.sessionKey)).toBe(false);
expect(seenPrompts).toHaveLength(1);
});
const accepted = registry.initDb().prepare(`
const accepted = dbModule.initDb().prepare(`
SELECT id, status FROM callback_deliveries WHERE delivery_kind = 'manager-visibility'
`).get();
callbacks.notifyManagerVisibility(manager.id, details);
await new Promise((resolve) => setTimeout(resolve, 25));
expect(registry.initDb().prepare(`
expect(dbModule.initDb().prepare(`
SELECT COUNT(*) AS n FROM callback_deliveries WHERE delivery_kind = 'manager-visibility'
`).get()).toEqual({ n: 1 });
expect(registry.initDb().prepare(`
expect(dbModule.initDb().prepare(`
SELECT id, status FROM callback_deliveries WHERE delivery_kind = 'manager-visibility'
`).get()).toEqual(accepted);
expect(registry.getMessages(manager.id).filter((message) => message.role === "notification"))
Expand Down Expand Up @@ -338,7 +339,7 @@ describe("parent callback reliability", () => {
expect(queue.isRunning(parent.sessionKey)).toBe(false);
expect(seenPrompts).toHaveLength(1);
});
const rateLimitedPayload = JSON.parse((registry.initDb().prepare(`
const rateLimitedPayload = JSON.parse((dbModule.initDb().prepare(`
SELECT payload FROM callback_deliveries WHERE delivery_kind = 'rate-limited'
`).get() as { payload: string }).payload) as Record<string, unknown>;
expect(rateLimitedPayload).not.toHaveProperty("meta");
Expand All @@ -359,7 +360,7 @@ describe("parent callback reliability", () => {
expect(queue.isRunning(parent.sessionKey)).toBe(false);
expect(seenPrompts).toHaveLength(3);
});
expect(registry.initDb().prepare(`
expect(dbModule.initDb().prepare(`
SELECT delivery_kind AS kind, COUNT(*) AS n
FROM callback_deliveries
GROUP BY delivery_kind
Expand Down Expand Up @@ -441,7 +442,7 @@ describe("parent callback reliability", () => {
expect(seenPrompts).toHaveLength(1);
});
expect(registry.getMessages(parent.id).filter((message) => message.role === "notification")).toHaveLength(1);
expect(registry.initDb().prepare(`
expect(dbModule.initDb().prepare(`
SELECT COUNT(*) AS n FROM callback_deliveries WHERE delivery_kind = 'rate-limit-resumed'
`).get()).toEqual({ n: 1 });
expect(events.filter(({ event }) => event === "session:notification")).toHaveLength(1);
Expand Down Expand Up @@ -473,7 +474,7 @@ describe("parent callback reliability", () => {
callbacks.notifyRateLimited(active);
callbacks.notifyRateLimitResumed(active);
await eventually(() => {
const rows = registry.initDb().prepare(`
const rows = dbModule.initDb().prepare(`
SELECT delivery_kind AS kind FROM callback_deliveries ORDER BY delivery_kind
`).all();
expect(rows).toEqual([{ kind: "rate-limit-resumed" }, { kind: "rate-limited" }]);
Expand Down Expand Up @@ -543,7 +544,7 @@ describe("parent callback reliability", () => {
expect(queue.isRunning(parent.sessionKey)).toBe(false);
expect(seenPrompts).toEqual([expect.stringContaining("one immutable completion")]);
expect(registry.getMessages(parent.id).filter((message) => message.role === "notification")).toHaveLength(1);
expect(registry.initDb().prepare("SELECT COUNT(*) AS n FROM callback_deliveries").get()).toEqual({ n: 1 });
expect(dbModule.initDb().prepare("SELECT COUNT(*) AS n FROM callback_deliveries").get()).toEqual({ n: 1 });
});
expect(routeFetch).toHaveBeenCalledOnce();
expect(events.filter(({ event }) => event === "session:notification")).toHaveLength(1);
Expand Down Expand Up @@ -623,15 +624,15 @@ describe("parent callback reliability", () => {
});

await eventually(() => {
const receipt = registry.initDb().prepare(`
const receipt = dbModule.initDb().prepare(`
SELECT status FROM callback_deliveries WHERE delivery_kind = 'delegation-completion-nudge'
`).get();
expect(receipt).toEqual({ status: "accepted" });
});
expect(routeFetch).toHaveBeenCalledOnce();
expect(registry.getMessages(child.id).filter((message) => message.role === "notification")).toHaveLength(1);
expect(registry.getMessages(parent.id)).toEqual([]);
expect(registry.initDb().prepare(`
expect(dbModule.initDb().prepare(`
SELECT COUNT(*) AS n FROM callback_deliveries WHERE delivery_kind = 'parent-completion'
`).get()).toEqual({ n: 0 });
expect(registry.getSession(child.id)?.transportMeta).toMatchObject({
Expand Down Expand Up @@ -760,7 +761,7 @@ describe("parent callback reliability", () => {
parentSessionId: parent.id,
prompt: "finish after poison",
});
const database = registry.initDb();
const database = dbModule.initDb();
database.pragma("ignore_check_constraints = ON");
database.prepare(`
INSERT INTO callback_deliveries (
Expand Down Expand Up @@ -857,7 +858,7 @@ describe("parent callback reliability", () => {
]);
const stored = registry.getSessionDelivery(delivery.id)!;
expect(stored).toMatchObject({ status: "accepted" });
expect(registry.initDb().prepare("SELECT COUNT(*) AS n FROM queue_items WHERE id = ?").get(stored.queueItemId))
expect(dbModule.initDb().prepare("SELECT COUNT(*) AS n FROM queue_items WHERE id = ?").get(stored.queueItemId))
.toEqual({ n: 1 });
expect(events.filter(({ event }) => event === "session:notification")).toEqual([
expect.objectContaining({
Expand Down Expand Up @@ -1218,7 +1219,7 @@ describe("callback live retry sweep", () => {

callbacks.notifyParentSession(child, { result: "accepted once" });
await vi.advanceTimersByTimeAsync(0);
const delivery = registry.initDb().prepare(`
const delivery = dbModule.initDb().prepare(`
SELECT id FROM callback_deliveries WHERE delivery_kind = 'parent-completion'
`).get() as { id: string };
await vi.advanceTimersByTimeAsync(24 * 60 * 60 * 1_000);
Expand All @@ -1241,7 +1242,7 @@ describe("callback live retry sweep", () => {
await vi.advanceTimersByTimeAsync(delay);
await vi.runAllTicks();
}
const delivery = registry.initDb().prepare(`SELECT id FROM callback_deliveries`).get() as { id: string };
const delivery = dbModule.initDb().prepare(`SELECT id FROM callback_deliveries`).get() as { id: string };
expect(registry.getSessionDelivery(delivery.id)).toMatchObject({
status: "dead_letter",
attemptCount: callbacks.CALLBACK_DELIVERY_MAX_ATTEMPTS,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ beforeAll(async () => {
const paths = (await import("../../shared/paths.js")) as Paths;
({ ptySnapshotStore } = await import("../../engines/pty-snapshot.js"));
CODEX_HOMES_DIR = paths.CODEX_HOMES_DIR;
registry.initDb();
(await import("../../shared/db.js")).initDb();
});

describe("session delete removes the per-session Codex CODEX_HOME overlay", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ beforeAll(async () => {
approvals = await import("../../work-items/approvals.js");
approvalAuthority = await import("../approval-authority.js");
auth = await import("../auth.js");
registry.initDb();
(await import("../../shared/db.js")).initDb();
worker = registry.createSession({ engine: "codex", source: "web", sourceRef: "worker", title: "worker", employee: "platform-worker" });
peer = registry.createSession({ engine: "codex", source: "web", sourceRef: "peer", title: "peer", employee: "platform-peer" });
manager = registry.createSession({ engine: "codex", source: "web", sourceRef: "manager", title: "manager", employee: "platform-manager" });
Expand Down Expand Up @@ -538,7 +538,7 @@ describe("portal fallback is a virtual root, not employee authority", () => {
expect(approval.approvalTarget).toBe(legacyRoot);
expect(approval.approvalTargetKind).toBe("virtual");

registry.initDb().prepare("UPDATE work_items SET approval_target_kind = NULL WHERE id = ?").run(approval.id);
(await import("../../shared/db.js")).initDb().prepare("UPDATE work_items SET approval_target_kind = NULL WHERE id = ?").run(approval.id);
fs.writeFileSync(
legacyFile,
"name: Legacy Root\ndisplayName: Legacy Root\ndepartment: platform\nrank: employee\nreportsTo: platform-manager\nengine: codex\nmodel: gpt-5.5\npersona: Attempts to claim a legacy persisted approval target.\n",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ vi.mock("../../work-items/store.js", async (importOriginal) => {
// Isolated home for registry DB + org dir. Set BEFORE the dynamic api import.
const tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), "jinn-delegations-route-"));
process.env.JINN_HOME = tmpHome;
const dbModule = await import("../../shared/db.js");

// A real employee for the employee-path assertions (scanOrg requires name+persona).
fs.mkdirSync(path.join(tmpHome, "org"), { recursive: true });
Expand Down Expand Up @@ -123,7 +124,7 @@ const engineStub = {
run: async (opts: Record<string, unknown>) => {
// Snapshot the DB link AT TURN START — the codex finding-1 pin: the work
// item ↔ session link must already be durable when the worker runs.
const row = reg
const row = dbModule
.initDb()
.prepare("SELECT work_item_id FROM sessions WHERE id = ?")
.get(String(opts.sessionId)) as { work_item_id: string | null } | undefined;
Expand Down
4 changes: 3 additions & 1 deletion packages/jinn/src/gateway/__tests__/dispatch-route.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ fs.writeFileSync(
].join("\n"),
);

const dbModule = await import("../../shared/db.js");

type Api = typeof import("../api.js");
type Registry = typeof import("../../sessions/registry.js");
type WorkItems = typeof import("../../work-items/store.js");
Expand Down Expand Up @@ -162,7 +164,7 @@ beforeAll(async () => {
registry = await import("../../sessions/registry.js");
workItems = await import("../../work-items/store.js");
org = await import("../org.js");
registry.initDb();
dbModule.initDb();
const { setJinnAttachGate } = await import("../../mcp/attachment.js");
setJinnAttachGate({ ok: true });
});
Expand Down
2 changes: 1 addition & 1 deletion packages/jinn/src/gateway/__tests__/external-turns.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ let ext: Ext;
beforeAll(async () => {
reg = await import("../../sessions/registry.js");
ext = await import("../external-turns.js");
reg.initDb();
(await import("../../shared/db.js")).initDb();
});

let seq = 0;
Expand Down
2 changes: 1 addition & 1 deletion packages/jinn/src/gateway/__tests__/file-cache.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ beforeAll(async () => {
paths = await import("../../shared/paths.js");
reg = await import("../../sessions/registry.js");
files = await import("../files.js");
reg.initDb();
(await import("../../shared/db.js")).initDb();
});

describe("file cache helpers", () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/jinn/src/gateway/__tests__/file-read.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ beforeAll(async () => {
files = await import("../files.js");
registry = await import("../../sessions/registry.js");
identity = await import("../../mcp/identity.js");
registry.initDb();
(await import("../../shared/db.js")).initDb();
fileSession = registry.createSession({ engine: "codex", source: "web", sourceRef: "file-reader", employee: "file-reader" });
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest"

const registryHome = fs.mkdtempSync(path.join(os.tmpdir(), "jinn-migration-api-registry-"))
process.env.JINN_HOME = registryHome
const dbModule = await import("../../shared/db.js");

const home = fs.mkdtempSync(path.join(os.tmpdir(), "jinn-migration-api-home-"))
const migrationsDir = path.join(home, "package-migrations")
Expand Down Expand Up @@ -109,7 +110,7 @@ async function request(method: string, url: string, body?: unknown, authorized =
beforeAll(async () => {
api = await import("../api.js")
registry = await import("../../sessions/registry.js")
registry.initDb()
dbModule.initDb()
})

beforeEach(() => {
Expand Down Expand Up @@ -169,8 +170,8 @@ describe("instance migration API", () => {
expect(dispatched).toHaveLength(1)
expect(registry.getQueueItems(`instance-migration:${pending.body.migrationKey}`)).toHaveLength(1)

registry.__closeDbForTest()
registry.initDb()
dbModule.__closeDbForTest()
dbModule.initDb()
expect(registry.getQueueItems(`instance-migration:${pending.body.migrationKey}`)).toHaveLength(1)
const afterRestart = await request("POST", "/api/instance-migration/open", { migrationKey: pending.body.migrationKey })
expect(afterRestart).toMatchObject({
Expand Down
7 changes: 4 additions & 3 deletions packages/jinn/src/gateway/__tests__/pins-api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Readable } from "node:stream";
import type { ServerResponse } from "node:http";

process.env.JINN_HOME = fs.mkdtempSync(path.join(os.tmpdir(), "jinn-pins-api-"));
const dbModule = await import("../../shared/db.js");

type Api = typeof import("../api.js");
type Registry = typeof import("../../sessions/registry.js");
Expand Down Expand Up @@ -70,7 +71,7 @@ async function request(method: string, url: string, body?: unknown) {
beforeAll(async () => {
registry = await import("../../sessions/registry.js");
api = await import("../api.js");
registry.initDb();
dbModule.initDb();
});

describe("chat pin API", () => {
Expand Down Expand Up @@ -102,7 +103,7 @@ describe("chat pin API", () => {
const newer = registry.createSession({ engine: "codex", source: "web", sourceRef: "web:api-newer" });
const archived = registry.createSession({ engine: "claude", source: "web", sourceRef: "web:api-archived" });
const unpinned = registry.createSession({ engine: "claude", source: "web", sourceRef: "web:api-unpinned" });
const database = registry.initDb();
const database = dbModule.initDb();
database.prepare("UPDATE sessions SET last_activity = ? WHERE id = ?").run("2026-02-01T00:00:00.000Z", older.id);
database.prepare("UPDATE sessions SET last_activity = ? WHERE id = ?").run("2026-02-02T00:00:00.000Z", newer.id);
registry.pinChat(older.id);
Expand Down Expand Up @@ -131,7 +132,7 @@ describe("chat pin API", () => {
});

it("filters an orphaned session key even if the database invariant was bypassed", async () => {
registry.initDb().prepare(
dbModule.initDb().prepare(
"INSERT INTO chat_pins (pin_key, pinned_at) VALUES (?, ?)",
).run("missing-session", "2026-01-01T00:00:00.000Z");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ beforeAll(async () => {
registry = await import("../../sessions/registry.js");
identity = await import("../../mcp/identity.js");
paths = await import("../../shared/paths.js");
registry.initDb();
(await import("../../shared/db.js")).initDb();
const fileDir = path.join(paths.FILES_DIR, fileId);
fs.mkdirSync(fileDir, { recursive: true });
fs.writeFileSync(path.join(fileDir, "visible.txt"), "visible managed file");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ let reg: Reg;
beforeAll(async () => {
reg = await import("../../sessions/registry.js");
api = await import("../api.js");
reg.initDb();
(await import("../../shared/db.js")).initDb();
});

beforeEach(() => {
const db = reg.initDb();
beforeEach(async () => {
const db = (await import("../../shared/db.js")).initDb();
db.exec("DELETE FROM messages; DELETE FROM queue_items; DELETE FROM sessions;");
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ let reg: Reg;
beforeAll(async () => {
reg = await import("../../sessions/registry.js");
files = await import("../files.js");
reg.initDb();
(await import("../../shared/db.js")).initDb();
// Seed a session to attach to.
const db = reg.initDb();
const db = (await import("../../shared/db.js")).initDb();
db.prepare(
"INSERT INTO sessions (id, engine, source, source_ref, status, created_at, last_activity) VALUES ('sess-att','claude','web','web:sess-att','idle','t','t')",
).run();
Expand Down
Loading
Loading