@agtd/agent 0.1.1 → 0.1.2
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__/codexAdapterFindFile.test.d.ts +2 -0
- package/dist/__tests__/codexAdapterFindFile.test.d.ts.map +1 -0
- package/dist/__tests__/codexAdapterFindFile.test.js +298 -0
- package/dist/__tests__/codexAdapterFindFile.test.js.map +1 -0
- package/dist/__tests__/enrichers.test.d.ts +2 -0
- package/dist/__tests__/enrichers.test.d.ts.map +1 -0
- package/dist/__tests__/enrichers.test.js +47 -0
- package/dist/__tests__/enrichers.test.js.map +1 -0
- package/dist/__tests__/tmux.integration.test.d.ts +2 -0
- package/dist/__tests__/tmux.integration.test.d.ts.map +1 -0
- package/dist/__tests__/tmux.integration.test.js +112 -0
- package/dist/__tests__/tmux.integration.test.js.map +1 -0
- package/dist/__tests__/tmux.test.d.ts +2 -0
- package/dist/__tests__/tmux.test.d.ts.map +1 -0
- package/dist/__tests__/tmux.test.js +26 -0
- package/dist/__tests__/tmux.test.js.map +1 -0
- package/dist/__tests__/transcriptAdapters.test.d.ts +2 -0
- package/dist/__tests__/transcriptAdapters.test.d.ts.map +1 -0
- package/dist/__tests__/transcriptAdapters.test.js +133 -0
- package/dist/__tests__/transcriptAdapters.test.js.map +1 -0
- package/dist/adapters/claude-code.d.ts +3 -0
- package/dist/adapters/claude-code.d.ts.map +1 -0
- package/dist/adapters/claude-code.js +48 -0
- package/dist/adapters/claude-code.js.map +1 -0
- package/dist/adapters/codex.d.ts +3 -0
- package/dist/adapters/codex.d.ts.map +1 -0
- package/dist/adapters/codex.js +33 -0
- package/dist/adapters/codex.js.map +1 -0
- package/dist/adapters/generic.d.ts +3 -0
- package/dist/adapters/generic.d.ts.map +1 -0
- package/dist/adapters/generic.js +38 -0
- package/dist/adapters/generic.js.map +1 -0
- package/dist/adapters/index.d.ts +7 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +12 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/agent.d.ts +3 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +49 -6
- package/dist/agent.js.map +1 -0
- package/dist/cli.d.ts +11 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +120 -186
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +26 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +48 -0
- package/dist/config.js.map +1 -0
- package/dist/enrichers/git.d.ts +6 -0
- package/dist/enrichers/git.d.ts.map +1 -0
- package/dist/enrichers/git.js +20 -0
- package/dist/enrichers/git.js.map +1 -0
- package/dist/enrichers/pr.d.ts +2 -0
- package/dist/enrichers/pr.d.ts.map +1 -0
- package/dist/enrichers/pr.js +10 -0
- package/dist/enrichers/pr.js.map +1 -0
- package/dist/enrichers/transcript.d.ts +8 -0
- package/dist/enrichers/transcript.d.ts.map +1 -0
- package/dist/enrichers/transcript.js +33 -0
- package/dist/enrichers/transcript.js.map +1 -0
- package/dist/heartbeat.d.ts +4 -0
- package/dist/heartbeat.d.ts.map +1 -0
- package/dist/heartbeat.js +15 -0
- package/dist/heartbeat.js.map +1 -0
- package/dist/init.d.ts +10 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +70 -0
- package/dist/init.js.map +1 -0
- package/dist/register.d.ts +3 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +22 -0
- package/dist/register.js.map +1 -0
- package/dist/sessionScanner.d.ts +20 -0
- package/dist/sessionScanner.d.ts.map +1 -0
- package/dist/sessionScanner.js +479 -0
- package/dist/sessionScanner.js.map +1 -0
- package/dist/spawn.d.ts +8 -0
- package/dist/spawn.d.ts.map +1 -0
- package/dist/spawn.js +73 -0
- package/dist/spawn.js.map +1 -0
- package/dist/syncProjects.d.ts +3 -0
- package/dist/syncProjects.d.ts.map +1 -0
- package/dist/syncProjects.js +91 -0
- package/dist/syncProjects.js.map +1 -0
- package/dist/terminalBridge.d.ts +4 -0
- package/dist/terminalBridge.d.ts.map +1 -0
- package/dist/terminalBridge.js +42 -0
- package/dist/terminalBridge.js.map +1 -0
- package/dist/tmux.d.ts +21 -0
- package/dist/tmux.d.ts.map +1 -0
- package/dist/tmux.js +89 -0
- package/dist/tmux.js.map +1 -0
- package/dist/transcriptAdapters/claude-code.d.ts +3 -0
- package/dist/transcriptAdapters/claude-code.d.ts.map +1 -0
- package/dist/transcriptAdapters/claude-code.js +147 -0
- package/dist/transcriptAdapters/claude-code.js.map +1 -0
- package/dist/transcriptAdapters/codex.d.ts +3 -0
- package/dist/transcriptAdapters/codex.d.ts.map +1 -0
- package/dist/transcriptAdapters/codex.js +251 -0
- package/dist/transcriptAdapters/codex.js.map +1 -0
- package/dist/transcriptAdapters/index.d.ts +17 -0
- package/dist/transcriptAdapters/index.d.ts.map +1 -0
- package/dist/transcriptAdapters/index.js +9 -0
- package/dist/transcriptAdapters/index.js.map +1 -0
- package/dist/wsClient.d.ts +6 -0
- package/dist/wsClient.d.ts.map +1 -0
- package/dist/wsClient.js +156 -0
- package/dist/wsClient.js.map +1 -0
- package/package.json +6 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codexAdapterFindFile.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/codexAdapterFindFile.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration tests for codexAdapter.findFile() — the three-tier lookup:
|
|
3
|
+
*
|
|
4
|
+
* Tier 1: stored codexThreadId → exact match, unique per session
|
|
5
|
+
* Tier 2: tmux session creation time → used when codexThreadId absent
|
|
6
|
+
* Tier 3: latest thread by cwd → last resort, may collide if cwd shared
|
|
7
|
+
*
|
|
8
|
+
* node:child_process is mocked so these tests run without sqlite3 CLI or tmux.
|
|
9
|
+
*/
|
|
10
|
+
import { describe, it, expect, beforeAll, afterAll, beforeEach, vi } from "vitest";
|
|
11
|
+
import { writeFileSync, mkdirSync, rmSync } from "node:fs";
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
import { tmpdir } from "node:os";
|
|
14
|
+
vi.mock("node:child_process", () => ({
|
|
15
|
+
execSync: vi.fn(),
|
|
16
|
+
}));
|
|
17
|
+
// Import AFTER vi.mock so the adapter picks up the mocked execSync
|
|
18
|
+
import { codexAdapter } from "../transcriptAdapters/codex.js";
|
|
19
|
+
import { execSync } from "node:child_process";
|
|
20
|
+
const mockExecSync = vi.mocked(execSync);
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// Fixture setup
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
const THREAD_ID_1 = "01234567-0000-7000-0000-000000000001";
|
|
25
|
+
const THREAD_ID_2 = "01234567-0000-7000-0000-000000000002";
|
|
26
|
+
const SHARED_CWD = "/projects/shared-project";
|
|
27
|
+
const TMUX_SESSION_1 = "aidash-sess_aaa11111";
|
|
28
|
+
const TMUX_SESSION_2 = "aidash-sess_bbb22222";
|
|
29
|
+
const TMUX_CREATED_1 = "1700000000"; // earlier session
|
|
30
|
+
const TMUX_CREATED_2 = "1700000300"; // later session (5 min later)
|
|
31
|
+
let tmpDir;
|
|
32
|
+
let jsonlPath1; // rollout file for thread 1
|
|
33
|
+
let jsonlPath2; // rollout file for thread 2
|
|
34
|
+
beforeAll(() => {
|
|
35
|
+
tmpDir = join(tmpdir(), "agtd-codex-findfile-" + Date.now());
|
|
36
|
+
mkdirSync(join(tmpDir, ".codex"), { recursive: true });
|
|
37
|
+
// A zero-byte file is enough — existsSync(dbPath) just needs to pass
|
|
38
|
+
writeFileSync(join(tmpDir, ".codex", "state_5.sqlite"), "");
|
|
39
|
+
// Create real JSONL files so existsSync(rolloutPath) passes
|
|
40
|
+
jsonlPath1 = join(tmpDir, "rollout-thread1.jsonl");
|
|
41
|
+
jsonlPath2 = join(tmpDir, "rollout-thread2.jsonl");
|
|
42
|
+
writeFileSync(jsonlPath1, JSON.stringify({
|
|
43
|
+
type: "response_item",
|
|
44
|
+
timestamp: "2026-01-01T00:00:00Z",
|
|
45
|
+
payload: {
|
|
46
|
+
type: "message",
|
|
47
|
+
role: "user",
|
|
48
|
+
content: [{ type: "text", text: "session 1 message" }],
|
|
49
|
+
},
|
|
50
|
+
}) + "\n");
|
|
51
|
+
writeFileSync(jsonlPath2, JSON.stringify({
|
|
52
|
+
type: "response_item",
|
|
53
|
+
timestamp: "2026-01-02T00:00:00Z",
|
|
54
|
+
payload: {
|
|
55
|
+
type: "message",
|
|
56
|
+
role: "user",
|
|
57
|
+
content: [{ type: "text", text: "session 2 message" }],
|
|
58
|
+
},
|
|
59
|
+
}) + "\n");
|
|
60
|
+
});
|
|
61
|
+
afterAll(() => {
|
|
62
|
+
rmSync(tmpDir, { recursive: true, force: true });
|
|
63
|
+
});
|
|
64
|
+
beforeEach(() => {
|
|
65
|
+
mockExecSync.mockReset();
|
|
66
|
+
});
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
// Tier 1 tests — codexThreadId direct lookup
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
describe("Tier 1: codexThreadId lookup", () => {
|
|
71
|
+
it("returns the rollout file matching the stored codexThreadId", () => {
|
|
72
|
+
mockExecSync.mockReturnValueOnce((jsonlPath1 + "\n"));
|
|
73
|
+
const session = {
|
|
74
|
+
id: "sess_1",
|
|
75
|
+
cwd: SHARED_CWD,
|
|
76
|
+
agentType: "codex",
|
|
77
|
+
codexThreadId: THREAD_ID_1,
|
|
78
|
+
tmuxSession: TMUX_SESSION_1,
|
|
79
|
+
};
|
|
80
|
+
const result = codexAdapter.findFile(session, tmpDir);
|
|
81
|
+
expect(result).toBe(jsonlPath1);
|
|
82
|
+
// Must query by thread ID, not by cwd
|
|
83
|
+
expect(mockExecSync).toHaveBeenCalledWith(expect.stringContaining(THREAD_ID_1), expect.any(Object));
|
|
84
|
+
});
|
|
85
|
+
it("two sessions with the SAME cwd get DIFFERENT transcripts via codexThreadId", () => {
|
|
86
|
+
// Session 1 lookup
|
|
87
|
+
mockExecSync.mockReturnValueOnce((jsonlPath1 + "\n"));
|
|
88
|
+
const session1 = {
|
|
89
|
+
id: "sess_1",
|
|
90
|
+
cwd: SHARED_CWD,
|
|
91
|
+
codexThreadId: THREAD_ID_1,
|
|
92
|
+
};
|
|
93
|
+
const file1 = codexAdapter.findFile(session1, tmpDir);
|
|
94
|
+
mockExecSync.mockReset();
|
|
95
|
+
// Session 2 lookup
|
|
96
|
+
mockExecSync.mockReturnValueOnce((jsonlPath2 + "\n"));
|
|
97
|
+
const session2 = {
|
|
98
|
+
id: "sess_2",
|
|
99
|
+
cwd: SHARED_CWD,
|
|
100
|
+
codexThreadId: THREAD_ID_2,
|
|
101
|
+
};
|
|
102
|
+
const file2 = codexAdapter.findFile(session2, tmpDir);
|
|
103
|
+
expect(file1).toBe(jsonlPath1);
|
|
104
|
+
expect(file2).toBe(jsonlPath2);
|
|
105
|
+
// KEY regression assertion: same cwd must not produce same transcript
|
|
106
|
+
expect(file1).not.toBe(file2);
|
|
107
|
+
});
|
|
108
|
+
it("falls through to Tier 2 when Tier 1 returns a non-existent path", () => {
|
|
109
|
+
// Tier 1: returns a path that does not exist on disk
|
|
110
|
+
mockExecSync
|
|
111
|
+
.mockReturnValueOnce(("/nonexistent/rollout.jsonl\n")) // Tier 1 sqlite3
|
|
112
|
+
.mockReturnValueOnce((TMUX_CREATED_1 + "\n")) // Tier 2: tmux display-message
|
|
113
|
+
.mockReturnValueOnce((jsonlPath1 + "\n")); // Tier 2: sqlite3 by timestamp
|
|
114
|
+
const session = {
|
|
115
|
+
id: "sess_1",
|
|
116
|
+
cwd: SHARED_CWD,
|
|
117
|
+
codexThreadId: THREAD_ID_1,
|
|
118
|
+
tmuxSession: TMUX_SESSION_1,
|
|
119
|
+
};
|
|
120
|
+
const result = codexAdapter.findFile(session, tmpDir);
|
|
121
|
+
expect(result).toBe(jsonlPath1);
|
|
122
|
+
});
|
|
123
|
+
it("falls through to Tier 3 when codexThreadId returns empty string", () => {
|
|
124
|
+
// Tier 1: sqlite3 returns empty (thread not found)
|
|
125
|
+
// Tier 2: no tmuxSession → skipped
|
|
126
|
+
// Tier 3: returns latest by cwd
|
|
127
|
+
mockExecSync
|
|
128
|
+
.mockReturnValueOnce(("")) // Tier 1: empty
|
|
129
|
+
.mockReturnValueOnce((jsonlPath2 + "\n")); // Tier 3: latest by cwd
|
|
130
|
+
const session = {
|
|
131
|
+
id: "sess_x",
|
|
132
|
+
cwd: SHARED_CWD,
|
|
133
|
+
codexThreadId: THREAD_ID_1,
|
|
134
|
+
tmuxSession: null, // no tmux → skip Tier 2
|
|
135
|
+
};
|
|
136
|
+
const result = codexAdapter.findFile(session, tmpDir);
|
|
137
|
+
expect(result).toBe(jsonlPath2);
|
|
138
|
+
expect(mockExecSync).toHaveBeenCalledWith(expect.stringContaining("ORDER BY updated_at DESC"), expect.any(Object));
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
// ---------------------------------------------------------------------------
|
|
142
|
+
// Tier 2 tests — tmux session creation time
|
|
143
|
+
// ---------------------------------------------------------------------------
|
|
144
|
+
describe("Tier 2: tmux session creation time lookup", () => {
|
|
145
|
+
it("uses tmux creation time when codexThreadId is null", () => {
|
|
146
|
+
mockExecSync
|
|
147
|
+
.mockReturnValueOnce((TMUX_CREATED_1 + "\n")) // tmux display-message
|
|
148
|
+
.mockReturnValueOnce((jsonlPath1 + "\n")); // sqlite3 WHERE created_at >=
|
|
149
|
+
const session = {
|
|
150
|
+
id: "sess_3",
|
|
151
|
+
cwd: SHARED_CWD,
|
|
152
|
+
codexThreadId: null,
|
|
153
|
+
tmuxSession: TMUX_SESSION_1,
|
|
154
|
+
};
|
|
155
|
+
const result = codexAdapter.findFile(session, tmpDir);
|
|
156
|
+
expect(result).toBe(jsonlPath1);
|
|
157
|
+
expect(mockExecSync).toHaveBeenCalledWith(expect.stringContaining(`tmux display-message -t '${TMUX_SESSION_1}'`), expect.any(Object));
|
|
158
|
+
expect(mockExecSync).toHaveBeenCalledWith(expect.stringContaining(`created_at >= ${TMUX_CREATED_1}`), expect.any(Object));
|
|
159
|
+
});
|
|
160
|
+
it("two sessions sharing cwd get correct files via different tmux creation times", () => {
|
|
161
|
+
// Session 1: earlier tmux time → finds thread 1
|
|
162
|
+
mockExecSync
|
|
163
|
+
.mockReturnValueOnce((TMUX_CREATED_1 + "\n"))
|
|
164
|
+
.mockReturnValueOnce((jsonlPath1 + "\n"));
|
|
165
|
+
const session1 = {
|
|
166
|
+
id: "sess_3",
|
|
167
|
+
cwd: SHARED_CWD,
|
|
168
|
+
codexThreadId: null,
|
|
169
|
+
tmuxSession: TMUX_SESSION_1,
|
|
170
|
+
};
|
|
171
|
+
const file1 = codexAdapter.findFile(session1, tmpDir);
|
|
172
|
+
expect(file1).toBe(jsonlPath1);
|
|
173
|
+
mockExecSync.mockReset();
|
|
174
|
+
// Session 2: later tmux time → finds thread 2
|
|
175
|
+
mockExecSync
|
|
176
|
+
.mockReturnValueOnce((TMUX_CREATED_2 + "\n"))
|
|
177
|
+
.mockReturnValueOnce((jsonlPath2 + "\n"));
|
|
178
|
+
const session2 = {
|
|
179
|
+
id: "sess_4",
|
|
180
|
+
cwd: SHARED_CWD,
|
|
181
|
+
codexThreadId: null,
|
|
182
|
+
tmuxSession: TMUX_SESSION_2,
|
|
183
|
+
};
|
|
184
|
+
const file2 = codexAdapter.findFile(session2, tmpDir);
|
|
185
|
+
expect(file2).toBe(jsonlPath2);
|
|
186
|
+
expect(file1).not.toBe(file2);
|
|
187
|
+
});
|
|
188
|
+
it("falls through to Tier 3 when tmux command fails", () => {
|
|
189
|
+
mockExecSync
|
|
190
|
+
.mockImplementationOnce(() => {
|
|
191
|
+
throw new Error("no server running on /tmp/tmux/default");
|
|
192
|
+
})
|
|
193
|
+
.mockReturnValueOnce((jsonlPath2 + "\n")); // Tier 3 fallback
|
|
194
|
+
const session = {
|
|
195
|
+
id: "sess_5",
|
|
196
|
+
cwd: SHARED_CWD,
|
|
197
|
+
codexThreadId: null,
|
|
198
|
+
tmuxSession: TMUX_SESSION_1,
|
|
199
|
+
};
|
|
200
|
+
const result = codexAdapter.findFile(session, tmpDir);
|
|
201
|
+
expect(result).toBe(jsonlPath2);
|
|
202
|
+
expect(mockExecSync).toHaveBeenCalledWith(expect.stringContaining("ORDER BY updated_at DESC"), expect.any(Object));
|
|
203
|
+
});
|
|
204
|
+
it("falls through to Tier 3 when tmux returns non-numeric output", () => {
|
|
205
|
+
mockExecSync
|
|
206
|
+
.mockReturnValueOnce(("not-a-number\n")) // tmux returns garbage
|
|
207
|
+
.mockReturnValueOnce((jsonlPath2 + "\n")); // Tier 3
|
|
208
|
+
const session = {
|
|
209
|
+
id: "sess_6",
|
|
210
|
+
cwd: SHARED_CWD,
|
|
211
|
+
codexThreadId: null,
|
|
212
|
+
tmuxSession: TMUX_SESSION_1,
|
|
213
|
+
};
|
|
214
|
+
const result = codexAdapter.findFile(session, tmpDir);
|
|
215
|
+
expect(result).toBe(jsonlPath2);
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
// ---------------------------------------------------------------------------
|
|
219
|
+
// Tier 3 tests — latest thread by cwd (last resort)
|
|
220
|
+
// ---------------------------------------------------------------------------
|
|
221
|
+
describe("Tier 3: latest thread by cwd (last resort)", () => {
|
|
222
|
+
it("returns latest updated thread when no codexThreadId and no tmuxSession", () => {
|
|
223
|
+
mockExecSync.mockReturnValueOnce((jsonlPath2 + "\n"));
|
|
224
|
+
const session = {
|
|
225
|
+
id: "sess_7",
|
|
226
|
+
cwd: SHARED_CWD,
|
|
227
|
+
codexThreadId: null,
|
|
228
|
+
tmuxSession: null,
|
|
229
|
+
};
|
|
230
|
+
const result = codexAdapter.findFile(session, tmpDir);
|
|
231
|
+
expect(result).toBe(jsonlPath2);
|
|
232
|
+
expect(mockExecSync).toHaveBeenCalledWith(expect.stringContaining("ORDER BY updated_at DESC LIMIT 1"), expect.any(Object));
|
|
233
|
+
});
|
|
234
|
+
it("WARNING: returns same file for two sessions with same cwd (Tier 3 limitation)", () => {
|
|
235
|
+
// This test documents the known limitation of Tier 3 — it cannot disambiguate
|
|
236
|
+
// sessions sharing the same cwd without codexThreadId or tmuxSession.
|
|
237
|
+
// Tier 1 and Tier 2 exist to avoid hitting this case.
|
|
238
|
+
const session1 = { id: "sess_8", cwd: SHARED_CWD, codexThreadId: null, tmuxSession: null };
|
|
239
|
+
const session2 = { id: "sess_9", cwd: SHARED_CWD, codexThreadId: null, tmuxSession: null };
|
|
240
|
+
mockExecSync.mockReturnValueOnce((jsonlPath2 + "\n"));
|
|
241
|
+
const file1 = codexAdapter.findFile(session1, tmpDir);
|
|
242
|
+
mockExecSync.mockReset();
|
|
243
|
+
mockExecSync.mockReturnValueOnce((jsonlPath2 + "\n"));
|
|
244
|
+
const file2 = codexAdapter.findFile(session2, tmpDir);
|
|
245
|
+
// Both get the same (latest) file — this is the documented limitation
|
|
246
|
+
expect(file1).toBe(jsonlPath2);
|
|
247
|
+
expect(file2).toBe(jsonlPath2);
|
|
248
|
+
expect(file1).toBe(file2); // expected collision — document this behavior
|
|
249
|
+
});
|
|
250
|
+
it("returns null when cwd is empty", () => {
|
|
251
|
+
// No SQLite DB fallback and no sessions dir
|
|
252
|
+
const session = {
|
|
253
|
+
id: "sess_10",
|
|
254
|
+
cwd: "",
|
|
255
|
+
codexThreadId: null,
|
|
256
|
+
tmuxSession: null,
|
|
257
|
+
};
|
|
258
|
+
const result = codexAdapter.findFile(session, join(tmpDir, "no-sessions-dir"));
|
|
259
|
+
expect(result).toBeNull();
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
// ---------------------------------------------------------------------------
|
|
263
|
+
// SQL injection / quoting edge cases
|
|
264
|
+
// ---------------------------------------------------------------------------
|
|
265
|
+
describe("shell quoting — paths with special characters", () => {
|
|
266
|
+
it("handles cwd containing single quotes in SQLite query", () => {
|
|
267
|
+
// This is the exact bug that broke Tier 2 before the fix:
|
|
268
|
+
// using single-quote outer wrapping with a cwd like /Users/foo/it's-project
|
|
269
|
+
// broke because the shell interpreter saw the inner ' as ending the argument.
|
|
270
|
+
mockExecSync.mockReturnValueOnce((jsonlPath1 + "\n"));
|
|
271
|
+
const session = {
|
|
272
|
+
id: "sess_sq",
|
|
273
|
+
cwd: "/projects/it's-project",
|
|
274
|
+
codexThreadId: THREAD_ID_1,
|
|
275
|
+
tmuxSession: null,
|
|
276
|
+
};
|
|
277
|
+
// Should not throw; the quoting logic must handle single quotes in paths
|
|
278
|
+
expect(() => codexAdapter.findFile(session, tmpDir)).not.toThrow();
|
|
279
|
+
});
|
|
280
|
+
it("Tier 3 CWD query uses double-quote outer wrapping (regression: near '/' syntax error)", () => {
|
|
281
|
+
// The original bug: sqlite3 'db' 'WHERE cwd='/Users/...' was broken because
|
|
282
|
+
// the shell split on / in the path. Fixed by using "double-quote wrapping".
|
|
283
|
+
// Verify the query string passed to execSync uses the correct quoting.
|
|
284
|
+
mockExecSync.mockReturnValueOnce((jsonlPath1 + "\n"));
|
|
285
|
+
const session = {
|
|
286
|
+
id: "sess_dq",
|
|
287
|
+
cwd: "/Users/robyparapat/workspace/repo/payment-connectors-service",
|
|
288
|
+
codexThreadId: null,
|
|
289
|
+
tmuxSession: null,
|
|
290
|
+
};
|
|
291
|
+
codexAdapter.findFile(session, tmpDir);
|
|
292
|
+
// The execSync call must use double quotes as outer wrapper for the SQL argument
|
|
293
|
+
// so the cwd single quotes are treated as literal characters, not shell delimiters
|
|
294
|
+
const call = mockExecSync.mock.calls[0][0];
|
|
295
|
+
expect(call).toMatch(/sqlite3 '.*' "SELECT rollout_path/);
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
//# sourceMappingURL=codexAdapterFindFile.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codexAdapterFindFile.test.js","sourceRoot":"","sources":["../../src/__tests__/codexAdapterFindFile.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enrichers.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/enrichers.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { derivePrUrl } from "../enrichers/pr.js";
|
|
3
|
+
import { parseTranscript } from "../enrichers/transcript.js";
|
|
4
|
+
describe("PR URL enricher", () => {
|
|
5
|
+
it("derives GitHub PR search URL from HTTPS remote", () => {
|
|
6
|
+
const url = derivePrUrl("https://github.com/user/repo.git", "feat/my-branch");
|
|
7
|
+
expect(url).toContain("github.com/user/repo/pulls");
|
|
8
|
+
expect(url).toContain("head:feat%2Fmy-branch");
|
|
9
|
+
});
|
|
10
|
+
it("handles SSH remote URLs", () => {
|
|
11
|
+
const url = derivePrUrl("git@github.com:user/repo.git", "fix/bug");
|
|
12
|
+
expect(url).toContain("github.com/user/repo/pulls");
|
|
13
|
+
expect(url).toContain("fix%2Fbug");
|
|
14
|
+
});
|
|
15
|
+
it("returns null for non-GitHub remotes", () => {
|
|
16
|
+
expect(derivePrUrl("https://gitlab.com/user/repo.git", "main")).toBeNull();
|
|
17
|
+
});
|
|
18
|
+
it("returns null for empty inputs", () => {
|
|
19
|
+
expect(derivePrUrl("", "main")).toBeNull();
|
|
20
|
+
expect(derivePrUrl("https://github.com/u/r", "")).toBeNull();
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
describe("Transcript parser", () => {
|
|
24
|
+
it("extracts model name", () => {
|
|
25
|
+
const result = parseTranscript("Using model: claude-sonnet-4-5");
|
|
26
|
+
expect(result.model).toBe("claude-sonnet-4-5");
|
|
27
|
+
});
|
|
28
|
+
it("extracts context percentage", () => {
|
|
29
|
+
const result = parseTranscript("context: 61%");
|
|
30
|
+
expect(result.contextPercent).toBe(61);
|
|
31
|
+
});
|
|
32
|
+
it("extracts MCP servers", () => {
|
|
33
|
+
const result = parseTranscript("mcp: [github, filesystem]");
|
|
34
|
+
expect(result.mcpServers).toEqual(["github", "filesystem"]);
|
|
35
|
+
});
|
|
36
|
+
it("returns nulls for empty input", () => {
|
|
37
|
+
const result = parseTranscript("");
|
|
38
|
+
expect(result.model).toBeNull();
|
|
39
|
+
expect(result.contextPercent).toBeNull();
|
|
40
|
+
expect(result.mcpServers).toBeNull();
|
|
41
|
+
});
|
|
42
|
+
it("handles GPT model names", () => {
|
|
43
|
+
const result = parseTranscript("model: gpt-4o-mini");
|
|
44
|
+
expect(result.model).toBe("gpt-4o-mini");
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
//# sourceMappingURL=enrichers.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enrichers.test.js","sourceRoot":"","sources":["../../src/__tests__/enrichers.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tmux.integration.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/tmux.integration.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration tests for tmux key-sending approaches.
|
|
3
|
+
*
|
|
4
|
+
* Key findings from empirical testing:
|
|
5
|
+
* - Both hex mode (buildSendKeysCmd) and plain send-keys (buildSendMessageCmd) deliver
|
|
6
|
+
* the SAME bytes to the running program. For 'hello world' + Enter, both deliver
|
|
7
|
+
* the string as a single data event with bytes [68 65 6c 6c 6f 20 77 6f 72 6c 64 0d].
|
|
8
|
+
* - readline.emitKeypressEvents (used by Ink/Codex internally) correctly parses a
|
|
9
|
+
* batched data event into individual keypress events: h, e, l, l, o, ..., return.
|
|
10
|
+
* - However, Ink TUIs may be mid-render when input arrives; sending chars one at a
|
|
11
|
+
* time (with 20ms delays) is more reliable for interactive TUIs.
|
|
12
|
+
*
|
|
13
|
+
* Skipped automatically if tmux is not available.
|
|
14
|
+
*/
|
|
15
|
+
import { describe, it, expect, afterEach } from "vitest";
|
|
16
|
+
import { execSync } from "node:child_process";
|
|
17
|
+
import * as fs from "node:fs";
|
|
18
|
+
import * as os from "node:os";
|
|
19
|
+
import * as path from "node:path";
|
|
20
|
+
import { isTmuxAvailable, tmuxExec, buildSendKeysCmd, buildSendMessageCmd, buildCapturePaneCmd, sanitizeShellArg, } from "../tmux.js";
|
|
21
|
+
const AVAILABLE = isTmuxAvailable();
|
|
22
|
+
const PREFIX = `agtd-itest-${Date.now()}`;
|
|
23
|
+
function killSession(name) {
|
|
24
|
+
try {
|
|
25
|
+
execSync(`tmux kill-session -t '${sanitizeShellArg(name)}'`, {
|
|
26
|
+
stdio: "pipe",
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
catch { }
|
|
30
|
+
}
|
|
31
|
+
function newSession(name) {
|
|
32
|
+
tmuxExec(`tmux new-session -d -s '${sanitizeShellArg(name)}'`);
|
|
33
|
+
}
|
|
34
|
+
/** Poll capture-pane every 100 ms until pattern matches or timeout. */
|
|
35
|
+
async function waitFor(session, pattern, timeoutMs = 5000) {
|
|
36
|
+
const deadline = Date.now() + timeoutMs;
|
|
37
|
+
while (Date.now() < deadline) {
|
|
38
|
+
const out = tmuxExec(buildCapturePaneCmd(session));
|
|
39
|
+
if (pattern.test(out))
|
|
40
|
+
return out;
|
|
41
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
42
|
+
}
|
|
43
|
+
return tmuxExec(buildCapturePaneCmd(session));
|
|
44
|
+
}
|
|
45
|
+
function writeTmpScript(code) {
|
|
46
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "agtd-test-"));
|
|
47
|
+
const file = path.join(dir, "script.mjs");
|
|
48
|
+
fs.writeFileSync(file, code);
|
|
49
|
+
return file;
|
|
50
|
+
}
|
|
51
|
+
// ── Verify byte delivery ──────────────────────────────────────────────────
|
|
52
|
+
describe.skipIf(!AVAILABLE)("tmux byte delivery — both send approaches", () => {
|
|
53
|
+
const session = `${PREFIX}-bytes`;
|
|
54
|
+
afterEach(() => killSession(session));
|
|
55
|
+
// Raw-mode Node.js script that logs each keypress (uses readline.emitKeypressEvents
|
|
56
|
+
// internally, same as Ink/Codex)
|
|
57
|
+
const SCRIPT = writeTmpScript(`
|
|
58
|
+
import readline from 'readline';
|
|
59
|
+
readline.emitKeypressEvents(process.stdin);
|
|
60
|
+
if (process.stdin.isTTY) process.stdin.setRawMode(true);
|
|
61
|
+
process.stdin.resume();
|
|
62
|
+
process.stdin.setEncoding('utf8');
|
|
63
|
+
let buf = '';
|
|
64
|
+
process.stdin.on('keypress', (ch, key) => {
|
|
65
|
+
if (key?.name === 'return') {
|
|
66
|
+
process.stdout.write('GOT:' + buf + '\\n');
|
|
67
|
+
buf = '';
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (key?.ctrl && key?.name === 'c') process.exit(0);
|
|
71
|
+
if (ch) buf += ch;
|
|
72
|
+
});
|
|
73
|
+
process.stdout.write('READY\\n');
|
|
74
|
+
`);
|
|
75
|
+
async function setup() {
|
|
76
|
+
killSession(session);
|
|
77
|
+
newSession(session);
|
|
78
|
+
tmuxExec(`tmux send-keys -t '${sanitizeShellArg(session)}' 'node ${SCRIPT}' Enter`);
|
|
79
|
+
await waitFor(session, /READY/, 3000);
|
|
80
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
81
|
+
}
|
|
82
|
+
it("buildSendMessageCmd ('text' Enter) delivers chars via emitKeypressEvents", async () => {
|
|
83
|
+
await setup();
|
|
84
|
+
tmuxExec(buildSendMessageCmd(session, "hello world"));
|
|
85
|
+
const out = await waitFor(session, /GOT:/, 3000);
|
|
86
|
+
expect(out).toContain("GOT:hello world");
|
|
87
|
+
});
|
|
88
|
+
it("char-by-char hex mode (user-message approach) delivers chars correctly", async () => {
|
|
89
|
+
await setup();
|
|
90
|
+
// Simulate what the user-message handler now does: send each char, then CR
|
|
91
|
+
for (const char of "hello chars") {
|
|
92
|
+
tmuxExec(buildSendKeysCmd(session, char));
|
|
93
|
+
await new Promise((r) => setTimeout(r, 20));
|
|
94
|
+
}
|
|
95
|
+
tmuxExec(buildSendKeysCmd(session, "\r"));
|
|
96
|
+
const out = await waitFor(session, /GOT:/, 3000);
|
|
97
|
+
expect(out).toContain("GOT:hello chars");
|
|
98
|
+
});
|
|
99
|
+
it("messages with special characters (quotes, backticks) are delivered", async () => {
|
|
100
|
+
await setup();
|
|
101
|
+
const msg = "fix it's bug";
|
|
102
|
+
// char-by-char (agent approach)
|
|
103
|
+
for (const char of msg) {
|
|
104
|
+
tmuxExec(buildSendKeysCmd(session, char));
|
|
105
|
+
await new Promise((r) => setTimeout(r, 20));
|
|
106
|
+
}
|
|
107
|
+
tmuxExec(buildSendKeysCmd(session, "\r"));
|
|
108
|
+
const out = await waitFor(session, /GOT:/, 3000);
|
|
109
|
+
expect(out).toContain(`GOT:${msg}`);
|
|
110
|
+
});
|
|
111
|
+
}, { timeout: 30000 });
|
|
112
|
+
//# sourceMappingURL=tmux.integration.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tmux.integration.test.js","sourceRoot":"","sources":["../../src/__tests__/tmux.integration.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tmux.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/tmux.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { buildCreateSessionCmd, buildCreateWindowCmd, buildSendKeysCmd, buildCapturePaneCmd, } from "../tmux.js";
|
|
3
|
+
describe("tmux command builders", () => {
|
|
4
|
+
it("builds create session command", () => {
|
|
5
|
+
const cmd = buildCreateSessionCmd("aidash-s1", "/code/proj");
|
|
6
|
+
expect(cmd).toBe("tmux new-session -d -s 'aidash-s1' -c '/code/proj'");
|
|
7
|
+
});
|
|
8
|
+
it("builds create window command", () => {
|
|
9
|
+
const cmd = buildCreateWindowCmd("aidash-s1", "my-window", "/code/proj");
|
|
10
|
+
expect(cmd).toBe("tmux new-window -t 'aidash-s1' -n 'my-window' -c '/code/proj'");
|
|
11
|
+
});
|
|
12
|
+
it("builds send-keys command with hex-encoded bytes", () => {
|
|
13
|
+
const cmd = buildSendKeysCmd("aidash-s1", "hi");
|
|
14
|
+
// "hi" = 0x68 0x69
|
|
15
|
+
expect(cmd).toBe("tmux send-keys -t 'aidash-s1' -H 68 69");
|
|
16
|
+
});
|
|
17
|
+
it("sends Enter key as hex 0d (carriage return)", () => {
|
|
18
|
+
const cmd = buildSendKeysCmd("aidash-s1", "\r");
|
|
19
|
+
expect(cmd).toBe("tmux send-keys -t 'aidash-s1' -H 0d");
|
|
20
|
+
});
|
|
21
|
+
it("builds capture-pane command with ANSI escape preservation", () => {
|
|
22
|
+
const cmd = buildCapturePaneCmd("aidash-s1");
|
|
23
|
+
expect(cmd).toBe("tmux capture-pane -t 'aidash-s1' -p -e -S -");
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
//# sourceMappingURL=tmux.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tmux.test.js","sourceRoot":"","sources":["../../src/__tests__/tmux.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,YAAY,CAAC;AAEpB,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,GAAG,GAAG,qBAAqB,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;QAC7D,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,oDAAoD,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,GAAG,GAAG,oBAAoB,CAAC,WAAW,EAAE,WAAW,EAAE,YAAY,CAAC,CAAC;QACzE,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CACd,+DAA+D,CAChE,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,GAAG,GAAG,gBAAgB,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;QAChD,mBAAmB;QACnB,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,GAAG,GAAG,gBAAgB,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;QAChD,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,qCAAqC,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,MAAM,GAAG,GAAG,mBAAmB,CAAC,WAAW,CAAC,CAAC;QAC7C,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,6CAA6C,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transcriptAdapters.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/transcriptAdapters.test.ts"],"names":[],"mappings":""}
|