@opencode-trace/plugin 0.0.4 → 0.0.5
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/README.md +4 -11
- package/dist/__tests__/tracer.test.d.ts +2 -0
- package/dist/__tests__/tracer.test.d.ts.map +1 -0
- package/dist/__tests__/tracer.test.js +276 -0
- package/dist/__tests__/tracer.test.js.map +1 -0
- package/dist/integration.test.js +508 -11
- package/dist/integration.test.js.map +1 -1
- package/dist/plugin-instance.d.ts +31 -17
- package/dist/plugin-instance.d.ts.map +1 -1
- package/dist/plugin-instance.js +249 -78
- package/dist/plugin-instance.js.map +1 -1
- package/dist/plugin-instance.test.js +672 -25
- package/dist/plugin-instance.test.js.map +1 -1
- package/dist/trace.d.ts.map +1 -1
- package/dist/trace.js +209 -54
- package/dist/trace.js.map +1 -1
- package/dist/trace.test.js +630 -47
- package/dist/trace.test.js.map +1 -1
- package/dist/tracer.d.ts +20 -0
- package/dist/tracer.d.ts.map +1 -0
- package/dist/tracer.js +12 -0
- package/dist/tracer.js.map +1 -0
- package/dist/write-queue.d.ts +27 -2
- package/dist/write-queue.d.ts.map +1 -1
- package/dist/write-queue.js +99 -14
- package/dist/write-queue.js.map +1 -1
- package/dist/write-queue.test.js +373 -6
- package/dist/write-queue.test.js.map +1 -1
- package/package.json +11 -4
- package/dist/state-queue.d.ts +0 -14
- package/dist/state-queue.d.ts.map +0 -1
- package/dist/state-queue.js +0 -44
- package/dist/state-queue.js.map +0 -1
- package/dist/state-queue.test.d.ts +0 -2
- package/dist/state-queue.test.d.ts.map +0 -1
- package/dist/state-queue.test.js +0 -99
- package/dist/state-queue.test.js.map +0 -1
package/dist/integration.test.js
CHANGED
|
@@ -1,13 +1,26 @@
|
|
|
1
|
-
import { describe, test, expect, beforeEach, afterEach } from "vitest";
|
|
1
|
+
import { describe, test, expect, beforeEach, afterEach, vi } from "vitest";
|
|
2
2
|
import { TracePlugin } from "./plugin-instance.js";
|
|
3
|
-
import
|
|
3
|
+
import entrypoint, { _resetForTesting } from "./trace.js";
|
|
4
|
+
import { mkdtempSync, rmSync, readdirSync, readFileSync, writeFileSync, existsSync, promises as fs, } from "node:fs";
|
|
4
5
|
import { tmpdir } from "node:os";
|
|
5
6
|
import { join } from "node:path";
|
|
7
|
+
vi.mock("node:os", async (importOriginal) => {
|
|
8
|
+
const original = await importOriginal();
|
|
9
|
+
return {
|
|
10
|
+
...original,
|
|
11
|
+
homedir: () => {
|
|
12
|
+
const testDir = process.env._INTEGRATION_TEST_DIR_;
|
|
13
|
+
if (testDir)
|
|
14
|
+
return testDir;
|
|
15
|
+
return original.homedir();
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
});
|
|
6
19
|
async function waitForFiles(dir, count, timeoutMs = 5000) {
|
|
7
20
|
const startTime = Date.now();
|
|
8
21
|
while (true) {
|
|
9
22
|
if (existsSync(dir)) {
|
|
10
|
-
const files = readdirSync(dir).filter(f => f
|
|
23
|
+
const files = readdirSync(dir).filter((f) => /^\d+\.json$/.test(f));
|
|
11
24
|
if (files.length >= count) {
|
|
12
25
|
let allValid = true;
|
|
13
26
|
for (const file of files) {
|
|
@@ -31,7 +44,26 @@ async function waitForFiles(dir, count, timeoutMs = 5000) {
|
|
|
31
44
|
if (Date.now() - startTime > timeoutMs) {
|
|
32
45
|
throw new Error(`Timeout waiting for ${count} valid files in ${dir} after ${timeoutMs}ms`);
|
|
33
46
|
}
|
|
34
|
-
await new Promise(r => setTimeout(r, 10));
|
|
47
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async function waitForFile(filePath, timeoutMs = 5000) {
|
|
51
|
+
const startTime = Date.now();
|
|
52
|
+
while (true) {
|
|
53
|
+
if (existsSync(filePath)) {
|
|
54
|
+
try {
|
|
55
|
+
const content = readFileSync(filePath, "utf-8");
|
|
56
|
+
if (content && content.length > 0) {
|
|
57
|
+
JSON.parse(content);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
catch { }
|
|
62
|
+
}
|
|
63
|
+
if (Date.now() - startTime > timeoutMs) {
|
|
64
|
+
throw new Error(`Timeout waiting for valid file ${filePath} after ${timeoutMs}ms`);
|
|
65
|
+
}
|
|
66
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
35
67
|
}
|
|
36
68
|
}
|
|
37
69
|
describe("Integration: TracePlugin full flow", () => {
|
|
@@ -39,7 +71,7 @@ describe("Integration: TracePlugin full flow", () => {
|
|
|
39
71
|
let plugin;
|
|
40
72
|
beforeEach(async () => {
|
|
41
73
|
tempDir = mkdtempSync(join(tmpdir(), "integration-test-"));
|
|
42
|
-
plugin = new TracePlugin(tempDir, tempDir);
|
|
74
|
+
plugin = new TracePlugin({ globalDir: tempDir, localDir: tempDir });
|
|
43
75
|
});
|
|
44
76
|
afterEach(() => {
|
|
45
77
|
plugin.uninstallInterceptor();
|
|
@@ -49,22 +81,24 @@ describe("Integration: TracePlugin full flow", () => {
|
|
|
49
81
|
const originalFetch = globalThis.fetch;
|
|
50
82
|
globalThis.fetch = async (input) => {
|
|
51
83
|
const req = new Request(input);
|
|
52
|
-
await new Promise(resolve => setTimeout(resolve, 50));
|
|
84
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
53
85
|
return new Response(JSON.stringify({ url: req.url }), { status: 200 });
|
|
54
86
|
};
|
|
55
87
|
plugin.installInterceptor();
|
|
56
88
|
await plugin.initStateManager();
|
|
57
89
|
const sessionId = "concurrent-test";
|
|
58
|
-
plugin
|
|
90
|
+
plugin.getStateManager().startSession(sessionId);
|
|
59
91
|
const requests = Array.from({ length: 5 }, (_, i) => plugin.tracedFetch(`https://example.com/${i}`, {
|
|
60
92
|
method: "GET",
|
|
61
|
-
headers: { "x-opencode-session": sessionId }
|
|
93
|
+
headers: { "x-opencode-session": sessionId },
|
|
62
94
|
}));
|
|
63
95
|
const responses = await Promise.all(requests);
|
|
64
|
-
expect(responses.every(r => r.status === 200)).toBe(true);
|
|
96
|
+
expect(responses.every((r) => r.status === 200)).toBe(true);
|
|
97
|
+
await plugin.flush();
|
|
65
98
|
const sessionDir = join(tempDir, sessionId);
|
|
66
|
-
|
|
67
|
-
|
|
99
|
+
const files = readdirSync(sessionDir)
|
|
100
|
+
.filter((f) => /^\d+\.json$/.test(f))
|
|
101
|
+
.sort();
|
|
68
102
|
expect(files.length).toBe(5);
|
|
69
103
|
for (let i = 0; i < 5; i++) {
|
|
70
104
|
const content = JSON.parse(readFileSync(join(sessionDir, files[i]), "utf-8"));
|
|
@@ -73,4 +107,467 @@ describe("Integration: TracePlugin full flow", () => {
|
|
|
73
107
|
globalThis.fetch = originalFetch;
|
|
74
108
|
});
|
|
75
109
|
});
|
|
110
|
+
// =============================================================================
|
|
111
|
+
// ST1: Real plugin SDK hooks lifecycle via entrypoint(input)
|
|
112
|
+
// =============================================================================
|
|
113
|
+
// Constructs the plugin through the real SDK entrypoint with a mocked
|
|
114
|
+
// PluginInput, then exercises the actually-wired hooks (`event`,
|
|
115
|
+
// `tool.execute.after`, `config`, `tool.trace_on/trace_off/trace_status`).
|
|
116
|
+
// Verifies real side effects on disk: session dir, metadata.json, config.json,
|
|
117
|
+
// subSessions array, and effective enabled state.
|
|
118
|
+
//
|
|
119
|
+
// The plugin DOES wire `chat.message`, `chat.params`, and `tool.execute.before`
|
|
120
|
+
// (they just `logger.info` and return — they do not change the existing flow).
|
|
121
|
+
// =============================================================================
|
|
122
|
+
describe("ST1: real plugin SDK hooks lifecycle (entrypoint + PluginInput)", () => {
|
|
123
|
+
let tempDir;
|
|
124
|
+
beforeEach(() => {
|
|
125
|
+
tempDir = mkdtempSync(join(tmpdir(), "integration-st1-"));
|
|
126
|
+
process.env._INTEGRATION_TEST_DIR_ = tempDir;
|
|
127
|
+
_resetForTesting();
|
|
128
|
+
});
|
|
129
|
+
afterEach(() => {
|
|
130
|
+
_resetForTesting();
|
|
131
|
+
delete process.env._INTEGRATION_TEST_DIR_;
|
|
132
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
133
|
+
});
|
|
134
|
+
test("entrypoint.server returns wired hooks, and the wired hooks have real side effects", async () => {
|
|
135
|
+
const hooks = await entrypoint.server({
|
|
136
|
+
client: {},
|
|
137
|
+
project: {},
|
|
138
|
+
directory: tempDir,
|
|
139
|
+
worktree: tempDir,
|
|
140
|
+
experimental_workspace: { register: vi.fn() },
|
|
141
|
+
serverUrl: new URL("http://localhost"),
|
|
142
|
+
$: {},
|
|
143
|
+
});
|
|
144
|
+
// Wired hooks per trace.ts
|
|
145
|
+
expect(hooks.event).toBeDefined();
|
|
146
|
+
expect(hooks["tool.execute.after"]).toBeDefined();
|
|
147
|
+
expect(hooks.config).toBeDefined();
|
|
148
|
+
expect(hooks["command.execute.before"]).toBeDefined();
|
|
149
|
+
expect(hooks.tool).toBeDefined();
|
|
150
|
+
expect(hooks.tool.trace_on).toBeDefined();
|
|
151
|
+
expect(hooks.tool.trace_off).toBeDefined();
|
|
152
|
+
expect(hooks.tool.trace_status).toBeDefined();
|
|
153
|
+
// Wired: chat.message / chat.params / tool.execute.before (logger.info only,
|
|
154
|
+
// no state change). Assert they exist and are functions.
|
|
155
|
+
expect(typeof hooks["chat.message"]).toBe("function");
|
|
156
|
+
expect(typeof hooks["chat.params"]).toBe("function");
|
|
157
|
+
expect(typeof hooks["tool.execute.before"]).toBe("function");
|
|
158
|
+
// Step 1: `event` hook with session.created creates the session dir and metadata.
|
|
159
|
+
const parentId = "st1-parent-session";
|
|
160
|
+
await hooks.event({
|
|
161
|
+
event: {
|
|
162
|
+
type: "session.created",
|
|
163
|
+
properties: {
|
|
164
|
+
info: {
|
|
165
|
+
id: parentId,
|
|
166
|
+
projectID: "p",
|
|
167
|
+
directory: tempDir,
|
|
168
|
+
title: "ST1 Parent",
|
|
169
|
+
version: "1.0",
|
|
170
|
+
time: { created: Date.now(), updated: Date.now() },
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
});
|
|
175
|
+
const globalTraceDir = join(tempDir, ".opencode-trace");
|
|
176
|
+
const parentSessionDir = join(globalTraceDir, parentId);
|
|
177
|
+
expect(existsSync(parentSessionDir)).toBe(true);
|
|
178
|
+
const parentMetaPath = join(parentSessionDir, "metadata.json");
|
|
179
|
+
expect(existsSync(parentMetaPath)).toBe(true);
|
|
180
|
+
const parentMeta = JSON.parse(readFileSync(parentMetaPath, "utf-8"));
|
|
181
|
+
expect(parentMeta.title).toBe("ST1 Parent");
|
|
182
|
+
expect(parentMeta.folderPath).toBe(tempDir);
|
|
183
|
+
// global config.json is initialized by initStateManager()
|
|
184
|
+
expect(existsSync(join(globalTraceDir, "config.json"))).toBe(true);
|
|
185
|
+
// Step 2: `config` hook registers the /trace command
|
|
186
|
+
const cfgIn = {};
|
|
187
|
+
await hooks.config(cfgIn);
|
|
188
|
+
expect(cfgIn.command?.trace?.description).toMatch(/Control trace recording/);
|
|
189
|
+
// Step 3: tool.trace_on enables session
|
|
190
|
+
const onResult = await hooks.tool.trace_on.execute({}, { sessionID: parentId });
|
|
191
|
+
expect(String(onResult)).toContain("Trace enabled for session");
|
|
192
|
+
// Step 4: tool.trace_status reflects new effective state for session
|
|
193
|
+
const statusResult = await hooks.tool.trace_status.execute({}, { sessionID: parentId });
|
|
194
|
+
expect(String(statusResult)).toContain("Trace Status");
|
|
195
|
+
expect(String(statusResult)).toContain("Session : ON");
|
|
196
|
+
expect(String(statusResult)).toMatch(/Effective: (RECORDING|PAUSED)/);
|
|
197
|
+
// Step 5: tool.trace_off disables the session again
|
|
198
|
+
const offResult = await hooks.tool.trace_off.execute({}, { sessionID: parentId });
|
|
199
|
+
expect(String(offResult)).toContain("Trace disabled for session");
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
// =============================================================================
|
|
203
|
+
// ST2: SSE (text/event-stream) roundtrip
|
|
204
|
+
// =============================================================================
|
|
205
|
+
// Mocks fetch to return a `ReadableStream` of SSE chunks, calls tracedFetch
|
|
206
|
+
// with `stream: true` body, and verifies:
|
|
207
|
+
// - Response stream is still drainable by the caller and yields the same chunks
|
|
208
|
+
// - __latencyMeta is attached to the wrapped Response
|
|
209
|
+
// - firstTokenAt/lastTokenAt become populated as chunks flow through
|
|
210
|
+
// - Persisted {seq}.json record carries those latency fields
|
|
211
|
+
//
|
|
212
|
+
// NOTE: The plugin does NOT currently write a raw `1.sse` file even though the
|
|
213
|
+
// README documents one — only `{seq}.json` and `{seq}.parsed` are emitted.
|
|
214
|
+
// =============================================================================
|
|
215
|
+
describe("ST2: SSE stream roundtrip", () => {
|
|
216
|
+
let tempDir;
|
|
217
|
+
let plugin;
|
|
218
|
+
let originalFetch;
|
|
219
|
+
beforeEach(async () => {
|
|
220
|
+
tempDir = mkdtempSync(join(tmpdir(), "integration-st2-"));
|
|
221
|
+
plugin = new TracePlugin({ globalDir: tempDir, localDir: tempDir });
|
|
222
|
+
await plugin.initStateManager();
|
|
223
|
+
originalFetch = globalThis.fetch;
|
|
224
|
+
});
|
|
225
|
+
afterEach(() => {
|
|
226
|
+
plugin.uninstallInterceptor();
|
|
227
|
+
globalThis.fetch = originalFetch;
|
|
228
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
229
|
+
});
|
|
230
|
+
test("stream body is drained by caller and latency fields land in {seq}.json", async () => {
|
|
231
|
+
const encoder = new TextEncoder();
|
|
232
|
+
const sseChunks = [
|
|
233
|
+
'data: {"delta":"Hello"}\n\n',
|
|
234
|
+
'data: {"delta":" world"}\n\n',
|
|
235
|
+
"data: [DONE]\n\n",
|
|
236
|
+
];
|
|
237
|
+
const mockFetch = vi.fn(async () => {
|
|
238
|
+
const stream = new ReadableStream({
|
|
239
|
+
start(controller) {
|
|
240
|
+
for (const c of sseChunks)
|
|
241
|
+
controller.enqueue(encoder.encode(c));
|
|
242
|
+
controller.close();
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
return new Response(stream, {
|
|
246
|
+
status: 200,
|
|
247
|
+
headers: { "content-type": "text/event-stream" },
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
globalThis.fetch = mockFetch;
|
|
251
|
+
plugin.installInterceptor();
|
|
252
|
+
const sessionId = "st2-sse";
|
|
253
|
+
plugin.getStateManager().startSession(sessionId);
|
|
254
|
+
const res = await plugin.tracedFetch("https://api.example.com/v1/messages", {
|
|
255
|
+
method: "POST",
|
|
256
|
+
headers: {
|
|
257
|
+
"content-type": "application/json",
|
|
258
|
+
"x-opencode-session": sessionId,
|
|
259
|
+
},
|
|
260
|
+
body: JSON.stringify({
|
|
261
|
+
stream: true,
|
|
262
|
+
messages: [{ role: "user", content: "hi" }],
|
|
263
|
+
}),
|
|
264
|
+
});
|
|
265
|
+
expect(res.status).toBe(200);
|
|
266
|
+
expect(res.headers.get("content-type")).toBe("text/event-stream");
|
|
267
|
+
// __latencyMeta should be present BEFORE consumption
|
|
268
|
+
const latencyBefore = res.__latencyMeta;
|
|
269
|
+
expect(latencyBefore).toBeDefined();
|
|
270
|
+
expect(typeof latencyBefore.requestSentAt).toBe("number");
|
|
271
|
+
expect(latencyBefore.firstTokenAt).toBeNull();
|
|
272
|
+
expect(latencyBefore.lastTokenAt).toBeNull();
|
|
273
|
+
// Drain the body as a downstream caller would
|
|
274
|
+
const reader = res.body.getReader();
|
|
275
|
+
const received = [];
|
|
276
|
+
while (true) {
|
|
277
|
+
const { done, value } = await reader.read();
|
|
278
|
+
if (done)
|
|
279
|
+
break;
|
|
280
|
+
received.push(value);
|
|
281
|
+
}
|
|
282
|
+
// Caller received the same chunks the mock emitted
|
|
283
|
+
expect(received.length).toBe(sseChunks.length);
|
|
284
|
+
const decoder = new TextDecoder();
|
|
285
|
+
const reassembled = received.map((c) => decoder.decode(c)).join("");
|
|
286
|
+
expect(reassembled).toBe(sseChunks.join(""));
|
|
287
|
+
// After draining, latency fields should be populated
|
|
288
|
+
const latencyAfter = res.__latencyMeta;
|
|
289
|
+
expect(latencyAfter.firstTokenAt).not.toBeNull();
|
|
290
|
+
expect(latencyAfter.lastTokenAt).not.toBeNull();
|
|
291
|
+
expect(latencyAfter.lastTokenAt).toBeGreaterThanOrEqual(latencyAfter.firstTokenAt);
|
|
292
|
+
await plugin.flush();
|
|
293
|
+
const sessionDir = join(tempDir, sessionId);
|
|
294
|
+
await waitForFiles(sessionDir, 1);
|
|
295
|
+
const recordPath = join(sessionDir, "1.json");
|
|
296
|
+
const record = JSON.parse(readFileSync(recordPath, "utf-8"));
|
|
297
|
+
expect(record.id).toBe(1);
|
|
298
|
+
expect(record.requestSentAt).toBeDefined();
|
|
299
|
+
expect(typeof record.firstTokenAt).toBe("number");
|
|
300
|
+
expect(typeof record.lastTokenAt).toBe("number");
|
|
301
|
+
expect(record.lastTokenAt).toBeGreaterThanOrEqual(record.firstTokenAt);
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
// =============================================================================
|
|
305
|
+
// ST3: parentID / subSessions chain from tool.execute.after
|
|
306
|
+
// =============================================================================
|
|
307
|
+
// Verifies what the `tool.execute.after` hook actually does for the "task" tool:
|
|
308
|
+
// it appends the child session id to the PARENT's metadata.json `subSessions`
|
|
309
|
+
// array, AND eagerly writes the child's metadata.json with `parentID` set so
|
|
310
|
+
// the child is linked immediately, regardless of whether `session.created`
|
|
311
|
+
// arrives for it later. We assert both behaviors so the contract is locked in.
|
|
312
|
+
// =============================================================================
|
|
313
|
+
describe("ST3: subSessions chain from tool.execute.after", () => {
|
|
314
|
+
let tempDir;
|
|
315
|
+
beforeEach(() => {
|
|
316
|
+
tempDir = mkdtempSync(join(tmpdir(), "integration-st3-"));
|
|
317
|
+
process.env._INTEGRATION_TEST_DIR_ = tempDir;
|
|
318
|
+
_resetForTesting();
|
|
319
|
+
});
|
|
320
|
+
afterEach(() => {
|
|
321
|
+
_resetForTesting();
|
|
322
|
+
delete process.env._INTEGRATION_TEST_DIR_;
|
|
323
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
324
|
+
});
|
|
325
|
+
test("tool.execute.after task appends to parent.subSessions AND eagerly sets child.parentID", async () => {
|
|
326
|
+
const hooks = await entrypoint.server({
|
|
327
|
+
client: {},
|
|
328
|
+
project: {},
|
|
329
|
+
directory: tempDir,
|
|
330
|
+
worktree: tempDir,
|
|
331
|
+
experimental_workspace: { register: vi.fn() },
|
|
332
|
+
serverUrl: new URL("http://localhost"),
|
|
333
|
+
$: {},
|
|
334
|
+
});
|
|
335
|
+
const parentId = "st3-parent";
|
|
336
|
+
const childId = "st3-child";
|
|
337
|
+
// Create the parent session via the event hook
|
|
338
|
+
await hooks.event({
|
|
339
|
+
event: {
|
|
340
|
+
type: "session.created",
|
|
341
|
+
properties: {
|
|
342
|
+
info: {
|
|
343
|
+
id: parentId,
|
|
344
|
+
projectID: "p",
|
|
345
|
+
directory: tempDir,
|
|
346
|
+
title: "Parent",
|
|
347
|
+
version: "1.0",
|
|
348
|
+
time: { created: Date.now(), updated: Date.now() },
|
|
349
|
+
},
|
|
350
|
+
},
|
|
351
|
+
},
|
|
352
|
+
});
|
|
353
|
+
// Simulate a Task tool returning a child sessionID in its metadata
|
|
354
|
+
await hooks["tool.execute.after"]({
|
|
355
|
+
tool: "task",
|
|
356
|
+
sessionID: parentId,
|
|
357
|
+
callID: "call-1",
|
|
358
|
+
args: { description: "spawn child", prompt: "go" },
|
|
359
|
+
}, {
|
|
360
|
+
title: "Task done",
|
|
361
|
+
output: "ok",
|
|
362
|
+
metadata: { session_id: childId },
|
|
363
|
+
});
|
|
364
|
+
const globalTraceDir = join(tempDir, ".opencode-trace");
|
|
365
|
+
const parentMetaPath = join(globalTraceDir, parentId, "metadata.json");
|
|
366
|
+
await waitForFile(parentMetaPath);
|
|
367
|
+
const parentMeta = JSON.parse(readFileSync(parentMetaPath, "utf-8"));
|
|
368
|
+
expect(Array.isArray(parentMeta.subSessions)).toBe(true);
|
|
369
|
+
expect(parentMeta.subSessions).toContain(childId);
|
|
370
|
+
// The child's metadata.json IS eagerly created by tool.execute.after with
|
|
371
|
+
// parentID set, so the link is race-free and survives missing session.created.
|
|
372
|
+
const childMetaPath = join(globalTraceDir, childId, "metadata.json");
|
|
373
|
+
expect(existsSync(childMetaPath)).toBe(true);
|
|
374
|
+
const eagerChildMeta = JSON.parse(readFileSync(childMetaPath, "utf-8"));
|
|
375
|
+
expect(eagerChildMeta.parentID).toBe(parentId);
|
|
376
|
+
// Now simulate the child's own session.created event carrying parentID.
|
|
377
|
+
// This is idempotent: parentID is already correct, and addSubSession
|
|
378
|
+
// dedupes so the parent's subSessions array still has the child exactly once.
|
|
379
|
+
const childEvent = {
|
|
380
|
+
type: "session.created",
|
|
381
|
+
properties: {
|
|
382
|
+
info: {
|
|
383
|
+
id: childId,
|
|
384
|
+
projectID: "p",
|
|
385
|
+
directory: tempDir,
|
|
386
|
+
title: "Child",
|
|
387
|
+
parentID: parentId,
|
|
388
|
+
version: "1.0",
|
|
389
|
+
time: { created: Date.now(), updated: Date.now() },
|
|
390
|
+
},
|
|
391
|
+
},
|
|
392
|
+
};
|
|
393
|
+
await hooks.event({ event: childEvent });
|
|
394
|
+
const childMeta = JSON.parse(readFileSync(childMetaPath, "utf-8"));
|
|
395
|
+
expect(childMeta.parentID).toBe(parentId);
|
|
396
|
+
expect(childMeta.title).toBe("Child");
|
|
397
|
+
// The parent still has the child listed exactly once (idempotent).
|
|
398
|
+
const parentMeta2 = JSON.parse(readFileSync(parentMetaPath, "utf-8"));
|
|
399
|
+
expect(parentMeta2.subSessions.filter((s) => s === childId).length).toBe(1);
|
|
400
|
+
// Sanity: non-"task" tool with metadata.session_id does NOTHING.
|
|
401
|
+
const noopChildId = "st3-noop-child";
|
|
402
|
+
await hooks["tool.execute.after"]({
|
|
403
|
+
tool: "bash",
|
|
404
|
+
sessionID: parentId,
|
|
405
|
+
callID: "call-2",
|
|
406
|
+
args: { command: "ls" },
|
|
407
|
+
}, {
|
|
408
|
+
title: "Ran bash",
|
|
409
|
+
output: "",
|
|
410
|
+
metadata: { session_id: noopChildId },
|
|
411
|
+
});
|
|
412
|
+
const parentMeta3 = JSON.parse(readFileSync(parentMetaPath, "utf-8"));
|
|
413
|
+
expect(parentMeta3.subSessions).not.toContain(noopChildId);
|
|
414
|
+
const noopChildPath = join(globalTraceDir, noopChildId, "metadata.json");
|
|
415
|
+
expect(existsSync(noopChildPath)).toBe(false);
|
|
416
|
+
});
|
|
417
|
+
});
|
|
418
|
+
// =============================================================================
|
|
419
|
+
// ST4: corrupted {seq}.json record on disk does not crash later requests
|
|
420
|
+
// =============================================================================
|
|
421
|
+
// The plugin keeps `seq` in memory (this.ids Map), not on disk, so a corrupted
|
|
422
|
+
// file should not affect new writes. We do one successful request (seq=1),
|
|
423
|
+
// corrupt 1.json in-place, then trigger another request and verify seq=2 is
|
|
424
|
+
// written cleanly and the plugin process survives.
|
|
425
|
+
// =============================================================================
|
|
426
|
+
describe("ST4: corrupted record recovery", () => {
|
|
427
|
+
let tempDir;
|
|
428
|
+
let plugin;
|
|
429
|
+
let originalFetch;
|
|
430
|
+
beforeEach(async () => {
|
|
431
|
+
tempDir = mkdtempSync(join(tmpdir(), "integration-st4-"));
|
|
432
|
+
plugin = new TracePlugin({ globalDir: tempDir, localDir: tempDir });
|
|
433
|
+
await plugin.initStateManager();
|
|
434
|
+
originalFetch = globalThis.fetch;
|
|
435
|
+
});
|
|
436
|
+
afterEach(() => {
|
|
437
|
+
plugin.uninstallInterceptor();
|
|
438
|
+
globalThis.fetch = originalFetch;
|
|
439
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
440
|
+
});
|
|
441
|
+
test("a corrupted prior record does not break subsequent writes", async () => {
|
|
442
|
+
let callCount = 0;
|
|
443
|
+
globalThis.fetch = (async () => {
|
|
444
|
+
callCount++;
|
|
445
|
+
return new Response(JSON.stringify({ ok: true, call: callCount }), {
|
|
446
|
+
status: 200,
|
|
447
|
+
headers: { "content-type": "application/json" },
|
|
448
|
+
});
|
|
449
|
+
});
|
|
450
|
+
plugin.installInterceptor();
|
|
451
|
+
const sessionId = "st4-corrupt";
|
|
452
|
+
plugin.getStateManager().startSession(sessionId);
|
|
453
|
+
// First request — should land as 1.json with valid JSON
|
|
454
|
+
const r1 = await plugin.tracedFetch("https://example.com/a", {
|
|
455
|
+
method: "GET",
|
|
456
|
+
headers: { "x-opencode-session": sessionId },
|
|
457
|
+
});
|
|
458
|
+
expect(r1.status).toBe(200);
|
|
459
|
+
await plugin.flush();
|
|
460
|
+
const sessionDir = join(tempDir, sessionId);
|
|
461
|
+
await waitForFiles(sessionDir, 1);
|
|
462
|
+
const file1 = join(sessionDir, "1.json");
|
|
463
|
+
expect(existsSync(file1)).toBe(true);
|
|
464
|
+
// Corrupt the existing 1.json
|
|
465
|
+
writeFileSync(file1, "not valid json {{{ definitely broken", "utf-8");
|
|
466
|
+
expect(() => JSON.parse(readFileSync(file1, "utf-8"))).toThrow();
|
|
467
|
+
// Second request should produce 2.json cleanly without throwing
|
|
468
|
+
const r2 = await plugin.tracedFetch("https://example.com/b", {
|
|
469
|
+
method: "GET",
|
|
470
|
+
headers: { "x-opencode-session": sessionId },
|
|
471
|
+
});
|
|
472
|
+
expect(r2.status).toBe(200);
|
|
473
|
+
await plugin.flush();
|
|
474
|
+
// Don't use waitForFiles here: 1.json is now corrupted, so the
|
|
475
|
+
// "all files valid" precondition would never hold. Wait specifically
|
|
476
|
+
// for 2.json instead.
|
|
477
|
+
const file2 = join(sessionDir, "2.json");
|
|
478
|
+
await waitForFile(file2);
|
|
479
|
+
expect(existsSync(file2)).toBe(true);
|
|
480
|
+
const record2 = JSON.parse(readFileSync(file2, "utf-8"));
|
|
481
|
+
expect(record2.id).toBe(2);
|
|
482
|
+
expect(record2.response.status).toBe(200);
|
|
483
|
+
expect(record2.request.url).toBe("https://example.com/b");
|
|
484
|
+
// The corrupted 1.json is left untouched — plugin never re-reads it
|
|
485
|
+
const stillCorrupt = readFileSync(file1, "utf-8");
|
|
486
|
+
expect(stillCorrupt).toBe("not valid json {{{ definitely broken");
|
|
487
|
+
// No fallback dir created because no rename actually failed
|
|
488
|
+
expect(existsSync(join(tempDir, "fallback"))).toBe(false);
|
|
489
|
+
});
|
|
490
|
+
});
|
|
491
|
+
// =============================================================================
|
|
492
|
+
// ST5: Windows-style transient rename failure is retried by safeRename
|
|
493
|
+
// =============================================================================
|
|
494
|
+
// Spies on fs.promises.rename and throws an EPERM-like error on the first call,
|
|
495
|
+
// then lets the real rename through on subsequent calls. Verifies:
|
|
496
|
+
// - The .tmp file ends up renamed to the final {seq}.json
|
|
497
|
+
// - No .tmp leftover
|
|
498
|
+
// - No fallback file (because retry succeeded)
|
|
499
|
+
//
|
|
500
|
+
// NOTE: safeRename currently retries SILENTLY — it does not call logger.warn
|
|
501
|
+
// on each retry. The task description anticipates a warn log; we assert the
|
|
502
|
+
// observed behavior and surface this gap in the report.
|
|
503
|
+
// =============================================================================
|
|
504
|
+
describe("ST5: Windows rename retry", () => {
|
|
505
|
+
let tempDir;
|
|
506
|
+
let plugin;
|
|
507
|
+
let originalFetch;
|
|
508
|
+
let renameSpy = null;
|
|
509
|
+
beforeEach(async () => {
|
|
510
|
+
tempDir = mkdtempSync(join(tmpdir(), "integration-st5-"));
|
|
511
|
+
plugin = new TracePlugin({ globalDir: tempDir, localDir: tempDir });
|
|
512
|
+
await plugin.initStateManager();
|
|
513
|
+
originalFetch = globalThis.fetch;
|
|
514
|
+
});
|
|
515
|
+
afterEach(() => {
|
|
516
|
+
plugin.uninstallInterceptor();
|
|
517
|
+
globalThis.fetch = originalFetch;
|
|
518
|
+
if (renameSpy) {
|
|
519
|
+
renameSpy.mockRestore();
|
|
520
|
+
renameSpy = null;
|
|
521
|
+
}
|
|
522
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
523
|
+
});
|
|
524
|
+
test("fs.rename throwing EPERM once is recovered transparently by safeRename", async () => {
|
|
525
|
+
globalThis.fetch = (async () => new Response(JSON.stringify({ ok: true }), {
|
|
526
|
+
status: 200,
|
|
527
|
+
headers: { "content-type": "application/json" },
|
|
528
|
+
}));
|
|
529
|
+
// Spy on the real fs.promises.rename. Throw EPERM the first time it is
|
|
530
|
+
// called for OUR session dir, then call through on every subsequent
|
|
531
|
+
// invocation. Tests for OTHER sessions in parallel files share the same
|
|
532
|
+
// singleton — so we scope by destination path.
|
|
533
|
+
const realRename = fs.rename.bind(fs);
|
|
534
|
+
const sessionId = "st5-rename-retry";
|
|
535
|
+
const sessionDir = join(tempDir, sessionId);
|
|
536
|
+
let throwsRemaining = 1;
|
|
537
|
+
renameSpy = vi
|
|
538
|
+
.spyOn(fs, "rename")
|
|
539
|
+
.mockImplementation(async (src, dest) => {
|
|
540
|
+
const destStr = String(dest);
|
|
541
|
+
if (throwsRemaining > 0 && destStr.startsWith(sessionDir)) {
|
|
542
|
+
throwsRemaining--;
|
|
543
|
+
const err = new Error("EPERM: simulated transient lock");
|
|
544
|
+
err.code = "EPERM";
|
|
545
|
+
throw err;
|
|
546
|
+
}
|
|
547
|
+
return realRename(src, dest);
|
|
548
|
+
});
|
|
549
|
+
plugin.installInterceptor();
|
|
550
|
+
plugin.getStateManager().startSession(sessionId);
|
|
551
|
+
const res = await plugin.tracedFetch("https://example.com/x", {
|
|
552
|
+
method: "GET",
|
|
553
|
+
headers: { "x-opencode-session": sessionId },
|
|
554
|
+
});
|
|
555
|
+
expect(res.status).toBe(200);
|
|
556
|
+
await plugin.flush();
|
|
557
|
+
// Give safeRename's 50ms backoff a window plus a bit
|
|
558
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
559
|
+
await waitForFiles(sessionDir, 1);
|
|
560
|
+
// The first rename for our session was thrown
|
|
561
|
+
const renameCalls = renameSpy.mock.calls.filter((c) => String(c[1]).startsWith(sessionDir));
|
|
562
|
+
expect(renameCalls.length).toBeGreaterThanOrEqual(2);
|
|
563
|
+
// Final {seq}.json exists and parses; no .tmp leftover
|
|
564
|
+
const finalPath = join(sessionDir, "1.json");
|
|
565
|
+
expect(existsSync(finalPath)).toBe(true);
|
|
566
|
+
const rec = JSON.parse(readFileSync(finalPath, "utf-8"));
|
|
567
|
+
expect(rec.id).toBe(1);
|
|
568
|
+
expect(existsSync(join(sessionDir, "1.json.tmp"))).toBe(false);
|
|
569
|
+
// Retry succeeded → no fallback file should have been emitted
|
|
570
|
+
expect(existsSync(join(tempDir, "fallback"))).toBe(false);
|
|
571
|
+
});
|
|
572
|
+
});
|
|
76
573
|
//# sourceMappingURL=integration.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"integration.test.js","sourceRoot":"","sources":["../src/integration.test.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"integration.test.js","sourceRoot":"","sources":["../src/integration.test.ts"],"names":[],"mappings":"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"}
|