gsd-pi 2.44.0-dev.62b5d6c → 2.44.0-dev.a5271fc
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/bootstrap/system-context.js +46 -12
- package/dist/resources/extensions/gsd/commands/handlers/workflow.js +5 -0
- package/dist/resources/extensions/gsd/preferences.js +9 -1
- package/dist/resources/extensions/gsd/state.js +19 -2
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +19 -19
- 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 +19 -19
- 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/bootstrap/system-context.ts +48 -11
- package/src/resources/extensions/gsd/commands/handlers/workflow.ts +8 -0
- package/src/resources/extensions/gsd/preferences.ts +11 -1
- package/src/resources/extensions/gsd/state.ts +19 -1
- 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 +183 -181
- 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/knowledge.test.ts +89 -0
- 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/preferences.test.ts +27 -0
- 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 → JyimLR2pZuvKEzv26gI3w}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{fOnWQBjWXMKUs4bqTg530 → JyimLR2pZuvKEzv26gI3w}/_ssgManifest.js +0 -0
|
@@ -53,43 +53,37 @@ function cleanup(dir: string): void {
|
|
|
53
53
|
|
|
54
54
|
// ─── hasGitTrackedGsdFiles ───────────────────────────────────────────
|
|
55
55
|
|
|
56
|
-
test("hasGitTrackedGsdFiles returns false when .gsd/ does not exist", () => {
|
|
56
|
+
test("hasGitTrackedGsdFiles returns false when .gsd/ does not exist", (t) => {
|
|
57
57
|
const dir = makeTempRepo();
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
cleanup(dir);
|
|
62
|
-
}
|
|
58
|
+
t.after(() => { cleanup(dir); });
|
|
59
|
+
|
|
60
|
+
assert.equal(hasGitTrackedGsdFiles(dir), false);
|
|
63
61
|
});
|
|
64
62
|
|
|
65
|
-
test("hasGitTrackedGsdFiles returns true when .gsd/ has tracked files", () => {
|
|
63
|
+
test("hasGitTrackedGsdFiles returns true when .gsd/ has tracked files", (t) => {
|
|
66
64
|
const dir = makeTempRepo();
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
cleanup(dir);
|
|
75
|
-
}
|
|
65
|
+
t.after(() => { cleanup(dir); });
|
|
66
|
+
|
|
67
|
+
mkdirSync(join(dir, ".gsd", "milestones"), { recursive: true });
|
|
68
|
+
writeFileSync(join(dir, ".gsd", "PROJECT.md"), "# Test Project\n");
|
|
69
|
+
git(dir, "add", ".gsd/PROJECT.md");
|
|
70
|
+
git(dir, "commit", "-m", "add gsd");
|
|
71
|
+
assert.equal(hasGitTrackedGsdFiles(dir), true);
|
|
76
72
|
});
|
|
77
73
|
|
|
78
|
-
test("hasGitTrackedGsdFiles returns false when .gsd/ exists but is untracked", () => {
|
|
74
|
+
test("hasGitTrackedGsdFiles returns false when .gsd/ exists but is untracked", (t) => {
|
|
79
75
|
const dir = makeTempRepo();
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
cleanup(dir);
|
|
87
|
-
}
|
|
76
|
+
t.after(() => { cleanup(dir); });
|
|
77
|
+
|
|
78
|
+
mkdirSync(join(dir, ".gsd"), { recursive: true });
|
|
79
|
+
writeFileSync(join(dir, ".gsd", "STATE.md"), "state\n");
|
|
80
|
+
// Not git-added — should return false
|
|
81
|
+
assert.equal(hasGitTrackedGsdFiles(dir), false);
|
|
88
82
|
});
|
|
89
83
|
|
|
90
84
|
// ─── ensureGitignore — tracked .gsd/ protection ─────────────────────
|
|
91
85
|
|
|
92
|
-
test("ensureGitignore does NOT add .gsd when .gsd/ has tracked files (#1364)", () => {
|
|
86
|
+
test("ensureGitignore does NOT add .gsd when .gsd/ has tracked files (#1364)", (t) => {
|
|
93
87
|
const dir = makeTempRepo();
|
|
94
88
|
try {
|
|
95
89
|
// Set up .gsd/ with tracked files
|
|
@@ -118,7 +112,7 @@ test("ensureGitignore does NOT add .gsd when .gsd/ has tracked files (#1364)", (
|
|
|
118
112
|
}
|
|
119
113
|
});
|
|
120
114
|
|
|
121
|
-
test("ensureGitignore adds .gsd when .gsd/ has NO tracked files", () => {
|
|
115
|
+
test("ensureGitignore adds .gsd when .gsd/ has NO tracked files", (t) => {
|
|
122
116
|
const dir = makeTempRepo();
|
|
123
117
|
try {
|
|
124
118
|
// Run ensureGitignore (no .gsd/ at all)
|
|
@@ -136,20 +130,18 @@ test("ensureGitignore adds .gsd when .gsd/ has NO tracked files", () => {
|
|
|
136
130
|
}
|
|
137
131
|
});
|
|
138
132
|
|
|
139
|
-
test("ensureGitignore respects manageGitignore: false", () => {
|
|
133
|
+
test("ensureGitignore respects manageGitignore: false", (t) => {
|
|
140
134
|
const dir = makeTempRepo();
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
cleanup(dir);
|
|
147
|
-
}
|
|
135
|
+
t.after(() => { cleanup(dir); });
|
|
136
|
+
|
|
137
|
+
const result = ensureGitignore(dir, { manageGitignore: false });
|
|
138
|
+
assert.equal(result, false);
|
|
139
|
+
assert.ok(!existsSync(join(dir, ".gitignore")), "Should not create .gitignore");
|
|
148
140
|
});
|
|
149
141
|
|
|
150
142
|
// ─── ensureGitignore — verify no tracked files become invisible ─────
|
|
151
143
|
|
|
152
|
-
test("ensureGitignore with tracked .gsd/ does not cause git to see files as deleted", () => {
|
|
144
|
+
test("ensureGitignore with tracked .gsd/ does not cause git to see files as deleted", (t) => {
|
|
153
145
|
const dir = makeTempRepo();
|
|
154
146
|
try {
|
|
155
147
|
// Create tracked .gsd/ files
|
|
@@ -183,7 +175,7 @@ test("ensureGitignore with tracked .gsd/ does not cause git to see files as dele
|
|
|
183
175
|
}
|
|
184
176
|
});
|
|
185
177
|
|
|
186
|
-
test("hasGitTrackedGsdFiles returns true (fail-safe) when git is not available", () => {
|
|
178
|
+
test("hasGitTrackedGsdFiles returns true (fail-safe) when git is not available", (t) => {
|
|
187
179
|
const dir = makeTempRepo();
|
|
188
180
|
try {
|
|
189
181
|
// Create and track .gsd/ files
|
|
@@ -207,7 +199,7 @@ test("hasGitTrackedGsdFiles returns true (fail-safe) when git is not available",
|
|
|
207
199
|
|
|
208
200
|
// ─── migrateToExternalState — tracked .gsd/ protection ──────────────
|
|
209
201
|
|
|
210
|
-
test("migrateToExternalState aborts when .gsd/ has tracked files (#1364)", () => {
|
|
202
|
+
test("migrateToExternalState aborts when .gsd/ has tracked files (#1364)", (t) => {
|
|
211
203
|
const dir = makeTempRepo();
|
|
212
204
|
try {
|
|
213
205
|
// Create tracked .gsd/ files
|
|
@@ -235,7 +227,7 @@ test("migrateToExternalState aborts when .gsd/ has tracked files (#1364)", () =>
|
|
|
235
227
|
}
|
|
236
228
|
});
|
|
237
229
|
|
|
238
|
-
test("migrateToExternalState cleans git index so tracked files don't show as deleted (#1364 path 2)", () => {
|
|
230
|
+
test("migrateToExternalState cleans git index so tracked files don't show as deleted (#1364 path 2)", (t) => {
|
|
239
231
|
const dir = makeTempRepo();
|
|
240
232
|
try {
|
|
241
233
|
// Track .gsd/ files, then untrack them so migration proceeds
|
|
@@ -56,7 +56,7 @@ function makeStep(overrides: Partial<GraphStep> & { id: string }): GraphStep {
|
|
|
56
56
|
// ─── writeGraph + readGraph round-trip ───────────────────────────────────
|
|
57
57
|
|
|
58
58
|
describe("writeGraph + readGraph round-trip", () => {
|
|
59
|
-
it("preserves all fields including parentStepId and dependsOn", () => {
|
|
59
|
+
it("preserves all fields including parentStepId and dependsOn", (t) => {
|
|
60
60
|
const dir = makeTmpDir();
|
|
61
61
|
try {
|
|
62
62
|
const graph = makeGraph([
|
|
@@ -89,7 +89,7 @@ describe("writeGraph + readGraph round-trip", () => {
|
|
|
89
89
|
}
|
|
90
90
|
});
|
|
91
91
|
|
|
92
|
-
it("preserves startedAt and finishedAt fields", () => {
|
|
92
|
+
it("preserves startedAt and finishedAt fields", (t) => {
|
|
93
93
|
const dir = makeTmpDir();
|
|
94
94
|
try {
|
|
95
95
|
const graph = makeGraph([
|
|
@@ -110,7 +110,7 @@ describe("writeGraph + readGraph round-trip", () => {
|
|
|
110
110
|
}
|
|
111
111
|
});
|
|
112
112
|
|
|
113
|
-
it("creates directory if it does not exist", () => {
|
|
113
|
+
it("creates directory if it does not exist", (t) => {
|
|
114
114
|
const base = makeTmpDir();
|
|
115
115
|
const nested = join(base, "sub", "dir");
|
|
116
116
|
try {
|
|
@@ -129,59 +129,53 @@ describe("writeGraph + readGraph round-trip", () => {
|
|
|
129
129
|
// ─── readGraph error paths ───────────────────────────────────────────────
|
|
130
130
|
|
|
131
131
|
describe("readGraph error paths", () => {
|
|
132
|
-
it("throws with descriptive error when file is missing", () => {
|
|
132
|
+
it("throws with descriptive error when file is missing", (t) => {
|
|
133
133
|
const dir = makeTmpDir();
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
cleanupDir(dir);
|
|
145
|
-
}
|
|
134
|
+
t.after(() => { cleanupDir(dir); });
|
|
135
|
+
|
|
136
|
+
assert.throws(
|
|
137
|
+
() => readGraph(dir),
|
|
138
|
+
(err: Error) => {
|
|
139
|
+
assert.ok(err.message.includes("GRAPH.yaml not found"));
|
|
140
|
+
assert.ok(err.message.includes(dir));
|
|
141
|
+
return true;
|
|
142
|
+
},
|
|
143
|
+
);
|
|
146
144
|
});
|
|
147
145
|
|
|
148
|
-
it("throws with descriptive error when YAML is malformed (missing steps)", () => {
|
|
146
|
+
it("throws with descriptive error when YAML is malformed (missing steps)", (t) => {
|
|
149
147
|
const dir = makeTmpDir();
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
cleanupDir(dir);
|
|
161
|
-
}
|
|
148
|
+
t.after(() => { cleanupDir(dir); });
|
|
149
|
+
|
|
150
|
+
writeFileSync(join(dir, "GRAPH.yaml"), "metadata:\n name: bad\n", "utf-8");
|
|
151
|
+
assert.throws(
|
|
152
|
+
() => readGraph(dir),
|
|
153
|
+
(err: Error) => {
|
|
154
|
+
assert.ok(err.message.includes("missing or invalid 'steps' array"));
|
|
155
|
+
return true;
|
|
156
|
+
},
|
|
157
|
+
);
|
|
162
158
|
});
|
|
163
159
|
|
|
164
|
-
it("throws when steps is not an array", () => {
|
|
160
|
+
it("throws when steps is not an array", (t) => {
|
|
165
161
|
const dir = makeTmpDir();
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
cleanupDir(dir);
|
|
177
|
-
}
|
|
162
|
+
t.after(() => { cleanupDir(dir); });
|
|
163
|
+
|
|
164
|
+
writeFileSync(join(dir, "GRAPH.yaml"), "steps: not-an-array\nmetadata:\n name: bad\n", "utf-8");
|
|
165
|
+
assert.throws(
|
|
166
|
+
() => readGraph(dir),
|
|
167
|
+
(err: Error) => {
|
|
168
|
+
assert.ok(err.message.includes("missing or invalid 'steps' array"));
|
|
169
|
+
return true;
|
|
170
|
+
},
|
|
171
|
+
);
|
|
178
172
|
});
|
|
179
173
|
});
|
|
180
174
|
|
|
181
175
|
// ─── getNextPendingStep ──────────────────────────────────────────────────
|
|
182
176
|
|
|
183
177
|
describe("getNextPendingStep", () => {
|
|
184
|
-
it("returns first step with all deps complete", () => {
|
|
178
|
+
it("returns first step with all deps complete", (t) => {
|
|
185
179
|
const graph = makeGraph([
|
|
186
180
|
makeStep({ id: "a", status: "complete" }),
|
|
187
181
|
makeStep({ id: "b", dependsOn: ["a"] }),
|
|
@@ -192,7 +186,7 @@ describe("getNextPendingStep", () => {
|
|
|
192
186
|
assert.equal(next?.id, "b");
|
|
193
187
|
});
|
|
194
188
|
|
|
195
|
-
it("skips steps with incomplete deps", () => {
|
|
189
|
+
it("skips steps with incomplete deps", (t) => {
|
|
196
190
|
const graph = makeGraph([
|
|
197
191
|
makeStep({ id: "a" }),
|
|
198
192
|
makeStep({ id: "b", dependsOn: ["a"] }),
|
|
@@ -203,7 +197,7 @@ describe("getNextPendingStep", () => {
|
|
|
203
197
|
assert.equal(next?.id, "a");
|
|
204
198
|
});
|
|
205
199
|
|
|
206
|
-
it("returns null when all steps are complete", () => {
|
|
200
|
+
it("returns null when all steps are complete", (t) => {
|
|
207
201
|
const graph = makeGraph([
|
|
208
202
|
makeStep({ id: "a", status: "complete" }),
|
|
209
203
|
makeStep({ id: "b", status: "complete" }),
|
|
@@ -212,7 +206,7 @@ describe("getNextPendingStep", () => {
|
|
|
212
206
|
assert.equal(getNextPendingStep(graph), null);
|
|
213
207
|
});
|
|
214
208
|
|
|
215
|
-
it("returns null when all pending steps are blocked", () => {
|
|
209
|
+
it("returns null when all pending steps are blocked", (t) => {
|
|
216
210
|
const graph = makeGraph([
|
|
217
211
|
makeStep({ id: "a", status: "active" }), // not complete
|
|
218
212
|
makeStep({ id: "b", dependsOn: ["a"] }), // blocked
|
|
@@ -221,7 +215,7 @@ describe("getNextPendingStep", () => {
|
|
|
221
215
|
assert.equal(getNextPendingStep(graph), null);
|
|
222
216
|
});
|
|
223
217
|
|
|
224
|
-
it("returns first pending step with no deps when root steps exist", () => {
|
|
218
|
+
it("returns first pending step with no deps when root steps exist", (t) => {
|
|
225
219
|
const graph = makeGraph([
|
|
226
220
|
makeStep({ id: "a" }),
|
|
227
221
|
makeStep({ id: "b" }),
|
|
@@ -231,7 +225,7 @@ describe("getNextPendingStep", () => {
|
|
|
231
225
|
assert.equal(next?.id, "a");
|
|
232
226
|
});
|
|
233
227
|
|
|
234
|
-
it("skips expanded steps", () => {
|
|
228
|
+
it("skips expanded steps", (t) => {
|
|
235
229
|
const graph = makeGraph([
|
|
236
230
|
makeStep({ id: "a", status: "expanded" }),
|
|
237
231
|
makeStep({ id: "b" }),
|
|
@@ -245,7 +239,7 @@ describe("getNextPendingStep", () => {
|
|
|
245
239
|
// ─── markStepComplete ────────────────────────────────────────────────────
|
|
246
240
|
|
|
247
241
|
describe("markStepComplete", () => {
|
|
248
|
-
it("returns new graph with step status 'complete' (original unchanged)", () => {
|
|
242
|
+
it("returns new graph with step status 'complete' (original unchanged)", (t) => {
|
|
249
243
|
const original = makeGraph([
|
|
250
244
|
makeStep({ id: "a" }),
|
|
251
245
|
makeStep({ id: "b" }),
|
|
@@ -264,7 +258,7 @@ describe("markStepComplete", () => {
|
|
|
264
258
|
assert.equal(updated.steps[1].status, "pending");
|
|
265
259
|
});
|
|
266
260
|
|
|
267
|
-
it("sets finishedAt timestamp", () => {
|
|
261
|
+
it("sets finishedAt timestamp", (t) => {
|
|
268
262
|
const graph = makeGraph([makeStep({ id: "a" })]);
|
|
269
263
|
const updated = markStepComplete(graph, "a");
|
|
270
264
|
assert.ok(updated.steps[0].finishedAt);
|
|
@@ -272,7 +266,7 @@ describe("markStepComplete", () => {
|
|
|
272
266
|
assert.ok(!isNaN(Date.parse(updated.steps[0].finishedAt!)));
|
|
273
267
|
});
|
|
274
268
|
|
|
275
|
-
it("throws for unknown step ID", () => {
|
|
269
|
+
it("throws for unknown step ID", (t) => {
|
|
276
270
|
const graph = makeGraph([makeStep({ id: "a" })]);
|
|
277
271
|
assert.throws(
|
|
278
272
|
() => markStepComplete(graph, "nonexistent"),
|
|
@@ -284,7 +278,7 @@ describe("markStepComplete", () => {
|
|
|
284
278
|
);
|
|
285
279
|
});
|
|
286
280
|
|
|
287
|
-
it("preserves metadata in returned graph", () => {
|
|
281
|
+
it("preserves metadata in returned graph", (t) => {
|
|
288
282
|
const graph = makeGraph([makeStep({ id: "a" })], "my-workflow");
|
|
289
283
|
const updated = markStepComplete(graph, "a");
|
|
290
284
|
assert.equal(updated.metadata.name, "my-workflow");
|
|
@@ -295,7 +289,7 @@ describe("markStepComplete", () => {
|
|
|
295
289
|
// ─── expandIteration ─────────────────────────────────────────────────────
|
|
296
290
|
|
|
297
291
|
describe("expandIteration", () => {
|
|
298
|
-
it("creates instance steps with correct IDs (stepId--001, stepId--002)", () => {
|
|
292
|
+
it("creates instance steps with correct IDs (stepId--001, stepId--002)", (t) => {
|
|
299
293
|
const graph = makeGraph([
|
|
300
294
|
makeStep({ id: "iter-step", title: "Process items" }),
|
|
301
295
|
makeStep({ id: "final", dependsOn: ["iter-step"] }),
|
|
@@ -317,7 +311,7 @@ describe("expandIteration", () => {
|
|
|
317
311
|
assert.equal(expanded.steps[3].id, "iter-step--003");
|
|
318
312
|
});
|
|
319
313
|
|
|
320
|
-
it("marks parent step as 'expanded'", () => {
|
|
314
|
+
it("marks parent step as 'expanded'", (t) => {
|
|
321
315
|
const graph = makeGraph([
|
|
322
316
|
makeStep({ id: "iter", title: "Iterate" }),
|
|
323
317
|
]);
|
|
@@ -326,7 +320,7 @@ describe("expandIteration", () => {
|
|
|
326
320
|
assert.equal(expanded.steps[0].status, "expanded");
|
|
327
321
|
});
|
|
328
322
|
|
|
329
|
-
it("instance steps have correct titles, prompts, parentStepId, and deps", () => {
|
|
323
|
+
it("instance steps have correct titles, prompts, parentStepId, and deps", (t) => {
|
|
330
324
|
const graph = makeGraph([
|
|
331
325
|
makeStep({ id: "pre", status: "complete" }),
|
|
332
326
|
makeStep({ id: "iter", title: "Process", dependsOn: ["pre"] }),
|
|
@@ -352,7 +346,7 @@ describe("expandIteration", () => {
|
|
|
352
346
|
assert.equal(inst2.parentStepId, "iter");
|
|
353
347
|
});
|
|
354
348
|
|
|
355
|
-
it("rewrites downstream deps from parent ID to all instance IDs", () => {
|
|
349
|
+
it("rewrites downstream deps from parent ID to all instance IDs", (t) => {
|
|
356
350
|
const graph = makeGraph([
|
|
357
351
|
makeStep({ id: "iter", title: "Iterate" }),
|
|
358
352
|
makeStep({ id: "after", dependsOn: ["iter"] }),
|
|
@@ -370,7 +364,7 @@ describe("expandIteration", () => {
|
|
|
370
364
|
assert.deepStrictEqual(afterStep.dependsOn, ["iter--001", "iter--002"]);
|
|
371
365
|
});
|
|
372
366
|
|
|
373
|
-
it("preserves steps that don't depend on the parent", () => {
|
|
367
|
+
it("preserves steps that don't depend on the parent", (t) => {
|
|
374
368
|
const graph = makeGraph([
|
|
375
369
|
makeStep({ id: "unrelated" }),
|
|
376
370
|
makeStep({ id: "iter", title: "Iterate" }),
|
|
@@ -382,7 +376,7 @@ describe("expandIteration", () => {
|
|
|
382
376
|
assert.deepStrictEqual(unrelated.dependsOn, []);
|
|
383
377
|
});
|
|
384
378
|
|
|
385
|
-
it("throws for non-pending parent step", () => {
|
|
379
|
+
it("throws for non-pending parent step", (t) => {
|
|
386
380
|
const graph = makeGraph([
|
|
387
381
|
makeStep({ id: "iter", status: "complete" }),
|
|
388
382
|
]);
|
|
@@ -397,7 +391,7 @@ describe("expandIteration", () => {
|
|
|
397
391
|
);
|
|
398
392
|
});
|
|
399
393
|
|
|
400
|
-
it("throws for unknown step ID", () => {
|
|
394
|
+
it("throws for unknown step ID", (t) => {
|
|
401
395
|
const graph = makeGraph([makeStep({ id: "a" })]);
|
|
402
396
|
assert.throws(
|
|
403
397
|
() => expandIteration(graph, "nonexistent", ["a"], "{{item}}"),
|
|
@@ -409,7 +403,7 @@ describe("expandIteration", () => {
|
|
|
409
403
|
);
|
|
410
404
|
});
|
|
411
405
|
|
|
412
|
-
it("does not mutate the input graph", () => {
|
|
406
|
+
it("does not mutate the input graph", (t) => {
|
|
413
407
|
const graph = makeGraph([
|
|
414
408
|
makeStep({ id: "iter", title: "Iterate" }),
|
|
415
409
|
makeStep({ id: "after", dependsOn: ["iter"] }),
|
|
@@ -430,7 +424,7 @@ describe("expandIteration", () => {
|
|
|
430
424
|
// ─── initializeGraph ─────────────────────────────────────────────────────
|
|
431
425
|
|
|
432
426
|
describe("initializeGraph", () => {
|
|
433
|
-
it("converts a valid 3-step definition to graph with all pending steps", () => {
|
|
427
|
+
it("converts a valid 3-step definition to graph with all pending steps", (t) => {
|
|
434
428
|
const def: WorkflowDefinition = {
|
|
435
429
|
version: 1,
|
|
436
430
|
name: "test-workflow",
|
|
@@ -465,7 +459,7 @@ describe("initializeGraph", () => {
|
|
|
465
459
|
assert.deepStrictEqual(graph.steps[2].dependsOn, ["s1", "s2"]);
|
|
466
460
|
});
|
|
467
461
|
|
|
468
|
-
it("is also exported as graphFromDefinition (backward compat)", () => {
|
|
462
|
+
it("is also exported as graphFromDefinition (backward compat)", (t) => {
|
|
469
463
|
assert.equal(graphFromDefinition, initializeGraph);
|
|
470
464
|
});
|
|
471
465
|
});
|
|
@@ -473,7 +467,7 @@ describe("initializeGraph", () => {
|
|
|
473
467
|
// ─── Atomic write safety ─────────────────────────────────────────────────
|
|
474
468
|
|
|
475
469
|
describe("atomic write safety", () => {
|
|
476
|
-
it("final file exists and .tmp file does not exist after write", () => {
|
|
470
|
+
it("final file exists and .tmp file does not exist after write", (t) => {
|
|
477
471
|
const dir = makeTmpDir();
|
|
478
472
|
try {
|
|
479
473
|
const graph = makeGraph([makeStep({ id: "s1" })]);
|
|
@@ -486,7 +480,7 @@ describe("atomic write safety", () => {
|
|
|
486
480
|
}
|
|
487
481
|
});
|
|
488
482
|
|
|
489
|
-
it("YAML content is valid and parseable", () => {
|
|
483
|
+
it("YAML content is valid and parseable", (t) => {
|
|
490
484
|
const dir = makeTmpDir();
|
|
491
485
|
try {
|
|
492
486
|
const graph = makeGraph([makeStep({ id: "s1" })]);
|
|
@@ -507,7 +501,7 @@ describe("atomic write safety", () => {
|
|
|
507
501
|
// ─── YAML snake_case / camelCase boundary ────────────────────────────────
|
|
508
502
|
|
|
509
503
|
describe("YAML snake_case / camelCase boundary", () => {
|
|
510
|
-
it("writes snake_case to disk and reads back as camelCase", () => {
|
|
504
|
+
it("writes snake_case to disk and reads back as camelCase", (t) => {
|
|
511
505
|
const dir = makeTmpDir();
|
|
512
506
|
try {
|
|
513
507
|
const graph = makeGraph([
|
|
@@ -541,7 +535,7 @@ describe("YAML snake_case / camelCase boundary", () => {
|
|
|
541
535
|
}
|
|
542
536
|
});
|
|
543
537
|
|
|
544
|
-
it("omits optional fields from YAML when undefined", () => {
|
|
538
|
+
it("omits optional fields from YAML when undefined", (t) => {
|
|
545
539
|
const dir = makeTmpDir();
|
|
546
540
|
try {
|
|
547
541
|
const graph = makeGraph([
|
|
@@ -565,7 +559,7 @@ describe("YAML snake_case / camelCase boundary", () => {
|
|
|
565
559
|
// ─── Edge cases ──────────────────────────────────────────────────────────
|
|
566
560
|
|
|
567
561
|
describe("edge cases", () => {
|
|
568
|
-
it("handles empty items array in expandIteration", () => {
|
|
562
|
+
it("handles empty items array in expandIteration", (t) => {
|
|
569
563
|
const graph = makeGraph([
|
|
570
564
|
makeStep({ id: "iter" }),
|
|
571
565
|
]);
|
|
@@ -576,7 +570,7 @@ describe("edge cases", () => {
|
|
|
576
570
|
assert.equal(expanded.steps[0].status, "expanded");
|
|
577
571
|
});
|
|
578
572
|
|
|
579
|
-
it("handles graph with single step", () => {
|
|
573
|
+
it("handles graph with single step", (t) => {
|
|
580
574
|
const graph = makeGraph([makeStep({ id: "only" })]);
|
|
581
575
|
const next = getNextPendingStep(graph);
|
|
582
576
|
assert.equal(next?.id, "only");
|
|
@@ -585,7 +579,7 @@ describe("edge cases", () => {
|
|
|
585
579
|
assert.equal(getNextPendingStep(completed), null);
|
|
586
580
|
});
|
|
587
581
|
|
|
588
|
-
it("initializeGraph handles steps with empty requires", () => {
|
|
582
|
+
it("initializeGraph handles steps with empty requires", (t) => {
|
|
589
583
|
const def: WorkflowDefinition = {
|
|
590
584
|
version: 1,
|
|
591
585
|
name: "empty-requires",
|