gsd-pi 2.44.0-dev.62b5d6c → 2.44.0-dev.848dd4c
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 +30 -12
- package/dist/resources/extensions/gsd/auto-start.js +10 -0
- package/dist/resources/extensions/gsd/commands/handlers/workflow.js +5 -0
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +18 -18
- 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 +2 -2
- 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 +18 -18
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js +6 -8
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +24 -26
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/fs-utils.test.js +29 -48
- package/packages/pi-coding-agent/dist/core/fs-utils.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +34 -44
- package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.test.js +30 -34
- package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +10 -12
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js +43 -47
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js.map +1 -1
- package/packages/pi-coding-agent/src/core/auth-storage.test.ts +7 -7
- package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +26 -26
- package/packages/pi-coding-agent/src/core/fs-utils.test.ts +31 -43
- package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +40 -45
- package/packages/pi-coding-agent/src/core/session-manager.test.ts +33 -33
- package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +17 -17
- package/packages/pi-coding-agent/src/resources/extensions/memory/storage.test.ts +74 -74
- package/src/resources/extensions/gsd/auto-start.ts +14 -0
- package/src/resources/extensions/gsd/commands/handlers/workflow.ts +8 -0
- package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +99 -99
- package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +14 -16
- package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +43 -57
- package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +11 -13
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +465 -523
- package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +73 -75
- package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +34 -56
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +533 -656
- package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +165 -143
- package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +29 -52
- package/src/resources/extensions/gsd/tests/captures.test.ts +148 -176
- package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +32 -33
- package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +141 -143
- package/src/resources/extensions/gsd/tests/commands-inspect-open-db.test.ts +25 -25
- package/src/resources/extensions/gsd/tests/commands-logs.test.ts +81 -81
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +38 -59
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +228 -263
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +250 -302
- package/src/resources/extensions/gsd/tests/context-store.test.ts +354 -367
- package/src/resources/extensions/gsd/tests/continue-here.test.ts +68 -72
- package/src/resources/extensions/gsd/tests/cost-projection.test.ts +92 -106
- package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +27 -35
- package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +220 -237
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +390 -420
- package/src/resources/extensions/gsd/tests/definition-loader.test.ts +76 -92
- package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +68 -83
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +152 -183
- package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +78 -101
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +192 -227
- package/src/resources/extensions/gsd/tests/detection.test.ts +232 -278
- package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +30 -34
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +164 -180
- package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +43 -49
- package/src/resources/extensions/gsd/tests/dispatch-uat-last-completed.test.ts +28 -32
- package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +27 -29
- package/src/resources/extensions/gsd/tests/doctor-delimiter-fix.test.ts +34 -38
- package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +54 -75
- package/src/resources/extensions/gsd/tests/doctor-environment-worktree.test.ts +21 -32
- package/src/resources/extensions/gsd/tests/doctor-environment.test.ts +72 -97
- package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +38 -44
- package/src/resources/extensions/gsd/tests/doctor-git.test.ts +104 -145
- package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +84 -106
- package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +54 -60
- package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +72 -93
- package/src/resources/extensions/gsd/tests/doctor.test.ts +104 -134
- package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +123 -131
- package/src/resources/extensions/gsd/tests/exit-command.test.ts +20 -24
- package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +48 -57
- package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +5 -7
- package/src/resources/extensions/gsd/tests/flag-file-db.test.ts +30 -42
- package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +198 -206
- package/src/resources/extensions/gsd/tests/git-locale.test.ts +13 -27
- package/src/resources/extensions/gsd/tests/git-service.test.ts +285 -388
- package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +31 -39
- package/src/resources/extensions/gsd/tests/graph-operations.test.ts +63 -69
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +255 -264
- package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +108 -119
- package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +81 -103
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +229 -262
- package/src/resources/extensions/gsd/tests/headless-answers.test.ts +13 -13
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +29 -37
- package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +81 -102
- package/src/resources/extensions/gsd/tests/init-wizard.test.ts +16 -18
- package/src/resources/extensions/gsd/tests/integration-edge.test.ts +41 -46
- package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +42 -53
- package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +75 -91
- package/src/resources/extensions/gsd/tests/integration-proof.test.ts +18 -18
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +150 -194
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +101 -125
- package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +45 -54
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +80 -93
- package/src/resources/extensions/gsd/tests/migrate-command.test.ts +57 -66
- package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +83 -93
- package/src/resources/extensions/gsd/tests/migrate-parser.test.ts +161 -170
- package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +125 -141
- package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +107 -131
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +87 -96
- package/src/resources/extensions/gsd/tests/migrate-writer.test.ts +125 -164
- package/src/resources/extensions/gsd/tests/must-have-parser.test.ts +81 -94
- package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +35 -36
- package/src/resources/extensions/gsd/tests/overrides.test.ts +99 -106
- package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +40 -47
- package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +25 -28
- package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +66 -83
- package/src/resources/extensions/gsd/tests/park-edge-cases.test.ts +54 -77
- package/src/resources/extensions/gsd/tests/park-milestone.test.ts +68 -115
- package/src/resources/extensions/gsd/tests/parsers.test.ts +546 -611
- package/src/resources/extensions/gsd/tests/paths.test.ts +72 -87
- package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +77 -117
- package/src/resources/extensions/gsd/tests/prompt-db.test.ts +56 -56
- package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +93 -119
- package/src/resources/extensions/gsd/tests/queue-order.test.ts +70 -82
- package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +42 -55
- package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +100 -0
- package/src/resources/extensions/gsd/tests/quick-branch-lifecycle.test.ts +45 -73
- package/src/resources/extensions/gsd/tests/reassess-prompt.test.ts +28 -38
- package/src/resources/extensions/gsd/tests/replan-slice.test.ts +73 -80
- package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +71 -74
- package/src/resources/extensions/gsd/tests/requirements.test.ts +70 -75
- package/src/resources/extensions/gsd/tests/retry-state-reset.test.ts +44 -66
- package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +114 -181
- package/src/resources/extensions/gsd/tests/rule-registry.test.ts +63 -65
- package/src/resources/extensions/gsd/tests/run-uat.test.ts +66 -128
- package/src/resources/extensions/gsd/tests/session-lock-multipath.test.ts +18 -25
- package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +37 -44
- package/src/resources/extensions/gsd/tests/shared-wal.test.ts +19 -26
- package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +63 -0
- package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +6 -8
- package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +22 -28
- package/src/resources/extensions/gsd/tests/token-savings.test.ts +54 -56
- package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +23 -25
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +9 -11
- package/src/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +66 -82
- package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +46 -47
- package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -22
- package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -86
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +41 -43
- package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +94 -96
- package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +11 -13
- package/src/resources/extensions/gsd/tests/worker-registry.test.ts +27 -29
- package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +50 -52
- package/src/resources/extensions/gsd/tests/worktree-bugfix.test.ts +10 -13
- package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +14 -18
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +38 -39
- package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +17 -21
- package/src/resources/extensions/gsd/tests/worktree-health.test.ts +25 -30
- package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +30 -37
- package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +15 -22
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +59 -66
- package/src/resources/extensions/gsd/tests/worktree.test.ts +44 -50
- /package/dist/web/standalone/.next/static/{fOnWQBjWXMKUs4bqTg530 → -zps1Q9mQmioAKLcQiCr8}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{fOnWQBjWXMKUs4bqTg530 → -zps1Q9mQmioAKLcQiCr8}/_ssgManifest.js +0 -0
|
@@ -91,142 +91,140 @@ async function loadGuidanceExport(): Promise<{ collectOneSecretWithGuidance: Fun
|
|
|
91
91
|
|
|
92
92
|
// ─── collectSecretsFromManifest: categorization ───────────────────────────────
|
|
93
93
|
|
|
94
|
-
test("collectSecretsFromManifest: categorizes entries — pending keys need collection, existing keys are skipped", async () => {
|
|
94
|
+
test("collectSecretsFromManifest: categorizes entries — pending keys need collection, existing keys are skipped", async (t) => {
|
|
95
95
|
const { collectSecretsFromManifest } = await loadOrchestrator();
|
|
96
96
|
|
|
97
97
|
const tmp = makeTempDir("manifest-collect");
|
|
98
98
|
const savedA = process.env.EXISTING_KEY_A;
|
|
99
|
-
|
|
100
|
-
process.env.EXISTING_KEY_A
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
99
|
+
t.after(() => {
|
|
100
|
+
delete process.env.EXISTING_KEY_A;
|
|
101
|
+
if (savedA !== undefined) process.env.EXISTING_KEY_A = savedA;
|
|
102
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
process.env.EXISTING_KEY_A = "already-set";
|
|
106
|
+
|
|
107
|
+
const manifest = makeManifest([
|
|
108
|
+
{ key: "EXISTING_KEY_A", status: "pending" },
|
|
109
|
+
{ key: "PENDING_KEY_B", status: "pending", guidance: ["Step 1: Go to dashboard", "Step 2: Click create key"] },
|
|
110
|
+
{ key: "SKIPPED_KEY_C", status: "skipped" },
|
|
111
|
+
]);
|
|
112
|
+
await writeManifestFile(tmp, manifest);
|
|
113
|
+
|
|
114
|
+
let callIndex = 0;
|
|
115
|
+
const mockCtx = {
|
|
116
|
+
cwd: tmp,
|
|
117
|
+
hasUI: true,
|
|
118
|
+
ui: {
|
|
119
|
+
custom: async (_factory: any) => {
|
|
120
|
+
callIndex++;
|
|
121
|
+
if (callIndex <= 1) return null; // summary screen dismiss
|
|
122
|
+
return "mock-secret-value"; // collect pending key
|
|
119
123
|
},
|
|
120
|
-
}
|
|
124
|
+
},
|
|
125
|
+
};
|
|
121
126
|
|
|
122
|
-
|
|
127
|
+
const result = await collectSecretsFromManifest(tmp, "M001", mockCtx as any);
|
|
123
128
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
129
|
+
// EXISTING_KEY_A should be in existingSkipped (it's in process.env)
|
|
130
|
+
assert.ok(result.existingSkipped?.includes("EXISTING_KEY_A"),
|
|
131
|
+
"EXISTING_KEY_A should be in existingSkipped");
|
|
127
132
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
133
|
+
// PENDING_KEY_B should have been collected (applied)
|
|
134
|
+
assert.ok(result.applied.includes("PENDING_KEY_B"),
|
|
135
|
+
"PENDING_KEY_B should be in applied");
|
|
131
136
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
} finally {
|
|
136
|
-
delete process.env.EXISTING_KEY_A;
|
|
137
|
-
if (savedA !== undefined) process.env.EXISTING_KEY_A = savedA;
|
|
138
|
-
rmSync(tmp, { recursive: true, force: true });
|
|
139
|
-
}
|
|
137
|
+
// SKIPPED_KEY_C should remain skipped
|
|
138
|
+
assert.ok(result.skipped.includes("SKIPPED_KEY_C"),
|
|
139
|
+
"SKIPPED_KEY_C should be in skipped");
|
|
140
140
|
});
|
|
141
141
|
|
|
142
|
-
test("collectSecretsFromManifest: existing keys are excluded from the collection list — not prompted", async () => {
|
|
142
|
+
test("collectSecretsFromManifest: existing keys are excluded from the collection list — not prompted", async (t) => {
|
|
143
143
|
const { collectSecretsFromManifest } = await loadOrchestrator();
|
|
144
144
|
|
|
145
145
|
const tmp = makeTempDir("manifest-collect-skip");
|
|
146
146
|
const savedA = process.env.ALREADY_SET_KEY;
|
|
147
|
-
|
|
148
|
-
process.env.ALREADY_SET_KEY = "present";
|
|
149
|
-
|
|
150
|
-
const manifest = makeManifest([
|
|
151
|
-
{ key: "ALREADY_SET_KEY", status: "pending" },
|
|
152
|
-
{ key: "NEEDS_COLLECTION", status: "pending" },
|
|
153
|
-
]);
|
|
154
|
-
await writeManifestFile(tmp, manifest);
|
|
155
|
-
|
|
156
|
-
const collectedKeyNames: string[] = [];
|
|
157
|
-
let summaryShown = false;
|
|
158
|
-
const mockCtx = {
|
|
159
|
-
cwd: tmp,
|
|
160
|
-
hasUI: true,
|
|
161
|
-
ui: {
|
|
162
|
-
custom: async (factory: any) => {
|
|
163
|
-
// Intercept the factory to check what key is being collected
|
|
164
|
-
if (!summaryShown) {
|
|
165
|
-
summaryShown = true;
|
|
166
|
-
return null; // dismiss summary
|
|
167
|
-
}
|
|
168
|
-
collectedKeyNames.push("prompted");
|
|
169
|
-
return "mock-value";
|
|
170
|
-
},
|
|
171
|
-
},
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
const result = await collectSecretsFromManifest(tmp, "M001", mockCtx as any);
|
|
175
|
-
|
|
176
|
-
// ALREADY_SET_KEY should not have been prompted — only NEEDS_COLLECTION should
|
|
177
|
-
assert.ok(!result.applied.includes("ALREADY_SET_KEY"),
|
|
178
|
-
"ALREADY_SET_KEY should not be in applied (it was auto-skipped)");
|
|
179
|
-
assert.ok(result.existingSkipped?.includes("ALREADY_SET_KEY"),
|
|
180
|
-
"ALREADY_SET_KEY should be in existingSkipped");
|
|
181
|
-
} finally {
|
|
147
|
+
t.after(() => {
|
|
182
148
|
delete process.env.ALREADY_SET_KEY;
|
|
183
149
|
if (savedA !== undefined) process.env.ALREADY_SET_KEY = savedA;
|
|
184
150
|
rmSync(tmp, { recursive: true, force: true });
|
|
185
|
-
}
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
process.env.ALREADY_SET_KEY = "present";
|
|
154
|
+
|
|
155
|
+
const manifest = makeManifest([
|
|
156
|
+
{ key: "ALREADY_SET_KEY", status: "pending" },
|
|
157
|
+
{ key: "NEEDS_COLLECTION", status: "pending" },
|
|
158
|
+
]);
|
|
159
|
+
await writeManifestFile(tmp, manifest);
|
|
160
|
+
|
|
161
|
+
const collectedKeyNames: string[] = [];
|
|
162
|
+
let summaryShown = false;
|
|
163
|
+
const mockCtx = {
|
|
164
|
+
cwd: tmp,
|
|
165
|
+
hasUI: true,
|
|
166
|
+
ui: {
|
|
167
|
+
custom: async (factory: any) => {
|
|
168
|
+
// Intercept the factory to check what key is being collected
|
|
169
|
+
if (!summaryShown) {
|
|
170
|
+
summaryShown = true;
|
|
171
|
+
return null; // dismiss summary
|
|
172
|
+
}
|
|
173
|
+
collectedKeyNames.push("prompted");
|
|
174
|
+
return "mock-value";
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
const result = await collectSecretsFromManifest(tmp, "M001", mockCtx as any);
|
|
180
|
+
|
|
181
|
+
// ALREADY_SET_KEY should not have been prompted — only NEEDS_COLLECTION should
|
|
182
|
+
assert.ok(!result.applied.includes("ALREADY_SET_KEY"),
|
|
183
|
+
"ALREADY_SET_KEY should not be in applied (it was auto-skipped)");
|
|
184
|
+
assert.ok(result.existingSkipped?.includes("ALREADY_SET_KEY"),
|
|
185
|
+
"ALREADY_SET_KEY should be in existingSkipped");
|
|
186
186
|
});
|
|
187
187
|
|
|
188
|
-
test("collectSecretsFromManifest: manifest statuses are updated after collection", async () => {
|
|
188
|
+
test("collectSecretsFromManifest: manifest statuses are updated after collection", async (t) => {
|
|
189
189
|
const { collectSecretsFromManifest } = await loadOrchestrator();
|
|
190
190
|
|
|
191
191
|
const tmp = makeTempDir("manifest-update");
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
192
|
+
t.after(() => rmSync(tmp, { recursive: true, force: true }));
|
|
193
|
+
|
|
194
|
+
const manifest = makeManifest([
|
|
195
|
+
{ key: "KEY_TO_COLLECT", status: "pending" },
|
|
196
|
+
{ key: "KEY_TO_SKIP", status: "pending" },
|
|
197
|
+
]);
|
|
198
|
+
const manifestPath = await writeManifestFile(tmp, manifest);
|
|
199
|
+
|
|
200
|
+
let callIndex = 0;
|
|
201
|
+
const mockCtx = {
|
|
202
|
+
cwd: tmp,
|
|
203
|
+
hasUI: true,
|
|
204
|
+
ui: {
|
|
205
|
+
custom: async (_factory: any) => {
|
|
206
|
+
callIndex++;
|
|
207
|
+
if (callIndex <= 1) return null; // summary screen dismiss
|
|
208
|
+
if (callIndex === 2) return "secret-value"; // KEY_TO_COLLECT
|
|
209
|
+
return null; // KEY_TO_SKIP — user skips
|
|
210
210
|
},
|
|
211
|
-
}
|
|
211
|
+
},
|
|
212
|
+
};
|
|
212
213
|
|
|
213
|
-
|
|
214
|
+
await collectSecretsFromManifest(tmp, "M001", mockCtx as any);
|
|
214
215
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
216
|
+
// Read back the manifest file and verify statuses were updated
|
|
217
|
+
const { parseSecretsManifest } = await loadFilesExports();
|
|
218
|
+
const updatedContent = readFileSync(manifestPath, "utf8");
|
|
219
|
+
const updatedManifest = parseSecretsManifest(updatedContent);
|
|
219
220
|
|
|
220
|
-
|
|
221
|
-
|
|
221
|
+
const keyToCollect = updatedManifest.entries.find(e => e.key === "KEY_TO_COLLECT");
|
|
222
|
+
const keyToSkip = updatedManifest.entries.find(e => e.key === "KEY_TO_SKIP");
|
|
222
223
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
} finally {
|
|
228
|
-
rmSync(tmp, { recursive: true, force: true });
|
|
229
|
-
}
|
|
224
|
+
assert.equal(keyToCollect?.status, "collected",
|
|
225
|
+
"KEY_TO_COLLECT should have status 'collected' after providing a value");
|
|
226
|
+
assert.equal(keyToSkip?.status, "skipped",
|
|
227
|
+
"KEY_TO_SKIP should have status 'skipped' after user skipped it");
|
|
230
228
|
});
|
|
231
229
|
|
|
232
230
|
// ─── showSecretsSummary: render output ────────────────────────────────────────
|
|
@@ -423,47 +421,47 @@ test("collectOneSecret: no guidance provided — render output has no guidance s
|
|
|
423
421
|
|
|
424
422
|
// ─── collectSecretsFromManifest: returns structured result ────────────────────
|
|
425
423
|
|
|
426
|
-
test("collectSecretsFromManifest: returns result with applied, skipped, and existingSkipped arrays", async () => {
|
|
424
|
+
test("collectSecretsFromManifest: returns result with applied, skipped, and existingSkipped arrays", async (t) => {
|
|
427
425
|
const { collectSecretsFromManifest } = await loadOrchestrator();
|
|
428
426
|
|
|
429
427
|
const tmp = makeTempDir("manifest-result");
|
|
430
428
|
const savedKey = process.env.RESULT_TEST_EXISTING;
|
|
431
|
-
|
|
432
|
-
process.env.RESULT_TEST_EXISTING
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
429
|
+
t.after(() => {
|
|
430
|
+
delete process.env.RESULT_TEST_EXISTING;
|
|
431
|
+
if (savedKey !== undefined) process.env.RESULT_TEST_EXISTING = savedKey;
|
|
432
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
process.env.RESULT_TEST_EXISTING = "already-here";
|
|
436
|
+
|
|
437
|
+
const manifest = makeManifest([
|
|
438
|
+
{ key: "RESULT_TEST_EXISTING", status: "pending" },
|
|
439
|
+
{ key: "RESULT_TEST_NEW", status: "pending" },
|
|
440
|
+
]);
|
|
441
|
+
await writeManifestFile(tmp, manifest);
|
|
442
|
+
|
|
443
|
+
let callIndex = 0;
|
|
444
|
+
const mockCtx = {
|
|
445
|
+
cwd: tmp,
|
|
446
|
+
hasUI: true,
|
|
447
|
+
ui: {
|
|
448
|
+
custom: async (_factory: any) => {
|
|
449
|
+
callIndex++;
|
|
450
|
+
if (callIndex <= 1) return null; // summary dismiss
|
|
451
|
+
return "secret-value"; // collect the pending key
|
|
450
452
|
},
|
|
451
|
-
}
|
|
453
|
+
},
|
|
454
|
+
};
|
|
452
455
|
|
|
453
|
-
|
|
456
|
+
const result = await collectSecretsFromManifest(tmp, "M001", mockCtx as any);
|
|
454
457
|
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
458
|
+
// Verify result shape
|
|
459
|
+
assert.ok(Array.isArray(result.applied), "result should have applied array");
|
|
460
|
+
assert.ok(Array.isArray(result.skipped), "result should have skipped array");
|
|
461
|
+
assert.ok(Array.isArray(result.existingSkipped), "result should have existingSkipped array");
|
|
459
462
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
} finally {
|
|
465
|
-
delete process.env.RESULT_TEST_EXISTING;
|
|
466
|
-
if (savedKey !== undefined) process.env.RESULT_TEST_EXISTING = savedKey;
|
|
467
|
-
rmSync(tmp, { recursive: true, force: true });
|
|
468
|
-
}
|
|
463
|
+
assert.ok(result.existingSkipped.includes("RESULT_TEST_EXISTING"),
|
|
464
|
+
"existing key should be in existingSkipped");
|
|
465
|
+
assert.ok(result.applied.includes("RESULT_TEST_NEW"),
|
|
466
|
+
"collected key should be in applied");
|
|
469
467
|
});
|
|
@@ -7,40 +7,40 @@ import fs from "node:fs";
|
|
|
7
7
|
import { handleInspect } from "../commands-inspect.ts";
|
|
8
8
|
import { closeDatabase, openDatabase } from "../gsd-db.ts";
|
|
9
9
|
|
|
10
|
-
test("/gsd inspect opens existing database when it was not yet opened in session", async () => {
|
|
10
|
+
test("/gsd inspect opens existing database when it was not yet opened in session", async (t) => {
|
|
11
11
|
closeDatabase();
|
|
12
12
|
|
|
13
13
|
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "gsd-inspect-db-"));
|
|
14
14
|
const prevCwd = process.cwd();
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
fs.mkdirSync(gsdDir, { recursive: true });
|
|
19
|
-
const dbPath = path.join(gsdDir, "gsd.db");
|
|
20
|
-
|
|
21
|
-
assert.equal(openDatabase(dbPath), true);
|
|
16
|
+
t.after(() => {
|
|
17
|
+
process.chdir(prevCwd);
|
|
22
18
|
closeDatabase();
|
|
19
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
20
|
+
});
|
|
23
21
|
|
|
24
|
-
|
|
22
|
+
const gsdDir = path.join(tmp, ".gsd");
|
|
23
|
+
fs.mkdirSync(gsdDir, { recursive: true });
|
|
24
|
+
const dbPath = path.join(gsdDir, "gsd.db");
|
|
25
|
+
|
|
26
|
+
assert.equal(openDatabase(dbPath), true);
|
|
27
|
+
closeDatabase();
|
|
25
28
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
process.chdir(tmp);
|
|
30
|
+
|
|
31
|
+
const notifications: Array<{ message: string; level: string }> = [];
|
|
32
|
+
const ctx = {
|
|
33
|
+
ui: {
|
|
34
|
+
notify(message: string, level: string) {
|
|
35
|
+
notifications.push({ message, level });
|
|
32
36
|
},
|
|
33
|
-
}
|
|
37
|
+
},
|
|
38
|
+
} as any;
|
|
34
39
|
|
|
35
|
-
|
|
40
|
+
await handleInspect(ctx);
|
|
36
41
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
} finally {
|
|
42
|
-
process.chdir(prevCwd);
|
|
43
|
-
closeDatabase();
|
|
44
|
-
fs.rmSync(tmp, { recursive: true, force: true });
|
|
45
|
-
}
|
|
42
|
+
assert.equal(notifications.length, 1);
|
|
43
|
+
assert.equal(notifications[0].level, "info");
|
|
44
|
+
assert.match(notifications[0].message, /=== GSD Database Inspect ===/);
|
|
45
|
+
assert.doesNotMatch(notifications[0].message, /No GSD database available/);
|
|
46
46
|
});
|
|
@@ -42,22 +42,22 @@ function writeDebugLog(dir: string, name: string, entries: Record<string, unknow
|
|
|
42
42
|
|
|
43
43
|
// ─── Tests ──────────────────────────────────────────────────────────────────
|
|
44
44
|
|
|
45
|
-
test("logs shows empty state message when no logs exist", async () => {
|
|
45
|
+
test("logs shows empty state message when no logs exist", async (t) => {
|
|
46
46
|
const dir = createTestDir();
|
|
47
47
|
const ctx = createMockCtx();
|
|
48
48
|
const origCwd = process.cwd();
|
|
49
49
|
process.chdir(dir);
|
|
50
|
-
|
|
51
|
-
await handleLogs("", ctx as any);
|
|
52
|
-
assert.equal(ctx.notifications.length, 1);
|
|
53
|
-
assert.ok(ctx.notifications[0].msg.includes("No logs found"));
|
|
54
|
-
} finally {
|
|
50
|
+
t.after(() => {
|
|
55
51
|
process.chdir(origCwd);
|
|
56
52
|
rmSync(dir, { recursive: true, force: true });
|
|
57
|
-
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
await handleLogs("", ctx as any);
|
|
56
|
+
assert.equal(ctx.notifications.length, 1);
|
|
57
|
+
assert.ok(ctx.notifications[0].msg.includes("No logs found"));
|
|
58
58
|
});
|
|
59
59
|
|
|
60
|
-
test("logs lists activity logs", async () => {
|
|
60
|
+
test("logs lists activity logs", async (t) => {
|
|
61
61
|
const dir = createTestDir();
|
|
62
62
|
const ctx = createMockCtx();
|
|
63
63
|
const origCwd = process.cwd();
|
|
@@ -71,21 +71,21 @@ test("logs lists activity logs", async () => {
|
|
|
71
71
|
{ role: "assistant", content: "Completing slice S01" },
|
|
72
72
|
]);
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
await handleLogs("", ctx as any);
|
|
76
|
-
assert.equal(ctx.notifications.length, 1);
|
|
77
|
-
const msg = ctx.notifications[0].msg;
|
|
78
|
-
assert.ok(msg.includes("Activity Logs"), "should show activity logs header");
|
|
79
|
-
assert.ok(msg.includes("execute-task"), "should show unit type");
|
|
80
|
-
assert.ok(msg.includes("complete-slice"), "should show second log");
|
|
81
|
-
assert.ok(msg.includes("/gsd logs <#>"), "should show usage hint");
|
|
82
|
-
} finally {
|
|
74
|
+
t.after(() => {
|
|
83
75
|
process.chdir(origCwd);
|
|
84
76
|
rmSync(dir, { recursive: true, force: true });
|
|
85
|
-
}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
await handleLogs("", ctx as any);
|
|
80
|
+
assert.equal(ctx.notifications.length, 1);
|
|
81
|
+
const msg = ctx.notifications[0].msg;
|
|
82
|
+
assert.ok(msg.includes("Activity Logs"), "should show activity logs header");
|
|
83
|
+
assert.ok(msg.includes("execute-task"), "should show unit type");
|
|
84
|
+
assert.ok(msg.includes("complete-slice"), "should show second log");
|
|
85
|
+
assert.ok(msg.includes("/gsd logs <#>"), "should show usage hint");
|
|
86
86
|
});
|
|
87
87
|
|
|
88
|
-
test("logs <N> shows activity log details", async () => {
|
|
88
|
+
test("logs <N> shows activity log details", async (t) => {
|
|
89
89
|
const dir = createTestDir();
|
|
90
90
|
const ctx = createMockCtx();
|
|
91
91
|
const origCwd = process.cwd();
|
|
@@ -99,40 +99,40 @@ test("logs <N> shows activity log details", async () => {
|
|
|
99
99
|
{ role: "assistant", content: "I ran the tests and wrote a file" },
|
|
100
100
|
]);
|
|
101
101
|
|
|
102
|
-
|
|
103
|
-
await handleLogs("1", ctx as any);
|
|
104
|
-
assert.equal(ctx.notifications.length, 1);
|
|
105
|
-
const msg = ctx.notifications[0].msg;
|
|
106
|
-
assert.ok(msg.includes("Activity Log #1"), "should show log number");
|
|
107
|
-
assert.ok(msg.includes("execute-task"), "should show unit type");
|
|
108
|
-
assert.ok(msg.includes("Tool calls: 2"), "should count tool calls");
|
|
109
|
-
assert.ok(msg.includes("Errors: 1"), "should count errors");
|
|
110
|
-
assert.ok(msg.includes("/tmp/test.ts"), "should show files written");
|
|
111
|
-
assert.ok(msg.includes("npm test"), "should show commands run");
|
|
112
|
-
} finally {
|
|
102
|
+
t.after(() => {
|
|
113
103
|
process.chdir(origCwd);
|
|
114
104
|
rmSync(dir, { recursive: true, force: true });
|
|
115
|
-
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
await handleLogs("1", ctx as any);
|
|
108
|
+
assert.equal(ctx.notifications.length, 1);
|
|
109
|
+
const msg = ctx.notifications[0].msg;
|
|
110
|
+
assert.ok(msg.includes("Activity Log #1"), "should show log number");
|
|
111
|
+
assert.ok(msg.includes("execute-task"), "should show unit type");
|
|
112
|
+
assert.ok(msg.includes("Tool calls: 2"), "should count tool calls");
|
|
113
|
+
assert.ok(msg.includes("Errors: 1"), "should count errors");
|
|
114
|
+
assert.ok(msg.includes("/tmp/test.ts"), "should show files written");
|
|
115
|
+
assert.ok(msg.includes("npm test"), "should show commands run");
|
|
116
116
|
});
|
|
117
117
|
|
|
118
|
-
test("logs <N> shows not found for invalid seq", async () => {
|
|
118
|
+
test("logs <N> shows not found for invalid seq", async (t) => {
|
|
119
119
|
const dir = createTestDir();
|
|
120
120
|
const ctx = createMockCtx();
|
|
121
121
|
const origCwd = process.cwd();
|
|
122
122
|
process.chdir(dir);
|
|
123
123
|
|
|
124
|
-
|
|
125
|
-
await handleLogs("999", ctx as any);
|
|
126
|
-
assert.equal(ctx.notifications.length, 1);
|
|
127
|
-
assert.ok(ctx.notifications[0].msg.includes("not found"));
|
|
128
|
-
assert.equal(ctx.notifications[0].level, "warning");
|
|
129
|
-
} finally {
|
|
124
|
+
t.after(() => {
|
|
130
125
|
process.chdir(origCwd);
|
|
131
126
|
rmSync(dir, { recursive: true, force: true });
|
|
132
|
-
}
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
await handleLogs("999", ctx as any);
|
|
130
|
+
assert.equal(ctx.notifications.length, 1);
|
|
131
|
+
assert.ok(ctx.notifications[0].msg.includes("not found"));
|
|
132
|
+
assert.equal(ctx.notifications[0].level, "warning");
|
|
133
133
|
});
|
|
134
134
|
|
|
135
|
-
test("logs debug lists debug logs", async () => {
|
|
135
|
+
test("logs debug lists debug logs", async (t) => {
|
|
136
136
|
const dir = createTestDir();
|
|
137
137
|
const ctx = createMockCtx();
|
|
138
138
|
const origCwd = process.cwd();
|
|
@@ -143,19 +143,19 @@ test("logs debug lists debug logs", async () => {
|
|
|
143
143
|
{ ts: "2026-03-18T10:35:00Z", event: "debug-summary", dispatches: 5 },
|
|
144
144
|
]);
|
|
145
145
|
|
|
146
|
-
|
|
147
|
-
await handleLogs("debug", ctx as any);
|
|
148
|
-
assert.equal(ctx.notifications.length, 1);
|
|
149
|
-
const msg = ctx.notifications[0].msg;
|
|
150
|
-
assert.ok(msg.includes("Debug Logs"), "should show debug logs header");
|
|
151
|
-
assert.ok(msg.includes("debug-2026-03-18T10-30-00.log"), "should show filename");
|
|
152
|
-
} finally {
|
|
146
|
+
t.after(() => {
|
|
153
147
|
process.chdir(origCwd);
|
|
154
148
|
rmSync(dir, { recursive: true, force: true });
|
|
155
|
-
}
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
await handleLogs("debug", ctx as any);
|
|
152
|
+
assert.equal(ctx.notifications.length, 1);
|
|
153
|
+
const msg = ctx.notifications[0].msg;
|
|
154
|
+
assert.ok(msg.includes("Debug Logs"), "should show debug logs header");
|
|
155
|
+
assert.ok(msg.includes("debug-2026-03-18T10-30-00.log"), "should show filename");
|
|
156
156
|
});
|
|
157
157
|
|
|
158
|
-
test("logs debug <N> shows debug log summary", async () => {
|
|
158
|
+
test("logs debug <N> shows debug log summary", async (t) => {
|
|
159
159
|
const dir = createTestDir();
|
|
160
160
|
const ctx = createMockCtx();
|
|
161
161
|
const origCwd = process.cwd();
|
|
@@ -167,21 +167,21 @@ test("logs debug <N> shows debug log summary", async () => {
|
|
|
167
167
|
{ ts: "2026-03-18T10:35:00Z", event: "debug-summary", dispatches: 5 },
|
|
168
168
|
]);
|
|
169
169
|
|
|
170
|
-
|
|
171
|
-
await handleLogs("debug 1", ctx as any);
|
|
172
|
-
assert.equal(ctx.notifications.length, 1);
|
|
173
|
-
const msg = ctx.notifications[0].msg;
|
|
174
|
-
assert.ok(msg.includes("Debug Log:"), "should show debug log header");
|
|
175
|
-
assert.ok(msg.includes("Events: 3"), "should count events");
|
|
176
|
-
assert.ok(msg.includes("Dispatches: 5"), "should show dispatch count");
|
|
177
|
-
assert.ok(msg.includes("dispatch-error"), "should show errors");
|
|
178
|
-
} finally {
|
|
170
|
+
t.after(() => {
|
|
179
171
|
process.chdir(origCwd);
|
|
180
172
|
rmSync(dir, { recursive: true, force: true });
|
|
181
|
-
}
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
await handleLogs("debug 1", ctx as any);
|
|
176
|
+
assert.equal(ctx.notifications.length, 1);
|
|
177
|
+
const msg = ctx.notifications[0].msg;
|
|
178
|
+
assert.ok(msg.includes("Debug Log:"), "should show debug log header");
|
|
179
|
+
assert.ok(msg.includes("Events: 3"), "should count events");
|
|
180
|
+
assert.ok(msg.includes("Dispatches: 5"), "should show dispatch count");
|
|
181
|
+
assert.ok(msg.includes("dispatch-error"), "should show errors");
|
|
182
182
|
});
|
|
183
183
|
|
|
184
|
-
test("logs tail shows recent activity summaries", async () => {
|
|
184
|
+
test("logs tail shows recent activity summaries", async (t) => {
|
|
185
185
|
const dir = createTestDir();
|
|
186
186
|
const ctx = createMockCtx();
|
|
187
187
|
const origCwd = process.cwd();
|
|
@@ -195,20 +195,20 @@ test("logs tail shows recent activity summaries", async () => {
|
|
|
195
195
|
{ role: "toolResult", toolCallId: "1", toolName: "bash", isError: true },
|
|
196
196
|
]);
|
|
197
197
|
|
|
198
|
-
|
|
199
|
-
await handleLogs("tail 2", ctx as any);
|
|
200
|
-
assert.equal(ctx.notifications.length, 1);
|
|
201
|
-
const msg = ctx.notifications[0].msg;
|
|
202
|
-
assert.ok(msg.includes("Last 2 activity log(s)"), "should show count");
|
|
203
|
-
assert.ok(msg.includes("#1"), "should show first log");
|
|
204
|
-
assert.ok(msg.includes("#2"), "should show second log");
|
|
205
|
-
} finally {
|
|
198
|
+
t.after(() => {
|
|
206
199
|
process.chdir(origCwd);
|
|
207
200
|
rmSync(dir, { recursive: true, force: true });
|
|
208
|
-
}
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
await handleLogs("tail 2", ctx as any);
|
|
204
|
+
assert.equal(ctx.notifications.length, 1);
|
|
205
|
+
const msg = ctx.notifications[0].msg;
|
|
206
|
+
assert.ok(msg.includes("Last 2 activity log(s)"), "should show count");
|
|
207
|
+
assert.ok(msg.includes("#1"), "should show first log");
|
|
208
|
+
assert.ok(msg.includes("#2"), "should show second log");
|
|
209
209
|
});
|
|
210
210
|
|
|
211
|
-
test("logs clear removes old logs", async () => {
|
|
211
|
+
test("logs clear removes old logs", async (t) => {
|
|
212
212
|
const dir = createTestDir();
|
|
213
213
|
const ctx = createMockCtx();
|
|
214
214
|
const origCwd = process.cwd();
|
|
@@ -225,17 +225,17 @@ test("logs clear removes old logs", async () => {
|
|
|
225
225
|
writeActivityLog(dir, i, "execute-task", `M001/S01/T0${i}`, [{ type: "toolCall" }]);
|
|
226
226
|
}
|
|
227
227
|
|
|
228
|
-
|
|
229
|
-
await handleLogs("clear", ctx as any);
|
|
230
|
-
assert.equal(ctx.notifications.length, 1);
|
|
231
|
-
// Old log should be removed, recent ones kept
|
|
232
|
-
assert.ok(!existsSync(oldFile), "old log should be removed");
|
|
233
|
-
assert.ok(
|
|
234
|
-
existsSync(join(dir, ".gsd", "activity", "007-execute-task-M001-S01-T07.jsonl")),
|
|
235
|
-
"most recent log should be kept",
|
|
236
|
-
);
|
|
237
|
-
} finally {
|
|
228
|
+
t.after(() => {
|
|
238
229
|
process.chdir(origCwd);
|
|
239
230
|
rmSync(dir, { recursive: true, force: true });
|
|
240
|
-
}
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
await handleLogs("clear", ctx as any);
|
|
234
|
+
assert.equal(ctx.notifications.length, 1);
|
|
235
|
+
// Old log should be removed, recent ones kept
|
|
236
|
+
assert.ok(!existsSync(oldFile), "old log should be removed");
|
|
237
|
+
assert.ok(
|
|
238
|
+
existsSync(join(dir, ".gsd", "activity", "007-execute-task-M001-S01-T07.jsonl")),
|
|
239
|
+
"most recent log should be kept",
|
|
240
|
+
);
|
|
241
241
|
});
|