gsd-pi 2.81.0-dev.72a81bdf3 → 2.82.0-dev.725028083
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 +46 -28
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/browser-tools/tools/screenshot.js +1 -0
- package/dist/resources/extensions/browser-tools/tools/zoom.js +1 -0
- package/dist/resources/extensions/gsd/auto/phases.js +9 -0
- package/dist/resources/extensions/gsd/auto-prompts.js +11 -3
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +5 -0
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +55 -12
- package/dist/resources/extensions/gsd/commands/handlers/core.js +1 -1
- package/dist/resources/extensions/gsd/commands-handlers.js +15 -2
- package/dist/resources/extensions/gsd/context-store.js +112 -0
- package/dist/resources/extensions/gsd/db-writer.js +150 -84
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/dist/resources/extensions/gsd/doctor-git-checks.js +41 -6
- package/dist/resources/extensions/gsd/knowledge-backfill.js +144 -0
- package/dist/resources/extensions/gsd/knowledge-capture.js +136 -0
- package/dist/resources/extensions/gsd/knowledge-parser.js +154 -0
- package/dist/resources/extensions/gsd/knowledge-projection.js +210 -0
- package/dist/resources/extensions/gsd/markdown-renderer.js +6 -1
- package/dist/resources/extensions/gsd/memory-backfill.js +73 -17
- package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +222 -0
- package/dist/resources/extensions/gsd/prompts/system.md +2 -2
- package/dist/resources/extensions/gsd/provider-switch-observer.js +146 -0
- package/dist/resources/extensions/gsd/templates/knowledge.md +2 -2
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +3 -2
- package/packages/daemon/package.json +2 -2
- package/packages/mcp-server/README.md +2 -0
- package/packages/mcp-server/package.json +2 -2
- package/packages/mcp-server/src/workflow-tools-parity.test.ts +244 -0
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/index.d.ts +2 -2
- package/packages/pi-ai/dist/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/index.js +1 -1
- package/packages/pi-ai/dist/index.js.map +1 -1
- package/packages/pi-ai/dist/providers/transform-messages.d.ts +11 -0
- package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/transform-messages.js +20 -0
- package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-ai/src/index.ts +7 -2
- package/packages/pi-ai/src/providers/transform-messages.ts +24 -0
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +4 -4
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js +17 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js.map +1 -0
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/system-prompt.ts +4 -4
- package/packages/pi-coding-agent/src/tests/system-prompt-file-safety.test.ts +22 -0
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/package.json +1 -1
- package/packages/rpc-client/package.json +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/browser-tools/tools/screenshot.ts +1 -0
- package/src/resources/extensions/browser-tools/tools/zoom.ts +1 -0
- package/src/resources/extensions/gsd/auto/phases.ts +14 -0
- package/src/resources/extensions/gsd/auto-prompts.ts +11 -3
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +6 -0
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +58 -15
- package/src/resources/extensions/gsd/commands/handlers/core.ts +1 -1
- package/src/resources/extensions/gsd/commands-handlers.ts +19 -2
- package/src/resources/extensions/gsd/context-store.ts +120 -1
- package/src/resources/extensions/gsd/db-writer.ts +167 -84
- package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/src/resources/extensions/gsd/doctor-git-checks.ts +44 -6
- package/src/resources/extensions/gsd/doctor-types.ts +2 -0
- package/src/resources/extensions/gsd/knowledge-backfill.ts +164 -0
- package/src/resources/extensions/gsd/knowledge-capture.ts +160 -0
- package/src/resources/extensions/gsd/knowledge-parser.ts +174 -0
- package/src/resources/extensions/gsd/knowledge-projection.ts +241 -0
- package/src/resources/extensions/gsd/markdown-renderer.ts +6 -1
- package/src/resources/extensions/gsd/memory-backfill.ts +89 -17
- package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +277 -0
- package/src/resources/extensions/gsd/prompts/system.md +2 -2
- package/src/resources/extensions/gsd/provider-switch-observer.ts +185 -0
- package/src/resources/extensions/gsd/templates/knowledge.md +2 -2
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/browser-tools-compatibility-declarations.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/context-store-decisions-from-memories.test.ts +312 -0
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +13 -8
- package/src/resources/extensions/gsd/tests/decisions-projection-from-memories.test.ts +453 -0
- package/src/resources/extensions/gsd/tests/decisions-stop-table-writes.test.ts +348 -0
- package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +8 -4
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +11 -7
- package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/integration/integration-lifecycle.test.ts +13 -5
- package/src/resources/extensions/gsd/tests/knowledge-backfill-projection.test.ts +323 -0
- package/src/resources/extensions/gsd/tests/knowledge-capture.test.ts +242 -0
- package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -2
- package/src/resources/extensions/gsd/tests/load-knowledge-block-rules-only.test.ts +209 -0
- package/src/resources/extensions/gsd/tests/memory-consolidation-scanner.test.ts +316 -0
- package/src/resources/extensions/gsd/tests/plan-milestone-sketch-render.test.ts +157 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/provider-switch-observer.test.ts +252 -0
- package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +16 -4
- package/src/resources/extensions/gsd/workflow-logger.ts +4 -0
- /package/dist/web/standalone/.next/static/{rIkMv4YSNlfSeqmGqWVns → KDRTXR-22LPCsa80X9dey}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{rIkMv4YSNlfSeqmGqWVns → KDRTXR-22LPCsa80X9dey}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
// ADR-008 validation criterion #3 — behavior-parity lock-in for gsd_task_complete.
|
|
2
|
+
//
|
|
3
|
+
// ADR-008 §1 ("One handler layer, multiple transports") is shipped: both
|
|
4
|
+
// native (`db-tools.ts`) and MCP (`workflow-tools.ts`) registrations wrap the
|
|
5
|
+
// same `executeTaskComplete` from `workflow-tool-executors.ts`. This test
|
|
6
|
+
// guards the equivalence so a future executor refactor cannot silently drift
|
|
7
|
+
// the two transports apart.
|
|
8
|
+
//
|
|
9
|
+
// Strategy: run the same completion against two equivalent fresh basePaths,
|
|
10
|
+
// one via the native path (direct call to the shared executor — which is
|
|
11
|
+
// faithfully what `db-tools.ts:670-674` does after `resolveCtxCwd`) and one
|
|
12
|
+
// via the MCP path (`registerWorkflowTools` + tool.handler). Snapshot DB row,
|
|
13
|
+
// summary file content, and journal events for each. Assert equivalence
|
|
14
|
+
// modulo expected diffs (timestamps).
|
|
15
|
+
|
|
16
|
+
import { describe, it } from "node:test";
|
|
17
|
+
import assert from "node:assert/strict";
|
|
18
|
+
import { mkdirSync, rmSync, writeFileSync, readFileSync, existsSync } from "node:fs";
|
|
19
|
+
import { join } from "node:path";
|
|
20
|
+
import { tmpdir } from "node:os";
|
|
21
|
+
import { randomUUID } from "node:crypto";
|
|
22
|
+
|
|
23
|
+
import {
|
|
24
|
+
closeDatabase,
|
|
25
|
+
getTask,
|
|
26
|
+
} from "../../../src/resources/extensions/gsd/gsd-db.ts";
|
|
27
|
+
import { executeTaskComplete } from "../../../src/resources/extensions/gsd/tools/workflow-tool-executors.ts";
|
|
28
|
+
import { registerWorkflowTools } from "./workflow-tools.ts";
|
|
29
|
+
|
|
30
|
+
function makeTmpBase(): string {
|
|
31
|
+
const base = join(tmpdir(), `gsd-mcp-parity-${randomUUID()}`);
|
|
32
|
+
mkdirSync(join(base, ".gsd"), { recursive: true });
|
|
33
|
+
return base;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function seedMilestoneAndSlice(base: string): void {
|
|
37
|
+
mkdirSync(join(base, ".gsd", "milestones", "M001", "slices", "S01"), { recursive: true });
|
|
38
|
+
writeFileSync(
|
|
39
|
+
join(base, ".gsd", "milestones", "M001", "slices", "S01", "S01-PLAN.md"),
|
|
40
|
+
"# S01\n\n- [ ] **T01: Demo** `est:5m`\n",
|
|
41
|
+
"utf-8",
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function cleanup(base: string): void {
|
|
46
|
+
try {
|
|
47
|
+
closeDatabase();
|
|
48
|
+
} catch {
|
|
49
|
+
// swallow
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
rmSync(base, { recursive: true, force: true });
|
|
53
|
+
} catch {
|
|
54
|
+
// swallow
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function makeMockServer() {
|
|
59
|
+
const tools: Array<{
|
|
60
|
+
name: string;
|
|
61
|
+
handler: (args: Record<string, unknown>) => Promise<unknown>;
|
|
62
|
+
}> = [];
|
|
63
|
+
return {
|
|
64
|
+
tools,
|
|
65
|
+
tool(
|
|
66
|
+
name: string,
|
|
67
|
+
_description: string,
|
|
68
|
+
_params: Record<string, unknown>,
|
|
69
|
+
handler: (args: Record<string, unknown>) => Promise<unknown>,
|
|
70
|
+
) {
|
|
71
|
+
tools.push({ name, handler });
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
interface SnapshotShape {
|
|
77
|
+
/** SUMMARY.md content, trimmed, with ISO timestamps replaced by a sentinel. */
|
|
78
|
+
summary: string;
|
|
79
|
+
/** Task row, with volatile fields (timestamps, derived ids) elided. */
|
|
80
|
+
taskRow: Record<string, unknown>;
|
|
81
|
+
/** Journal events for this completion, with timestamps and ids normalized. */
|
|
82
|
+
journalEvents: Array<{ cmd: string; params: Record<string, unknown>; actor: string }>;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const ISO_TIMESTAMP_RE = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z/g;
|
|
86
|
+
|
|
87
|
+
function normalizeTimestamps(text: string): string {
|
|
88
|
+
return text.replace(ISO_TIMESTAMP_RE, "<NORMALIZED-TS>");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function normalizeParams(params: Record<string, unknown>): Record<string, unknown> {
|
|
92
|
+
// Recursively replace ISO timestamps in any string value so the deep-equal
|
|
93
|
+
// doesn't fail on `ts`/`completed_at` style fields nested in the payload.
|
|
94
|
+
const out: Record<string, unknown> = {};
|
|
95
|
+
for (const [k, v] of Object.entries(params)) {
|
|
96
|
+
if (typeof v === "string") {
|
|
97
|
+
out[k] = normalizeTimestamps(v);
|
|
98
|
+
} else if (Array.isArray(v)) {
|
|
99
|
+
out[k] = v.map((item) =>
|
|
100
|
+
typeof item === "string"
|
|
101
|
+
? normalizeTimestamps(item)
|
|
102
|
+
: item && typeof item === "object"
|
|
103
|
+
? normalizeParams(item as Record<string, unknown>)
|
|
104
|
+
: item,
|
|
105
|
+
);
|
|
106
|
+
} else if (v !== null && typeof v === "object") {
|
|
107
|
+
out[k] = normalizeParams(v as Record<string, unknown>);
|
|
108
|
+
} else {
|
|
109
|
+
out[k] = v;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return out;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function snapshotState(base: string, milestoneId: string, sliceId: string, taskId: string): SnapshotShape {
|
|
116
|
+
const summaryPath = join(base, ".gsd", "milestones", milestoneId, "slices", sliceId, "tasks", `${taskId}-SUMMARY.md`);
|
|
117
|
+
assert.ok(existsSync(summaryPath), `summary file must exist at ${summaryPath}`);
|
|
118
|
+
const summary = normalizeTimestamps(readFileSync(summaryPath, "utf-8").trim());
|
|
119
|
+
|
|
120
|
+
const row = getTask(milestoneId, sliceId, taskId);
|
|
121
|
+
assert.ok(row, "task row must exist in DB after completion");
|
|
122
|
+
// Recursively normalize ISO timestamps in the row (the SQLite row uses
|
|
123
|
+
// snake_case `completed_at` and embeds another ISO timestamp inside the
|
|
124
|
+
// string field `full_summary_md`). Recursive normalization is simpler and
|
|
125
|
+
// more robust than maintaining an elision list.
|
|
126
|
+
const taskRow = normalizeParams(row as Record<string, unknown>);
|
|
127
|
+
assert.equal(taskRow.status, "complete", "task status must be 'complete' after completion");
|
|
128
|
+
|
|
129
|
+
const journalPath = join(base, ".gsd", "event-log.jsonl");
|
|
130
|
+
const journalEvents: SnapshotShape["journalEvents"] = [];
|
|
131
|
+
if (existsSync(journalPath)) {
|
|
132
|
+
const lines = readFileSync(journalPath, "utf-8")
|
|
133
|
+
.split("\n")
|
|
134
|
+
.filter((l) => l.length > 0);
|
|
135
|
+
for (const line of lines) {
|
|
136
|
+
try {
|
|
137
|
+
const evt = JSON.parse(line) as { cmd: string; params: Record<string, unknown>; actor: string };
|
|
138
|
+
if (evt.cmd === "complete-task" || evt.cmd === "complete_task") {
|
|
139
|
+
// Normalize cmd to canonical hyphen form, and elide ISO timestamps
|
|
140
|
+
// in the payload so the wall-clock skew between the two runs doesn't
|
|
141
|
+
// produce a spurious diff.
|
|
142
|
+
journalEvents.push({
|
|
143
|
+
cmd: "complete-task",
|
|
144
|
+
params: normalizeParams(evt.params),
|
|
145
|
+
actor: evt.actor,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
} catch {
|
|
149
|
+
// Skip corrupted lines — non-fatal for parity comparison.
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return { summary, taskRow, journalEvents };
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const COMPLETION_ARGS = {
|
|
158
|
+
taskId: "T01",
|
|
159
|
+
sliceId: "S01",
|
|
160
|
+
milestoneId: "M001",
|
|
161
|
+
oneLiner: "Completed the demo task",
|
|
162
|
+
narrative: "Did the work described in the plan. Verified by running the test suite.",
|
|
163
|
+
verification: "npm test — all passing",
|
|
164
|
+
deviations: "None.",
|
|
165
|
+
knownIssues: "None.",
|
|
166
|
+
keyFiles: ["src/demo.ts"],
|
|
167
|
+
keyDecisions: ["Used Option A from the plan."],
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
describe("ADR-008 parity: gsd_task_complete native vs MCP", () => {
|
|
171
|
+
it("native and MCP produce equivalent DB row, summary, and journal event", async () => {
|
|
172
|
+
let baseNative = "";
|
|
173
|
+
let baseMcp = "";
|
|
174
|
+
try {
|
|
175
|
+
// ─── Native path ─────────────────────────────────────────────────
|
|
176
|
+
// The native wrapper in db-tools.ts:670-674 is:
|
|
177
|
+
// const taskCompleteExecute = async (_tcid, params, ...) => {
|
|
178
|
+
// const { executeTaskComplete } = await loadWorkflowExecutors();
|
|
179
|
+
// return executeTaskComplete(params, resolveCtxCwd(_ctx));
|
|
180
|
+
// };
|
|
181
|
+
// Calling executeTaskComplete directly with a basePath is the same
|
|
182
|
+
// post-resolution call shape.
|
|
183
|
+
baseNative = makeTmpBase();
|
|
184
|
+
seedMilestoneAndSlice(baseNative);
|
|
185
|
+
const nativeResult = await executeTaskComplete(COMPLETION_ARGS, baseNative);
|
|
186
|
+
assert.ok(!nativeResult.isError, "native completion must succeed");
|
|
187
|
+
|
|
188
|
+
const snapshotNative = snapshotState(baseNative, "M001", "S01", "T01");
|
|
189
|
+
closeDatabase();
|
|
190
|
+
|
|
191
|
+
// ─── MCP path ────────────────────────────────────────────────────
|
|
192
|
+
baseMcp = makeTmpBase();
|
|
193
|
+
seedMilestoneAndSlice(baseMcp);
|
|
194
|
+
|
|
195
|
+
const server = makeMockServer();
|
|
196
|
+
registerWorkflowTools(server as Parameters<typeof registerWorkflowTools>[0]);
|
|
197
|
+
const taskTool = server.tools.find((t) => t.name === "gsd_task_complete");
|
|
198
|
+
assert.ok(taskTool, "gsd_task_complete must be registered on the MCP surface");
|
|
199
|
+
|
|
200
|
+
const mcpResult = await taskTool.handler({ projectDir: baseMcp, ...COMPLETION_ARGS });
|
|
201
|
+
assert.ok(!mcpResult.isError, "mcp completion must succeed");
|
|
202
|
+
|
|
203
|
+
const snapshotMcp = snapshotState(baseMcp, "M001", "S01", "T01");
|
|
204
|
+
|
|
205
|
+
// ─── Compare ─────────────────────────────────────────────────────
|
|
206
|
+
assert.equal(
|
|
207
|
+
snapshotNative.summary,
|
|
208
|
+
snapshotMcp.summary,
|
|
209
|
+
"SUMMARY.md content must be byte-equal between native and MCP completions",
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
assert.deepEqual(
|
|
213
|
+
snapshotNative.taskRow,
|
|
214
|
+
snapshotMcp.taskRow,
|
|
215
|
+
"tasks DB row (modulo volatile timestamps and ids) must be equal",
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
// Journal event count must match (1 complete-task event per completion).
|
|
219
|
+
assert.equal(
|
|
220
|
+
snapshotNative.journalEvents.length,
|
|
221
|
+
snapshotMcp.journalEvents.length,
|
|
222
|
+
"both transports must emit the same number of complete-task journal events",
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
// Each journal event's params must match (these encode the completion
|
|
226
|
+
// payload; cmd is normalized and actor must align).
|
|
227
|
+
for (let i = 0; i < snapshotNative.journalEvents.length; i++) {
|
|
228
|
+
assert.equal(
|
|
229
|
+
snapshotNative.journalEvents[i].actor,
|
|
230
|
+
snapshotMcp.journalEvents[i].actor,
|
|
231
|
+
`journal event #${i} actor must match between native and MCP`,
|
|
232
|
+
);
|
|
233
|
+
assert.deepEqual(
|
|
234
|
+
snapshotNative.journalEvents[i].params,
|
|
235
|
+
snapshotMcp.journalEvents[i].params,
|
|
236
|
+
`journal event #${i} params must match between native and MCP`,
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
} finally {
|
|
240
|
+
if (baseNative) cleanup(baseNative);
|
|
241
|
+
if (baseMcp) cleanup(baseMcp);
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
});
|