@ai-devkit/agent-manager 0.33.1 → 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/__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__/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/adapters/index.d.ts +1 -1
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js +1 -1
- 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 +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/{adapters → providers/opencode}/OpenCodeAdapter.d.ts +5 -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/package.json +1 -1
- 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__/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/adapters/index.ts +1 -1
- 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 +8 -3
- 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/dist/__tests__/adapters/OpenCodeAdapter.test.js +0 -636
- package/dist/__tests__/adapters/OpenCodeAdapter.test.js.map +0 -1
- package/dist/adapters/OpenCodeAdapter.d.ts.map +0 -1
- package/dist/adapters/OpenCodeAdapter.js +0 -289
- package/dist/adapters/OpenCodeAdapter.js.map +0 -1
- package/src/__tests__/adapters/OpenCodeAdapter.test.ts +0 -544
- package/src/adapters/OpenCodeAdapter.ts +0 -373
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { AgentStatus } from "../../../adapters/AgentAdapter.js";
|
|
3
|
+
import { OpenCodeAgentMapper } from "../../../providers/opencode/OpenCodeAgentMapper.js";
|
|
4
|
+
describe("OpenCodeAgentMapper", ()=>{
|
|
5
|
+
const mapper = new OpenCodeAgentMapper("/tmp/opencode.db");
|
|
6
|
+
it("maps completed assistant sessions as waiting", ()=>{
|
|
7
|
+
const now = Date.now();
|
|
8
|
+
const agent = mapper.mapSessionToAgent({
|
|
9
|
+
sessionId: "sess-1",
|
|
10
|
+
directory: "/repo",
|
|
11
|
+
timeCreated: now - 60_000
|
|
12
|
+
}, {
|
|
13
|
+
lastRole: "assistant",
|
|
14
|
+
lastTimeUpdated: now - 30_000,
|
|
15
|
+
lastAssistantCompleted: true,
|
|
16
|
+
lastAssistantErrored: false,
|
|
17
|
+
summary: "Ship the feature"
|
|
18
|
+
}, {
|
|
19
|
+
pid: 123,
|
|
20
|
+
command: "opencode",
|
|
21
|
+
cwd: "/repo"
|
|
22
|
+
});
|
|
23
|
+
expect(agent).toMatchObject({
|
|
24
|
+
type: "opencode",
|
|
25
|
+
status: AgentStatus.WAITING,
|
|
26
|
+
summary: "Ship the feature",
|
|
27
|
+
pid: 123,
|
|
28
|
+
projectPath: "/repo",
|
|
29
|
+
sessionId: "sess-1",
|
|
30
|
+
sessionFilePath: "/tmp/opencode.db::sess-1"
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
it("keeps incomplete assistant sessions running even when they are quiet briefly", ()=>{
|
|
34
|
+
const now = Date.now();
|
|
35
|
+
const agent = mapper.mapSessionToAgent({
|
|
36
|
+
sessionId: "sess-2",
|
|
37
|
+
directory: "/repo",
|
|
38
|
+
timeCreated: now - 120_000
|
|
39
|
+
}, {
|
|
40
|
+
lastRole: "assistant",
|
|
41
|
+
lastTimeUpdated: now - 120_000,
|
|
42
|
+
lastAssistantCompleted: false,
|
|
43
|
+
lastAssistantErrored: false,
|
|
44
|
+
summary: ""
|
|
45
|
+
}, {
|
|
46
|
+
pid: 124,
|
|
47
|
+
command: "opencode",
|
|
48
|
+
cwd: "/repo"
|
|
49
|
+
});
|
|
50
|
+
expect(agent.status).toBe(AgentStatus.RUNNING);
|
|
51
|
+
expect(agent.summary).toBe("OpenCode session active");
|
|
52
|
+
});
|
|
53
|
+
it("marks stale sessions idle", ()=>{
|
|
54
|
+
const staleTime = Date.now() - 10 * 60 * 1000;
|
|
55
|
+
const agent = mapper.mapSessionToAgent({
|
|
56
|
+
sessionId: "sess-3",
|
|
57
|
+
directory: "/old",
|
|
58
|
+
timeCreated: staleTime
|
|
59
|
+
}, {
|
|
60
|
+
lastRole: "assistant",
|
|
61
|
+
lastTimeUpdated: staleTime,
|
|
62
|
+
lastAssistantCompleted: true,
|
|
63
|
+
lastAssistantErrored: false,
|
|
64
|
+
summary: ""
|
|
65
|
+
}, {
|
|
66
|
+
pid: 125,
|
|
67
|
+
command: "opencode",
|
|
68
|
+
cwd: "/old"
|
|
69
|
+
});
|
|
70
|
+
expect(agent.status).toBe(AgentStatus.IDLE);
|
|
71
|
+
});
|
|
72
|
+
it("maps unmatched processes as running process-only agents", ()=>{
|
|
73
|
+
const agent = mapper.mapProcessOnlyAgent({
|
|
74
|
+
pid: 500,
|
|
75
|
+
command: "opencode",
|
|
76
|
+
cwd: "/repo"
|
|
77
|
+
});
|
|
78
|
+
expect(agent).toMatchObject({
|
|
79
|
+
type: "opencode",
|
|
80
|
+
status: AgentStatus.RUNNING,
|
|
81
|
+
summary: "OpenCode process running",
|
|
82
|
+
pid: 500,
|
|
83
|
+
projectPath: "/repo",
|
|
84
|
+
sessionId: "pid-500"
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
//# sourceMappingURL=OpenCodeAgentMapper.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/__tests__/providers/opencode/OpenCodeAgentMapper.test.ts"],"sourcesContent":["import { describe, expect, it } from \"vitest\";\nimport { AgentStatus } from \"../../../adapters/AgentAdapter.js\";\nimport { OpenCodeAgentMapper } from \"../../../providers/opencode/OpenCodeAgentMapper.js\";\n\ndescribe(\"OpenCodeAgentMapper\", () => {\n const mapper = new OpenCodeAgentMapper(\"/tmp/opencode.db\");\n\n it(\"maps completed assistant sessions as waiting\", () => {\n const now = Date.now();\n\n const agent = mapper.mapSessionToAgent(\n { sessionId: \"sess-1\", directory: \"/repo\", timeCreated: now - 60_000 },\n {\n lastRole: \"assistant\",\n lastTimeUpdated: now - 30_000,\n lastAssistantCompleted: true,\n lastAssistantErrored: false,\n summary: \"Ship the feature\",\n },\n { pid: 123, command: \"opencode\", cwd: \"/repo\" },\n );\n\n expect(agent).toMatchObject({\n type: \"opencode\",\n status: AgentStatus.WAITING,\n summary: \"Ship the feature\",\n pid: 123,\n projectPath: \"/repo\",\n sessionId: \"sess-1\",\n sessionFilePath: \"/tmp/opencode.db::sess-1\",\n });\n });\n\n it(\"keeps incomplete assistant sessions running even when they are quiet briefly\", () => {\n const now = Date.now();\n\n const agent = mapper.mapSessionToAgent(\n { sessionId: \"sess-2\", directory: \"/repo\", timeCreated: now - 120_000 },\n {\n lastRole: \"assistant\",\n lastTimeUpdated: now - 120_000,\n lastAssistantCompleted: false,\n lastAssistantErrored: false,\n summary: \"\",\n },\n { pid: 124, command: \"opencode\", cwd: \"/repo\" },\n );\n\n expect(agent.status).toBe(AgentStatus.RUNNING);\n expect(agent.summary).toBe(\"OpenCode session active\");\n });\n\n it(\"marks stale sessions idle\", () => {\n const staleTime = Date.now() - 10 * 60 * 1000;\n\n const agent = mapper.mapSessionToAgent(\n { sessionId: \"sess-3\", directory: \"/old\", timeCreated: staleTime },\n {\n lastRole: \"assistant\",\n lastTimeUpdated: staleTime,\n lastAssistantCompleted: true,\n lastAssistantErrored: false,\n summary: \"\",\n },\n { pid: 125, command: \"opencode\", cwd: \"/old\" },\n );\n\n expect(agent.status).toBe(AgentStatus.IDLE);\n });\n\n it(\"maps unmatched processes as running process-only agents\", () => {\n const agent = mapper.mapProcessOnlyAgent({ pid: 500, command: \"opencode\", cwd: \"/repo\" });\n\n expect(agent).toMatchObject({\n type: \"opencode\",\n status: AgentStatus.RUNNING,\n summary: \"OpenCode process running\",\n pid: 500,\n projectPath: \"/repo\",\n sessionId: \"pid-500\",\n });\n });\n});\n"],"names":["describe","expect","it","AgentStatus","OpenCodeAgentMapper","mapper","now","Date","agent","mapSessionToAgent","sessionId","directory","timeCreated","lastRole","lastTimeUpdated","lastAssistantCompleted","lastAssistantErrored","summary","pid","command","cwd","toMatchObject","type","status","WAITING","projectPath","sessionFilePath","toBe","RUNNING","staleTime","IDLE","mapProcessOnlyAgent"],"mappings":"AAAA,SAASA,QAAQ,EAAEC,MAAM,EAAEC,EAAE,QAAQ,SAAS;AAC9C,SAASC,WAAW,QAAQ,oCAAoC;AAChE,SAASC,mBAAmB,QAAQ,qDAAqD;AAEzFJ,SAAS,uBAAuB;IAC9B,MAAMK,SAAS,IAAID,oBAAoB;IAEvCF,GAAG,gDAAgD;QACjD,MAAMI,MAAMC,KAAKD,GAAG;QAEpB,MAAME,QAAQH,OAAOI,iBAAiB,CACpC;YAAEC,WAAW;YAAUC,WAAW;YAASC,aAAaN,MAAM;QAAO,GACrE;YACEO,UAAU;YACVC,iBAAiBR,MAAM;YACvBS,wBAAwB;YACxBC,sBAAsB;YACtBC,SAAS;QACX,GACA;YAAEC,KAAK;YAAKC,SAAS;YAAYC,KAAK;QAAQ;QAGhDnB,OAAOO,OAAOa,aAAa,CAAC;YAC1BC,MAAM;YACNC,QAAQpB,YAAYqB,OAAO;YAC3BP,SAAS;YACTC,KAAK;YACLO,aAAa;YACbf,WAAW;YACXgB,iBAAiB;QACnB;IACF;IAEAxB,GAAG,gFAAgF;QACjF,MAAMI,MAAMC,KAAKD,GAAG;QAEpB,MAAME,QAAQH,OAAOI,iBAAiB,CACpC;YAAEC,WAAW;YAAUC,WAAW;YAASC,aAAaN,MAAM;QAAQ,GACtE;YACEO,UAAU;YACVC,iBAAiBR,MAAM;YACvBS,wBAAwB;YACxBC,sBAAsB;YACtBC,SAAS;QACX,GACA;YAAEC,KAAK;YAAKC,SAAS;YAAYC,KAAK;QAAQ;QAGhDnB,OAAOO,MAAMe,MAAM,EAAEI,IAAI,CAACxB,YAAYyB,OAAO;QAC7C3B,OAAOO,MAAMS,OAAO,EAAEU,IAAI,CAAC;IAC7B;IAEAzB,GAAG,6BAA6B;QAC9B,MAAM2B,YAAYtB,KAAKD,GAAG,KAAK,KAAK,KAAK;QAEzC,MAAME,QAAQH,OAAOI,iBAAiB,CACpC;YAAEC,WAAW;YAAUC,WAAW;YAAQC,aAAaiB;QAAU,GACjE;YACEhB,UAAU;YACVC,iBAAiBe;YACjBd,wBAAwB;YACxBC,sBAAsB;YACtBC,SAAS;QACX,GACA;YAAEC,KAAK;YAAKC,SAAS;YAAYC,KAAK;QAAO;QAG/CnB,OAAOO,MAAMe,MAAM,EAAEI,IAAI,CAACxB,YAAY2B,IAAI;IAC5C;IAEA5B,GAAG,2DAA2D;QAC5D,MAAMM,QAAQH,OAAO0B,mBAAmB,CAAC;YAAEb,KAAK;YAAKC,SAAS;YAAYC,KAAK;QAAQ;QAEvFnB,OAAOO,OAAOa,aAAa,CAAC;YAC1BC,MAAM;YACNC,QAAQpB,YAAYyB,OAAO;YAC3BX,SAAS;YACTC,KAAK;YACLO,aAAa;YACbf,WAAW;QACb;IACF;AACF"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import Database from "better-sqlite3";
|
|
2
|
+
import * as fs from "fs";
|
|
3
|
+
import * as os from "os";
|
|
4
|
+
import * as path from "path";
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
6
|
+
import { OpenCodeSessionLocator } from "../../../providers/opencode/OpenCodeSessionLocator.js";
|
|
7
|
+
import { OpenCodeSessionParser } from "../../../providers/opencode/OpenCodeSessionParser.js";
|
|
8
|
+
describe("OpenCodeSessionLocator", ()=>{
|
|
9
|
+
let tmpDir;
|
|
10
|
+
let dbPath;
|
|
11
|
+
let locator;
|
|
12
|
+
beforeEach(()=>{
|
|
13
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "opencode-locator-test-"));
|
|
14
|
+
dbPath = path.join(tmpDir, "opencode.db");
|
|
15
|
+
locator = new OpenCodeSessionLocator(dbPath, new OpenCodeSessionParser());
|
|
16
|
+
});
|
|
17
|
+
afterEach(()=>{
|
|
18
|
+
locator.close();
|
|
19
|
+
fs.rmSync(tmpDir, {
|
|
20
|
+
recursive: true,
|
|
21
|
+
force: true
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
it("returns null when the database file does not exist", ()=>{
|
|
25
|
+
expect(locator.openDb()).toBeNull();
|
|
26
|
+
expect(locator.listSessions()).toEqual([]);
|
|
27
|
+
});
|
|
28
|
+
it("finds the newest session for a directory", ()=>{
|
|
29
|
+
writeDatabase(dbPath, [
|
|
30
|
+
{
|
|
31
|
+
id: "old",
|
|
32
|
+
directory: "/repo",
|
|
33
|
+
timeCreated: 1000
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
id: "new",
|
|
37
|
+
directory: "/repo",
|
|
38
|
+
timeCreated: 2000
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
id: "other",
|
|
42
|
+
directory: "/other",
|
|
43
|
+
timeCreated: 3000
|
|
44
|
+
}
|
|
45
|
+
]);
|
|
46
|
+
const db = locator.openDb();
|
|
47
|
+
expect(db).not.toBeNull();
|
|
48
|
+
expect(locator.findSessionForDirectory(db, "/repo")).toEqual({
|
|
49
|
+
sessionId: "new",
|
|
50
|
+
directory: "/repo",
|
|
51
|
+
timeCreated: 2000
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
it("lists sessions and filters by cwd", ()=>{
|
|
55
|
+
writeDatabase(dbPath, [
|
|
56
|
+
{
|
|
57
|
+
id: "sess-a",
|
|
58
|
+
directory: "/repo-a",
|
|
59
|
+
timeCreated: 1000
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
id: "sess-b",
|
|
63
|
+
directory: "/repo-b",
|
|
64
|
+
timeCreated: 2000
|
|
65
|
+
}
|
|
66
|
+
]);
|
|
67
|
+
const sessions = locator.listSessions({
|
|
68
|
+
cwd: "/repo-a"
|
|
69
|
+
});
|
|
70
|
+
expect(sessions).toEqual([
|
|
71
|
+
expect.objectContaining({
|
|
72
|
+
type: "opencode",
|
|
73
|
+
sessionId: "sess-a",
|
|
74
|
+
cwd: "/repo-a",
|
|
75
|
+
sessionFilePath: `${dbPath}::sess-a`
|
|
76
|
+
})
|
|
77
|
+
]);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
function writeDatabase(filePath, sessions) {
|
|
81
|
+
const db = new Database(filePath);
|
|
82
|
+
db.exec(`
|
|
83
|
+
CREATE TABLE session (id TEXT, directory TEXT, time_created INTEGER);
|
|
84
|
+
CREATE TABLE message (id TEXT, session_id TEXT, data TEXT, time_created INTEGER, time_updated INTEGER);
|
|
85
|
+
CREATE TABLE part (message_id TEXT, session_id TEXT, data TEXT, time_created INTEGER);
|
|
86
|
+
`);
|
|
87
|
+
const insertSession = db.prepare("INSERT INTO session (id, directory, time_created) VALUES (?, ?, ?)");
|
|
88
|
+
for (const session of sessions){
|
|
89
|
+
insertSession.run(session.id, session.directory, session.timeCreated);
|
|
90
|
+
}
|
|
91
|
+
db.close();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
//# sourceMappingURL=OpenCodeSessionLocator.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/__tests__/providers/opencode/OpenCodeSessionLocator.test.ts"],"sourcesContent":["import Database from \"better-sqlite3\";\nimport * as fs from \"fs\";\nimport * as os from \"os\";\nimport * as path from \"path\";\nimport { afterEach, beforeEach, describe, expect, it } from \"vitest\";\nimport { OpenCodeSessionLocator } from \"../../../providers/opencode/OpenCodeSessionLocator.js\";\nimport { OpenCodeSessionParser } from \"../../../providers/opencode/OpenCodeSessionParser.js\";\n\ndescribe(\"OpenCodeSessionLocator\", () => {\n let tmpDir: string;\n let dbPath: string;\n let locator: OpenCodeSessionLocator;\n\n beforeEach(() => {\n tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), \"opencode-locator-test-\"));\n dbPath = path.join(tmpDir, \"opencode.db\");\n locator = new OpenCodeSessionLocator(dbPath, new OpenCodeSessionParser());\n });\n\n afterEach(() => {\n locator.close();\n fs.rmSync(tmpDir, { recursive: true, force: true });\n });\n\n it(\"returns null when the database file does not exist\", () => {\n expect(locator.openDb()).toBeNull();\n expect(locator.listSessions()).toEqual([]);\n });\n\n it(\"finds the newest session for a directory\", () => {\n writeDatabase(dbPath, [\n { id: \"old\", directory: \"/repo\", timeCreated: 1000 },\n { id: \"new\", directory: \"/repo\", timeCreated: 2000 },\n { id: \"other\", directory: \"/other\", timeCreated: 3000 },\n ]);\n\n const db = locator.openDb();\n expect(db).not.toBeNull();\n expect(locator.findSessionForDirectory(db!, \"/repo\")).toEqual({\n sessionId: \"new\",\n directory: \"/repo\",\n timeCreated: 2000,\n });\n });\n\n it(\"lists sessions and filters by cwd\", () => {\n writeDatabase(dbPath, [\n { id: \"sess-a\", directory: \"/repo-a\", timeCreated: 1000 },\n { id: \"sess-b\", directory: \"/repo-b\", timeCreated: 2000 },\n ]);\n\n const sessions = locator.listSessions({ cwd: \"/repo-a\" });\n\n expect(sessions).toEqual([\n expect.objectContaining({\n type: \"opencode\",\n sessionId: \"sess-a\",\n cwd: \"/repo-a\",\n sessionFilePath: `${dbPath}::sess-a`,\n }),\n ]);\n });\n});\n\nfunction writeDatabase(\n filePath: string,\n sessions: Array<{ id: string; directory: string; timeCreated: number }>,\n): void {\n const db = new Database(filePath);\n db.exec(`\n CREATE TABLE session (id TEXT, directory TEXT, time_created INTEGER);\n CREATE TABLE message (id TEXT, session_id TEXT, data TEXT, time_created INTEGER, time_updated INTEGER);\n CREATE TABLE part (message_id TEXT, session_id TEXT, data TEXT, time_created INTEGER);\n `);\n\n const insertSession = db.prepare(\n \"INSERT INTO session (id, directory, time_created) VALUES (?, ?, ?)\",\n );\n for (const session of sessions) {\n insertSession.run(session.id, session.directory, session.timeCreated);\n }\n\n db.close();\n}\n"],"names":["Database","fs","os","path","afterEach","beforeEach","describe","expect","it","OpenCodeSessionLocator","OpenCodeSessionParser","tmpDir","dbPath","locator","mkdtempSync","join","tmpdir","close","rmSync","recursive","force","openDb","toBeNull","listSessions","toEqual","writeDatabase","id","directory","timeCreated","db","not","findSessionForDirectory","sessionId","sessions","cwd","objectContaining","type","sessionFilePath","filePath","exec","insertSession","prepare","session","run"],"mappings":"AAAA,OAAOA,cAAc,iBAAiB;AACtC,YAAYC,QAAQ,KAAK;AACzB,YAAYC,QAAQ,KAAK;AACzB,YAAYC,UAAU,OAAO;AAC7B,SAASC,SAAS,EAAEC,UAAU,EAAEC,QAAQ,EAAEC,MAAM,EAAEC,EAAE,QAAQ,SAAS;AACrE,SAASC,sBAAsB,QAAQ,wDAAwD;AAC/F,SAASC,qBAAqB,QAAQ,uDAAuD;AAE7FJ,SAAS,0BAA0B;IACjC,IAAIK;IACJ,IAAIC;IACJ,IAAIC;IAEJR,WAAW;QACTM,SAASV,GAAGa,WAAW,CAACX,KAAKY,IAAI,CAACb,GAAGc,MAAM,IAAI;QAC/CJ,SAAST,KAAKY,IAAI,CAACJ,QAAQ;QAC3BE,UAAU,IAAIJ,uBAAuBG,QAAQ,IAAIF;IACnD;IAEAN,UAAU;QACRS,QAAQI,KAAK;QACbhB,GAAGiB,MAAM,CAACP,QAAQ;YAAEQ,WAAW;YAAMC,OAAO;QAAK;IACnD;IAEAZ,GAAG,sDAAsD;QACvDD,OAAOM,QAAQQ,MAAM,IAAIC,QAAQ;QACjCf,OAAOM,QAAQU,YAAY,IAAIC,OAAO,CAAC,EAAE;IAC3C;IAEAhB,GAAG,4CAA4C;QAC7CiB,cAAcb,QAAQ;YACpB;gBAAEc,IAAI;gBAAOC,WAAW;gBAASC,aAAa;YAAK;YACnD;gBAAEF,IAAI;gBAAOC,WAAW;gBAASC,aAAa;YAAK;YACnD;gBAAEF,IAAI;gBAASC,WAAW;gBAAUC,aAAa;YAAK;SACvD;QAED,MAAMC,KAAKhB,QAAQQ,MAAM;QACzBd,OAAOsB,IAAIC,GAAG,CAACR,QAAQ;QACvBf,OAAOM,QAAQkB,uBAAuB,CAACF,IAAK,UAAUL,OAAO,CAAC;YAC5DQ,WAAW;YACXL,WAAW;YACXC,aAAa;QACf;IACF;IAEApB,GAAG,qCAAqC;QACtCiB,cAAcb,QAAQ;YACpB;gBAAEc,IAAI;gBAAUC,WAAW;gBAAWC,aAAa;YAAK;YACxD;gBAAEF,IAAI;gBAAUC,WAAW;gBAAWC,aAAa;YAAK;SACzD;QAED,MAAMK,WAAWpB,QAAQU,YAAY,CAAC;YAAEW,KAAK;QAAU;QAEvD3B,OAAO0B,UAAUT,OAAO,CAAC;YACvBjB,OAAO4B,gBAAgB,CAAC;gBACtBC,MAAM;gBACNJ,WAAW;gBACXE,KAAK;gBACLG,iBAAiB,GAAGzB,OAAO,QAAQ,CAAC;YACtC;SACD;IACH;AACF;AAEA,SAASa,cACPa,QAAgB,EAChBL,QAAuE;IAEvE,MAAMJ,KAAK,IAAI7B,SAASsC;IACxBT,GAAGU,IAAI,CAAC,CAAC;;;;EAIT,CAAC;IAED,MAAMC,gBAAgBX,GAAGY,OAAO,CAC9B;IAEF,KAAK,MAAMC,WAAWT,SAAU;QAC9BO,cAAcG,GAAG,CAACD,QAAQhB,EAAE,EAAEgB,QAAQf,SAAS,EAAEe,QAAQd,WAAW;IACtE;IAEAC,GAAGZ,KAAK;AACV"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import Database from "better-sqlite3";
|
|
2
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
3
|
+
import { OpenCodeSessionParser } from "../../../providers/opencode/OpenCodeSessionParser.js";
|
|
4
|
+
describe("OpenCodeSessionParser", ()=>{
|
|
5
|
+
let db;
|
|
6
|
+
let parser;
|
|
7
|
+
beforeEach(()=>{
|
|
8
|
+
db = new Database(":memory:");
|
|
9
|
+
db.exec(`
|
|
10
|
+
CREATE TABLE message (id TEXT, session_id TEXT, data TEXT, time_created INTEGER, time_updated INTEGER);
|
|
11
|
+
CREATE TABLE part (message_id TEXT, session_id TEXT, data TEXT, time_created INTEGER);
|
|
12
|
+
`);
|
|
13
|
+
parser = new OpenCodeSessionParser();
|
|
14
|
+
});
|
|
15
|
+
afterEach(()=>{
|
|
16
|
+
db.close();
|
|
17
|
+
});
|
|
18
|
+
it("extracts session stats from OpenCode messages and parts", ()=>{
|
|
19
|
+
insertMessage(db, {
|
|
20
|
+
id: "msg-user",
|
|
21
|
+
sessionId: "sess-1",
|
|
22
|
+
role: "user",
|
|
23
|
+
timeCreated: 1000,
|
|
24
|
+
timeUpdated: 1000
|
|
25
|
+
});
|
|
26
|
+
insertMessage(db, {
|
|
27
|
+
id: "msg-assistant",
|
|
28
|
+
sessionId: "sess-1",
|
|
29
|
+
role: "assistant",
|
|
30
|
+
timeCreated: 2000,
|
|
31
|
+
timeUpdated: 2500,
|
|
32
|
+
completed: 2400
|
|
33
|
+
});
|
|
34
|
+
insertPart(db, {
|
|
35
|
+
messageId: "msg-user",
|
|
36
|
+
sessionId: "sess-1",
|
|
37
|
+
data: {
|
|
38
|
+
type: "text",
|
|
39
|
+
text: "Plan the migration"
|
|
40
|
+
},
|
|
41
|
+
timeCreated: 1000
|
|
42
|
+
});
|
|
43
|
+
expect(parser.getSessionStats(db, "sess-1")).toEqual({
|
|
44
|
+
lastRole: "assistant",
|
|
45
|
+
lastTimeUpdated: 2500,
|
|
46
|
+
lastAssistantCompleted: true,
|
|
47
|
+
lastAssistantErrored: false,
|
|
48
|
+
summary: "Plan the migration"
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
it("orders stats by message creation time, not metadata update time", ()=>{
|
|
52
|
+
insertMessage(db, {
|
|
53
|
+
id: "msg-user",
|
|
54
|
+
sessionId: "sess-1",
|
|
55
|
+
role: "user",
|
|
56
|
+
timeCreated: 1000,
|
|
57
|
+
timeUpdated: 3000
|
|
58
|
+
});
|
|
59
|
+
insertMessage(db, {
|
|
60
|
+
id: "msg-assistant",
|
|
61
|
+
sessionId: "sess-1",
|
|
62
|
+
role: "assistant",
|
|
63
|
+
timeCreated: 2000,
|
|
64
|
+
timeUpdated: 2100,
|
|
65
|
+
completed: 2200
|
|
66
|
+
});
|
|
67
|
+
expect(parser.getSessionStats(db, "sess-1").lastRole).toBe("assistant");
|
|
68
|
+
});
|
|
69
|
+
it("reads visible conversation text and hides verbose-only parts by default", ()=>{
|
|
70
|
+
insertMessage(db, {
|
|
71
|
+
id: "msg-user",
|
|
72
|
+
sessionId: "sess-1",
|
|
73
|
+
role: "user",
|
|
74
|
+
timeCreated: 1000,
|
|
75
|
+
timeUpdated: 1000
|
|
76
|
+
});
|
|
77
|
+
insertMessage(db, {
|
|
78
|
+
id: "msg-assistant",
|
|
79
|
+
sessionId: "sess-1",
|
|
80
|
+
role: "assistant",
|
|
81
|
+
timeCreated: 2000,
|
|
82
|
+
timeUpdated: 2000
|
|
83
|
+
});
|
|
84
|
+
insertPart(db, {
|
|
85
|
+
messageId: "msg-user",
|
|
86
|
+
sessionId: "sess-1",
|
|
87
|
+
data: {
|
|
88
|
+
type: "text",
|
|
89
|
+
text: "Hello"
|
|
90
|
+
},
|
|
91
|
+
timeCreated: 1000
|
|
92
|
+
});
|
|
93
|
+
insertPart(db, {
|
|
94
|
+
messageId: "msg-assistant",
|
|
95
|
+
sessionId: "sess-1",
|
|
96
|
+
data: {
|
|
97
|
+
type: "reasoning",
|
|
98
|
+
reasoning: "private thought"
|
|
99
|
+
},
|
|
100
|
+
timeCreated: 2000
|
|
101
|
+
});
|
|
102
|
+
insertPart(db, {
|
|
103
|
+
messageId: "msg-assistant",
|
|
104
|
+
sessionId: "sess-1",
|
|
105
|
+
data: {
|
|
106
|
+
type: "tool",
|
|
107
|
+
tool: "read_file"
|
|
108
|
+
},
|
|
109
|
+
timeCreated: 3000
|
|
110
|
+
});
|
|
111
|
+
expect(parser.getConversation(db, "sess-1")).toEqual([
|
|
112
|
+
{
|
|
113
|
+
role: "user",
|
|
114
|
+
content: "Hello"
|
|
115
|
+
}
|
|
116
|
+
]);
|
|
117
|
+
expect(parser.getConversation(db, "sess-1", {
|
|
118
|
+
verbose: true
|
|
119
|
+
})).toEqual([
|
|
120
|
+
{
|
|
121
|
+
role: "user",
|
|
122
|
+
content: "Hello"
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
role: "assistant",
|
|
126
|
+
content: "[thinking] private thought"
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
role: "assistant",
|
|
130
|
+
content: "[tool: read_file]"
|
|
131
|
+
}
|
|
132
|
+
]);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
function insertMessage(db, input) {
|
|
136
|
+
db.prepare("INSERT INTO message (id, session_id, data, time_created, time_updated) VALUES (?, ?, ?, ?, ?)").run(input.id, input.sessionId, JSON.stringify({
|
|
137
|
+
role: input.role,
|
|
138
|
+
time: input.completed === undefined ? {} : {
|
|
139
|
+
completed: input.completed
|
|
140
|
+
}
|
|
141
|
+
}), input.timeCreated, input.timeUpdated);
|
|
142
|
+
}
|
|
143
|
+
function insertPart(db, input) {
|
|
144
|
+
db.prepare("INSERT INTO part (message_id, session_id, data, time_created) VALUES (?, ?, ?, ?)").run(input.messageId, input.sessionId, JSON.stringify(input.data), input.timeCreated);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
//# sourceMappingURL=OpenCodeSessionParser.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/__tests__/providers/opencode/OpenCodeSessionParser.test.ts"],"sourcesContent":["import Database from \"better-sqlite3\";\nimport { afterEach, beforeEach, describe, expect, it } from \"vitest\";\nimport { OpenCodeSessionParser } from \"../../../providers/opencode/OpenCodeSessionParser.js\";\n\ndescribe(\"OpenCodeSessionParser\", () => {\n let db: Database.Database;\n let parser: OpenCodeSessionParser;\n\n beforeEach(() => {\n db = new Database(\":memory:\");\n db.exec(`\n CREATE TABLE message (id TEXT, session_id TEXT, data TEXT, time_created INTEGER, time_updated INTEGER);\n CREATE TABLE part (message_id TEXT, session_id TEXT, data TEXT, time_created INTEGER);\n `);\n parser = new OpenCodeSessionParser();\n });\n\n afterEach(() => {\n db.close();\n });\n\n it(\"extracts session stats from OpenCode messages and parts\", () => {\n insertMessage(db, {\n id: \"msg-user\",\n sessionId: \"sess-1\",\n role: \"user\",\n timeCreated: 1000,\n timeUpdated: 1000,\n });\n insertMessage(db, {\n id: \"msg-assistant\",\n sessionId: \"sess-1\",\n role: \"assistant\",\n timeCreated: 2000,\n timeUpdated: 2500,\n completed: 2400,\n });\n insertPart(db, {\n messageId: \"msg-user\",\n sessionId: \"sess-1\",\n data: { type: \"text\", text: \"Plan the migration\" },\n timeCreated: 1000,\n });\n\n expect(parser.getSessionStats(db, \"sess-1\")).toEqual({\n lastRole: \"assistant\",\n lastTimeUpdated: 2500,\n lastAssistantCompleted: true,\n lastAssistantErrored: false,\n summary: \"Plan the migration\",\n });\n });\n\n it(\"orders stats by message creation time, not metadata update time\", () => {\n insertMessage(db, {\n id: \"msg-user\",\n sessionId: \"sess-1\",\n role: \"user\",\n timeCreated: 1000,\n timeUpdated: 3000,\n });\n insertMessage(db, {\n id: \"msg-assistant\",\n sessionId: \"sess-1\",\n role: \"assistant\",\n timeCreated: 2000,\n timeUpdated: 2100,\n completed: 2200,\n });\n\n expect(parser.getSessionStats(db, \"sess-1\").lastRole).toBe(\"assistant\");\n });\n\n it(\"reads visible conversation text and hides verbose-only parts by default\", () => {\n insertMessage(db, {\n id: \"msg-user\",\n sessionId: \"sess-1\",\n role: \"user\",\n timeCreated: 1000,\n timeUpdated: 1000,\n });\n insertMessage(db, {\n id: \"msg-assistant\",\n sessionId: \"sess-1\",\n role: \"assistant\",\n timeCreated: 2000,\n timeUpdated: 2000,\n });\n insertPart(db, {\n messageId: \"msg-user\",\n sessionId: \"sess-1\",\n data: { type: \"text\", text: \"Hello\" },\n timeCreated: 1000,\n });\n insertPart(db, {\n messageId: \"msg-assistant\",\n sessionId: \"sess-1\",\n data: { type: \"reasoning\", reasoning: \"private thought\" },\n timeCreated: 2000,\n });\n insertPart(db, {\n messageId: \"msg-assistant\",\n sessionId: \"sess-1\",\n data: { type: \"tool\", tool: \"read_file\" },\n timeCreated: 3000,\n });\n\n expect(parser.getConversation(db, \"sess-1\")).toEqual([{ role: \"user\", content: \"Hello\" }]);\n expect(parser.getConversation(db, \"sess-1\", { verbose: true })).toEqual([\n { role: \"user\", content: \"Hello\" },\n { role: \"assistant\", content: \"[thinking] private thought\" },\n { role: \"assistant\", content: \"[tool: read_file]\" },\n ]);\n });\n});\n\nfunction insertMessage(\n db: Database.Database,\n input: {\n id: string;\n sessionId: string;\n role: string;\n timeCreated: number;\n timeUpdated: number;\n completed?: number;\n },\n): void {\n db.prepare(\n \"INSERT INTO message (id, session_id, data, time_created, time_updated) VALUES (?, ?, ?, ?, ?)\",\n ).run(\n input.id,\n input.sessionId,\n JSON.stringify({\n role: input.role,\n time: input.completed === undefined ? {} : { completed: input.completed },\n }),\n input.timeCreated,\n input.timeUpdated,\n );\n}\n\nfunction insertPart(\n db: Database.Database,\n input: { messageId: string; sessionId: string; data: unknown; timeCreated: number },\n): void {\n db.prepare(\"INSERT INTO part (message_id, session_id, data, time_created) VALUES (?, ?, ?, ?)\")\n .run(input.messageId, input.sessionId, JSON.stringify(input.data), input.timeCreated);\n}\n"],"names":["Database","afterEach","beforeEach","describe","expect","it","OpenCodeSessionParser","db","parser","exec","close","insertMessage","id","sessionId","role","timeCreated","timeUpdated","completed","insertPart","messageId","data","type","text","getSessionStats","toEqual","lastRole","lastTimeUpdated","lastAssistantCompleted","lastAssistantErrored","summary","toBe","reasoning","tool","getConversation","content","verbose","input","prepare","run","JSON","stringify","time","undefined"],"mappings":"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"}
|
package/dist/adapters/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export { CodexAdapter } from "../providers/codex/CodexAdapter.js";
|
|
|
3
3
|
export { CopilotAdapter } from "../providers/copilot/CopilotAdapter.js";
|
|
4
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,wCAAwC,CAAC;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAC3E,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,eAAe,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
|
@@ -3,7 +3,7 @@ export { CodexAdapter } from "../providers/codex/CodexAdapter.js";
|
|
|
3
3
|
export { CopilotAdapter } from "../providers/copilot/CopilotAdapter.js";
|
|
4
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 \"../providers/copilot/CopilotAdapter.js\";\nexport { GeminiCliAdapter } from \"../providers/gemini/GeminiCliAdapter.js\";\nexport { GrokCliAdapter } from \"./GrokCliAdapter.js\";\nexport { OpenCodeAdapter } 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":"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"}
|
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"}
|