@ai-devkit/agent-manager 0.33.0 → 0.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AgentManager.d.ts +11 -2
- package/dist/AgentManager.d.ts.map +1 -1
- package/dist/AgentManager.js +37 -6
- package/dist/AgentManager.js.map +1 -1
- package/dist/__tests__/AgentManager.test.js +212 -5
- package/dist/__tests__/AgentManager.test.js.map +1 -1
- package/dist/__tests__/capacity/codex.test.js +2 -1
- package/dist/__tests__/capacity/codex.test.js.map +1 -1
- package/dist/__tests__/capacity/index.test.js +6 -3
- package/dist/__tests__/capacity/index.test.js.map +1 -1
- package/dist/__tests__/capacity/zai.test.js +213 -0
- package/dist/__tests__/capacity/zai.test.js.map +1 -0
- package/dist/__tests__/{adapters → providers/copilot}/CopilotAdapter.test.js +19 -14
- package/dist/__tests__/providers/copilot/CopilotAdapter.test.js.map +1 -0
- package/dist/__tests__/{adapters → providers/gemini}/GeminiCliAdapter.test.js +37 -29
- package/dist/__tests__/providers/gemini/GeminiCliAdapter.test.js.map +1 -0
- package/dist/__tests__/providers/opencode/OpenCodeAdapter.test.js +189 -0
- package/dist/__tests__/providers/opencode/OpenCodeAdapter.test.js.map +1 -0
- package/dist/__tests__/providers/opencode/OpenCodeAgentMapper.test.js +89 -0
- package/dist/__tests__/providers/opencode/OpenCodeAgentMapper.test.js.map +1 -0
- package/dist/__tests__/providers/opencode/OpenCodeSessionLocator.test.js +94 -0
- package/dist/__tests__/providers/opencode/OpenCodeSessionLocator.test.js.map +1 -0
- package/dist/__tests__/providers/opencode/OpenCodeSessionParser.test.js +147 -0
- package/dist/__tests__/providers/opencode/OpenCodeSessionParser.test.js.map +1 -0
- package/dist/__tests__/runtime/HerdrAgentDiscovery.test.js +164 -0
- package/dist/__tests__/runtime/HerdrAgentDiscovery.test.js.map +1 -0
- package/dist/__tests__/runtime/HerdrAgentRuntime.test.js +37 -1
- package/dist/__tests__/runtime/HerdrAgentRuntime.test.js.map +1 -1
- package/dist/__tests__/utils/AgentRegistry.test.js +20 -13
- package/dist/__tests__/utils/AgentRegistry.test.js.map +1 -1
- package/dist/adapters/index.d.ts +3 -3
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js +3 -3
- package/dist/adapters/index.js.map +1 -1
- package/dist/capacity/codex.d.ts +1 -0
- package/dist/capacity/codex.d.ts.map +1 -1
- package/dist/capacity/codex.js +9 -4
- package/dist/capacity/codex.js.map +1 -1
- package/dist/capacity/index.d.ts +8 -0
- package/dist/capacity/index.d.ts.map +1 -1
- package/dist/capacity/index.js +10 -9
- package/dist/capacity/index.js.map +1 -1
- package/dist/capacity/types.d.ts +8 -0
- package/dist/capacity/types.d.ts.map +1 -1
- package/dist/capacity/types.js.map +1 -1
- package/dist/capacity/zai.d.ts +14 -0
- package/dist/capacity/zai.d.ts.map +1 -0
- package/dist/capacity/zai.js +203 -0
- package/dist/capacity/zai.js.map +1 -0
- package/dist/index.d.ts +8 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -4
- package/dist/index.js.map +1 -1
- package/dist/{adapters → providers/copilot}/CopilotAdapter.d.ts +11 -25
- package/dist/providers/copilot/CopilotAdapter.d.ts.map +1 -0
- package/dist/providers/copilot/CopilotAdapter.js +108 -0
- package/dist/providers/copilot/CopilotAdapter.js.map +1 -0
- package/dist/providers/copilot/CopilotAgentMapper.d.ts +9 -0
- package/dist/providers/copilot/CopilotAgentMapper.d.ts.map +1 -0
- package/dist/providers/copilot/CopilotAgentMapper.js +37 -0
- package/dist/providers/copilot/CopilotAgentMapper.js.map +1 -0
- package/dist/providers/copilot/CopilotSessionLocator.d.ts +19 -0
- package/dist/providers/copilot/CopilotSessionLocator.d.ts.map +1 -0
- package/dist/providers/copilot/CopilotSessionLocator.js +41 -0
- package/dist/providers/copilot/CopilotSessionLocator.js.map +1 -0
- package/dist/providers/copilot/CopilotSessionParser.d.ts +30 -0
- package/dist/providers/copilot/CopilotSessionParser.d.ts.map +1 -0
- package/dist/providers/copilot/CopilotSessionParser.js +181 -0
- package/dist/providers/copilot/CopilotSessionParser.js.map +1 -0
- package/dist/providers/gemini/GeminiAgentMapper.d.ts +9 -0
- package/dist/providers/gemini/GeminiAgentMapper.d.ts.map +1 -0
- package/dist/providers/gemini/GeminiAgentMapper.js +37 -0
- package/dist/providers/gemini/GeminiAgentMapper.js.map +1 -0
- package/dist/providers/gemini/GeminiCliAdapter.d.ts +52 -0
- package/dist/providers/gemini/GeminiCliAdapter.d.ts.map +1 -0
- package/dist/providers/gemini/GeminiCliAdapter.js +188 -0
- package/dist/providers/gemini/GeminiCliAdapter.js.map +1 -0
- package/dist/providers/gemini/GeminiSessionLocator.d.ts +30 -0
- package/dist/providers/gemini/GeminiSessionLocator.d.ts.map +1 -0
- package/dist/providers/gemini/GeminiSessionLocator.js +142 -0
- package/dist/providers/gemini/GeminiSessionLocator.js.map +1 -0
- package/dist/providers/gemini/GeminiSessionParser.d.ts +94 -0
- package/dist/providers/gemini/GeminiSessionParser.d.ts.map +1 -0
- package/dist/providers/gemini/GeminiSessionParser.js +166 -0
- package/dist/providers/gemini/GeminiSessionParser.js.map +1 -0
- package/dist/{adapters → providers/opencode}/OpenCodeAdapter.d.ts +6 -12
- package/dist/providers/opencode/OpenCodeAdapter.d.ts.map +1 -0
- package/dist/providers/opencode/OpenCodeAdapter.js +86 -0
- package/dist/providers/opencode/OpenCodeAdapter.js.map +1 -0
- package/dist/providers/opencode/OpenCodeAgentMapper.d.ts +11 -0
- package/dist/providers/opencode/OpenCodeAgentMapper.d.ts.map +1 -0
- package/dist/providers/opencode/OpenCodeAgentMapper.js +50 -0
- package/dist/providers/opencode/OpenCodeAgentMapper.js.map +1 -0
- package/dist/providers/opencode/OpenCodeSessionLocator.d.ts +21 -0
- package/dist/providers/opencode/OpenCodeSessionLocator.d.ts.map +1 -0
- package/dist/providers/opencode/OpenCodeSessionLocator.js +99 -0
- package/dist/providers/opencode/OpenCodeSessionLocator.js.map +1 -0
- package/dist/providers/opencode/OpenCodeSessionParser.d.ts +18 -0
- package/dist/providers/opencode/OpenCodeSessionParser.d.ts.map +1 -0
- package/dist/providers/opencode/OpenCodeSessionParser.js +104 -0
- package/dist/providers/opencode/OpenCodeSessionParser.js.map +1 -0
- package/dist/runtime/herdr/HerdrAgentDiscovery.d.ts +18 -0
- package/dist/runtime/herdr/HerdrAgentDiscovery.d.ts.map +1 -0
- package/dist/runtime/herdr/HerdrAgentDiscovery.js +183 -0
- package/dist/runtime/herdr/HerdrAgentDiscovery.js.map +1 -0
- package/dist/runtime/herdr/HerdrAgentRuntime.d.ts +5 -0
- package/dist/runtime/herdr/HerdrAgentRuntime.d.ts.map +1 -1
- package/dist/runtime/herdr/HerdrAgentRuntime.js +26 -8
- package/dist/runtime/herdr/HerdrAgentRuntime.js.map +1 -1
- package/dist/runtime/herdr/HerdrResponseParsers.d.ts +2 -0
- package/dist/runtime/herdr/HerdrResponseParsers.d.ts.map +1 -1
- package/dist/runtime/herdr/HerdrResponseParsers.js +12 -1
- package/dist/runtime/herdr/HerdrResponseParsers.js.map +1 -1
- package/dist/utils/AgentRegistry.d.ts.map +1 -1
- package/dist/utils/AgentRegistry.js +5 -5
- package/dist/utils/AgentRegistry.js.map +1 -1
- package/package.json +1 -1
- package/src/AgentManager.ts +67 -5
- package/src/__tests__/AgentManager.test.ts +231 -5
- package/src/__tests__/capacity/codex.test.ts +94 -26
- package/src/__tests__/capacity/fixtures/zai-auth.json +6 -0
- package/src/__tests__/capacity/fixtures/zai-quota-invalid.json +7 -0
- package/src/__tests__/capacity/fixtures/zai-quota.json +38 -0
- package/src/__tests__/capacity/index.test.ts +10 -3
- package/src/__tests__/capacity/zai.test.ts +186 -0
- package/src/__tests__/{adapters → providers/copilot}/CopilotAdapter.test.ts +13 -16
- package/src/__tests__/{adapters → providers/gemini}/GeminiCliAdapter.test.ts +39 -31
- package/src/__tests__/providers/opencode/OpenCodeAdapter.test.ts +197 -0
- package/src/__tests__/providers/opencode/OpenCodeAgentMapper.test.ts +83 -0
- package/src/__tests__/providers/opencode/OpenCodeSessionLocator.test.ts +84 -0
- package/src/__tests__/providers/opencode/OpenCodeSessionParser.test.ts +148 -0
- package/src/__tests__/runtime/HerdrAgentDiscovery.test.ts +131 -0
- package/src/__tests__/runtime/HerdrAgentRuntime.test.ts +20 -1
- package/src/__tests__/utils/AgentRegistry.test.ts +20 -10
- package/src/adapters/index.ts +3 -3
- package/src/capacity/codex.ts +96 -28
- package/src/capacity/index.ts +29 -11
- package/src/capacity/types.ts +8 -0
- package/src/capacity/zai.ts +237 -0
- package/src/index.ts +18 -6
- package/src/providers/copilot/CopilotAdapter.ts +145 -0
- package/src/providers/copilot/CopilotAgentMapper.ts +36 -0
- package/src/providers/copilot/CopilotSessionLocator.ts +57 -0
- package/src/providers/copilot/CopilotSessionParser.ts +289 -0
- package/src/providers/gemini/GeminiAgentMapper.ts +36 -0
- package/src/providers/gemini/GeminiCliAdapter.ts +266 -0
- package/src/providers/gemini/GeminiSessionLocator.ts +183 -0
- package/src/providers/gemini/GeminiSessionParser.ts +271 -0
- package/src/providers/opencode/OpenCodeAdapter.ts +112 -0
- package/src/providers/opencode/OpenCodeAgentMapper.ts +61 -0
- package/src/providers/opencode/OpenCodeSessionLocator.ts +123 -0
- package/src/providers/opencode/OpenCodeSessionParser.ts +145 -0
- package/src/runtime/herdr/HerdrAgentDiscovery.ts +178 -0
- package/src/runtime/herdr/HerdrAgentRuntime.ts +33 -7
- package/src/runtime/herdr/HerdrResponseParsers.ts +11 -1
- package/src/utils/AgentRegistry.ts +8 -6
- package/dist/__tests__/adapters/CopilotAdapter.test.js.map +0 -1
- package/dist/__tests__/adapters/GeminiCliAdapter.test.js.map +0 -1
- package/dist/__tests__/adapters/OpenCodeAdapter.test.js +0 -635
- package/dist/__tests__/adapters/OpenCodeAdapter.test.js.map +0 -1
- package/dist/adapters/CopilotAdapter.d.ts.map +0 -1
- package/dist/adapters/CopilotAdapter.js +0 -329
- package/dist/adapters/CopilotAdapter.js.map +0 -1
- package/dist/adapters/GeminiCliAdapter.d.ts +0 -98
- package/dist/adapters/GeminiCliAdapter.d.ts.map +0 -1
- package/dist/adapters/GeminiCliAdapter.js +0 -513
- package/dist/adapters/GeminiCliAdapter.js.map +0 -1
- package/dist/adapters/OpenCodeAdapter.d.ts.map +0 -1
- package/dist/adapters/OpenCodeAdapter.js +0 -286
- package/dist/adapters/OpenCodeAdapter.js.map +0 -1
- package/src/__tests__/adapters/OpenCodeAdapter.test.ts +0 -543
- package/src/adapters/CopilotAdapter.ts +0 -483
- package/src/adapters/GeminiCliAdapter.ts +0 -699
- package/src/adapters/OpenCodeAdapter.ts +0 -369
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/__tests__/utils/AgentRegistry.test.ts"],"sourcesContent":["import fs from \"fs\";\nimport os from \"os\";\nimport path from \"path\";\nimport Database from \"better-sqlite3\";\nimport {\n AgentRegistry,\n RenameNotFoundError,\n RenameConflictError,\n type RegistryEntry,\n} from \"../../utils/AgentRegistry.js\";\n\nfunction makeEntry(over: Partial<RegistryEntry> = {}): RegistryEntry {\n return {\n name: \"agent1\",\n type: \"claude\",\n pid: process.pid,\n cwd: \"/tmp\",\n startedAt: \"2026-05-30T00:00:00.000Z\",\n sessionId: \"sid-1\",\n sessionFilePath: \"/tmp/session.jsonl\",\n pinned: false,\n runtime: \"tmux\",\n runtimeRef: { session: \"agent1\" },\n ...over,\n };\n}\n\ndescribe(\"AgentRegistry\", () => {\n let tmpDir: string;\n let regPath: string;\n let registry: AgentRegistry;\n\n beforeEach(() => {\n tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), \"agent-registry-\"));\n regPath = path.join(tmpDir, \"nested\", \"agents.json\");\n registry = new AgentRegistry(regPath);\n });\n\n afterEach(() => {\n vi.restoreAllMocks();\n fs.rmSync(tmpDir, { recursive: true, force: true });\n });\n\n describe(\"register\", () => {\n it(\"creates the SQLite database and parent directory if missing\", () => {\n registry.register(makeEntry());\n expect(fs.existsSync(regPath.replace(/\\.json$/, \".db\"))).toBe(true);\n expect(registry.list()[0].name).toBe(\"agent1\");\n });\n\n it(\"appends a new entry when name is unique\", () => {\n registry.register(makeEntry({ name: \"a\" }));\n registry.register(makeEntry({ name: \"b\", pid: process.ppid }));\n expect(registry.list()).toHaveLength(2);\n });\n\n it(\"upserts in place when type and pid already exist\", () => {\n registry.register(makeEntry({ name: \"a\", pid: process.pid }));\n registry.register(makeEntry({ name: \"fallback\", pid: process.pid, runtimeRef: null }));\n const all = registry.list();\n expect(all).toHaveLength(1);\n expect(all[0].pid).toBe(process.pid);\n expect(all[0].name).toBe(\"a\");\n });\n\n it(\"does not write through the legacy fixed .tmp path\", () => {\n registry.register(makeEntry());\n expect(fs.existsSync(`${regPath}.tmp`)).toBe(false);\n });\n\n it(\"persists session fields\", () => {\n registry.register(makeEntry({ sessionId: \"sid-xyz\", sessionFilePath: \"/foo/bar.jsonl\" }));\n const saved = registry.list()[0];\n expect(saved.sessionId).toBe(\"sid-xyz\");\n expect(saved.sessionFilePath).toBe(\"/foo/bar.jsonl\");\n });\n\n it(\"persists runtime metadata for Herdr-backed entries\", () => {\n const runtimeRef = { session: \"default\", paneId: \"w1:p2\", agentName: \"reviewer\" };\n\n registry.register(\n makeEntry({\n name: \"reviewer\",\n runtime: \"herdr\",\n runtimeRef,\n }),\n );\n\n expect(registry.lookup(\"reviewer\")).toMatchObject({\n runtime: \"herdr\",\n runtimeRef,\n });\n });\n\n it(\"lets a Herdr managed start replace an existing same-pid name\", () => {\n const runtimeRef = { session: \"default\", paneId: \"w1:p2\", agentName: \"requested-name\" };\n\n registry.register(makeEntry({ name: \"old-name\", pid: process.pid }));\n registry.register(\n makeEntry({\n name: \"requested-name\",\n pid: process.pid,\n runtime: \"herdr\",\n runtimeRef,\n }),\n );\n\n expect(registry.lookup(\"old-name\")).toBeNull();\n expect(registry.lookup(\"requested-name\")).toMatchObject({\n pid: process.pid,\n runtime: \"herdr\",\n runtimeRef,\n });\n });\n\n it(\"preserves existing runtime ref when incoming runtime ref is empty\", () => {\n registry.register(makeEntry({ name: \"a\", runtimeRef: { session: \"pinned\" } }));\n registry.register(makeEntry({ name: \"fallback\", runtimeRef: null, pid: process.pid }));\n const saved = registry.lookup(\"a\");\n expect(saved?.runtimeRef).toEqual({ session: \"pinned\" });\n expect(saved?.pid).toBe(process.pid);\n });\n\n it(\"defaults an empty tmux runtime ref from the tmux session\", () => {\n registry.register(makeEntry({ name: \"a\", runtimeRef: null }));\n\n expect(registry.lookup(\"a\")?.runtimeRef).toBeNull();\n });\n\n it(\"lets a managed start entry replace a generated fallback for the same pid\", () => {\n registry.register(makeEntry({ name: `ai-devkit-${process.pid}`, runtimeRef: null }));\n registry.register(makeEntry({ name: \"custom-name\", runtimeRef: { session: \"custom-name\" } }));\n expect(registry.lookup(\"custom-name\")?.runtimeRef).toEqual({ session: \"custom-name\" });\n expect(registry.lookup(`ai-devkit-${process.pid}`)).toBeNull();\n expect(registry.list()).toHaveLength(1);\n });\n\n it(\"preserves an existing name conflict when its probe fails with EPERM\", () => {\n registry.register(makeEntry({ name: \"claimed-name\", pid: process.pid }));\n vi.spyOn(process, \"kill\").mockImplementation(() => {\n throw Object.assign(new Error(\"operation not permitted\"), { code: \"EPERM\" });\n });\n\n expect(() =>\n registry.register(\n makeEntry({\n name: \"claimed-name\",\n pid: process.pid + 1,\n }),\n ),\n ).toThrow();\n expect(registry.lookup(\"claimed-name\")?.pid).toBe(process.pid);\n });\n });\n\n describe(\"registerBatch\", () => {\n it(\"is a no-op on empty array\", () => {\n registry.registerBatch([]);\n expect(fs.existsSync(regPath)).toBe(false);\n });\n\n it(\"upserts multiple entries in a single batch\", () => {\n registry.registerBatch([\n makeEntry({ name: \"a\" }),\n makeEntry({ name: \"b\", pid: process.pid + 1 }),\n makeEntry({ name: \"c\", pid: process.pid + 2 }),\n ]);\n expect(registry.list()).toHaveLength(3);\n });\n\n it(\"applies the tmux runtime ref merge per entry\", () => {\n registry.register(makeEntry({ name: \"a\", runtimeRef: { session: \"pinned\" } }));\n registry.registerBatch([\n makeEntry({ name: \"fallback\", runtimeRef: null, pid: process.pid }),\n makeEntry({ name: \"b\", runtimeRef: null, pid: process.pid + 1 }),\n ]);\n expect(registry.lookup(\"a\")?.runtimeRef).toEqual({ session: \"pinned\" });\n expect(registry.lookup(\"a\")?.pid).toBe(process.pid);\n expect(registry.lookup(\"b\")?.runtimeRef).toBeNull();\n });\n\n it(\"handles concurrent registry instances without duplicate pid rows\", () => {\n const other = new AgentRegistry(regPath);\n registry.register(makeEntry({ name: `ai-devkit-${process.pid}`, runtimeRef: null }));\n other.register(makeEntry({ name: \"custom-name\", runtimeRef: { session: \"custom-name\" } }));\n registry.register(makeEntry({ name: `ai-devkit-${process.pid}`, runtimeRef: null }));\n\n expect(registry.list()).toHaveLength(1);\n expect(registry.lookup(\"custom-name\")?.pid).toBe(process.pid);\n });\n\n it(\"cleans up a cross-type row when its pid has been reused\", () => {\n registry.register(makeEntry({ name: \"old-claude\", type: \"claude\", pid: process.pid }));\n\n registry.register(\n makeEntry({\n name: \"new-codex\",\n type: \"codex\",\n pid: process.pid,\n runtimeRef: null,\n }),\n );\n\n expect(registry.lookup(\"old-claude\")).toBeNull();\n expect(registry.lookup(\"new-codex\")).toMatchObject({ type: \"codex\", pid: process.pid });\n expect(registry.list()).toHaveLength(1);\n });\n\n it(\"rolls back the whole batch when a live name conflict rejects one entry\", () => {\n registry.register(makeEntry({ name: \"taken\", pid: process.pid }));\n\n expect(() =>\n registry.registerBatch([\n makeEntry({ name: \"fresh\", pid: 999998 }),\n makeEntry({ name: \"taken\", type: \"codex\", pid: 999997 }),\n ]),\n ).toThrow(/UNIQUE constraint failed/);\n\n expect(registry.lookup(\"fresh\")).toBeNull();\n expect(registry.lookup(\"taken\")?.pid).toBe(process.pid);\n });\n });\n\n describe(\"lookup\", () => {\n it(\"returns null when name not found\", () => {\n expect(registry.lookup(\"missing\")).toBeNull();\n });\n\n it(\"returns the entry when name matches\", () => {\n registry.register(makeEntry({ name: \"a\" }));\n expect(registry.lookup(\"a\")?.name).toBe(\"a\");\n });\n });\n\n describe(\"pinning\", () => {\n it(\"defaults new rows to unpinned and toggles the persisted state\", () => {\n registry.register(makeEntry());\n\n expect(registry.lookup(\"agent1\")?.pinned).toBe(false);\n expect(registry.togglePin(\"claude\", process.pid)).toBe(true);\n expect(registry.lookup(\"agent1\")?.pinned).toBe(true);\n expect(registry.togglePin(\"claude\", process.pid)).toBe(false);\n expect(registry.lookup(\"agent1\")?.pinned).toBe(false);\n });\n\n it(\"updates existing recency when toggled\", () => {\n let now = new Date(\"2026-08-16T10:00:00.000Z\");\n const clocked = new AgentRegistry(regPath, { now: () => now });\n clocked.register(makeEntry());\n now = new Date(\"2026-08-16T10:01:00.000Z\");\n\n clocked.togglePin(\"claude\", process.pid);\n\n expect(clocked.lookup(\"agent1\")?.updatedAt).toBe(now.toISOString());\n const db = new Database(regPath.replace(/\\.json$/, \".db\"), { readonly: true });\n const row = db\n .prepare(\"SELECT updated_at FROM agents WHERE type = ? AND pid = ?\")\n .get(\"claude\", process.pid) as { updated_at: string };\n db.close();\n expect(row.updated_at).toBe(now.toISOString());\n });\n\n it(\"returns null when the process row has disappeared\", () => {\n expect(registry.togglePin(\"claude\", 999999)).toBeNull();\n });\n\n it(\"preserves a pin when poll registration updates the row\", () => {\n registry.register(makeEntry({ sessionId: \"before\" }));\n registry.togglePin(\"claude\", process.pid);\n\n registry.register(makeEntry({ sessionId: \"after\" }));\n\n expect(registry.lookup(\"agent1\")).toMatchObject({ sessionId: \"after\", pinned: true });\n });\n\n it(\"preserves a pin through rename\", () => {\n registry.register(makeEntry({ name: \"before\" }));\n registry.togglePin(\"claude\", process.pid);\n\n registry.rename(\"before\", \"after\");\n\n expect(registry.lookup(\"after\")?.pinned).toBe(true);\n });\n\n it(\"removes the pin with a pruned process row\", () => {\n registry.register(makeEntry({ pid: 999999 }));\n registry.togglePin(\"claude\", 999999);\n\n registry.prune();\n\n expect(registry.lookup(\"agent1\")).toBeNull();\n });\n\n it(\"reports a clear error when a readonly registry toggles a pin\", () => {\n registry.register(makeEntry());\n const readonlyRegistry = new AgentRegistry(regPath, { readonly: true });\n\n expect(() => readonlyRegistry.togglePin(\"claude\", process.pid)).toThrow(/readonly/i);\n });\n });\n\n describe(\"list\", () => {\n it(\"returns empty array when database does not contain entries\", () => {\n expect(registry.list()).toEqual([]);\n });\n\n it(\"ignores existing legacy agents.json entries\", () => {\n const legacyEntry = makeEntry({ name: \"legacy\", runtimeRef: { session: \"legacy\" } });\n fs.mkdirSync(path.dirname(regPath), { recursive: true });\n fs.writeFileSync(regPath, JSON.stringify({ entries: [legacyEntry] }), \"utf8\");\n\n const legacyRegistry = new AgentRegistry(regPath);\n\n expect(legacyRegistry.lookup(\"legacy\")).toBeNull();\n expect(legacyRegistry.list()).toEqual([]);\n expect(fs.existsSync(regPath.replace(/\\.json$/, \".db\"))).toBe(true);\n });\n\n it(\"reads pre-runtime SQLite rows as tmux-backed records\", () => {\n const dbPath = regPath.replace(/\\.json$/, \".db\");\n fs.mkdirSync(path.dirname(dbPath), { recursive: true });\n fs.rmSync(dbPath, { force: true });\n fs.rmSync(`${dbPath}-wal`, { force: true });\n fs.rmSync(`${dbPath}-shm`, { force: true });\n const db = new Database(dbPath);\n db.exec(`\n CREATE TABLE agents (\n type TEXT NOT NULL,\n pid INTEGER NOT NULL,\n name TEXT NOT NULL UNIQUE,\n tmux_session TEXT NOT NULL DEFAULT '',\n cwd TEXT NOT NULL DEFAULT '',\n started_at TEXT NOT NULL,\n session_id TEXT NOT NULL DEFAULT '',\n session_file_path TEXT NOT NULL DEFAULT '',\n updated_at TEXT NOT NULL,\n PRIMARY KEY (type, pid)\n );\n INSERT INTO agents (\n type, pid, name, tmux_session, cwd, started_at, session_id, session_file_path, updated_at\n ) VALUES (\n 'claude', ${process.pid}, 'legacy-sqlite', 'legacy-sqlite', '/tmp',\n '2026-05-30T00:00:00.000Z', 'sid-1', '/tmp/session.jsonl', '2026-05-30T00:00:00.000Z'\n );\n PRAGMA user_version = 1;\n `);\n db.close();\n\n const migratedRegistry = new AgentRegistry(regPath);\n\n expect(migratedRegistry.lookup(\"legacy-sqlite\")).toMatchObject({\n runtime: \"tmux\",\n runtimeRef: { session: \"legacy-sqlite\" },\n });\n });\n });\n\n describe(\"isAlive\", () => {\n it(\"returns true for the current process\", () => {\n expect(registry.isAlive(makeEntry({ pid: process.pid }))).toBe(true);\n });\n\n it(\"returns false for a PID that does not exist\", () => {\n expect(registry.isAlive(makeEntry({ pid: 999999 }))).toBe(false);\n });\n\n it(\"returns true when the process probe is forbidden with EPERM\", () => {\n vi.spyOn(process, \"kill\").mockImplementation(() => {\n throw Object.assign(new Error(\"operation not permitted\"), { code: \"EPERM\" });\n });\n\n expect(registry.isAlive(makeEntry())).toBe(true);\n });\n\n it(\"returns false when the process probe reports ESRCH\", () => {\n vi.spyOn(process, \"kill\").mockImplementation(() => {\n throw Object.assign(new Error(\"no such process\"), { code: \"ESRCH\" });\n });\n\n expect(registry.isAlive(makeEntry())).toBe(false);\n });\n\n it(\"returns true when the process probe fails without a definitive error code\", () => {\n vi.spyOn(process, \"kill\").mockImplementation(() => {\n throw new Error(\"indeterminate probe failure\");\n });\n\n expect(registry.isAlive(makeEntry())).toBe(true);\n });\n });\n\n describe(\"prune\", () => {\n it(\"removes entries whose PIDs are dead\", () => {\n registry.register(makeEntry({ name: \"alive\", pid: process.pid }));\n registry.register(makeEntry({ name: \"dead\", pid: 999999 }));\n registry.prune();\n const remaining = registry.list();\n expect(remaining).toHaveLength(1);\n expect(remaining[0].name).toBe(\"alive\");\n });\n\n it(\"is a no-op when all entries are alive\", () => {\n registry.register(makeEntry({ pid: process.pid }));\n const before = registry.list();\n registry.prune();\n const after = registry.list();\n expect(after).toEqual(before);\n });\n\n it(\"preserves entries when liveness probing fails with EPERM\", () => {\n registry.register(makeEntry({ name: \"custom-name\", runtimeRef: { session: \"tmux-custom\" } }));\n vi.spyOn(process, \"kill\").mockImplementation(() => {\n throw Object.assign(new Error(\"operation not permitted\"), { code: \"EPERM\" });\n });\n\n registry.prune();\n\n expect(registry.lookup(\"custom-name\")).toMatchObject({\n name: \"custom-name\",\n runtimeRef: { session: \"tmux-custom\" },\n });\n });\n\n it(\"removes entries when liveness probing fails with ESRCH\", () => {\n registry.register(makeEntry({ name: \"dead\" }));\n vi.spyOn(process, \"kill\").mockImplementation(() => {\n throw Object.assign(new Error(\"no such process\"), { code: \"ESRCH\" });\n });\n\n registry.prune();\n\n expect(registry.lookup(\"dead\")).toBeNull();\n });\n\n it(\"does nothing when file is missing\", () => {\n expect(() => registry.prune()).not.toThrow();\n });\n\n it(\"keeps forced prune available before the passive cadence is due\", () => {\n let nowMs = Date.parse(\"2026-08-14T10:00:00.000Z\");\n const clocked = new AgentRegistry(regPath, {\n now: () => new Date(nowMs),\n pruneIntervalMs: 30_000,\n });\n clocked.register(makeEntry({ name: \"forced\", pid: process.pid }));\n const alive = vi.spyOn(clocked, \"isAlive\").mockReturnValue(true);\n clocked.pruneIfDue();\n alive.mockReturnValue(false);\n nowMs += 1;\n\n clocked.prune();\n\n expect(alive).toHaveBeenCalledTimes(2);\n expect(clocked.lookup(\"forced\")).toBeNull();\n });\n });\n\n describe(\"default()\", () => {\n it(\"returns a singleton instance\", () => {\n expect(AgentRegistry.default()).toBe(AgentRegistry.default());\n });\n });\n\n describe(\"rename\", () => {\n it(\"updates the name of an existing entry\", () => {\n registry.register(makeEntry({ name: \"old-name\", pid: process.pid }));\n registry.rename(\"old-name\", \"new-name\");\n expect(registry.lookup(\"new-name\")?.name).toBe(\"new-name\");\n expect(registry.lookup(\"old-name\")).toBeNull();\n });\n\n it(\"preserves all other fields on the renamed entry\", () => {\n registry.register(\n makeEntry({\n name: \"old-name\",\n pid: process.pid,\n runtimeRef: { session: \"old-name\" },\n cwd: \"/my/cwd\",\n }),\n );\n registry.rename(\"old-name\", \"new-name\");\n const entry = registry.lookup(\"new-name\");\n expect(entry?.runtimeRef).toEqual({ session: \"old-name\" });\n expect(entry?.cwd).toBe(\"/my/cwd\");\n expect(entry?.pid).toBe(process.pid);\n });\n\n it(\"throws RenameNotFoundError when current name does not exist\", () => {\n expect(() => registry.rename(\"ghost\", \"new-name\")).toThrow(RenameNotFoundError);\n });\n\n it(\"throws RenameConflictError when new name is already in use by a live entry\", () => {\n registry.register(makeEntry({ name: \"agent-a\", pid: process.pid }));\n registry.register(makeEntry({ name: \"agent-b\", pid: process.ppid }));\n expect(() => registry.rename(\"agent-a\", \"agent-b\")).toThrow(RenameConflictError);\n });\n\n it(\"throws RenameConflictError when the conflicting entry probe fails with EPERM\", () => {\n registry.register(makeEntry({ name: \"agent-a\", pid: process.pid }));\n registry.register(makeEntry({ name: \"agent-b\", pid: process.ppid }));\n vi.spyOn(process, \"kill\").mockImplementation(() => {\n throw Object.assign(new Error(\"operation not permitted\"), { code: \"EPERM\" });\n });\n\n expect(() => registry.rename(\"agent-a\", \"agent-b\")).toThrow(RenameConflictError);\n expect(registry.lookup(\"agent-b\")?.pid).toBe(process.ppid);\n });\n\n it(\"succeeds when new name exists only as a stale (dead) entry\", () => {\n registry.register(makeEntry({ name: \"agent-a\", pid: process.pid }));\n registry.register(makeEntry({ name: \"agent-b\", pid: 999999 }));\n expect(() => registry.rename(\"agent-a\", \"agent-b\")).not.toThrow();\n expect(registry.lookup(\"agent-b\")?.pid).toBe(process.pid);\n });\n\n it(\"does not create the legacy fixed .tmp path on rename\", () => {\n registry.register(makeEntry({ name: \"old-name\", pid: process.pid }));\n registry.rename(\"old-name\", \"new-name\");\n expect(fs.existsSync(`${regPath}.tmp`)).toBe(false);\n });\n });\n});\n"],"names":["fs","os","path","Database","AgentRegistry","RenameNotFoundError","RenameConflictError","makeEntry","over","name","type","pid","process","cwd","startedAt","sessionId","sessionFilePath","pinned","runtime","runtimeRef","session","describe","tmpDir","regPath","registry","beforeEach","mkdtempSync","join","tmpdir","afterEach","vi","restoreAllMocks","rmSync","recursive","force","it","register","expect","existsSync","replace","toBe","list","ppid","toHaveLength","all","saved","paneId","agentName","lookup","toMatchObject","toBeNull","toEqual","spyOn","mockImplementation","Object","assign","Error","code","toThrow","registerBatch","other","togglePin","now","Date","clocked","updatedAt","toISOString","db","readonly","row","prepare","get","close","updated_at","rename","prune","readonlyRegistry","legacyEntry","mkdirSync","dirname","writeFileSync","JSON","stringify","entries","legacyRegistry","dbPath","exec","migratedRegistry","isAlive","remaining","before","after","not","nowMs","parse","pruneIntervalMs","alive","mockReturnValue","pruneIfDue","toHaveBeenCalledTimes","default","entry"],"mappings":"AAAA,OAAOA,QAAQ,KAAK;AACpB,OAAOC,QAAQ,KAAK;AACpB,OAAOC,UAAU,OAAO;AACxB,OAAOC,cAAc,iBAAiB;AACtC,SACEC,aAAa,EACbC,mBAAmB,EACnBC,mBAAmB,QAEd,+BAA+B;AAEtC,SAASC,UAAUC,OAA+B,CAAC,CAAC;IAClD,OAAO;QACLC,MAAM;QACNC,MAAM;QACNC,KAAKC,QAAQD,GAAG;QAChBE,KAAK;QACLC,WAAW;QACXC,WAAW;QACXC,iBAAiB;QACjBC,QAAQ;QACRC,SAAS;QACTC,YAAY;YAAEC,SAAS;QAAS;QAChC,GAAGZ,IAAI;IACT;AACF;AAEAa,SAAS,iBAAiB;IACxB,IAAIC;IACJ,IAAIC;IACJ,IAAIC;IAEJC,WAAW;QACTH,SAAStB,GAAG0B,WAAW,CAACxB,KAAKyB,IAAI,CAAC1B,GAAG2B,MAAM,IAAI;QAC/CL,UAAUrB,KAAKyB,IAAI,CAACL,QAAQ,UAAU;QACtCE,WAAW,IAAIpB,cAAcmB;IAC/B;IAEAM,UAAU;QACRC,GAAGC,eAAe;QAClB/B,GAAGgC,MAAM,CAACV,QAAQ;YAAEW,WAAW;YAAMC,OAAO;QAAK;IACnD;IAEAb,SAAS,YAAY;QACnBc,GAAG,+DAA+D;YAChEX,SAASY,QAAQ,CAAC7B;YAClB8B,OAAOrC,GAAGsC,UAAU,CAACf,QAAQgB,OAAO,CAAC,WAAW,SAASC,IAAI,CAAC;YAC9DH,OAAOb,SAASiB,IAAI,EAAE,CAAC,EAAE,CAAChC,IAAI,EAAE+B,IAAI,CAAC;QACvC;QAEAL,GAAG,2CAA2C;YAC5CX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;YAAI;YACxCe,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAKE,KAAKC,QAAQ8B,IAAI;YAAC;YAC3DL,OAAOb,SAASiB,IAAI,IAAIE,YAAY,CAAC;QACvC;QAEAR,GAAG,oDAAoD;YACrDX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAKE,KAAKC,QAAQD,GAAG;YAAC;YAC1Da,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAYE,KAAKC,QAAQD,GAAG;gBAAEQ,YAAY;YAAK;YACnF,MAAMyB,MAAMpB,SAASiB,IAAI;YACzBJ,OAAOO,KAAKD,YAAY,CAAC;YACzBN,OAAOO,GAAG,CAAC,EAAE,CAACjC,GAAG,EAAE6B,IAAI,CAAC5B,QAAQD,GAAG;YACnC0B,OAAOO,GAAG,CAAC,EAAE,CAACnC,IAAI,EAAE+B,IAAI,CAAC;QAC3B;QAEAL,GAAG,qDAAqD;YACtDX,SAASY,QAAQ,CAAC7B;YAClB8B,OAAOrC,GAAGsC,UAAU,CAAC,GAAGf,QAAQ,IAAI,CAAC,GAAGiB,IAAI,CAAC;QAC/C;QAEAL,GAAG,2BAA2B;YAC5BX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEQ,WAAW;gBAAWC,iBAAiB;YAAiB;YACtF,MAAM6B,QAAQrB,SAASiB,IAAI,EAAE,CAAC,EAAE;YAChCJ,OAAOQ,MAAM9B,SAAS,EAAEyB,IAAI,CAAC;YAC7BH,OAAOQ,MAAM7B,eAAe,EAAEwB,IAAI,CAAC;QACrC;QAEAL,GAAG,sDAAsD;YACvD,MAAMhB,aAAa;gBAAEC,SAAS;gBAAW0B,QAAQ;gBAASC,WAAW;YAAW;YAEhFvB,SAASY,QAAQ,CACf7B,UAAU;gBACRE,MAAM;gBACNS,SAAS;gBACTC;YACF;YAGFkB,OAAOb,SAASwB,MAAM,CAAC,aAAaC,aAAa,CAAC;gBAChD/B,SAAS;gBACTC;YACF;QACF;QAEAgB,GAAG,gEAAgE;YACjE,MAAMhB,aAAa;gBAAEC,SAAS;gBAAW0B,QAAQ;gBAASC,WAAW;YAAiB;YAEtFvB,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAYE,KAAKC,QAAQD,GAAG;YAAC;YACjEa,SAASY,QAAQ,CACf7B,UAAU;gBACRE,MAAM;gBACNE,KAAKC,QAAQD,GAAG;gBAChBO,SAAS;gBACTC;YACF;YAGFkB,OAAOb,SAASwB,MAAM,CAAC,aAAaE,QAAQ;YAC5Cb,OAAOb,SAASwB,MAAM,CAAC,mBAAmBC,aAAa,CAAC;gBACtDtC,KAAKC,QAAQD,GAAG;gBAChBO,SAAS;gBACTC;YACF;QACF;QAEAgB,GAAG,qEAAqE;YACtEX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAKU,YAAY;oBAAEC,SAAS;gBAAS;YAAE;YAC3EI,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAYU,YAAY;gBAAMR,KAAKC,QAAQD,GAAG;YAAC;YACnF,MAAMkC,QAAQrB,SAASwB,MAAM,CAAC;YAC9BX,OAAOQ,OAAO1B,YAAYgC,OAAO,CAAC;gBAAE/B,SAAS;YAAS;YACtDiB,OAAOQ,OAAOlC,KAAK6B,IAAI,CAAC5B,QAAQD,GAAG;QACrC;QAEAwB,GAAG,4DAA4D;YAC7DX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAKU,YAAY;YAAK;YAE1DkB,OAAOb,SAASwB,MAAM,CAAC,MAAM7B,YAAY+B,QAAQ;QACnD;QAEAf,GAAG,4EAA4E;YAC7EX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM,CAAC,UAAU,EAAEG,QAAQD,GAAG,EAAE;gBAAEQ,YAAY;YAAK;YACjFK,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAeU,YAAY;oBAAEC,SAAS;gBAAc;YAAE;YAC1FiB,OAAOb,SAASwB,MAAM,CAAC,gBAAgB7B,YAAYgC,OAAO,CAAC;gBAAE/B,SAAS;YAAc;YACpFiB,OAAOb,SAASwB,MAAM,CAAC,CAAC,UAAU,EAAEpC,QAAQD,GAAG,EAAE,GAAGuC,QAAQ;YAC5Db,OAAOb,SAASiB,IAAI,IAAIE,YAAY,CAAC;QACvC;QAEAR,GAAG,uEAAuE;YACxEX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAgBE,KAAKC,QAAQD,GAAG;YAAC;YACrEmB,GAAGsB,KAAK,CAACxC,SAAS,QAAQyC,kBAAkB,CAAC;gBAC3C,MAAMC,OAAOC,MAAM,CAAC,IAAIC,MAAM,4BAA4B;oBAAEC,MAAM;gBAAQ;YAC5E;YAEApB,OAAO,IACLb,SAASY,QAAQ,CACf7B,UAAU;oBACRE,MAAM;oBACNE,KAAKC,QAAQD,GAAG,GAAG;gBACrB,KAEF+C,OAAO;YACTrB,OAAOb,SAASwB,MAAM,CAAC,iBAAiBrC,KAAK6B,IAAI,CAAC5B,QAAQD,GAAG;QAC/D;IACF;IAEAU,SAAS,iBAAiB;QACxBc,GAAG,6BAA6B;YAC9BX,SAASmC,aAAa,CAAC,EAAE;YACzBtB,OAAOrC,GAAGsC,UAAU,CAACf,UAAUiB,IAAI,CAAC;QACtC;QAEAL,GAAG,8CAA8C;YAC/CX,SAASmC,aAAa,CAAC;gBACrBpD,UAAU;oBAAEE,MAAM;gBAAI;gBACtBF,UAAU;oBAAEE,MAAM;oBAAKE,KAAKC,QAAQD,GAAG,GAAG;gBAAE;gBAC5CJ,UAAU;oBAAEE,MAAM;oBAAKE,KAAKC,QAAQD,GAAG,GAAG;gBAAE;aAC7C;YACD0B,OAAOb,SAASiB,IAAI,IAAIE,YAAY,CAAC;QACvC;QAEAR,GAAG,gDAAgD;YACjDX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAKU,YAAY;oBAAEC,SAAS;gBAAS;YAAE;YAC3EI,SAASmC,aAAa,CAAC;gBACrBpD,UAAU;oBAAEE,MAAM;oBAAYU,YAAY;oBAAMR,KAAKC,QAAQD,GAAG;gBAAC;gBACjEJ,UAAU;oBAAEE,MAAM;oBAAKU,YAAY;oBAAMR,KAAKC,QAAQD,GAAG,GAAG;gBAAE;aAC/D;YACD0B,OAAOb,SAASwB,MAAM,CAAC,MAAM7B,YAAYgC,OAAO,CAAC;gBAAE/B,SAAS;YAAS;YACrEiB,OAAOb,SAASwB,MAAM,CAAC,MAAMrC,KAAK6B,IAAI,CAAC5B,QAAQD,GAAG;YAClD0B,OAAOb,SAASwB,MAAM,CAAC,MAAM7B,YAAY+B,QAAQ;QACnD;QAEAf,GAAG,oEAAoE;YACrE,MAAMyB,QAAQ,IAAIxD,cAAcmB;YAChCC,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM,CAAC,UAAU,EAAEG,QAAQD,GAAG,EAAE;gBAAEQ,YAAY;YAAK;YACjFyC,MAAMxB,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAeU,YAAY;oBAAEC,SAAS;gBAAc;YAAE;YACvFI,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM,CAAC,UAAU,EAAEG,QAAQD,GAAG,EAAE;gBAAEQ,YAAY;YAAK;YAEjFkB,OAAOb,SAASiB,IAAI,IAAIE,YAAY,CAAC;YACrCN,OAAOb,SAASwB,MAAM,CAAC,gBAAgBrC,KAAK6B,IAAI,CAAC5B,QAAQD,GAAG;QAC9D;QAEAwB,GAAG,2DAA2D;YAC5DX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAcC,MAAM;gBAAUC,KAAKC,QAAQD,GAAG;YAAC;YAEnFa,SAASY,QAAQ,CACf7B,UAAU;gBACRE,MAAM;gBACNC,MAAM;gBACNC,KAAKC,QAAQD,GAAG;gBAChBQ,YAAY;YACd;YAGFkB,OAAOb,SAASwB,MAAM,CAAC,eAAeE,QAAQ;YAC9Cb,OAAOb,SAASwB,MAAM,CAAC,cAAcC,aAAa,CAAC;gBAAEvC,MAAM;gBAASC,KAAKC,QAAQD,GAAG;YAAC;YACrF0B,OAAOb,SAASiB,IAAI,IAAIE,YAAY,CAAC;QACvC;QAEAR,GAAG,0EAA0E;YAC3EX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAASE,KAAKC,QAAQD,GAAG;YAAC;YAE9D0B,OAAO,IACLb,SAASmC,aAAa,CAAC;oBACrBpD,UAAU;wBAAEE,MAAM;wBAASE,KAAK;oBAAO;oBACvCJ,UAAU;wBAAEE,MAAM;wBAASC,MAAM;wBAASC,KAAK;oBAAO;iBACvD,GACD+C,OAAO,CAAC;YAEVrB,OAAOb,SAASwB,MAAM,CAAC,UAAUE,QAAQ;YACzCb,OAAOb,SAASwB,MAAM,CAAC,UAAUrC,KAAK6B,IAAI,CAAC5B,QAAQD,GAAG;QACxD;IACF;IAEAU,SAAS,UAAU;QACjBc,GAAG,oCAAoC;YACrCE,OAAOb,SAASwB,MAAM,CAAC,YAAYE,QAAQ;QAC7C;QAEAf,GAAG,uCAAuC;YACxCX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;YAAI;YACxC4B,OAAOb,SAASwB,MAAM,CAAC,MAAMvC,MAAM+B,IAAI,CAAC;QAC1C;IACF;IAEAnB,SAAS,WAAW;QAClBc,GAAG,iEAAiE;YAClEX,SAASY,QAAQ,CAAC7B;YAElB8B,OAAOb,SAASwB,MAAM,CAAC,WAAW/B,QAAQuB,IAAI,CAAC;YAC/CH,OAAOb,SAASqC,SAAS,CAAC,UAAUjD,QAAQD,GAAG,GAAG6B,IAAI,CAAC;YACvDH,OAAOb,SAASwB,MAAM,CAAC,WAAW/B,QAAQuB,IAAI,CAAC;YAC/CH,OAAOb,SAASqC,SAAS,CAAC,UAAUjD,QAAQD,GAAG,GAAG6B,IAAI,CAAC;YACvDH,OAAOb,SAASwB,MAAM,CAAC,WAAW/B,QAAQuB,IAAI,CAAC;QACjD;QAEAL,GAAG,yCAAyC;YAC1C,IAAI2B,MAAM,IAAIC,KAAK;YACnB,MAAMC,UAAU,IAAI5D,cAAcmB,SAAS;gBAAEuC,KAAK,IAAMA;YAAI;YAC5DE,QAAQ5B,QAAQ,CAAC7B;YACjBuD,MAAM,IAAIC,KAAK;YAEfC,QAAQH,SAAS,CAAC,UAAUjD,QAAQD,GAAG;YAEvC0B,OAAO2B,QAAQhB,MAAM,CAAC,WAAWiB,WAAWzB,IAAI,CAACsB,IAAII,WAAW;YAChE,MAAMC,KAAK,IAAIhE,SAASoB,QAAQgB,OAAO,CAAC,WAAW,QAAQ;gBAAE6B,UAAU;YAAK;YAC5E,MAAMC,MAAMF,GACTG,OAAO,CAAC,4DACRC,GAAG,CAAC,UAAU3D,QAAQD,GAAG;YAC5BwD,GAAGK,KAAK;YACRnC,OAAOgC,IAAII,UAAU,EAAEjC,IAAI,CAACsB,IAAII,WAAW;QAC7C;QAEA/B,GAAG,qDAAqD;YACtDE,OAAOb,SAASqC,SAAS,CAAC,UAAU,SAASX,QAAQ;QACvD;QAEAf,GAAG,0DAA0D;YAC3DX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEQ,WAAW;YAAS;YAClDS,SAASqC,SAAS,CAAC,UAAUjD,QAAQD,GAAG;YAExCa,SAASY,QAAQ,CAAC7B,UAAU;gBAAEQ,WAAW;YAAQ;YAEjDsB,OAAOb,SAASwB,MAAM,CAAC,WAAWC,aAAa,CAAC;gBAAElC,WAAW;gBAASE,QAAQ;YAAK;QACrF;QAEAkB,GAAG,kCAAkC;YACnCX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;YAAS;YAC7Ce,SAASqC,SAAS,CAAC,UAAUjD,QAAQD,GAAG;YAExCa,SAASkD,MAAM,CAAC,UAAU;YAE1BrC,OAAOb,SAASwB,MAAM,CAAC,UAAU/B,QAAQuB,IAAI,CAAC;QAChD;QAEAL,GAAG,6CAA6C;YAC9CX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEI,KAAK;YAAO;YAC1Ca,SAASqC,SAAS,CAAC,UAAU;YAE7BrC,SAASmD,KAAK;YAEdtC,OAAOb,SAASwB,MAAM,CAAC,WAAWE,QAAQ;QAC5C;QAEAf,GAAG,gEAAgE;YACjEX,SAASY,QAAQ,CAAC7B;YAClB,MAAMqE,mBAAmB,IAAIxE,cAAcmB,SAAS;gBAAE6C,UAAU;YAAK;YAErE/B,OAAO,IAAMuC,iBAAiBf,SAAS,CAAC,UAAUjD,QAAQD,GAAG,GAAG+C,OAAO,CAAC;QAC1E;IACF;IAEArC,SAAS,QAAQ;QACfc,GAAG,8DAA8D;YAC/DE,OAAOb,SAASiB,IAAI,IAAIU,OAAO,CAAC,EAAE;QACpC;QAEAhB,GAAG,+CAA+C;YAChD,MAAM0C,cAActE,UAAU;gBAAEE,MAAM;gBAAUU,YAAY;oBAAEC,SAAS;gBAAS;YAAE;YAClFpB,GAAG8E,SAAS,CAAC5E,KAAK6E,OAAO,CAACxD,UAAU;gBAAEU,WAAW;YAAK;YACtDjC,GAAGgF,aAAa,CAACzD,SAAS0D,KAAKC,SAAS,CAAC;gBAAEC,SAAS;oBAACN;iBAAY;YAAC,IAAI;YAEtE,MAAMO,iBAAiB,IAAIhF,cAAcmB;YAEzCc,OAAO+C,eAAepC,MAAM,CAAC,WAAWE,QAAQ;YAChDb,OAAO+C,eAAe3C,IAAI,IAAIU,OAAO,CAAC,EAAE;YACxCd,OAAOrC,GAAGsC,UAAU,CAACf,QAAQgB,OAAO,CAAC,WAAW,SAASC,IAAI,CAAC;QAChE;QAEAL,GAAG,wDAAwD;YACzD,MAAMkD,SAAS9D,QAAQgB,OAAO,CAAC,WAAW;YAC1CvC,GAAG8E,SAAS,CAAC5E,KAAK6E,OAAO,CAACM,SAAS;gBAAEpD,WAAW;YAAK;YACrDjC,GAAGgC,MAAM,CAACqD,QAAQ;gBAAEnD,OAAO;YAAK;YAChClC,GAAGgC,MAAM,CAAC,GAAGqD,OAAO,IAAI,CAAC,EAAE;gBAAEnD,OAAO;YAAK;YACzClC,GAAGgC,MAAM,CAAC,GAAGqD,OAAO,IAAI,CAAC,EAAE;gBAAEnD,OAAO;YAAK;YACzC,MAAMiC,KAAK,IAAIhE,SAASkF;YACxBlB,GAAGmB,IAAI,CAAC,CAAC;;;;;;;;;;;;;;;;8BAgBe,EAAE1E,QAAQD,GAAG,CAAC;;;;YAIhC,CAAC;YACPwD,GAAGK,KAAK;YAER,MAAMe,mBAAmB,IAAInF,cAAcmB;YAE3Cc,OAAOkD,iBAAiBvC,MAAM,CAAC,kBAAkBC,aAAa,CAAC;gBAC7D/B,SAAS;gBACTC,YAAY;oBAAEC,SAAS;gBAAgB;YACzC;QACF;IACF;IAEAC,SAAS,WAAW;QAClBc,GAAG,wCAAwC;YACzCE,OAAOb,SAASgE,OAAO,CAACjF,UAAU;gBAAEI,KAAKC,QAAQD,GAAG;YAAC,KAAK6B,IAAI,CAAC;QACjE;QAEAL,GAAG,+CAA+C;YAChDE,OAAOb,SAASgE,OAAO,CAACjF,UAAU;gBAAEI,KAAK;YAAO,KAAK6B,IAAI,CAAC;QAC5D;QAEAL,GAAG,+DAA+D;YAChEL,GAAGsB,KAAK,CAACxC,SAAS,QAAQyC,kBAAkB,CAAC;gBAC3C,MAAMC,OAAOC,MAAM,CAAC,IAAIC,MAAM,4BAA4B;oBAAEC,MAAM;gBAAQ;YAC5E;YAEApB,OAAOb,SAASgE,OAAO,CAACjF,cAAciC,IAAI,CAAC;QAC7C;QAEAL,GAAG,sDAAsD;YACvDL,GAAGsB,KAAK,CAACxC,SAAS,QAAQyC,kBAAkB,CAAC;gBAC3C,MAAMC,OAAOC,MAAM,CAAC,IAAIC,MAAM,oBAAoB;oBAAEC,MAAM;gBAAQ;YACpE;YAEApB,OAAOb,SAASgE,OAAO,CAACjF,cAAciC,IAAI,CAAC;QAC7C;QAEAL,GAAG,6EAA6E;YAC9EL,GAAGsB,KAAK,CAACxC,SAAS,QAAQyC,kBAAkB,CAAC;gBAC3C,MAAM,IAAIG,MAAM;YAClB;YAEAnB,OAAOb,SAASgE,OAAO,CAACjF,cAAciC,IAAI,CAAC;QAC7C;IACF;IAEAnB,SAAS,SAAS;QAChBc,GAAG,uCAAuC;YACxCX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAASE,KAAKC,QAAQD,GAAG;YAAC;YAC9Da,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAQE,KAAK;YAAO;YACxDa,SAASmD,KAAK;YACd,MAAMc,YAAYjE,SAASiB,IAAI;YAC/BJ,OAAOoD,WAAW9C,YAAY,CAAC;YAC/BN,OAAOoD,SAAS,CAAC,EAAE,CAAChF,IAAI,EAAE+B,IAAI,CAAC;QACjC;QAEAL,GAAG,yCAAyC;YAC1CX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEI,KAAKC,QAAQD,GAAG;YAAC;YAC/C,MAAM+E,SAASlE,SAASiB,IAAI;YAC5BjB,SAASmD,KAAK;YACd,MAAMgB,QAAQnE,SAASiB,IAAI;YAC3BJ,OAAOsD,OAAOxC,OAAO,CAACuC;QACxB;QAEAvD,GAAG,4DAA4D;YAC7DX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAeU,YAAY;oBAAEC,SAAS;gBAAc;YAAE;YAC1FU,GAAGsB,KAAK,CAACxC,SAAS,QAAQyC,kBAAkB,CAAC;gBAC3C,MAAMC,OAAOC,MAAM,CAAC,IAAIC,MAAM,4BAA4B;oBAAEC,MAAM;gBAAQ;YAC5E;YAEAjC,SAASmD,KAAK;YAEdtC,OAAOb,SAASwB,MAAM,CAAC,gBAAgBC,aAAa,CAAC;gBACnDxC,MAAM;gBACNU,YAAY;oBAAEC,SAAS;gBAAc;YACvC;QACF;QAEAe,GAAG,0DAA0D;YAC3DX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;YAAO;YAC3CqB,GAAGsB,KAAK,CAACxC,SAAS,QAAQyC,kBAAkB,CAAC;gBAC3C,MAAMC,OAAOC,MAAM,CAAC,IAAIC,MAAM,oBAAoB;oBAAEC,MAAM;gBAAQ;YACpE;YAEAjC,SAASmD,KAAK;YAEdtC,OAAOb,SAASwB,MAAM,CAAC,SAASE,QAAQ;QAC1C;QAEAf,GAAG,qCAAqC;YACtCE,OAAO,IAAMb,SAASmD,KAAK,IAAIiB,GAAG,CAAClC,OAAO;QAC5C;QAEAvB,GAAG,kEAAkE;YACnE,IAAI0D,QAAQ9B,KAAK+B,KAAK,CAAC;YACvB,MAAM9B,UAAU,IAAI5D,cAAcmB,SAAS;gBACzCuC,KAAK,IAAM,IAAIC,KAAK8B;gBACpBE,iBAAiB;YACnB;YACA/B,QAAQ5B,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAUE,KAAKC,QAAQD,GAAG;YAAC;YAC9D,MAAMqF,QAAQlE,GAAGsB,KAAK,CAACY,SAAS,WAAWiC,eAAe,CAAC;YAC3DjC,QAAQkC,UAAU;YAClBF,MAAMC,eAAe,CAAC;YACtBJ,SAAS;YAET7B,QAAQW,KAAK;YAEbtC,OAAO2D,OAAOG,qBAAqB,CAAC;YACpC9D,OAAO2B,QAAQhB,MAAM,CAAC,WAAWE,QAAQ;QAC3C;IACF;IAEA7B,SAAS,aAAa;QACpBc,GAAG,gCAAgC;YACjCE,OAAOjC,cAAcgG,OAAO,IAAI5D,IAAI,CAACpC,cAAcgG,OAAO;QAC5D;IACF;IAEA/E,SAAS,UAAU;QACjBc,GAAG,yCAAyC;YAC1CX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAYE,KAAKC,QAAQD,GAAG;YAAC;YACjEa,SAASkD,MAAM,CAAC,YAAY;YAC5BrC,OAAOb,SAASwB,MAAM,CAAC,aAAavC,MAAM+B,IAAI,CAAC;YAC/CH,OAAOb,SAASwB,MAAM,CAAC,aAAaE,QAAQ;QAC9C;QAEAf,GAAG,mDAAmD;YACpDX,SAASY,QAAQ,CACf7B,UAAU;gBACRE,MAAM;gBACNE,KAAKC,QAAQD,GAAG;gBAChBQ,YAAY;oBAAEC,SAAS;gBAAW;gBAClCP,KAAK;YACP;YAEFW,SAASkD,MAAM,CAAC,YAAY;YAC5B,MAAM2B,QAAQ7E,SAASwB,MAAM,CAAC;YAC9BX,OAAOgE,OAAOlF,YAAYgC,OAAO,CAAC;gBAAE/B,SAAS;YAAW;YACxDiB,OAAOgE,OAAOxF,KAAK2B,IAAI,CAAC;YACxBH,OAAOgE,OAAO1F,KAAK6B,IAAI,CAAC5B,QAAQD,GAAG;QACrC;QAEAwB,GAAG,+DAA+D;YAChEE,OAAO,IAAMb,SAASkD,MAAM,CAAC,SAAS,aAAahB,OAAO,CAACrD;QAC7D;QAEA8B,GAAG,8EAA8E;YAC/EX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAWE,KAAKC,QAAQD,GAAG;YAAC;YAChEa,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAWE,KAAKC,QAAQ8B,IAAI;YAAC;YACjEL,OAAO,IAAMb,SAASkD,MAAM,CAAC,WAAW,YAAYhB,OAAO,CAACpD;QAC9D;QAEA6B,GAAG,gFAAgF;YACjFX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAWE,KAAKC,QAAQD,GAAG;YAAC;YAChEa,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAWE,KAAKC,QAAQ8B,IAAI;YAAC;YACjEZ,GAAGsB,KAAK,CAACxC,SAAS,QAAQyC,kBAAkB,CAAC;gBAC3C,MAAMC,OAAOC,MAAM,CAAC,IAAIC,MAAM,4BAA4B;oBAAEC,MAAM;gBAAQ;YAC5E;YAEApB,OAAO,IAAMb,SAASkD,MAAM,CAAC,WAAW,YAAYhB,OAAO,CAACpD;YAC5D+B,OAAOb,SAASwB,MAAM,CAAC,YAAYrC,KAAK6B,IAAI,CAAC5B,QAAQ8B,IAAI;QAC3D;QAEAP,GAAG,8DAA8D;YAC/DX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAWE,KAAKC,QAAQD,GAAG;YAAC;YAChEa,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAWE,KAAK;YAAO;YAC3D0B,OAAO,IAAMb,SAASkD,MAAM,CAAC,WAAW,YAAYkB,GAAG,CAAClC,OAAO;YAC/DrB,OAAOb,SAASwB,MAAM,CAAC,YAAYrC,KAAK6B,IAAI,CAAC5B,QAAQD,GAAG;QAC1D;QAEAwB,GAAG,wDAAwD;YACzDX,SAASY,QAAQ,CAAC7B,UAAU;gBAAEE,MAAM;gBAAYE,KAAKC,QAAQD,GAAG;YAAC;YACjEa,SAASkD,MAAM,CAAC,YAAY;YAC5BrC,OAAOrC,GAAGsC,UAAU,CAAC,GAAGf,QAAQ,IAAI,CAAC,GAAGiB,IAAI,CAAC;QAC/C;IACF;AACF"}
|
|
1
|
+
{"version":3,"sources":["../../../src/__tests__/utils/AgentRegistry.test.ts"],"sourcesContent":["import fs from \"fs\";\nimport os from \"os\";\nimport path from \"path\";\nimport Database from \"better-sqlite3\";\nimport {\n AgentRegistry,\n RenameNotFoundError,\n RenameConflictError,\n type RegistryEntry,\n} from \"../../utils/AgentRegistry.js\";\n\nfunction makeEntry(over: Partial<RegistryEntry> = {}): RegistryEntry {\n return {\n name: \"agent1\",\n type: \"claude\",\n pid: process.pid,\n cwd: \"/tmp\",\n startedAt: \"2026-05-30T00:00:00.000Z\",\n sessionId: \"sid-1\",\n sessionFilePath: \"/tmp/session.jsonl\",\n pinned: false,\n runtime: \"tmux\",\n runtimeRef: { session: \"agent1\" },\n ...over,\n };\n}\n\ndescribe(\"AgentRegistry\", () => {\n let tmpDir: string;\n let regPath: string;\n let registry: AgentRegistry;\n\n beforeEach(() => {\n tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), \"agent-registry-\"));\n regPath = path.join(tmpDir, \"nested\", \"agents.json\");\n registry = new AgentRegistry(regPath);\n });\n\n afterEach(() => {\n vi.restoreAllMocks();\n fs.rmSync(tmpDir, { recursive: true, force: true });\n });\n\n describe(\"register\", () => {\n it(\"creates the SQLite database and parent directory if missing\", () => {\n registry.register(makeEntry());\n expect(fs.existsSync(regPath.replace(/\\.json$/, \".db\"))).toBe(true);\n expect(registry.list()[0].name).toBe(\"agent1\");\n });\n\n it(\"appends a new entry when name is unique\", () => {\n registry.register(makeEntry({ name: \"a\" }));\n registry.register(makeEntry({ name: \"b\", pid: process.ppid }));\n expect(registry.list()).toHaveLength(2);\n });\n\n it(\"upserts in place when type and pid already exist\", () => {\n registry.register(makeEntry({ name: \"a\", pid: process.pid }));\n registry.register(makeEntry({ name: \"fallback\", pid: process.pid, runtimeRef: null }));\n const all = registry.list();\n expect(all).toHaveLength(1);\n expect(all[0].pid).toBe(process.pid);\n expect(all[0].name).toBe(\"a\");\n });\n\n it(\"does not write through the legacy fixed .tmp path\", () => {\n registry.register(makeEntry());\n expect(fs.existsSync(`${regPath}.tmp`)).toBe(false);\n });\n\n it(\"persists session fields\", () => {\n registry.register(makeEntry({ sessionId: \"sid-xyz\", sessionFilePath: \"/foo/bar.jsonl\" }));\n const saved = registry.list()[0];\n expect(saved.sessionId).toBe(\"sid-xyz\");\n expect(saved.sessionFilePath).toBe(\"/foo/bar.jsonl\");\n });\n\n it(\"persists runtime metadata for Herdr-backed entries\", () => {\n const runtimeRef = { session: \"default\", paneId: \"w1:p2\", agentName: \"reviewer\" };\n\n registry.register(\n makeEntry({\n name: \"reviewer\",\n runtime: \"herdr\",\n runtimeRef,\n }),\n );\n\n expect(registry.lookup(\"reviewer\")).toMatchObject({\n runtime: \"herdr\",\n runtimeRef,\n });\n });\n\n it(\"preserves existing identity and routing fields for same-pid refreshes\", () => {\n const runtimeRef = { session: \"default\", paneId: \"w1:p2\", agentName: \"requested-name\" };\n\n registry.register(\n makeEntry({\n name: \"old-name\",\n pid: process.pid,\n runtime: \"tmux\",\n runtimeRef: { session: \"old-name\" },\n cwd: \"/original\",\n }),\n );\n registry.register(\n makeEntry({\n name: \"requested-name\",\n pid: process.pid,\n runtime: \"herdr\",\n runtimeRef,\n cwd: \"/incoming\",\n }),\n );\n\n expect(registry.lookup(\"requested-name\")).toBeNull();\n expect(registry.lookup(\"old-name\")).toMatchObject({\n pid: process.pid,\n runtime: \"tmux\",\n runtimeRef: { session: \"old-name\" },\n cwd: \"/original\",\n });\n });\n\n it(\"preserves existing runtime ref when incoming runtime ref is empty\", () => {\n registry.register(makeEntry({ name: \"a\", runtimeRef: { session: \"pinned\" } }));\n registry.register(makeEntry({ name: \"fallback\", runtimeRef: null, pid: process.pid }));\n const saved = registry.lookup(\"a\");\n expect(saved?.runtimeRef).toEqual({ session: \"pinned\" });\n expect(saved?.pid).toBe(process.pid);\n });\n\n it(\"defaults an empty tmux runtime ref from the tmux session\", () => {\n registry.register(makeEntry({ name: \"a\", runtimeRef: null }));\n\n expect(registry.lookup(\"a\")?.runtimeRef).toBeNull();\n });\n\n it(\"preserves an existing generated fallback for the same pid\", () => {\n registry.register(makeEntry({ name: `ai-devkit-${process.pid}`, runtimeRef: null }));\n registry.register(makeEntry({ name: \"custom-name\", runtimeRef: { session: \"custom-name\" } }));\n expect(registry.lookup(\"custom-name\")).toBeNull();\n expect(registry.lookup(`ai-devkit-${process.pid}`)?.runtimeRef).toBeNull();\n expect(registry.list()).toHaveLength(1);\n });\n\n it(\"preserves an existing name conflict when its probe fails with EPERM\", () => {\n registry.register(makeEntry({ name: \"claimed-name\", pid: process.pid }));\n vi.spyOn(process, \"kill\").mockImplementation(() => {\n throw Object.assign(new Error(\"operation not permitted\"), { code: \"EPERM\" });\n });\n\n expect(() =>\n registry.register(\n makeEntry({\n name: \"claimed-name\",\n pid: process.pid + 1,\n }),\n ),\n ).toThrow();\n expect(registry.lookup(\"claimed-name\")?.pid).toBe(process.pid);\n });\n });\n\n describe(\"registerBatch\", () => {\n it(\"is a no-op on empty array\", () => {\n registry.registerBatch([]);\n expect(fs.existsSync(regPath)).toBe(false);\n });\n\n it(\"upserts multiple entries in a single batch\", () => {\n registry.registerBatch([\n makeEntry({ name: \"a\" }),\n makeEntry({ name: \"b\", pid: process.pid + 1 }),\n makeEntry({ name: \"c\", pid: process.pid + 2 }),\n ]);\n expect(registry.list()).toHaveLength(3);\n });\n\n it(\"applies the tmux runtime ref merge per entry\", () => {\n registry.register(makeEntry({ name: \"a\", runtimeRef: { session: \"pinned\" } }));\n registry.registerBatch([\n makeEntry({ name: \"fallback\", runtimeRef: null, pid: process.pid }),\n makeEntry({ name: \"b\", runtimeRef: null, pid: process.pid + 1 }),\n ]);\n expect(registry.lookup(\"a\")?.runtimeRef).toEqual({ session: \"pinned\" });\n expect(registry.lookup(\"a\")?.pid).toBe(process.pid);\n expect(registry.lookup(\"b\")?.runtimeRef).toBeNull();\n });\n\n it(\"handles concurrent registry instances without duplicate pid rows\", () => {\n const other = new AgentRegistry(regPath);\n registry.register(makeEntry({ name: `ai-devkit-${process.pid}`, runtimeRef: null }));\n other.register(makeEntry({ name: \"custom-name\", runtimeRef: { session: \"custom-name\" } }));\n registry.register(makeEntry({ name: `ai-devkit-${process.pid}`, runtimeRef: null }));\n\n expect(registry.list()).toHaveLength(1);\n expect(registry.lookup(`ai-devkit-${process.pid}`)?.pid).toBe(process.pid);\n });\n\n it(\"cleans up a cross-type row when its pid has been reused\", () => {\n registry.register(makeEntry({ name: \"old-claude\", type: \"claude\", pid: process.pid }));\n\n registry.register(\n makeEntry({\n name: \"new-codex\",\n type: \"codex\",\n pid: process.pid,\n runtimeRef: null,\n }),\n );\n\n expect(registry.lookup(\"old-claude\")).toBeNull();\n expect(registry.lookup(\"new-codex\")).toMatchObject({ type: \"codex\", pid: process.pid });\n expect(registry.list()).toHaveLength(1);\n });\n\n it(\"rolls back the whole batch when a live name conflict rejects one entry\", () => {\n registry.register(makeEntry({ name: \"taken\", pid: process.pid }));\n\n expect(() =>\n registry.registerBatch([\n makeEntry({ name: \"fresh\", pid: 999998 }),\n makeEntry({ name: \"taken\", type: \"codex\", pid: 999997 }),\n ]),\n ).toThrow(/UNIQUE constraint failed/);\n\n expect(registry.lookup(\"fresh\")).toBeNull();\n expect(registry.lookup(\"taken\")?.pid).toBe(process.pid);\n });\n });\n\n describe(\"lookup\", () => {\n it(\"returns null when name not found\", () => {\n expect(registry.lookup(\"missing\")).toBeNull();\n });\n\n it(\"returns the entry when name matches\", () => {\n registry.register(makeEntry({ name: \"a\" }));\n expect(registry.lookup(\"a\")?.name).toBe(\"a\");\n });\n });\n\n describe(\"pinning\", () => {\n it(\"defaults new rows to unpinned and toggles the persisted state\", () => {\n registry.register(makeEntry());\n\n expect(registry.lookup(\"agent1\")?.pinned).toBe(false);\n expect(registry.togglePin(\"claude\", process.pid)).toBe(true);\n expect(registry.lookup(\"agent1\")?.pinned).toBe(true);\n expect(registry.togglePin(\"claude\", process.pid)).toBe(false);\n expect(registry.lookup(\"agent1\")?.pinned).toBe(false);\n });\n\n it(\"updates existing recency when toggled\", () => {\n let now = new Date(\"2026-08-16T10:00:00.000Z\");\n const clocked = new AgentRegistry(regPath, { now: () => now });\n clocked.register(makeEntry());\n now = new Date(\"2026-08-16T10:01:00.000Z\");\n\n clocked.togglePin(\"claude\", process.pid);\n\n expect(clocked.lookup(\"agent1\")?.updatedAt).toBe(now.toISOString());\n const db = new Database(regPath.replace(/\\.json$/, \".db\"), { readonly: true });\n const row = db\n .prepare(\"SELECT updated_at FROM agents WHERE type = ? AND pid = ?\")\n .get(\"claude\", process.pid) as { updated_at: string };\n db.close();\n expect(row.updated_at).toBe(now.toISOString());\n });\n\n it(\"returns null when the process row has disappeared\", () => {\n expect(registry.togglePin(\"claude\", 999999)).toBeNull();\n });\n\n it(\"preserves a pin when poll registration updates the row\", () => {\n registry.register(makeEntry({ sessionId: \"before\" }));\n registry.togglePin(\"claude\", process.pid);\n\n registry.register(makeEntry({ sessionId: \"after\" }));\n\n expect(registry.lookup(\"agent1\")).toMatchObject({ sessionId: \"after\", pinned: true });\n });\n\n it(\"preserves a pin through rename\", () => {\n registry.register(makeEntry({ name: \"before\" }));\n registry.togglePin(\"claude\", process.pid);\n\n registry.rename(\"before\", \"after\");\n\n expect(registry.lookup(\"after\")?.pinned).toBe(true);\n });\n\n it(\"removes the pin with a pruned process row\", () => {\n registry.register(makeEntry({ pid: 999999 }));\n registry.togglePin(\"claude\", 999999);\n\n registry.prune();\n\n expect(registry.lookup(\"agent1\")).toBeNull();\n });\n\n it(\"reports a clear error when a readonly registry toggles a pin\", () => {\n registry.register(makeEntry());\n const readonlyRegistry = new AgentRegistry(regPath, { readonly: true });\n\n expect(() => readonlyRegistry.togglePin(\"claude\", process.pid)).toThrow(/readonly/i);\n });\n });\n\n describe(\"list\", () => {\n it(\"returns empty array when database does not contain entries\", () => {\n expect(registry.list()).toEqual([]);\n });\n\n it(\"ignores existing legacy agents.json entries\", () => {\n const legacyEntry = makeEntry({ name: \"legacy\", runtimeRef: { session: \"legacy\" } });\n fs.mkdirSync(path.dirname(regPath), { recursive: true });\n fs.writeFileSync(regPath, JSON.stringify({ entries: [legacyEntry] }), \"utf8\");\n\n const legacyRegistry = new AgentRegistry(regPath);\n\n expect(legacyRegistry.lookup(\"legacy\")).toBeNull();\n expect(legacyRegistry.list()).toEqual([]);\n expect(fs.existsSync(regPath.replace(/\\.json$/, \".db\"))).toBe(true);\n });\n\n it(\"reads pre-runtime SQLite rows as tmux-backed records\", () => {\n const dbPath = regPath.replace(/\\.json$/, \".db\");\n fs.mkdirSync(path.dirname(dbPath), { recursive: true });\n fs.rmSync(dbPath, { force: true });\n fs.rmSync(`${dbPath}-wal`, { force: true });\n fs.rmSync(`${dbPath}-shm`, { force: true });\n const db = new Database(dbPath);\n db.exec(`\n CREATE TABLE agents (\n type TEXT NOT NULL,\n pid INTEGER NOT NULL,\n name TEXT NOT NULL UNIQUE,\n tmux_session TEXT NOT NULL DEFAULT '',\n cwd TEXT NOT NULL DEFAULT '',\n started_at TEXT NOT NULL,\n session_id TEXT NOT NULL DEFAULT '',\n session_file_path TEXT NOT NULL DEFAULT '',\n updated_at TEXT NOT NULL,\n PRIMARY KEY (type, pid)\n );\n INSERT INTO agents (\n type, pid, name, tmux_session, cwd, started_at, session_id, session_file_path, updated_at\n ) VALUES (\n 'claude', ${process.pid}, 'legacy-sqlite', 'legacy-sqlite', '/tmp',\n '2026-05-30T00:00:00.000Z', 'sid-1', '/tmp/session.jsonl', '2026-05-30T00:00:00.000Z'\n );\n PRAGMA user_version = 1;\n `);\n db.close();\n\n const migratedRegistry = new AgentRegistry(regPath);\n\n expect(migratedRegistry.lookup(\"legacy-sqlite\")).toMatchObject({\n runtime: \"tmux\",\n runtimeRef: { session: \"legacy-sqlite\" },\n });\n });\n });\n\n describe(\"isAlive\", () => {\n it(\"returns true for the current process\", () => {\n expect(registry.isAlive(makeEntry({ pid: process.pid }))).toBe(true);\n });\n\n it(\"returns false for a PID that does not exist\", () => {\n expect(registry.isAlive(makeEntry({ pid: 999999 }))).toBe(false);\n });\n\n it(\"returns true when the process probe is forbidden with EPERM\", () => {\n vi.spyOn(process, \"kill\").mockImplementation(() => {\n throw Object.assign(new Error(\"operation not permitted\"), { code: \"EPERM\" });\n });\n\n expect(registry.isAlive(makeEntry())).toBe(true);\n });\n\n it(\"returns false when the process probe reports ESRCH\", () => {\n vi.spyOn(process, \"kill\").mockImplementation(() => {\n throw Object.assign(new Error(\"no such process\"), { code: \"ESRCH\" });\n });\n\n expect(registry.isAlive(makeEntry())).toBe(false);\n });\n\n it(\"returns true when the process probe fails without a definitive error code\", () => {\n vi.spyOn(process, \"kill\").mockImplementation(() => {\n throw new Error(\"indeterminate probe failure\");\n });\n\n expect(registry.isAlive(makeEntry())).toBe(true);\n });\n });\n\n describe(\"prune\", () => {\n it(\"removes entries whose PIDs are dead\", () => {\n registry.register(makeEntry({ name: \"alive\", pid: process.pid }));\n registry.register(makeEntry({ name: \"dead\", pid: 999999 }));\n registry.prune();\n const remaining = registry.list();\n expect(remaining).toHaveLength(1);\n expect(remaining[0].name).toBe(\"alive\");\n });\n\n it(\"is a no-op when all entries are alive\", () => {\n registry.register(makeEntry({ pid: process.pid }));\n const before = registry.list();\n registry.prune();\n const after = registry.list();\n expect(after).toEqual(before);\n });\n\n it(\"preserves entries when liveness probing fails with EPERM\", () => {\n registry.register(makeEntry({ name: \"custom-name\", runtimeRef: { session: \"tmux-custom\" } }));\n vi.spyOn(process, \"kill\").mockImplementation(() => {\n throw Object.assign(new Error(\"operation not permitted\"), { code: \"EPERM\" });\n });\n\n registry.prune();\n\n expect(registry.lookup(\"custom-name\")).toMatchObject({\n name: \"custom-name\",\n runtimeRef: { session: \"tmux-custom\" },\n });\n });\n\n it(\"removes entries when liveness probing fails with ESRCH\", () => {\n registry.register(makeEntry({ name: \"dead\" }));\n vi.spyOn(process, \"kill\").mockImplementation(() => {\n throw Object.assign(new Error(\"no such process\"), { code: \"ESRCH\" });\n });\n\n registry.prune();\n\n expect(registry.lookup(\"dead\")).toBeNull();\n });\n\n it(\"does nothing when file is missing\", () => {\n expect(() => registry.prune()).not.toThrow();\n });\n\n it(\"keeps forced prune available before the passive cadence is due\", () => {\n let nowMs = Date.parse(\"2026-08-14T10:00:00.000Z\");\n const clocked = new AgentRegistry(regPath, {\n now: () => new Date(nowMs),\n pruneIntervalMs: 30_000,\n });\n clocked.register(makeEntry({ name: \"forced\", pid: process.pid }));\n const alive = vi.spyOn(clocked, \"isAlive\").mockReturnValue(true);\n clocked.pruneIfDue();\n alive.mockReturnValue(false);\n nowMs += 1;\n\n clocked.prune();\n\n expect(alive).toHaveBeenCalledTimes(2);\n expect(clocked.lookup(\"forced\")).toBeNull();\n });\n });\n\n describe(\"default()\", () => {\n it(\"returns a singleton instance\", () => {\n expect(AgentRegistry.default()).toBe(AgentRegistry.default());\n });\n });\n\n describe(\"rename\", () => {\n it(\"updates the name of an existing entry\", () => {\n registry.register(makeEntry({ name: \"old-name\", pid: process.pid }));\n registry.rename(\"old-name\", \"new-name\");\n expect(registry.lookup(\"new-name\")?.name).toBe(\"new-name\");\n expect(registry.lookup(\"old-name\")).toBeNull();\n });\n\n it(\"preserves all other fields on the renamed entry\", () => {\n registry.register(\n makeEntry({\n name: \"old-name\",\n pid: process.pid,\n runtimeRef: { session: \"old-name\" },\n cwd: \"/my/cwd\",\n }),\n );\n registry.rename(\"old-name\", \"new-name\");\n const entry = registry.lookup(\"new-name\");\n expect(entry?.runtimeRef).toEqual({ session: \"old-name\" });\n expect(entry?.cwd).toBe(\"/my/cwd\");\n expect(entry?.pid).toBe(process.pid);\n });\n\n it(\"throws RenameNotFoundError when current name does not exist\", () => {\n expect(() => registry.rename(\"ghost\", \"new-name\")).toThrow(RenameNotFoundError);\n });\n\n it(\"throws RenameConflictError when new name is already in use by a live entry\", () => {\n registry.register(makeEntry({ name: \"agent-a\", pid: process.pid }));\n registry.register(makeEntry({ name: \"agent-b\", pid: process.ppid }));\n expect(() => registry.rename(\"agent-a\", \"agent-b\")).toThrow(RenameConflictError);\n });\n\n it(\"throws RenameConflictError when the conflicting entry probe fails with EPERM\", () => {\n registry.register(makeEntry({ name: \"agent-a\", pid: process.pid }));\n registry.register(makeEntry({ name: \"agent-b\", pid: process.ppid }));\n vi.spyOn(process, \"kill\").mockImplementation(() => {\n throw Object.assign(new Error(\"operation not permitted\"), { code: \"EPERM\" });\n });\n\n expect(() => registry.rename(\"agent-a\", \"agent-b\")).toThrow(RenameConflictError);\n expect(registry.lookup(\"agent-b\")?.pid).toBe(process.ppid);\n });\n\n it(\"succeeds when new name exists only as a stale (dead) entry\", () => {\n registry.register(makeEntry({ name: \"agent-a\", pid: process.pid }));\n registry.register(makeEntry({ name: \"agent-b\", pid: 999999 }));\n expect(() => registry.rename(\"agent-a\", \"agent-b\")).not.toThrow();\n expect(registry.lookup(\"agent-b\")?.pid).toBe(process.pid);\n });\n\n it(\"does not create the legacy fixed .tmp path on rename\", () => {\n registry.register(makeEntry({ name: \"old-name\", pid: process.pid }));\n registry.rename(\"old-name\", \"new-name\");\n expect(fs.existsSync(`${regPath}.tmp`)).toBe(false);\n });\n });\n});\n"],"names":["fs","os","path","Database","AgentRegistry","RenameNotFoundError","RenameConflictError","makeEntry","over","name","type","pid","process","cwd","startedAt","sessionId","sessionFilePath","pinned","runtime","runtimeRef","session","describe","tmpDir","regPath","registry","beforeEach","mkdtempSync","join","tmpdir","afterEach","vi","restoreAllMocks","rmSync","recursive","force","it","register","expect","existsSync","replace","toBe","list","ppid","toHaveLength","all","saved","paneId","agentName","lookup","toMatchObject","toBeNull","toEqual","spyOn","mockImplementation","Object","assign","Error","code","toThrow","registerBatch","other","togglePin","now","Date","clocked","updatedAt","toISOString","db","readonly","row","prepare","get","close","updated_at","rename","prune","readonlyRegistry","legacyEntry","mkdirSync","dirname","writeFileSync","JSON","stringify","entries","legacyRegistry","dbPath","exec","migratedRegistry","isAlive","remaining","before","after","not","nowMs","parse","pruneIntervalMs","alive","mockReturnValue","pruneIfDue","toHaveBeenCalledTimes","default","entry"],"mappings":"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"}
|
package/dist/adapters/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export { ClaudeCodeAdapter } from "../providers/claude/ClaudeCodeAdapter.js";
|
|
2
2
|
export { CodexAdapter } from "../providers/codex/CodexAdapter.js";
|
|
3
|
-
export { CopilotAdapter } from "
|
|
4
|
-
export { GeminiCliAdapter } from "
|
|
3
|
+
export { CopilotAdapter } from "../providers/copilot/CopilotAdapter.js";
|
|
4
|
+
export { GeminiCliAdapter } from "../providers/gemini/GeminiCliAdapter.js";
|
|
5
5
|
export { GrokCliAdapter } from "./GrokCliAdapter.js";
|
|
6
|
-
export { OpenCodeAdapter } from "
|
|
6
|
+
export { OpenCodeAdapter } from "../providers/opencode/OpenCodeAdapter.js";
|
|
7
7
|
export { PiAdapter } from "../providers/pi/PiAdapter.js";
|
|
8
8
|
export { AgentStatus } from "./AgentAdapter.js";
|
|
9
9
|
export type { AgentAdapter, AgentType, AgentInfo, ProcessInfo, AgentDetectionContext, } from "./AgentAdapter.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,0CAA0C,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,0CAA0C,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAC3E,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,0CAA0C,CAAC;AAC3E,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EACV,YAAY,EACZ,SAAS,EACT,SAAS,EACT,WAAW,EACX,qBAAqB,GACtB,MAAM,mBAAmB,CAAC"}
|
package/dist/adapters/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export { ClaudeCodeAdapter } from "../providers/claude/ClaudeCodeAdapter.js";
|
|
2
2
|
export { CodexAdapter } from "../providers/codex/CodexAdapter.js";
|
|
3
|
-
export { CopilotAdapter } from "
|
|
4
|
-
export { GeminiCliAdapter } from "
|
|
3
|
+
export { CopilotAdapter } from "../providers/copilot/CopilotAdapter.js";
|
|
4
|
+
export { GeminiCliAdapter } from "../providers/gemini/GeminiCliAdapter.js";
|
|
5
5
|
export { GrokCliAdapter } from "./GrokCliAdapter.js";
|
|
6
|
-
export { OpenCodeAdapter } from "
|
|
6
|
+
export { OpenCodeAdapter } from "../providers/opencode/OpenCodeAdapter.js";
|
|
7
7
|
export { PiAdapter } from "../providers/pi/PiAdapter.js";
|
|
8
8
|
export { AgentStatus } from "./AgentAdapter.js";
|
|
9
9
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/adapters/index.ts"],"sourcesContent":["export { ClaudeCodeAdapter } from \"../providers/claude/ClaudeCodeAdapter.js\";\nexport { CodexAdapter } from \"../providers/codex/CodexAdapter.js\";\nexport { CopilotAdapter } from \"
|
|
1
|
+
{"version":3,"sources":["../../src/adapters/index.ts"],"sourcesContent":["export { ClaudeCodeAdapter } from \"../providers/claude/ClaudeCodeAdapter.js\";\nexport { CodexAdapter } from \"../providers/codex/CodexAdapter.js\";\nexport { CopilotAdapter } from \"../providers/copilot/CopilotAdapter.js\";\nexport { GeminiCliAdapter } from \"../providers/gemini/GeminiCliAdapter.js\";\nexport { GrokCliAdapter } from \"./GrokCliAdapter.js\";\nexport { OpenCodeAdapter } from \"../providers/opencode/OpenCodeAdapter.js\";\nexport { PiAdapter } from \"../providers/pi/PiAdapter.js\";\nexport { AgentStatus } from \"./AgentAdapter.js\";\nexport type {\n AgentAdapter,\n AgentType,\n AgentInfo,\n ProcessInfo,\n AgentDetectionContext,\n} from \"./AgentAdapter.js\";\n"],"names":["ClaudeCodeAdapter","CodexAdapter","CopilotAdapter","GeminiCliAdapter","GrokCliAdapter","OpenCodeAdapter","PiAdapter","AgentStatus"],"mappings":"AAAA,SAASA,iBAAiB,QAAQ,2CAA2C;AAC7E,SAASC,YAAY,QAAQ,qCAAqC;AAClE,SAASC,cAAc,QAAQ,yCAAyC;AACxE,SAASC,gBAAgB,QAAQ,0CAA0C;AAC3E,SAASC,cAAc,QAAQ,sBAAsB;AACrD,SAASC,eAAe,QAAQ,2CAA2C;AAC3E,SAASC,SAAS,QAAQ,+BAA+B;AACzD,SAASC,WAAW,QAAQ,oBAAoB"}
|
package/dist/capacity/codex.d.ts
CHANGED
|
@@ -31,6 +31,7 @@ export declare function resolveCodexAuthPath(env?: NodeJS.ProcessEnv): string;
|
|
|
31
31
|
export declare function toRateWindow(value: unknown, id: string, label: string): CapacityWindow | null;
|
|
32
32
|
export declare function parseUsage(raw: unknown, source: "pat" | "oauth"): UsageSnapshot;
|
|
33
33
|
export declare function parseCliUsage(raw: unknown): UsageSnapshot;
|
|
34
|
+
export declare function codexUnavailableReport(checkedAt: string): CapacityReport;
|
|
34
35
|
export declare function probeCodexCapacity(options: CodexProbeOptions): Promise<CapacityReport>;
|
|
35
36
|
export {};
|
|
36
37
|
//# sourceMappingURL=codex.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../../src/capacity/codex.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjE,KAAK,gBAAgB,GAAG,KAAK,GAAG,OAAO,GAAG,KAAK,CAAC;AAChD,KAAK,aAAa,GAAG;IACnB,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,MAAM,EAAE,gBAAgB,CAAC;CAC1B,CAAC;AAEF,KAAK,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAC7C,KAAK,UAAU,GAAG;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,aAAa,CAAA;CAAE,CAAC;AAC1E,KAAK,YAAY,GAAG;IAAE,UAAU,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC;AAC9D,KAAK,QAAQ,GAAG,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;AAElE,eAAO,MAAM,qBAAqB,+
|
|
1
|
+
{"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../../src/capacity/codex.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjE,KAAK,gBAAgB,GAAG,KAAK,GAAG,OAAO,GAAG,KAAK,CAAC;AAChD,KAAK,aAAa,GAAG;IACnB,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,MAAM,EAAE,gBAAgB,CAAC;CAC1B,CAAC;AAEF,KAAK,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAC7C,KAAK,UAAU,GAAG;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,aAAa,CAAA;CAAE,CAAC;AAC1E,KAAK,YAAY,GAAG;IAAE,UAAU,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC;AAC9D,KAAK,QAAQ,GAAG,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;AAElE,eAAO,MAAM,qBAAqB,+DAMxB,CAAC;AAEX,KAAK,iBAAiB,GAAG;IACvB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACvE,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC,GAAG,CAAC,EAAE,QAAQ,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAClB,CAAC;AA+BF,wBAAgB,oBAAoB,CAClC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,CAGR;AAED,wBAAgB,YAAY,CAC1B,KAAK,EAAE,OAAO,EACd,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,GACZ,cAAc,GAAG,IAAI,CAYvB;AAwBD,wBAAgB,UAAU,CACxB,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,KAAK,GAAG,OAAO,GACtB,aAAa,CAaf;AAgCD,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,aAAa,CAazD;AAyJD,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,CAUxE;AA+CD,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,cAAc,CAAC,CAuDzB"}
|
package/dist/capacity/codex.js
CHANGED
|
@@ -119,7 +119,8 @@ function capacityFromSnapshot(snapshot, context, raw) {
|
|
|
119
119
|
const reached = nonEmptyText(rateLimits?.rateLimitReachedType);
|
|
120
120
|
const resetCredits = record(record(raw)?.rateLimitResetCredits) ?? record(record(raw)?.usageLimitResetCredits);
|
|
121
121
|
return {
|
|
122
|
-
|
|
122
|
+
harness: "codex",
|
|
123
|
+
provider: "openai",
|
|
123
124
|
generatedAt: context.checkedAt,
|
|
124
125
|
authenticated: true,
|
|
125
126
|
available: reached ? "no" : hasUsage ? "yes" : "unknown",
|
|
@@ -225,16 +226,20 @@ function appServerRpc(messages, timeoutMs = 5000) {
|
|
|
225
226
|
child.stdin.write(`${JSON.stringify(messages[0])}\n`);
|
|
226
227
|
});
|
|
227
228
|
}
|
|
228
|
-
function
|
|
229
|
+
export function codexUnavailableReport(checkedAt) {
|
|
229
230
|
return {
|
|
230
|
-
|
|
231
|
-
|
|
231
|
+
harness: "codex",
|
|
232
|
+
provider: "openai",
|
|
233
|
+
generatedAt: checkedAt,
|
|
232
234
|
authenticated: null,
|
|
233
235
|
available: "unknown",
|
|
234
236
|
windows: [],
|
|
235
237
|
creditsRemaining: null
|
|
236
238
|
};
|
|
237
239
|
}
|
|
240
|
+
function unavailable(options) {
|
|
241
|
+
return codexUnavailableReport(options.checkedAt);
|
|
242
|
+
}
|
|
238
243
|
async function cliFallback(options) {
|
|
239
244
|
if (!options.installed) return unavailable(options);
|
|
240
245
|
const messages = [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/capacity/codex.ts"],"sourcesContent":["import { spawn } from \"node:child_process\";\nimport { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { CapacityReport, CapacityWindow } from \"./types.js\";\n\ntype CodexUsageSource = \"pat\" | \"oauth\" | \"cli\";\ntype UsageSnapshot = {\n windows: CapacityWindow[];\n creditsRemaining: number | null;\n source: CodexUsageSource;\n};\n\ntype UnknownRecord = Record<string, unknown>;\ntype RpcMessage = { id?: number; method: string; params?: UnknownRecord };\ntype CliResponses = { rateLimits: unknown; account: unknown };\ntype CodexRpc = (messages: RpcMessage[]) => Promise<CliResponses>;\n\nexport const CODEX_APP_SERVER_ARGS = [\"-s\", \"read-only\", \"-a\", \"untrusted\", \"app-server\"] as const;\n\ntype CodexProbeOptions = {\n installed: boolean;\n checkedAt: string;\n readFile?: (path: string, encoding: BufferEncoding) => Promise<string>;\n fetch?: typeof globalThis.fetch;\n rpc?: CodexRpc;\n timeoutMs?: number;\n env?: NodeJS.ProcessEnv;\n now?: () => Date;\n};\n\nfunction record(value: unknown): UnknownRecord | null {\n return value !== null && typeof value === \"object\" && !Array.isArray(value)\n ? (value as UnknownRecord)\n : null;\n}\n\nfunction finiteNumber(value: unknown): number | null {\n return typeof value === \"number\" && Number.isFinite(value) ? value : null;\n}\n\nfunction nonEmptyText(value: unknown): string | null {\n return typeof value === \"string\" && value.length > 0 ? value : null;\n}\n\nfunction resetTime(value: unknown): string | null {\n const seconds = finiteNumber(value);\n if (seconds !== null) return new Date(seconds * 1000).toISOString();\n if (typeof value === \"string\" && !Number.isNaN(Date.parse(value)))\n return new Date(value).toISOString();\n return null;\n}\n\nfunction safeIdentifier(value: unknown): string | null {\n const candidate = nonEmptyText(value);\n if (!candidate || !/^[a-z][a-z0-9_-]{0,63}$/i.test(candidate)) return null;\n if (/(?:account|token|secret|key)[_-]?\\d{6,}/i.test(candidate)) return null;\n return candidate;\n}\n\nexport function resolveCodexAuthPath(env: NodeJS.ProcessEnv = process.env): string {\n const root = env.CODEX_HOME || join(env.HOME || \"\", \".codex\");\n return join(root, \"auth.json\");\n}\n\nexport function toRateWindow(value: unknown, id: string, label: string): CapacityWindow | null {\n const input = record(value);\n if (!input) return null;\n const used = finiteNumber(input.used_percent);\n const seconds = finiteNumber(input.limit_window_seconds);\n return {\n id,\n label,\n durationMinutes: seconds === null ? null : seconds / 60,\n usedPercent: used,\n resetsAt: resetTime(input.reset_at),\n };\n}\n\nfunction extraWindows(value: unknown): CapacityWindow[] {\n if (!Array.isArray(value)) return [];\n return value.flatMap((entry, index) => {\n const limit = record(entry);\n if (!limit) return [];\n const scope = safeIdentifier(limit.limit_name) ?? `extra-${index + 1}`;\n const windows = record(limit.rate_limit) ?? limit;\n return [\n toRateWindow(windows.primary_window, `${scope}:primary`, `${scope} primary`),\n toRateWindow(windows.secondary_window, `${scope}:secondary`, `${scope} secondary`),\n ].filter((window): window is CapacityWindow => window !== null);\n });\n}\n\nexport function parseUsage(raw: unknown, source: \"pat\" | \"oauth\"): UsageSnapshot {\n const response = record(raw) ?? {};\n const limits = record(response.rate_limit) ?? {};\n const credits = record(response.credits) ?? {};\n return {\n windows: [\n toRateWindow(limits.primary_window, \"session\", \"Session\"),\n toRateWindow(limits.secondary_window, \"weekly\", \"Weekly\"),\n ...extraWindows(response.additional_rate_limits),\n ].filter((window): window is CapacityWindow => window !== null),\n creditsRemaining: finiteNumber(credits.balance),\n source,\n };\n}\n\nfunction cliWindow(value: unknown, id: string, label: string): CapacityWindow | null {\n const input = record(value);\n if (!input) return null;\n return {\n id,\n label,\n durationMinutes: finiteNumber(input.windowDurationMins),\n usedPercent: finiteNumber(input.usedPercent),\n resetsAt: resetTime(input.resetsAt),\n };\n}\n\nfunction cliSnapshotWindows(value: unknown, fallbackId: string): CapacityWindow[] {\n const snapshot = record(value);\n if (!snapshot) return [];\n const scope = safeIdentifier(snapshot.limitId) ?? safeIdentifier(fallbackId) ?? \"codex\";\n return [\n cliWindow(snapshot.primary, `${scope}:primary`, `${scope} primary`),\n cliWindow(snapshot.secondary, `${scope}:secondary`, `${scope} secondary`),\n ].filter((item): item is CapacityWindow => item !== null);\n}\n\nexport function parseCliUsage(raw: unknown): UsageSnapshot {\n const response = record(raw) ?? {};\n const primary = record(response.rateLimits);\n const windows = primary ? cliSnapshotWindows(primary, \"codex\") : [];\n const buckets = record(response.rateLimitsByLimitId);\n if (buckets) {\n for (const [id, snapshot] of Object.entries(buckets))\n windows.push(...cliSnapshotWindows(snapshot, id));\n }\n const unique = [...new Map(windows.map((window) => [window.id, window])).values()];\n return { windows: unique, creditsRemaining: null, source: \"cli\" };\n}\n\nfunction capacityFromSnapshot(\n snapshot: UsageSnapshot,\n context: CodexProbeOptions,\n raw?: unknown,\n): CapacityReport {\n const hasUsage = snapshot.windows.some((window) => window.usedPercent !== null);\n const rateLimits = record(record(raw)?.rateLimits);\n const reached = nonEmptyText(rateLimits?.rateLimitReachedType);\n const resetCredits =\n record(record(raw)?.rateLimitResetCredits) ?? record(record(raw)?.usageLimitResetCredits);\n return {\n provider: \"codex\",\n generatedAt: context.checkedAt,\n authenticated: true,\n available: reached ? \"no\" : hasUsage ? \"yes\" : \"unknown\",\n windows: snapshot.windows,\n creditsRemaining: snapshot.creditsRemaining ?? finiteNumber(resetCredits?.availableCount),\n };\n}\n\nfunction jwtExpiry(token: string): number | null {\n const part = token.split(\".\")[1];\n if (!part) return null;\n try {\n return finiteNumber(record(JSON.parse(Buffer.from(part, \"base64url\").toString(\"utf8\")))?.exp);\n } catch {\n return null;\n }\n}\n\nfunction staleOAuth(tokens: UnknownRecord, token: string, now: Date): boolean {\n const metadata = tokens.expires_at ?? tokens.expiresAt ?? tokens.expiry;\n let expiry: number | null = finiteNumber(metadata);\n if (typeof metadata === \"string\") {\n const parsed = Date.parse(metadata);\n expiry = Number.isNaN(parsed) ? null : parsed / 1000;\n }\n expiry ??= jwtExpiry(token);\n return expiry !== null && expiry <= now.getTime() / 1000;\n}\n\nasync function fetchJson(\n fetcher: typeof globalThis.fetch,\n url: string,\n init: RequestInit,\n timeoutMs: number,\n): Promise<unknown> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const response = await fetcher(url, { ...init, signal: controller.signal });\n if (!response.ok) throw new Error(response.status === 401 ? \"unauthorized\" : \"request failed\");\n return await response.json();\n } finally {\n clearTimeout(timer);\n }\n}\n\nasync function apiSnapshot(\n token: string,\n accountId: string,\n source: \"pat\" | \"oauth\",\n options: CodexProbeOptions,\n): Promise<UsageSnapshot> {\n const fetcher = options.fetch ?? globalThis.fetch;\n const raw = await fetchJson(\n fetcher,\n \"https://chatgpt.com/backend-api/wham/usage\",\n {\n headers: { Authorization: `Bearer ${token}`, \"ChatGPT-Account-Id\": accountId },\n },\n options.timeoutMs ?? 5000,\n );\n return parseUsage(raw, source);\n}\n\nfunction appServerRpc(messages: RpcMessage[], timeoutMs = 5000): Promise<CliResponses> {\n return new Promise((resolve, reject) => {\n const child = spawn(\"codex\", CODEX_APP_SERVER_ARGS, {\n stdio: [\"pipe\", \"pipe\", \"ignore\"],\n });\n const results: Partial<CliResponses> = {};\n let buffer = \"\";\n let settled = false;\n const finish = (error?: Error) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n child.kill();\n if (error) reject(error);\n else resolve(results as CliResponses);\n };\n const timer = setTimeout(() => finish(new Error(\"codex probe timed out\")), timeoutMs);\n child.once(\"error\", () => finish(new Error(\"codex app-server unavailable\")));\n child.once(\"exit\", () => {\n if (!settled) finish(new Error(\"codex app-server exited\"));\n });\n child.stdout.setEncoding(\"utf8\");\n child.stdout.on(\"data\", (chunk: string) => {\n buffer += chunk;\n for (;;) {\n const newline = buffer.indexOf(\"\\n\");\n if (newline < 0) break;\n const line = buffer.slice(0, newline).trim();\n buffer = buffer.slice(newline + 1);\n if (!line) continue;\n let message: UnknownRecord;\n try {\n message = JSON.parse(line) as UnknownRecord;\n } catch {\n continue;\n }\n if (message.id === 1) {\n for (const request of messages.slice(1))\n child.stdin.write(`${JSON.stringify(request)}\\n`);\n } else if (message.id === 2) {\n if (message.error) finish(new Error(\"codex rate-limit method failed\"));\n else results.rateLimits = message.result;\n } else if (message.id === 3) {\n if (message.error) finish(new Error(\"codex account method failed\"));\n else results.account = message.result;\n }\n if (\"rateLimits\" in results && \"account\" in results) finish();\n }\n });\n child.stdin.write(`${JSON.stringify(messages[0])}\\n`);\n });\n}\n\nfunction unavailable(options: CodexProbeOptions): CapacityReport {\n return {\n provider: \"codex\",\n generatedAt: options.checkedAt,\n authenticated: null,\n available: \"unknown\",\n windows: [],\n creditsRemaining: null,\n };\n}\n\nasync function cliFallback(options: CodexProbeOptions): Promise<CapacityReport> {\n if (!options.installed) return unavailable(options);\n const messages: RpcMessage[] = [\n {\n id: 1,\n method: \"initialize\",\n params: {\n clientInfo: { name: \"ai-devkit\", title: null, version: \"1\" },\n capabilities: null,\n },\n },\n { method: \"initialized\" },\n { id: 2, method: \"account/rateLimits/read\" },\n { id: 3, method: \"account/read\" },\n ];\n try {\n const rpc = options.rpc ?? ((requests) => appServerRpc(requests, options.timeoutMs));\n const response = await rpc(messages);\n const result = capacityFromSnapshot(\n parseCliUsage(response.rateLimits),\n options,\n response.rateLimits,\n );\n const accountEnvelope = record(response.account);\n if (\n accountEnvelope &&\n Object.hasOwn(accountEnvelope, \"account\") &&\n !record(accountEnvelope.account)\n ) {\n result.authenticated = false;\n result.available = \"unknown\";\n }\n return result;\n } catch {\n return unavailable(options);\n }\n}\n\nexport async function probeCodexCapacity(options: CodexProbeOptions): Promise<CapacityReport> {\n let parsed: UnknownRecord | null = null;\n try {\n const contents = await (options.readFile ?? readFile)(\n resolveCodexAuthPath(options.env),\n \"utf8\",\n );\n parsed = record(JSON.parse(contents));\n } catch {\n return cliFallback(options);\n }\n\n const auth = parsed ?? {};\n const pat = nonEmptyText(auth.personal_access_token);\n if (pat) {\n try {\n const fetcher = options.fetch ?? globalThis.fetch;\n const whoami = record(\n await fetchJson(\n fetcher,\n \"https://auth.openai.com/api/accounts/v1/user-auth-credential/whoami\",\n { headers: { Authorization: `Bearer ${pat}` } },\n options.timeoutMs ?? 5000,\n ),\n );\n const accountId = nonEmptyText(whoami?.chatgpt_account_id);\n if (!accountId) throw new Error(\"account unavailable\");\n return capacityFromSnapshot(await apiSnapshot(pat, accountId, \"pat\", options), options);\n } catch {\n // Continue to a separately available OAuth credential before using the CLI.\n }\n }\n\n const tokens = record(auth.tokens);\n const accessToken = nonEmptyText(tokens?.access_token);\n const accountId = nonEmptyText(tokens?.account_id);\n if (\n tokens &&\n accessToken &&\n accountId &&\n !staleOAuth(tokens, accessToken, (options.now ?? (() => new Date()))())\n ) {\n try {\n return capacityFromSnapshot(\n await apiSnapshot(accessToken, accountId, \"oauth\", options),\n options,\n );\n } catch {\n return cliFallback(options);\n }\n }\n return cliFallback(options);\n}\n"],"names":["spawn","readFile","join","CODEX_APP_SERVER_ARGS","record","value","Array","isArray","finiteNumber","Number","isFinite","nonEmptyText","length","resetTime","seconds","Date","toISOString","isNaN","parse","safeIdentifier","candidate","test","resolveCodexAuthPath","env","process","root","CODEX_HOME","HOME","toRateWindow","id","label","input","used","used_percent","limit_window_seconds","durationMinutes","usedPercent","resetsAt","reset_at","extraWindows","flatMap","entry","index","limit","scope","limit_name","windows","rate_limit","primary_window","secondary_window","filter","window","parseUsage","raw","source","response","limits","credits","additional_rate_limits","creditsRemaining","balance","cliWindow","windowDurationMins","cliSnapshotWindows","fallbackId","snapshot","limitId","primary","secondary","item","parseCliUsage","rateLimits","buckets","rateLimitsByLimitId","Object","entries","push","unique","Map","map","values","capacityFromSnapshot","context","hasUsage","some","reached","rateLimitReachedType","resetCredits","rateLimitResetCredits","usageLimitResetCredits","provider","generatedAt","checkedAt","authenticated","available","availableCount","jwtExpiry","token","part","split","JSON","Buffer","from","toString","exp","staleOAuth","tokens","now","metadata","expires_at","expiresAt","expiry","parsed","getTime","fetchJson","fetcher","url","init","timeoutMs","controller","AbortController","timer","setTimeout","abort","signal","ok","Error","status","json","clearTimeout","apiSnapshot","accountId","options","fetch","globalThis","headers","Authorization","appServerRpc","messages","Promise","resolve","reject","child","stdio","results","buffer","settled","finish","error","kill","once","stdout","setEncoding","on","chunk","newline","indexOf","line","slice","trim","message","request","stdin","write","stringify","result","account","unavailable","cliFallback","installed","method","params","clientInfo","name","title","version","capabilities","rpc","requests","accountEnvelope","hasOwn","probeCodexCapacity","contents","auth","pat","personal_access_token","whoami","chatgpt_account_id","accessToken","access_token","account_id"],"mappings":"AAAA,SAASA,KAAK,QAAQ,qBAAqB;AAC3C,SAASC,QAAQ,QAAQ,mBAAmB;AAC5C,SAASC,IAAI,QAAQ,YAAY;AAejC,OAAO,MAAMC,wBAAwB;IAAC;IAAM;IAAa;IAAM;IAAa;CAAa,CAAU;AAanG,SAASC,OAAOC,KAAc;IAC5B,OAAOA,UAAU,QAAQ,OAAOA,UAAU,YAAY,CAACC,MAAMC,OAAO,CAACF,SAChEA,QACD;AACN;AAEA,SAASG,aAAaH,KAAc;IAClC,OAAO,OAAOA,UAAU,YAAYI,OAAOC,QAAQ,CAACL,SAASA,QAAQ;AACvE;AAEA,SAASM,aAAaN,KAAc;IAClC,OAAO,OAAOA,UAAU,YAAYA,MAAMO,MAAM,GAAG,IAAIP,QAAQ;AACjE;AAEA,SAASQ,UAAUR,KAAc;IAC/B,MAAMS,UAAUN,aAAaH;IAC7B,IAAIS,YAAY,MAAM,OAAO,IAAIC,KAAKD,UAAU,MAAME,WAAW;IACjE,IAAI,OAAOX,UAAU,YAAY,CAACI,OAAOQ,KAAK,CAACF,KAAKG,KAAK,CAACb,SACxD,OAAO,IAAIU,KAAKV,OAAOW,WAAW;IACpC,OAAO;AACT;AAEA,SAASG,eAAed,KAAc;IACpC,MAAMe,YAAYT,aAAaN;IAC/B,IAAI,CAACe,aAAa,CAAC,2BAA2BC,IAAI,CAACD,YAAY,OAAO;IACtE,IAAI,2CAA2CC,IAAI,CAACD,YAAY,OAAO;IACvE,OAAOA;AACT;AAEA,OAAO,SAASE,qBAAqBC,MAAyBC,QAAQD,GAAG;IACvE,MAAME,OAAOF,IAAIG,UAAU,IAAIxB,KAAKqB,IAAII,IAAI,IAAI,IAAI;IACpD,OAAOzB,KAAKuB,MAAM;AACpB;AAEA,OAAO,SAASG,aAAavB,KAAc,EAAEwB,EAAU,EAAEC,KAAa;IACpE,MAAMC,QAAQ3B,OAAOC;IACrB,IAAI,CAAC0B,OAAO,OAAO;IACnB,MAAMC,OAAOxB,aAAauB,MAAME,YAAY;IAC5C,MAAMnB,UAAUN,aAAauB,MAAMG,oBAAoB;IACvD,OAAO;QACLL;QACAC;QACAK,iBAAiBrB,YAAY,OAAO,OAAOA,UAAU;QACrDsB,aAAaJ;QACbK,UAAUxB,UAAUkB,MAAMO,QAAQ;IACpC;AACF;AAEA,SAASC,aAAalC,KAAc;IAClC,IAAI,CAACC,MAAMC,OAAO,CAACF,QAAQ,OAAO,EAAE;IACpC,OAAOA,MAAMmC,OAAO,CAAC,CAACC,OAAOC;QAC3B,MAAMC,QAAQvC,OAAOqC;QACrB,IAAI,CAACE,OAAO,OAAO,EAAE;QACrB,MAAMC,QAAQzB,eAAewB,MAAME,UAAU,KAAK,CAAC,MAAM,EAAEH,QAAQ,GAAG;QACtE,MAAMI,UAAU1C,OAAOuC,MAAMI,UAAU,KAAKJ;QAC5C,OAAO;YACLf,aAAakB,QAAQE,cAAc,EAAE,GAAGJ,MAAM,QAAQ,CAAC,EAAE,GAAGA,MAAM,QAAQ,CAAC;YAC3EhB,aAAakB,QAAQG,gBAAgB,EAAE,GAAGL,MAAM,UAAU,CAAC,EAAE,GAAGA,MAAM,UAAU,CAAC;SAClF,CAACM,MAAM,CAAC,CAACC,SAAqCA,WAAW;IAC5D;AACF;AAEA,OAAO,SAASC,WAAWC,GAAY,EAAEC,MAAuB;IAC9D,MAAMC,WAAWnD,OAAOiD,QAAQ,CAAC;IACjC,MAAMG,SAASpD,OAAOmD,SAASR,UAAU,KAAK,CAAC;IAC/C,MAAMU,UAAUrD,OAAOmD,SAASE,OAAO,KAAK,CAAC;IAC7C,OAAO;QACLX,SAAS;YACPlB,aAAa4B,OAAOR,cAAc,EAAE,WAAW;YAC/CpB,aAAa4B,OAAOP,gBAAgB,EAAE,UAAU;eAC7CV,aAAagB,SAASG,sBAAsB;SAChD,CAACR,MAAM,CAAC,CAACC,SAAqCA,WAAW;QAC1DQ,kBAAkBnD,aAAaiD,QAAQG,OAAO;QAC9CN;IACF;AACF;AAEA,SAASO,UAAUxD,KAAc,EAAEwB,EAAU,EAAEC,KAAa;IAC1D,MAAMC,QAAQ3B,OAAOC;IACrB,IAAI,CAAC0B,OAAO,OAAO;IACnB,OAAO;QACLF;QACAC;QACAK,iBAAiB3B,aAAauB,MAAM+B,kBAAkB;QACtD1B,aAAa5B,aAAauB,MAAMK,WAAW;QAC3CC,UAAUxB,UAAUkB,MAAMM,QAAQ;IACpC;AACF;AAEA,SAAS0B,mBAAmB1D,KAAc,EAAE2D,UAAkB;IAC5D,MAAMC,WAAW7D,OAAOC;IACxB,IAAI,CAAC4D,UAAU,OAAO,EAAE;IACxB,MAAMrB,QAAQzB,eAAe8C,SAASC,OAAO,KAAK/C,eAAe6C,eAAe;IAChF,OAAO;QACLH,UAAUI,SAASE,OAAO,EAAE,GAAGvB,MAAM,QAAQ,CAAC,EAAE,GAAGA,MAAM,QAAQ,CAAC;QAClEiB,UAAUI,SAASG,SAAS,EAAE,GAAGxB,MAAM,UAAU,CAAC,EAAE,GAAGA,MAAM,UAAU,CAAC;KACzE,CAACM,MAAM,CAAC,CAACmB,OAAiCA,SAAS;AACtD;AAEA,OAAO,SAASC,cAAcjB,GAAY;IACxC,MAAME,WAAWnD,OAAOiD,QAAQ,CAAC;IACjC,MAAMc,UAAU/D,OAAOmD,SAASgB,UAAU;IAC1C,MAAMzB,UAAUqB,UAAUJ,mBAAmBI,SAAS,WAAW,EAAE;IACnE,MAAMK,UAAUpE,OAAOmD,SAASkB,mBAAmB;IACnD,IAAID,SAAS;QACX,KAAK,MAAM,CAAC3C,IAAIoC,SAAS,IAAIS,OAAOC,OAAO,CAACH,SAC1C1B,QAAQ8B,IAAI,IAAIb,mBAAmBE,UAAUpC;IACjD;IACA,MAAMgD,SAAS;WAAI,IAAIC,IAAIhC,QAAQiC,GAAG,CAAC,CAAC5B,SAAW;gBAACA,OAAOtB,EAAE;gBAAEsB;aAAO,GAAG6B,MAAM;KAAG;IAClF,OAAO;QAAElC,SAAS+B;QAAQlB,kBAAkB;QAAML,QAAQ;IAAM;AAClE;AAEA,SAAS2B,qBACPhB,QAAuB,EACvBiB,OAA0B,EAC1B7B,GAAa;IAEb,MAAM8B,WAAWlB,SAASnB,OAAO,CAACsC,IAAI,CAAC,CAACjC,SAAWA,OAAOf,WAAW,KAAK;IAC1E,MAAMmC,aAAanE,OAAOA,OAAOiD,MAAMkB;IACvC,MAAMc,UAAU1E,aAAa4D,YAAYe;IACzC,MAAMC,eACJnF,OAAOA,OAAOiD,MAAMmC,0BAA0BpF,OAAOA,OAAOiD,MAAMoC;IACpE,OAAO;QACLC,UAAU;QACVC,aAAaT,QAAQU,SAAS;QAC9BC,eAAe;QACfC,WAAWT,UAAU,OAAOF,WAAW,QAAQ;QAC/CrC,SAASmB,SAASnB,OAAO;QACzBa,kBAAkBM,SAASN,gBAAgB,IAAInD,aAAa+E,cAAcQ;IAC5E;AACF;AAEA,SAASC,UAAUC,KAAa;IAC9B,MAAMC,OAAOD,MAAME,KAAK,CAAC,IAAI,CAAC,EAAE;IAChC,IAAI,CAACD,MAAM,OAAO;IAClB,IAAI;QACF,OAAO1F,aAAaJ,OAAOgG,KAAKlF,KAAK,CAACmF,OAAOC,IAAI,CAACJ,MAAM,aAAaK,QAAQ,CAAC,WAAWC;IAC3F,EAAE,OAAM;QACN,OAAO;IACT;AACF;AAEA,SAASC,WAAWC,MAAqB,EAAET,KAAa,EAAEU,GAAS;IACjE,MAAMC,WAAWF,OAAOG,UAAU,IAAIH,OAAOI,SAAS,IAAIJ,OAAOK,MAAM;IACvE,IAAIA,SAAwBvG,aAAaoG;IACzC,IAAI,OAAOA,aAAa,UAAU;QAChC,MAAMI,SAASjG,KAAKG,KAAK,CAAC0F;QAC1BG,SAAStG,OAAOQ,KAAK,CAAC+F,UAAU,OAAOA,SAAS;IAClD;IACAD,WAAWf,UAAUC;IACrB,OAAOc,WAAW,QAAQA,UAAUJ,IAAIM,OAAO,KAAK;AACtD;AAEA,eAAeC,UACbC,OAAgC,EAChCC,GAAW,EACXC,IAAiB,EACjBC,SAAiB;IAEjB,MAAMC,aAAa,IAAIC;IACvB,MAAMC,QAAQC,WAAW,IAAMH,WAAWI,KAAK,IAAIL;IACnD,IAAI;QACF,MAAM/D,WAAW,MAAM4D,QAAQC,KAAK;YAAE,GAAGC,IAAI;YAAEO,QAAQL,WAAWK,MAAM;QAAC;QACzE,IAAI,CAACrE,SAASsE,EAAE,EAAE,MAAM,IAAIC,MAAMvE,SAASwE,MAAM,KAAK,MAAM,iBAAiB;QAC7E,OAAO,MAAMxE,SAASyE,IAAI;IAC5B,SAAU;QACRC,aAAaR;IACf;AACF;AAEA,eAAeS,YACbjC,KAAa,EACbkC,SAAiB,EACjB7E,MAAuB,EACvB8E,OAA0B;IAE1B,MAAMjB,UAAUiB,QAAQC,KAAK,IAAIC,WAAWD,KAAK;IACjD,MAAMhF,MAAM,MAAM6D,UAChBC,SACA,8CACA;QACEoB,SAAS;YAAEC,eAAe,CAAC,OAAO,EAAEvC,OAAO;YAAE,sBAAsBkC;QAAU;IAC/E,GACAC,QAAQd,SAAS,IAAI;IAEvB,OAAOlE,WAAWC,KAAKC;AACzB;AAEA,SAASmF,aAAaC,QAAsB,EAAEpB,YAAY,IAAI;IAC5D,OAAO,IAAIqB,QAAQ,CAACC,SAASC;QAC3B,MAAMC,QAAQ9I,MAAM,SAASG,uBAAuB;YAClD4I,OAAO;gBAAC;gBAAQ;gBAAQ;aAAS;QACnC;QACA,MAAMC,UAAiC,CAAC;QACxC,IAAIC,SAAS;QACb,IAAIC,UAAU;QACd,MAAMC,SAAS,CAACC;YACd,IAAIF,SAAS;YACbA,UAAU;YACVjB,aAAaR;YACbqB,MAAMO,IAAI;YACV,IAAID,OAAOP,OAAOO;iBACbR,QAAQI;QACf;QACA,MAAMvB,QAAQC,WAAW,IAAMyB,OAAO,IAAIrB,MAAM,2BAA2BR;QAC3EwB,MAAMQ,IAAI,CAAC,SAAS,IAAMH,OAAO,IAAIrB,MAAM;QAC3CgB,MAAMQ,IAAI,CAAC,QAAQ;YACjB,IAAI,CAACJ,SAASC,OAAO,IAAIrB,MAAM;QACjC;QACAgB,MAAMS,MAAM,CAACC,WAAW,CAAC;QACzBV,MAAMS,MAAM,CAACE,EAAE,CAAC,QAAQ,CAACC;YACvBT,UAAUS;YACV,OAAS;gBACP,MAAMC,UAAUV,OAAOW,OAAO,CAAC;gBAC/B,IAAID,UAAU,GAAG;gBACjB,MAAME,OAAOZ,OAAOa,KAAK,CAAC,GAAGH,SAASI,IAAI;gBAC1Cd,SAASA,OAAOa,KAAK,CAACH,UAAU;gBAChC,IAAI,CAACE,MAAM;gBACX,IAAIG;gBACJ,IAAI;oBACFA,UAAU5D,KAAKlF,KAAK,CAAC2I;gBACvB,EAAE,OAAM;oBACN;gBACF;gBACA,IAAIG,QAAQnI,EAAE,KAAK,GAAG;oBACpB,KAAK,MAAMoI,WAAWvB,SAASoB,KAAK,CAAC,GACnChB,MAAMoB,KAAK,CAACC,KAAK,CAAC,GAAG/D,KAAKgE,SAAS,CAACH,SAAS,EAAE,CAAC;gBACpD,OAAO,IAAID,QAAQnI,EAAE,KAAK,GAAG;oBAC3B,IAAImI,QAAQZ,KAAK,EAAED,OAAO,IAAIrB,MAAM;yBAC/BkB,QAAQzE,UAAU,GAAGyF,QAAQK,MAAM;gBAC1C,OAAO,IAAIL,QAAQnI,EAAE,KAAK,GAAG;oBAC3B,IAAImI,QAAQZ,KAAK,EAAED,OAAO,IAAIrB,MAAM;yBAC/BkB,QAAQsB,OAAO,GAAGN,QAAQK,MAAM;gBACvC;gBACA,IAAI,gBAAgBrB,WAAW,aAAaA,SAASG;YACvD;QACF;QACAL,MAAMoB,KAAK,CAACC,KAAK,CAAC,GAAG/D,KAAKgE,SAAS,CAAC1B,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC;IACtD;AACF;AAEA,SAAS6B,YAAYnC,OAA0B;IAC7C,OAAO;QACL1C,UAAU;QACVC,aAAayC,QAAQxC,SAAS;QAC9BC,eAAe;QACfC,WAAW;QACXhD,SAAS,EAAE;QACXa,kBAAkB;IACpB;AACF;AAEA,eAAe6G,YAAYpC,OAA0B;IACnD,IAAI,CAACA,QAAQqC,SAAS,EAAE,OAAOF,YAAYnC;IAC3C,MAAMM,WAAyB;QAC7B;YACE7G,IAAI;YACJ6I,QAAQ;YACRC,QAAQ;gBACNC,YAAY;oBAAEC,MAAM;oBAAaC,OAAO;oBAAMC,SAAS;gBAAI;gBAC3DC,cAAc;YAChB;QACF;QACA;YAAEN,QAAQ;QAAc;QACxB;YAAE7I,IAAI;YAAG6I,QAAQ;QAA0B;QAC3C;YAAE7I,IAAI;YAAG6I,QAAQ;QAAe;KACjC;IACD,IAAI;QACF,MAAMO,MAAM7C,QAAQ6C,GAAG,IAAK,CAAA,CAACC,WAAazC,aAAayC,UAAU9C,QAAQd,SAAS,CAAA;QAClF,MAAM/D,WAAW,MAAM0H,IAAIvC;QAC3B,MAAM2B,SAASpF,qBACbX,cAAcf,SAASgB,UAAU,GACjC6D,SACA7E,SAASgB,UAAU;QAErB,MAAM4G,kBAAkB/K,OAAOmD,SAAS+G,OAAO;QAC/C,IACEa,mBACAzG,OAAO0G,MAAM,CAACD,iBAAiB,cAC/B,CAAC/K,OAAO+K,gBAAgBb,OAAO,GAC/B;YACAD,OAAOxE,aAAa,GAAG;YACvBwE,OAAOvE,SAAS,GAAG;QACrB;QACA,OAAOuE;IACT,EAAE,OAAM;QACN,OAAOE,YAAYnC;IACrB;AACF;AAEA,OAAO,eAAeiD,mBAAmBjD,OAA0B;IACjE,IAAIpB,SAA+B;IACnC,IAAI;QACF,MAAMsE,WAAW,MAAM,AAAClD,CAAAA,QAAQnI,QAAQ,IAAIA,QAAO,EACjDqB,qBAAqB8G,QAAQ7G,GAAG,GAChC;QAEFyF,SAAS5G,OAAOgG,KAAKlF,KAAK,CAACoK;IAC7B,EAAE,OAAM;QACN,OAAOd,YAAYpC;IACrB;IAEA,MAAMmD,OAAOvE,UAAU,CAAC;IACxB,MAAMwE,MAAM7K,aAAa4K,KAAKE,qBAAqB;IACnD,IAAID,KAAK;QACP,IAAI;YACF,MAAMrE,UAAUiB,QAAQC,KAAK,IAAIC,WAAWD,KAAK;YACjD,MAAMqD,SAAStL,OACb,MAAM8G,UACJC,SACA,uEACA;gBAAEoB,SAAS;oBAAEC,eAAe,CAAC,OAAO,EAAEgD,KAAK;gBAAC;YAAE,GAC9CpD,QAAQd,SAAS,IAAI;YAGzB,MAAMa,YAAYxH,aAAa+K,QAAQC;YACvC,IAAI,CAACxD,WAAW,MAAM,IAAIL,MAAM;YAChC,OAAO7C,qBAAqB,MAAMiD,YAAYsD,KAAKrD,WAAW,OAAOC,UAAUA;QACjF,EAAE,OAAM;QACN,4EAA4E;QAC9E;IACF;IAEA,MAAM1B,SAAStG,OAAOmL,KAAK7E,MAAM;IACjC,MAAMkF,cAAcjL,aAAa+F,QAAQmF;IACzC,MAAM1D,YAAYxH,aAAa+F,QAAQoF;IACvC,IACEpF,UACAkF,eACAzD,aACA,CAAC1B,WAAWC,QAAQkF,aAAa,AAACxD,CAAAA,QAAQzB,GAAG,IAAK,CAAA,IAAM,IAAI5F,MAAK,CAAC,MAClE;QACA,IAAI;YACF,OAAOkE,qBACL,MAAMiD,YAAY0D,aAAazD,WAAW,SAASC,UACnDA;QAEJ,EAAE,OAAM;YACN,OAAOoC,YAAYpC;QACrB;IACF;IACA,OAAOoC,YAAYpC;AACrB"}
|
|
1
|
+
{"version":3,"sources":["../../src/capacity/codex.ts"],"sourcesContent":["import { spawn } from \"node:child_process\";\nimport { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { CapacityReport, CapacityWindow } from \"./types.js\";\n\ntype CodexUsageSource = \"pat\" | \"oauth\" | \"cli\";\ntype UsageSnapshot = {\n windows: CapacityWindow[];\n creditsRemaining: number | null;\n source: CodexUsageSource;\n};\n\ntype UnknownRecord = Record<string, unknown>;\ntype RpcMessage = { id?: number; method: string; params?: UnknownRecord };\ntype CliResponses = { rateLimits: unknown; account: unknown };\ntype CodexRpc = (messages: RpcMessage[]) => Promise<CliResponses>;\n\nexport const CODEX_APP_SERVER_ARGS = [\n \"-s\",\n \"read-only\",\n \"-a\",\n \"untrusted\",\n \"app-server\",\n] as const;\n\ntype CodexProbeOptions = {\n installed: boolean;\n checkedAt: string;\n readFile?: (path: string, encoding: BufferEncoding) => Promise<string>;\n fetch?: typeof globalThis.fetch;\n rpc?: CodexRpc;\n timeoutMs?: number;\n env?: NodeJS.ProcessEnv;\n now?: () => Date;\n};\n\nfunction record(value: unknown): UnknownRecord | null {\n return value !== null && typeof value === \"object\" && !Array.isArray(value)\n ? (value as UnknownRecord)\n : null;\n}\n\nfunction finiteNumber(value: unknown): number | null {\n return typeof value === \"number\" && Number.isFinite(value) ? value : null;\n}\n\nfunction nonEmptyText(value: unknown): string | null {\n return typeof value === \"string\" && value.length > 0 ? value : null;\n}\n\nfunction resetTime(value: unknown): string | null {\n const seconds = finiteNumber(value);\n if (seconds !== null) return new Date(seconds * 1000).toISOString();\n if (typeof value === \"string\" && !Number.isNaN(Date.parse(value)))\n return new Date(value).toISOString();\n return null;\n}\n\nfunction safeIdentifier(value: unknown): string | null {\n const candidate = nonEmptyText(value);\n if (!candidate || !/^[a-z][a-z0-9_-]{0,63}$/i.test(candidate)) return null;\n if (/(?:account|token|secret|key)[_-]?\\d{6,}/i.test(candidate)) return null;\n return candidate;\n}\n\nexport function resolveCodexAuthPath(\n env: NodeJS.ProcessEnv = process.env,\n): string {\n const root = env.CODEX_HOME || join(env.HOME || \"\", \".codex\");\n return join(root, \"auth.json\");\n}\n\nexport function toRateWindow(\n value: unknown,\n id: string,\n label: string,\n): CapacityWindow | null {\n const input = record(value);\n if (!input) return null;\n const used = finiteNumber(input.used_percent);\n const seconds = finiteNumber(input.limit_window_seconds);\n return {\n id,\n label,\n durationMinutes: seconds === null ? null : seconds / 60,\n usedPercent: used,\n resetsAt: resetTime(input.reset_at),\n };\n}\n\nfunction extraWindows(value: unknown): CapacityWindow[] {\n if (!Array.isArray(value)) return [];\n return value.flatMap((entry, index) => {\n const limit = record(entry);\n if (!limit) return [];\n const scope = safeIdentifier(limit.limit_name) ?? `extra-${index + 1}`;\n const windows = record(limit.rate_limit) ?? limit;\n return [\n toRateWindow(\n windows.primary_window,\n `${scope}:primary`,\n `${scope} primary`,\n ),\n toRateWindow(\n windows.secondary_window,\n `${scope}:secondary`,\n `${scope} secondary`,\n ),\n ].filter((window): window is CapacityWindow => window !== null);\n });\n}\n\nexport function parseUsage(\n raw: unknown,\n source: \"pat\" | \"oauth\",\n): UsageSnapshot {\n const response = record(raw) ?? {};\n const limits = record(response.rate_limit) ?? {};\n const credits = record(response.credits) ?? {};\n return {\n windows: [\n toRateWindow(limits.primary_window, \"session\", \"Session\"),\n toRateWindow(limits.secondary_window, \"weekly\", \"Weekly\"),\n ...extraWindows(response.additional_rate_limits),\n ].filter((window): window is CapacityWindow => window !== null),\n creditsRemaining: finiteNumber(credits.balance),\n source,\n };\n}\n\nfunction cliWindow(\n value: unknown,\n id: string,\n label: string,\n): CapacityWindow | null {\n const input = record(value);\n if (!input) return null;\n return {\n id,\n label,\n durationMinutes: finiteNumber(input.windowDurationMins),\n usedPercent: finiteNumber(input.usedPercent),\n resetsAt: resetTime(input.resetsAt),\n };\n}\n\nfunction cliSnapshotWindows(\n value: unknown,\n fallbackId: string,\n): CapacityWindow[] {\n const snapshot = record(value);\n if (!snapshot) return [];\n const scope =\n safeIdentifier(snapshot.limitId) ?? safeIdentifier(fallbackId) ?? \"codex\";\n return [\n cliWindow(snapshot.primary, `${scope}:primary`, `${scope} primary`),\n cliWindow(snapshot.secondary, `${scope}:secondary`, `${scope} secondary`),\n ].filter((item): item is CapacityWindow => item !== null);\n}\n\nexport function parseCliUsage(raw: unknown): UsageSnapshot {\n const response = record(raw) ?? {};\n const primary = record(response.rateLimits);\n const windows = primary ? cliSnapshotWindows(primary, \"codex\") : [];\n const buckets = record(response.rateLimitsByLimitId);\n if (buckets) {\n for (const [id, snapshot] of Object.entries(buckets))\n windows.push(...cliSnapshotWindows(snapshot, id));\n }\n const unique = [\n ...new Map(windows.map((window) => [window.id, window])).values(),\n ];\n return { windows: unique, creditsRemaining: null, source: \"cli\" };\n}\n\nfunction capacityFromSnapshot(\n snapshot: UsageSnapshot,\n context: CodexProbeOptions,\n raw?: unknown,\n): CapacityReport {\n const hasUsage = snapshot.windows.some(\n (window) => window.usedPercent !== null,\n );\n const rateLimits = record(record(raw)?.rateLimits);\n const reached = nonEmptyText(rateLimits?.rateLimitReachedType);\n const resetCredits =\n record(record(raw)?.rateLimitResetCredits) ??\n record(record(raw)?.usageLimitResetCredits);\n return {\n harness: \"codex\",\n provider: \"openai\",\n generatedAt: context.checkedAt,\n authenticated: true,\n available: reached ? \"no\" : hasUsage ? \"yes\" : \"unknown\",\n windows: snapshot.windows,\n creditsRemaining:\n snapshot.creditsRemaining ?? finiteNumber(resetCredits?.availableCount),\n };\n}\n\nfunction jwtExpiry(token: string): number | null {\n const part = token.split(\".\")[1];\n if (!part) return null;\n try {\n return finiteNumber(\n record(JSON.parse(Buffer.from(part, \"base64url\").toString(\"utf8\")))?.exp,\n );\n } catch {\n return null;\n }\n}\n\nfunction staleOAuth(tokens: UnknownRecord, token: string, now: Date): boolean {\n const metadata = tokens.expires_at ?? tokens.expiresAt ?? tokens.expiry;\n let expiry: number | null = finiteNumber(metadata);\n if (typeof metadata === \"string\") {\n const parsed = Date.parse(metadata);\n expiry = Number.isNaN(parsed) ? null : parsed / 1000;\n }\n expiry ??= jwtExpiry(token);\n return expiry !== null && expiry <= now.getTime() / 1000;\n}\n\nasync function fetchJson(\n fetcher: typeof globalThis.fetch,\n url: string,\n init: RequestInit,\n timeoutMs: number,\n): Promise<unknown> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const response = await fetcher(url, { ...init, signal: controller.signal });\n if (!response.ok)\n throw new Error(\n response.status === 401 ? \"unauthorized\" : \"request failed\",\n );\n return await response.json();\n } finally {\n clearTimeout(timer);\n }\n}\n\nasync function apiSnapshot(\n token: string,\n accountId: string,\n source: \"pat\" | \"oauth\",\n options: CodexProbeOptions,\n): Promise<UsageSnapshot> {\n const fetcher = options.fetch ?? globalThis.fetch;\n const raw = await fetchJson(\n fetcher,\n \"https://chatgpt.com/backend-api/wham/usage\",\n {\n headers: {\n Authorization: `Bearer ${token}`,\n \"ChatGPT-Account-Id\": accountId,\n },\n },\n options.timeoutMs ?? 5000,\n );\n return parseUsage(raw, source);\n}\n\nfunction appServerRpc(\n messages: RpcMessage[],\n timeoutMs = 5000,\n): Promise<CliResponses> {\n return new Promise((resolve, reject) => {\n const child = spawn(\"codex\", CODEX_APP_SERVER_ARGS, {\n stdio: [\"pipe\", \"pipe\", \"ignore\"],\n });\n const results: Partial<CliResponses> = {};\n let buffer = \"\";\n let settled = false;\n const finish = (error?: Error) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n child.kill();\n if (error) reject(error);\n else resolve(results as CliResponses);\n };\n const timer = setTimeout(\n () => finish(new Error(\"codex probe timed out\")),\n timeoutMs,\n );\n child.once(\"error\", () =>\n finish(new Error(\"codex app-server unavailable\")),\n );\n child.once(\"exit\", () => {\n if (!settled) finish(new Error(\"codex app-server exited\"));\n });\n child.stdout.setEncoding(\"utf8\");\n child.stdout.on(\"data\", (chunk: string) => {\n buffer += chunk;\n for (;;) {\n const newline = buffer.indexOf(\"\\n\");\n if (newline < 0) break;\n const line = buffer.slice(0, newline).trim();\n buffer = buffer.slice(newline + 1);\n if (!line) continue;\n let message: UnknownRecord;\n try {\n message = JSON.parse(line) as UnknownRecord;\n } catch {\n continue;\n }\n if (message.id === 1) {\n for (const request of messages.slice(1))\n child.stdin.write(`${JSON.stringify(request)}\\n`);\n } else if (message.id === 2) {\n if (message.error)\n finish(new Error(\"codex rate-limit method failed\"));\n else results.rateLimits = message.result;\n } else if (message.id === 3) {\n if (message.error) finish(new Error(\"codex account method failed\"));\n else results.account = message.result;\n }\n if (\"rateLimits\" in results && \"account\" in results) finish();\n }\n });\n child.stdin.write(`${JSON.stringify(messages[0])}\\n`);\n });\n}\n\nexport function codexUnavailableReport(checkedAt: string): CapacityReport {\n return {\n harness: \"codex\",\n provider: \"openai\",\n generatedAt: checkedAt,\n authenticated: null,\n available: \"unknown\",\n windows: [],\n creditsRemaining: null,\n };\n}\n\nfunction unavailable(options: CodexProbeOptions): CapacityReport {\n return codexUnavailableReport(options.checkedAt);\n}\n\nasync function cliFallback(\n options: CodexProbeOptions,\n): Promise<CapacityReport> {\n if (!options.installed) return unavailable(options);\n const messages: RpcMessage[] = [\n {\n id: 1,\n method: \"initialize\",\n params: {\n clientInfo: { name: \"ai-devkit\", title: null, version: \"1\" },\n capabilities: null,\n },\n },\n { method: \"initialized\" },\n { id: 2, method: \"account/rateLimits/read\" },\n { id: 3, method: \"account/read\" },\n ];\n try {\n const rpc =\n options.rpc ?? ((requests) => appServerRpc(requests, options.timeoutMs));\n const response = await rpc(messages);\n const result = capacityFromSnapshot(\n parseCliUsage(response.rateLimits),\n options,\n response.rateLimits,\n );\n const accountEnvelope = record(response.account);\n if (\n accountEnvelope &&\n Object.hasOwn(accountEnvelope, \"account\") &&\n !record(accountEnvelope.account)\n ) {\n result.authenticated = false;\n result.available = \"unknown\";\n }\n return result;\n } catch {\n return unavailable(options);\n }\n}\n\nexport async function probeCodexCapacity(\n options: CodexProbeOptions,\n): Promise<CapacityReport> {\n let parsed: UnknownRecord | null = null;\n try {\n const contents = await (options.readFile ?? readFile)(\n resolveCodexAuthPath(options.env),\n \"utf8\",\n );\n parsed = record(JSON.parse(contents));\n } catch {\n return cliFallback(options);\n }\n\n const auth = parsed ?? {};\n const pat = nonEmptyText(auth.personal_access_token);\n if (pat) {\n try {\n const fetcher = options.fetch ?? globalThis.fetch;\n const whoami = record(\n await fetchJson(\n fetcher,\n \"https://auth.openai.com/api/accounts/v1/user-auth-credential/whoami\",\n { headers: { Authorization: `Bearer ${pat}` } },\n options.timeoutMs ?? 5000,\n ),\n );\n const accountId = nonEmptyText(whoami?.chatgpt_account_id);\n if (!accountId) throw new Error(\"account unavailable\");\n return capacityFromSnapshot(\n await apiSnapshot(pat, accountId, \"pat\", options),\n options,\n );\n } catch {\n // Continue to a separately available OAuth credential before using the CLI.\n }\n }\n\n const tokens = record(auth.tokens);\n const accessToken = nonEmptyText(tokens?.access_token);\n const accountId = nonEmptyText(tokens?.account_id);\n if (\n tokens &&\n accessToken &&\n accountId &&\n !staleOAuth(tokens, accessToken, (options.now ?? (() => new Date()))())\n ) {\n try {\n return capacityFromSnapshot(\n await apiSnapshot(accessToken, accountId, \"oauth\", options),\n options,\n );\n } catch {\n return cliFallback(options);\n }\n }\n return cliFallback(options);\n}\n"],"names":["spawn","readFile","join","CODEX_APP_SERVER_ARGS","record","value","Array","isArray","finiteNumber","Number","isFinite","nonEmptyText","length","resetTime","seconds","Date","toISOString","isNaN","parse","safeIdentifier","candidate","test","resolveCodexAuthPath","env","process","root","CODEX_HOME","HOME","toRateWindow","id","label","input","used","used_percent","limit_window_seconds","durationMinutes","usedPercent","resetsAt","reset_at","extraWindows","flatMap","entry","index","limit","scope","limit_name","windows","rate_limit","primary_window","secondary_window","filter","window","parseUsage","raw","source","response","limits","credits","additional_rate_limits","creditsRemaining","balance","cliWindow","windowDurationMins","cliSnapshotWindows","fallbackId","snapshot","limitId","primary","secondary","item","parseCliUsage","rateLimits","buckets","rateLimitsByLimitId","Object","entries","push","unique","Map","map","values","capacityFromSnapshot","context","hasUsage","some","reached","rateLimitReachedType","resetCredits","rateLimitResetCredits","usageLimitResetCredits","harness","provider","generatedAt","checkedAt","authenticated","available","availableCount","jwtExpiry","token","part","split","JSON","Buffer","from","toString","exp","staleOAuth","tokens","now","metadata","expires_at","expiresAt","expiry","parsed","getTime","fetchJson","fetcher","url","init","timeoutMs","controller","AbortController","timer","setTimeout","abort","signal","ok","Error","status","json","clearTimeout","apiSnapshot","accountId","options","fetch","globalThis","headers","Authorization","appServerRpc","messages","Promise","resolve","reject","child","stdio","results","buffer","settled","finish","error","kill","once","stdout","setEncoding","on","chunk","newline","indexOf","line","slice","trim","message","request","stdin","write","stringify","result","account","codexUnavailableReport","unavailable","cliFallback","installed","method","params","clientInfo","name","title","version","capabilities","rpc","requests","accountEnvelope","hasOwn","probeCodexCapacity","contents","auth","pat","personal_access_token","whoami","chatgpt_account_id","accessToken","access_token","account_id"],"mappings":"AAAA,SAASA,KAAK,QAAQ,qBAAqB;AAC3C,SAASC,QAAQ,QAAQ,mBAAmB;AAC5C,SAASC,IAAI,QAAQ,YAAY;AAejC,OAAO,MAAMC,wBAAwB;IACnC;IACA;IACA;IACA;IACA;CACD,CAAU;AAaX,SAASC,OAAOC,KAAc;IAC5B,OAAOA,UAAU,QAAQ,OAAOA,UAAU,YAAY,CAACC,MAAMC,OAAO,CAACF,SAChEA,QACD;AACN;AAEA,SAASG,aAAaH,KAAc;IAClC,OAAO,OAAOA,UAAU,YAAYI,OAAOC,QAAQ,CAACL,SAASA,QAAQ;AACvE;AAEA,SAASM,aAAaN,KAAc;IAClC,OAAO,OAAOA,UAAU,YAAYA,MAAMO,MAAM,GAAG,IAAIP,QAAQ;AACjE;AAEA,SAASQ,UAAUR,KAAc;IAC/B,MAAMS,UAAUN,aAAaH;IAC7B,IAAIS,YAAY,MAAM,OAAO,IAAIC,KAAKD,UAAU,MAAME,WAAW;IACjE,IAAI,OAAOX,UAAU,YAAY,CAACI,OAAOQ,KAAK,CAACF,KAAKG,KAAK,CAACb,SACxD,OAAO,IAAIU,KAAKV,OAAOW,WAAW;IACpC,OAAO;AACT;AAEA,SAASG,eAAed,KAAc;IACpC,MAAMe,YAAYT,aAAaN;IAC/B,IAAI,CAACe,aAAa,CAAC,2BAA2BC,IAAI,CAACD,YAAY,OAAO;IACtE,IAAI,2CAA2CC,IAAI,CAACD,YAAY,OAAO;IACvE,OAAOA;AACT;AAEA,OAAO,SAASE,qBACdC,MAAyBC,QAAQD,GAAG;IAEpC,MAAME,OAAOF,IAAIG,UAAU,IAAIxB,KAAKqB,IAAII,IAAI,IAAI,IAAI;IACpD,OAAOzB,KAAKuB,MAAM;AACpB;AAEA,OAAO,SAASG,aACdvB,KAAc,EACdwB,EAAU,EACVC,KAAa;IAEb,MAAMC,QAAQ3B,OAAOC;IACrB,IAAI,CAAC0B,OAAO,OAAO;IACnB,MAAMC,OAAOxB,aAAauB,MAAME,YAAY;IAC5C,MAAMnB,UAAUN,aAAauB,MAAMG,oBAAoB;IACvD,OAAO;QACLL;QACAC;QACAK,iBAAiBrB,YAAY,OAAO,OAAOA,UAAU;QACrDsB,aAAaJ;QACbK,UAAUxB,UAAUkB,MAAMO,QAAQ;IACpC;AACF;AAEA,SAASC,aAAalC,KAAc;IAClC,IAAI,CAACC,MAAMC,OAAO,CAACF,QAAQ,OAAO,EAAE;IACpC,OAAOA,MAAMmC,OAAO,CAAC,CAACC,OAAOC;QAC3B,MAAMC,QAAQvC,OAAOqC;QACrB,IAAI,CAACE,OAAO,OAAO,EAAE;QACrB,MAAMC,QAAQzB,eAAewB,MAAME,UAAU,KAAK,CAAC,MAAM,EAAEH,QAAQ,GAAG;QACtE,MAAMI,UAAU1C,OAAOuC,MAAMI,UAAU,KAAKJ;QAC5C,OAAO;YACLf,aACEkB,QAAQE,cAAc,EACtB,GAAGJ,MAAM,QAAQ,CAAC,EAClB,GAAGA,MAAM,QAAQ,CAAC;YAEpBhB,aACEkB,QAAQG,gBAAgB,EACxB,GAAGL,MAAM,UAAU,CAAC,EACpB,GAAGA,MAAM,UAAU,CAAC;SAEvB,CAACM,MAAM,CAAC,CAACC,SAAqCA,WAAW;IAC5D;AACF;AAEA,OAAO,SAASC,WACdC,GAAY,EACZC,MAAuB;IAEvB,MAAMC,WAAWnD,OAAOiD,QAAQ,CAAC;IACjC,MAAMG,SAASpD,OAAOmD,SAASR,UAAU,KAAK,CAAC;IAC/C,MAAMU,UAAUrD,OAAOmD,SAASE,OAAO,KAAK,CAAC;IAC7C,OAAO;QACLX,SAAS;YACPlB,aAAa4B,OAAOR,cAAc,EAAE,WAAW;YAC/CpB,aAAa4B,OAAOP,gBAAgB,EAAE,UAAU;eAC7CV,aAAagB,SAASG,sBAAsB;SAChD,CAACR,MAAM,CAAC,CAACC,SAAqCA,WAAW;QAC1DQ,kBAAkBnD,aAAaiD,QAAQG,OAAO;QAC9CN;IACF;AACF;AAEA,SAASO,UACPxD,KAAc,EACdwB,EAAU,EACVC,KAAa;IAEb,MAAMC,QAAQ3B,OAAOC;IACrB,IAAI,CAAC0B,OAAO,OAAO;IACnB,OAAO;QACLF;QACAC;QACAK,iBAAiB3B,aAAauB,MAAM+B,kBAAkB;QACtD1B,aAAa5B,aAAauB,MAAMK,WAAW;QAC3CC,UAAUxB,UAAUkB,MAAMM,QAAQ;IACpC;AACF;AAEA,SAAS0B,mBACP1D,KAAc,EACd2D,UAAkB;IAElB,MAAMC,WAAW7D,OAAOC;IACxB,IAAI,CAAC4D,UAAU,OAAO,EAAE;IACxB,MAAMrB,QACJzB,eAAe8C,SAASC,OAAO,KAAK/C,eAAe6C,eAAe;IACpE,OAAO;QACLH,UAAUI,SAASE,OAAO,EAAE,GAAGvB,MAAM,QAAQ,CAAC,EAAE,GAAGA,MAAM,QAAQ,CAAC;QAClEiB,UAAUI,SAASG,SAAS,EAAE,GAAGxB,MAAM,UAAU,CAAC,EAAE,GAAGA,MAAM,UAAU,CAAC;KACzE,CAACM,MAAM,CAAC,CAACmB,OAAiCA,SAAS;AACtD;AAEA,OAAO,SAASC,cAAcjB,GAAY;IACxC,MAAME,WAAWnD,OAAOiD,QAAQ,CAAC;IACjC,MAAMc,UAAU/D,OAAOmD,SAASgB,UAAU;IAC1C,MAAMzB,UAAUqB,UAAUJ,mBAAmBI,SAAS,WAAW,EAAE;IACnE,MAAMK,UAAUpE,OAAOmD,SAASkB,mBAAmB;IACnD,IAAID,SAAS;QACX,KAAK,MAAM,CAAC3C,IAAIoC,SAAS,IAAIS,OAAOC,OAAO,CAACH,SAC1C1B,QAAQ8B,IAAI,IAAIb,mBAAmBE,UAAUpC;IACjD;IACA,MAAMgD,SAAS;WACV,IAAIC,IAAIhC,QAAQiC,GAAG,CAAC,CAAC5B,SAAW;gBAACA,OAAOtB,EAAE;gBAAEsB;aAAO,GAAG6B,MAAM;KAChE;IACD,OAAO;QAAElC,SAAS+B;QAAQlB,kBAAkB;QAAML,QAAQ;IAAM;AAClE;AAEA,SAAS2B,qBACPhB,QAAuB,EACvBiB,OAA0B,EAC1B7B,GAAa;IAEb,MAAM8B,WAAWlB,SAASnB,OAAO,CAACsC,IAAI,CACpC,CAACjC,SAAWA,OAAOf,WAAW,KAAK;IAErC,MAAMmC,aAAanE,OAAOA,OAAOiD,MAAMkB;IACvC,MAAMc,UAAU1E,aAAa4D,YAAYe;IACzC,MAAMC,eACJnF,OAAOA,OAAOiD,MAAMmC,0BACpBpF,OAAOA,OAAOiD,MAAMoC;IACtB,OAAO;QACLC,SAAS;QACTC,UAAU;QACVC,aAAaV,QAAQW,SAAS;QAC9BC,eAAe;QACfC,WAAWV,UAAU,OAAOF,WAAW,QAAQ;QAC/CrC,SAASmB,SAASnB,OAAO;QACzBa,kBACEM,SAASN,gBAAgB,IAAInD,aAAa+E,cAAcS;IAC5D;AACF;AAEA,SAASC,UAAUC,KAAa;IAC9B,MAAMC,OAAOD,MAAME,KAAK,CAAC,IAAI,CAAC,EAAE;IAChC,IAAI,CAACD,MAAM,OAAO;IAClB,IAAI;QACF,OAAO3F,aACLJ,OAAOiG,KAAKnF,KAAK,CAACoF,OAAOC,IAAI,CAACJ,MAAM,aAAaK,QAAQ,CAAC,WAAWC;IAEzE,EAAE,OAAM;QACN,OAAO;IACT;AACF;AAEA,SAASC,WAAWC,MAAqB,EAAET,KAAa,EAAEU,GAAS;IACjE,MAAMC,WAAWF,OAAOG,UAAU,IAAIH,OAAOI,SAAS,IAAIJ,OAAOK,MAAM;IACvE,IAAIA,SAAwBxG,aAAaqG;IACzC,IAAI,OAAOA,aAAa,UAAU;QAChC,MAAMI,SAASlG,KAAKG,KAAK,CAAC2F;QAC1BG,SAASvG,OAAOQ,KAAK,CAACgG,UAAU,OAAOA,SAAS;IAClD;IACAD,WAAWf,UAAUC;IACrB,OAAOc,WAAW,QAAQA,UAAUJ,IAAIM,OAAO,KAAK;AACtD;AAEA,eAAeC,UACbC,OAAgC,EAChCC,GAAW,EACXC,IAAiB,EACjBC,SAAiB;IAEjB,MAAMC,aAAa,IAAIC;IACvB,MAAMC,QAAQC,WAAW,IAAMH,WAAWI,KAAK,IAAIL;IACnD,IAAI;QACF,MAAMhE,WAAW,MAAM6D,QAAQC,KAAK;YAAE,GAAGC,IAAI;YAAEO,QAAQL,WAAWK,MAAM;QAAC;QACzE,IAAI,CAACtE,SAASuE,EAAE,EACd,MAAM,IAAIC,MACRxE,SAASyE,MAAM,KAAK,MAAM,iBAAiB;QAE/C,OAAO,MAAMzE,SAAS0E,IAAI;IAC5B,SAAU;QACRC,aAAaR;IACf;AACF;AAEA,eAAeS,YACbjC,KAAa,EACbkC,SAAiB,EACjB9E,MAAuB,EACvB+E,OAA0B;IAE1B,MAAMjB,UAAUiB,QAAQC,KAAK,IAAIC,WAAWD,KAAK;IACjD,MAAMjF,MAAM,MAAM8D,UAChBC,SACA,8CACA;QACEoB,SAAS;YACPC,eAAe,CAAC,OAAO,EAAEvC,OAAO;YAChC,sBAAsBkC;QACxB;IACF,GACAC,QAAQd,SAAS,IAAI;IAEvB,OAAOnE,WAAWC,KAAKC;AACzB;AAEA,SAASoF,aACPC,QAAsB,EACtBpB,YAAY,IAAI;IAEhB,OAAO,IAAIqB,QAAQ,CAACC,SAASC;QAC3B,MAAMC,QAAQ/I,MAAM,SAASG,uBAAuB;YAClD6I,OAAO;gBAAC;gBAAQ;gBAAQ;aAAS;QACnC;QACA,MAAMC,UAAiC,CAAC;QACxC,IAAIC,SAAS;QACb,IAAIC,UAAU;QACd,MAAMC,SAAS,CAACC;YACd,IAAIF,SAAS;YACbA,UAAU;YACVjB,aAAaR;YACbqB,MAAMO,IAAI;YACV,IAAID,OAAOP,OAAOO;iBACbR,QAAQI;QACf;QACA,MAAMvB,QAAQC,WACZ,IAAMyB,OAAO,IAAIrB,MAAM,2BACvBR;QAEFwB,MAAMQ,IAAI,CAAC,SAAS,IAClBH,OAAO,IAAIrB,MAAM;QAEnBgB,MAAMQ,IAAI,CAAC,QAAQ;YACjB,IAAI,CAACJ,SAASC,OAAO,IAAIrB,MAAM;QACjC;QACAgB,MAAMS,MAAM,CAACC,WAAW,CAAC;QACzBV,MAAMS,MAAM,CAACE,EAAE,CAAC,QAAQ,CAACC;YACvBT,UAAUS;YACV,OAAS;gBACP,MAAMC,UAAUV,OAAOW,OAAO,CAAC;gBAC/B,IAAID,UAAU,GAAG;gBACjB,MAAME,OAAOZ,OAAOa,KAAK,CAAC,GAAGH,SAASI,IAAI;gBAC1Cd,SAASA,OAAOa,KAAK,CAACH,UAAU;gBAChC,IAAI,CAACE,MAAM;gBACX,IAAIG;gBACJ,IAAI;oBACFA,UAAU5D,KAAKnF,KAAK,CAAC4I;gBACvB,EAAE,OAAM;oBACN;gBACF;gBACA,IAAIG,QAAQpI,EAAE,KAAK,GAAG;oBACpB,KAAK,MAAMqI,WAAWvB,SAASoB,KAAK,CAAC,GACnChB,MAAMoB,KAAK,CAACC,KAAK,CAAC,GAAG/D,KAAKgE,SAAS,CAACH,SAAS,EAAE,CAAC;gBACpD,OAAO,IAAID,QAAQpI,EAAE,KAAK,GAAG;oBAC3B,IAAIoI,QAAQZ,KAAK,EACfD,OAAO,IAAIrB,MAAM;yBACdkB,QAAQ1E,UAAU,GAAG0F,QAAQK,MAAM;gBAC1C,OAAO,IAAIL,QAAQpI,EAAE,KAAK,GAAG;oBAC3B,IAAIoI,QAAQZ,KAAK,EAAED,OAAO,IAAIrB,MAAM;yBAC/BkB,QAAQsB,OAAO,GAAGN,QAAQK,MAAM;gBACvC;gBACA,IAAI,gBAAgBrB,WAAW,aAAaA,SAASG;YACvD;QACF;QACAL,MAAMoB,KAAK,CAACC,KAAK,CAAC,GAAG/D,KAAKgE,SAAS,CAAC1B,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC;IACtD;AACF;AAEA,OAAO,SAAS6B,uBAAuB3E,SAAiB;IACtD,OAAO;QACLH,SAAS;QACTC,UAAU;QACVC,aAAaC;QACbC,eAAe;QACfC,WAAW;QACXjD,SAAS,EAAE;QACXa,kBAAkB;IACpB;AACF;AAEA,SAAS8G,YAAYpC,OAA0B;IAC7C,OAAOmC,uBAAuBnC,QAAQxC,SAAS;AACjD;AAEA,eAAe6E,YACbrC,OAA0B;IAE1B,IAAI,CAACA,QAAQsC,SAAS,EAAE,OAAOF,YAAYpC;IAC3C,MAAMM,WAAyB;QAC7B;YACE9G,IAAI;YACJ+I,QAAQ;YACRC,QAAQ;gBACNC,YAAY;oBAAEC,MAAM;oBAAaC,OAAO;oBAAMC,SAAS;gBAAI;gBAC3DC,cAAc;YAChB;QACF;QACA;YAAEN,QAAQ;QAAc;QACxB;YAAE/I,IAAI;YAAG+I,QAAQ;QAA0B;QAC3C;YAAE/I,IAAI;YAAG+I,QAAQ;QAAe;KACjC;IACD,IAAI;QACF,MAAMO,MACJ9C,QAAQ8C,GAAG,IAAK,CAAA,CAACC,WAAa1C,aAAa0C,UAAU/C,QAAQd,SAAS,CAAA;QACxE,MAAMhE,WAAW,MAAM4H,IAAIxC;QAC3B,MAAM2B,SAASrF,qBACbX,cAAcf,SAASgB,UAAU,GACjC8D,SACA9E,SAASgB,UAAU;QAErB,MAAM8G,kBAAkBjL,OAAOmD,SAASgH,OAAO;QAC/C,IACEc,mBACA3G,OAAO4G,MAAM,CAACD,iBAAiB,cAC/B,CAACjL,OAAOiL,gBAAgBd,OAAO,GAC/B;YACAD,OAAOxE,aAAa,GAAG;YACvBwE,OAAOvE,SAAS,GAAG;QACrB;QACA,OAAOuE;IACT,EAAE,OAAM;QACN,OAAOG,YAAYpC;IACrB;AACF;AAEA,OAAO,eAAekD,mBACpBlD,OAA0B;IAE1B,IAAIpB,SAA+B;IACnC,IAAI;QACF,MAAMuE,WAAW,MAAM,AAACnD,CAAAA,QAAQpI,QAAQ,IAAIA,QAAO,EACjDqB,qBAAqB+G,QAAQ9G,GAAG,GAChC;QAEF0F,SAAS7G,OAAOiG,KAAKnF,KAAK,CAACsK;IAC7B,EAAE,OAAM;QACN,OAAOd,YAAYrC;IACrB;IAEA,MAAMoD,OAAOxE,UAAU,CAAC;IACxB,MAAMyE,MAAM/K,aAAa8K,KAAKE,qBAAqB;IACnD,IAAID,KAAK;QACP,IAAI;YACF,MAAMtE,UAAUiB,QAAQC,KAAK,IAAIC,WAAWD,KAAK;YACjD,MAAMsD,SAASxL,OACb,MAAM+G,UACJC,SACA,uEACA;gBAAEoB,SAAS;oBAAEC,eAAe,CAAC,OAAO,EAAEiD,KAAK;gBAAC;YAAE,GAC9CrD,QAAQd,SAAS,IAAI;YAGzB,MAAMa,YAAYzH,aAAaiL,QAAQC;YACvC,IAAI,CAACzD,WAAW,MAAM,IAAIL,MAAM;YAChC,OAAO9C,qBACL,MAAMkD,YAAYuD,KAAKtD,WAAW,OAAOC,UACzCA;QAEJ,EAAE,OAAM;QACN,4EAA4E;QAC9E;IACF;IAEA,MAAM1B,SAASvG,OAAOqL,KAAK9E,MAAM;IACjC,MAAMmF,cAAcnL,aAAagG,QAAQoF;IACzC,MAAM3D,YAAYzH,aAAagG,QAAQqF;IACvC,IACErF,UACAmF,eACA1D,aACA,CAAC1B,WAAWC,QAAQmF,aAAa,AAACzD,CAAAA,QAAQzB,GAAG,IAAK,CAAA,IAAM,IAAI7F,MAAK,CAAC,MAClE;QACA,IAAI;YACF,OAAOkE,qBACL,MAAMkD,YAAY2D,aAAa1D,WAAW,SAASC,UACnDA;QAEJ,EAAE,OAAM;YACN,OAAOqC,YAAYrC;QACrB;IACF;IACA,OAAOqC,YAAYrC;AACrB"}
|
package/dist/capacity/index.d.ts
CHANGED
|
@@ -7,5 +7,13 @@ export type CapacityProbeOptions = {
|
|
|
7
7
|
access?: (target: string) => Promise<void>;
|
|
8
8
|
probe?: typeof probeCodexCapacity;
|
|
9
9
|
};
|
|
10
|
+
export type ZaiCapacityOptions = {
|
|
11
|
+
now?: () => Date;
|
|
12
|
+
env?: NodeJS.ProcessEnv;
|
|
13
|
+
readFile?: (path: string, encoding: BufferEncoding) => Promise<string>;
|
|
14
|
+
fetch?: typeof globalThis.fetch;
|
|
15
|
+
timeoutMs?: number;
|
|
16
|
+
};
|
|
10
17
|
export declare function getCodexCapacityReport(options?: CapacityProbeOptions): Promise<CapacityReport>;
|
|
18
|
+
export declare function getZaiCapacityReport(options?: ZaiCapacityOptions): Promise<CapacityReport>;
|
|
11
19
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/capacity/index.ts"],"names":[],"mappings":"AAGA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/capacity/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAA0B,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAExE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjE,MAAM,MAAM,oBAAoB,GAAG;IACjC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,KAAK,CAAC,EAAE,OAAO,kBAAkB,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACvE,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AA+BF,wBAAsB,sBAAsB,CAC1C,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,cAAc,CAAC,CAczB;AAED,wBAAsB,oBAAoB,CACxC,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,cAAc,CAAC,CAMzB"}
|
package/dist/capacity/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { constants } from "node:fs";
|
|
2
2
|
import { access as fsAccess } from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import { probeCodexCapacity } from "./codex.js";
|
|
4
|
+
import { codexUnavailableReport, probeCodexCapacity } from "./codex.js";
|
|
5
|
+
import { probeZaiCapacity } from "./zai.js";
|
|
5
6
|
async function canAccess(target, mode) {
|
|
6
7
|
try {
|
|
7
8
|
await fsAccess(target, mode);
|
|
@@ -35,15 +36,15 @@ export async function getCodexCapacityReport(options = {}) {
|
|
|
35
36
|
checkedAt: generatedAt
|
|
36
37
|
});
|
|
37
38
|
} catch {
|
|
38
|
-
return
|
|
39
|
-
provider: "codex",
|
|
40
|
-
generatedAt,
|
|
41
|
-
authenticated: null,
|
|
42
|
-
available: "unknown",
|
|
43
|
-
windows: [],
|
|
44
|
-
creditsRemaining: null
|
|
45
|
-
};
|
|
39
|
+
return codexUnavailableReport(generatedAt);
|
|
46
40
|
}
|
|
47
41
|
}
|
|
42
|
+
export async function getZaiCapacityReport(options = {}) {
|
|
43
|
+
const { now, ...probeOptions } = options;
|
|
44
|
+
return probeZaiCapacity({
|
|
45
|
+
...probeOptions,
|
|
46
|
+
checkedAt: (now?.() ?? new Date()).toISOString()
|
|
47
|
+
});
|
|
48
|
+
}
|
|
48
49
|
|
|
49
50
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/capacity/index.ts"],"sourcesContent":["import { constants } from \"node:fs\";\nimport { access as fsAccess } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { probeCodexCapacity } from \"./codex.js\";\nimport type { CapacityReport } from \"./types.js\";\n\nexport type { CapacityReport, CapacityWindow } from \"./types.js\";\n\nexport type CapacityProbeOptions = {\n now?: () => Date;\n path?: string;\n access?: (target: string) => Promise<void>;\n probe?: typeof probeCodexCapacity;\n};\n\nasync function canAccess(target: string, mode: number): Promise<boolean> {\n try {\n await fsAccess(target, mode);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function isCodexInstalled(\n pathValue: string,\n checkAccess?: (target: string) => Promise<void>,\n): Promise<boolean> {\n const directories = pathValue.split(path.delimiter).filter(Boolean);\n for (const directory of directories) {\n const executable = path.join(directory, \"codex\");\n if (checkAccess) {\n try {\n await checkAccess(executable);\n return true;\n } catch {\n continue;\n }\n }\n if (await canAccess(executable, constants.X_OK)) return true;\n }\n return false;\n}\n\nexport async function getCodexCapacityReport(\n options: CapacityProbeOptions = {},\n): Promise<CapacityReport> {\n const generatedAt = (options.now?.() ?? new Date()).toISOString();\n const installed = await isCodexInstalled(options.path ?? process.env.PATH ?? \"\"
|
|
1
|
+
{"version":3,"sources":["../../src/capacity/index.ts"],"sourcesContent":["import { constants } from \"node:fs\";\nimport { access as fsAccess } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { codexUnavailableReport, probeCodexCapacity } from \"./codex.js\";\nimport { probeZaiCapacity } from \"./zai.js\";\nimport type { CapacityReport } from \"./types.js\";\n\nexport type { CapacityReport, CapacityWindow } from \"./types.js\";\n\nexport type CapacityProbeOptions = {\n now?: () => Date;\n path?: string;\n access?: (target: string) => Promise<void>;\n probe?: typeof probeCodexCapacity;\n};\n\nexport type ZaiCapacityOptions = {\n now?: () => Date;\n env?: NodeJS.ProcessEnv;\n readFile?: (path: string, encoding: BufferEncoding) => Promise<string>;\n fetch?: typeof globalThis.fetch;\n timeoutMs?: number;\n};\n\nasync function canAccess(target: string, mode: number): Promise<boolean> {\n try {\n await fsAccess(target, mode);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function isCodexInstalled(\n pathValue: string,\n checkAccess?: (target: string) => Promise<void>,\n): Promise<boolean> {\n const directories = pathValue.split(path.delimiter).filter(Boolean);\n for (const directory of directories) {\n const executable = path.join(directory, \"codex\");\n if (checkAccess) {\n try {\n await checkAccess(executable);\n return true;\n } catch {\n continue;\n }\n }\n if (await canAccess(executable, constants.X_OK)) return true;\n }\n return false;\n}\n\nexport async function getCodexCapacityReport(\n options: CapacityProbeOptions = {},\n): Promise<CapacityReport> {\n const generatedAt = (options.now?.() ?? new Date()).toISOString();\n const installed = await isCodexInstalled(\n options.path ?? process.env.PATH ?? \"\",\n options.access,\n );\n try {\n return await (options.probe ?? probeCodexCapacity)({\n installed,\n checkedAt: generatedAt,\n });\n } catch {\n return codexUnavailableReport(generatedAt);\n }\n}\n\nexport async function getZaiCapacityReport(\n options: ZaiCapacityOptions = {},\n): Promise<CapacityReport> {\n const { now, ...probeOptions } = options;\n return probeZaiCapacity({\n ...probeOptions,\n checkedAt: (now?.() ?? new Date()).toISOString(),\n });\n}\n"],"names":["constants","access","fsAccess","path","codexUnavailableReport","probeCodexCapacity","probeZaiCapacity","canAccess","target","mode","isCodexInstalled","pathValue","checkAccess","directories","split","delimiter","filter","Boolean","directory","executable","join","X_OK","getCodexCapacityReport","options","generatedAt","now","Date","toISOString","installed","process","env","PATH","probe","checkedAt","getZaiCapacityReport","probeOptions"],"mappings":"AAAA,SAASA,SAAS,QAAQ,UAAU;AACpC,SAASC,UAAUC,QAAQ,QAAQ,mBAAmB;AACtD,OAAOC,UAAU,YAAY;AAC7B,SAASC,sBAAsB,EAAEC,kBAAkB,QAAQ,aAAa;AACxE,SAASC,gBAAgB,QAAQ,WAAW;AAoB5C,eAAeC,UAAUC,MAAc,EAAEC,IAAY;IACnD,IAAI;QACF,MAAMP,SAASM,QAAQC;QACvB,OAAO;IACT,EAAE,OAAM;QACN,OAAO;IACT;AACF;AAEA,eAAeC,iBACbC,SAAiB,EACjBC,WAA+C;IAE/C,MAAMC,cAAcF,UAAUG,KAAK,CAACX,KAAKY,SAAS,EAAEC,MAAM,CAACC;IAC3D,KAAK,MAAMC,aAAaL,YAAa;QACnC,MAAMM,aAAahB,KAAKiB,IAAI,CAACF,WAAW;QACxC,IAAIN,aAAa;YACf,IAAI;gBACF,MAAMA,YAAYO;gBAClB,OAAO;YACT,EAAE,OAAM;gBACN;YACF;QACF;QACA,IAAI,MAAMZ,UAAUY,YAAYnB,UAAUqB,IAAI,GAAG,OAAO;IAC1D;IACA,OAAO;AACT;AAEA,OAAO,eAAeC,uBACpBC,UAAgC,CAAC,CAAC;IAElC,MAAMC,cAAc,AAACD,CAAAA,QAAQE,GAAG,QAAQ,IAAIC,MAAK,EAAGC,WAAW;IAC/D,MAAMC,YAAY,MAAMlB,iBACtBa,QAAQpB,IAAI,IAAI0B,QAAQC,GAAG,CAACC,IAAI,IAAI,IACpCR,QAAQtB,MAAM;IAEhB,IAAI;QACF,OAAO,MAAM,AAACsB,CAAAA,QAAQS,KAAK,IAAI3B,kBAAiB,EAAG;YACjDuB;YACAK,WAAWT;QACb;IACF,EAAE,OAAM;QACN,OAAOpB,uBAAuBoB;IAChC;AACF;AAEA,OAAO,eAAeU,qBACpBX,UAA8B,CAAC,CAAC;IAEhC,MAAM,EAAEE,GAAG,EAAE,GAAGU,cAAc,GAAGZ;IACjC,OAAOjB,iBAAiB;QACtB,GAAG6B,YAAY;QACfF,WAAW,AAACR,CAAAA,WAAW,IAAIC,MAAK,EAAGC,WAAW;IAChD;AACF"}
|
package/dist/capacity/types.d.ts
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
export type Availability = "yes" | "no" | "unknown";
|
|
2
|
+
export type CapacityLimitType = "TOKENS_LIMIT" | "CREDIT_LIMIT" | "TIME_LIMIT";
|
|
2
3
|
export interface CapacityWindow {
|
|
3
4
|
id: string;
|
|
4
5
|
label: string;
|
|
5
6
|
durationMinutes: number | null;
|
|
6
7
|
usedPercent: number | null;
|
|
7
8
|
resetsAt: string | null;
|
|
9
|
+
limitType?: CapacityLimitType;
|
|
10
|
+
total?: number | null;
|
|
11
|
+
current?: number | null;
|
|
12
|
+
remaining?: number | null;
|
|
8
13
|
}
|
|
9
14
|
export interface CapacityReport {
|
|
15
|
+
/** Harness whose quota pool is measured, e.g. "pi" or "codex". */
|
|
16
|
+
harness: string;
|
|
17
|
+
/** Model provider backing the harness, e.g. "zai" or "openai". */
|
|
10
18
|
provider: string;
|
|
11
19
|
generatedAt: string;
|
|
12
20
|
authenticated: boolean | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/capacity/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,IAAI,GAAG,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/capacity/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,IAAI,GAAG,SAAS,CAAC;AACpD,MAAM,MAAM,iBAAiB,GAAG,cAAc,GAAG,cAAc,GAAG,YAAY,CAAC;AAE/E,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc;IAC7B,kEAAkE;IAClE,OAAO,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,OAAO,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,YAAY,CAAC;IACxB,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/capacity/types.ts"],"sourcesContent":["export type Availability = \"yes\" | \"no\" | \"unknown\";\n\nexport interface CapacityWindow {\n id: string;\n label: string;\n durationMinutes: number | null;\n usedPercent: number | null;\n resetsAt: string | null;\n}\n\nexport interface CapacityReport {\n provider: string;\n generatedAt: string;\n authenticated: boolean | null;\n available: Availability;\n windows: CapacityWindow[];\n creditsRemaining: number | null;\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../src/capacity/types.ts"],"sourcesContent":["export type Availability = \"yes\" | \"no\" | \"unknown\";\nexport type CapacityLimitType = \"TOKENS_LIMIT\" | \"CREDIT_LIMIT\" | \"TIME_LIMIT\";\n\nexport interface CapacityWindow {\n id: string;\n label: string;\n durationMinutes: number | null;\n usedPercent: number | null;\n resetsAt: string | null;\n limitType?: CapacityLimitType;\n total?: number | null;\n current?: number | null;\n remaining?: number | null;\n}\n\nexport interface CapacityReport {\n /** Harness whose quota pool is measured, e.g. \"pi\" or \"codex\". */\n harness: string;\n /** Model provider backing the harness, e.g. \"zai\" or \"openai\". */\n provider: string;\n generatedAt: string;\n authenticated: boolean | null;\n available: Availability;\n windows: CapacityWindow[];\n creditsRemaining: number | null;\n}\n"],"names":[],"mappings":"AAeA,WAUC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CapacityReport } from "./types.js";
|
|
2
|
+
export type ZaiCredentialOptions = {
|
|
3
|
+
env?: NodeJS.ProcessEnv;
|
|
4
|
+
readFile?: (path: string, encoding: BufferEncoding) => Promise<string>;
|
|
5
|
+
};
|
|
6
|
+
export type ZaiProbeOptions = ZaiCredentialOptions & {
|
|
7
|
+
checkedAt: string;
|
|
8
|
+
fetch?: typeof globalThis.fetch;
|
|
9
|
+
timeoutMs?: number;
|
|
10
|
+
};
|
|
11
|
+
export declare function resolveZaiApiKey(options?: ZaiCredentialOptions): Promise<string>;
|
|
12
|
+
export declare function parseZaiQuota(raw: unknown, checkedAt: string): CapacityReport;
|
|
13
|
+
export declare function probeZaiCapacity(options: ZaiProbeOptions): Promise<CapacityReport>;
|
|
14
|
+
//# sourceMappingURL=zai.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zai.d.ts","sourceRoot":"","sources":["../../src/capacity/zai.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAGV,cAAc,EAEf,MAAM,YAAY,CAAC;AAkBpB,MAAM,MAAM,oBAAoB,GAAG;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACxE,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,oBAAoB,GAAG;IACnD,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAqHF,wBAAsB,gBAAgB,CACpC,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,MAAM,CAAC,CA2BjB;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,cAAc,CAuB7E;AAED,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,cAAc,CAAC,CA0BzB"}
|