gsd-pi 2.58.0-dev.778d6ac → 2.58.0-dev.d63175c
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 +1 -1
- package/dist/cli.js +35 -49
- package/dist/headless-ui.d.ts +0 -17
- package/dist/headless-ui.js +3 -97
- package/dist/headless.js +6 -67
- package/dist/help-text.js +0 -1
- package/dist/onboarding.js +0 -44
- package/dist/resource-loader.js +1 -16
- package/dist/resources/agents/researcher.md +1 -1
- package/dist/resources/extensions/ask-user-questions.js +3 -16
- package/dist/resources/extensions/async-jobs/extension-manifest.json +1 -1
- package/dist/resources/extensions/bg-shell/extension-manifest.json +1 -1
- package/dist/resources/extensions/browser-tools/extension-manifest.json +1 -1
- package/dist/resources/extensions/claude-code-cli/partial-builder.js +6 -14
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +36 -59
- package/dist/resources/extensions/context7/extension-manifest.json +1 -1
- package/dist/resources/extensions/get-secrets-from-user.js +5 -8
- package/dist/resources/extensions/google-search/extension-manifest.json +1 -1
- package/dist/resources/extensions/google-search/index.js +1 -2
- package/dist/resources/extensions/gsd/auto/phases.js +21 -25
- package/dist/resources/extensions/gsd/auto-artifact-paths.js +2 -2
- package/dist/resources/extensions/gsd/auto-dashboard.js +20 -37
- package/dist/resources/extensions/gsd/auto-dispatch.js +2 -17
- package/dist/resources/extensions/gsd/auto-model-selection.js +3 -26
- package/dist/resources/extensions/gsd/auto-post-unit.js +4 -16
- package/dist/resources/extensions/gsd/auto-prompts.js +1 -1
- package/dist/resources/extensions/gsd/auto-recovery.js +5 -13
- package/dist/resources/extensions/gsd/auto-start.js +22 -35
- package/dist/resources/extensions/gsd/auto-worktree.js +12 -196
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +0 -32
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +8 -80
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +1 -32
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +18 -33
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +11 -44
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +0 -67
- package/dist/resources/extensions/gsd/captures.js +4 -56
- package/dist/resources/extensions/gsd/db-writer.js +8 -116
- package/dist/resources/extensions/gsd/doctor-git-checks.js +0 -28
- package/dist/resources/extensions/gsd/doctor-providers.js +1 -2
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +4 -5
- package/dist/resources/extensions/gsd/doctor.js +1 -3
- package/dist/resources/extensions/gsd/error-classifier.js +10 -13
- package/dist/resources/extensions/gsd/extension-manifest.json +1 -16
- package/dist/resources/extensions/gsd/forensics.js +20 -123
- package/dist/resources/extensions/gsd/git-service.js +1 -23
- package/dist/resources/extensions/gsd/gitignore.js +0 -33
- package/dist/resources/extensions/gsd/gsd-db.js +9 -36
- package/dist/resources/extensions/gsd/guided-flow.js +44 -106
- package/dist/resources/extensions/gsd/health-widget-core.js +0 -31
- package/dist/resources/extensions/gsd/health-widget.js +0 -17
- package/dist/resources/extensions/gsd/index.js +1 -1
- package/dist/resources/extensions/gsd/memory-extractor.js +0 -7
- package/dist/resources/extensions/gsd/migrate-external.js +1 -8
- package/dist/resources/extensions/gsd/model-cost-table.js +0 -18
- package/dist/resources/extensions/gsd/model-router.js +1 -35
- package/dist/resources/extensions/gsd/native-git-bridge.js +0 -17
- package/dist/resources/extensions/gsd/notifications.js +1 -16
- package/dist/resources/extensions/gsd/parallel-eligibility.js +2 -13
- package/dist/resources/extensions/gsd/parallel-merge.js +5 -78
- package/dist/resources/extensions/gsd/parsers-legacy.js +3 -20
- package/dist/resources/extensions/gsd/paths.js +0 -43
- package/dist/resources/extensions/gsd/preferences-models.js +1 -14
- package/dist/resources/extensions/gsd/preferences-types.js +1 -2
- package/dist/resources/extensions/gsd/preferences.js +16 -13
- package/dist/resources/extensions/gsd/prompt-loader.js +1 -4
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +2 -4
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +1 -1
- package/dist/resources/extensions/gsd/prompts/discuss.md +1 -1
- package/dist/resources/extensions/gsd/prompts/execute-task.md +1 -3
- package/dist/resources/extensions/gsd/prompts/forensics.md +2 -2
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +0 -2
- package/dist/resources/extensions/gsd/prompts/rethink.md +1 -1
- package/dist/resources/extensions/gsd/prompts/triage-captures.md +0 -1
- package/dist/resources/extensions/gsd/repo-identity.js +11 -205
- package/dist/resources/extensions/gsd/rethink.js +0 -5
- package/dist/resources/extensions/gsd/roadmap-slices.js +4 -5
- package/dist/resources/extensions/gsd/state.js +27 -85
- package/dist/resources/extensions/gsd/tests/dist-redirect.mjs +1 -20
- package/dist/resources/extensions/gsd/tools/complete-task.js +71 -34
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +2 -12
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +1 -29
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +3 -14
- package/dist/resources/extensions/gsd/triage-resolution.js +7 -22
- package/dist/resources/extensions/gsd/undo.js +2 -2
- package/dist/resources/extensions/gsd/unit-ownership.js +33 -164
- package/dist/resources/extensions/gsd/verdict-parser.js +8 -20
- package/dist/resources/extensions/gsd/workflow-manifest.js +5 -24
- package/dist/resources/extensions/gsd/workflow-projections.js +63 -95
- package/dist/resources/extensions/gsd/workflow-reconcile.js +5 -35
- package/dist/resources/extensions/gsd/workspace-index.js +0 -24
- package/dist/resources/extensions/gsd/worktree-manager.js +1 -105
- package/dist/resources/extensions/gsd/worktree-resolver.js +3 -20
- package/dist/resources/extensions/mcp-client/index.js +7 -11
- package/dist/resources/extensions/search-the-web/extension-manifest.json +1 -1
- package/dist/resources/extensions/shared/interview-ui.js +1 -11
- package/dist/resources/skills/create-gsd-extension/SKILL.md +3 -5
- package/dist/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +4 -5
- package/dist/resources/skills/create-gsd-extension/workflows/add-capability.md +2 -2
- package/dist/resources/skills/create-gsd-extension/workflows/create-extension.md +4 -4
- package/dist/resources/skills/create-gsd-extension/workflows/debug-extension.md +3 -5
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +17 -17
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
- package/dist/web/standalone/.next/required-server-files.json +1 -1
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- 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/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +2 -2
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- 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 +2 -2
- 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 +2 -2
- package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +2 -2
- 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 +2 -2
- 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 +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +17 -17
- package/dist/web/standalone/.next/server/chunks/2229.js +2 -2
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- 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/dist/web/standalone/.next/static/chunks/6502.8b732f67a11b11b4.js +9 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-a1c1e452c6b32d04.js → webpack-61d3afac6d0f0ce7.js} +1 -1
- package/dist/web/standalone/.next/static/css/a58ef8a151aa0493.css +1 -0
- package/dist/web/standalone/server.js +1 -1
- package/dist/web-mode.js +1 -2
- package/package.json +2 -2
- package/packages/native/dist/ast/index.js +5 -9
- package/packages/native/dist/ast/types.js +1 -2
- package/packages/native/dist/clipboard/index.js +7 -12
- package/packages/native/dist/clipboard/types.js +1 -2
- package/packages/native/dist/diff/index.js +7 -12
- package/packages/native/dist/diff/types.js +1 -2
- package/packages/native/dist/fd/index.js +3 -6
- package/packages/native/dist/fd/types.js +1 -2
- package/packages/native/dist/glob/index.js +5 -9
- package/packages/native/dist/glob/types.js +1 -2
- package/packages/native/dist/grep/index.js +5 -9
- package/packages/native/dist/grep/types.js +1 -2
- package/packages/native/dist/gsd-parser/index.js +11 -18
- package/packages/native/dist/gsd-parser/types.js +1 -2
- package/packages/native/dist/highlight/index.js +7 -12
- package/packages/native/dist/highlight/types.js +1 -2
- package/packages/native/dist/html/index.js +3 -6
- package/packages/native/dist/html/types.js +1 -2
- package/packages/native/dist/image/index.js +5 -10
- package/packages/native/dist/image/types.js +4 -7
- package/packages/native/dist/index.js +17 -70
- package/packages/native/dist/json-parse/index.js +8 -13
- package/packages/native/dist/native.js +10 -47
- package/packages/native/dist/ps/index.js +9 -15
- package/packages/native/dist/ps/types.js +1 -2
- package/packages/native/dist/stream-process/index.js +7 -12
- package/packages/native/dist/text/index.js +14 -24
- package/packages/native/dist/text/types.js +2 -5
- package/packages/native/dist/truncate/index.js +7 -12
- package/packages/native/dist/ttsr/index.js +7 -12
- package/packages/native/dist/ttsr/types.js +1 -2
- package/packages/native/dist/xxhash/index.js +5 -9
- package/packages/native/package.json +19 -19
- package/packages/native/src/native.ts +8 -9
- package/packages/pi-agent-core/dist/agent-loop.js +2 -3
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/dist/proxy.d.ts +1 -1
- package/packages/pi-agent-core/dist/proxy.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/proxy.js.map +1 -1
- package/packages/pi-agent-core/src/agent-loop.ts +2 -3
- package/packages/pi-agent-core/src/proxy.ts +1 -1
- package/packages/pi-ai/dist/env-api-keys.js +0 -1
- package/packages/pi-ai/dist/env-api-keys.js.map +1 -1
- package/packages/pi-ai/dist/index.d.ts +0 -1
- package/packages/pi-ai/dist/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/index.js +0 -1
- package/packages/pi-ai/dist/index.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.js +2 -19
- package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
- package/packages/pi-ai/dist/types.d.ts +3 -3
- package/packages/pi-ai/dist/types.d.ts.map +1 -1
- package/packages/pi-ai/dist/types.js.map +1 -1
- package/packages/pi-ai/dist/utils/json-parse.d.ts +0 -3
- package/packages/pi-ai/dist/utils/json-parse.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/json-parse.js +1 -24
- package/packages/pi-ai/dist/utils/json-parse.js.map +1 -1
- package/packages/pi-ai/src/env-api-keys.ts +0 -1
- package/packages/pi-ai/src/index.ts +0 -1
- package/packages/pi-ai/src/providers/anthropic-shared.ts +2 -17
- package/packages/pi-ai/src/types.ts +2 -3
- package/packages/pi-ai/src/utils/json-parse.ts +1 -28
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +0 -4
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +0 -31
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +1 -17
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js +2 -62
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/exec.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/exec.js +1 -3
- package/packages/pi-coding-agent/dist/core/exec.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/index.d.ts +0 -4
- package/packages/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/index.js +0 -2
- package/packages/pi-coding-agent/dist/core/extensions/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +0 -5
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +0 -5
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/core/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/index.js +1 -1
- package/packages/pi-coding-agent/dist/core/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/index.js +0 -3
- package/packages/pi-coding-agent/dist/core/lsp/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/lspmux.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/lspmux.js +0 -3
- package/packages/pi-coding-agent/dist/core/lsp/lspmux.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/messages.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/messages.js +2 -31
- package/packages/pi-coding-agent/dist/core/messages.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js +0 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.d.ts +0 -10
- package/packages/pi-coding-agent/dist/core/resource-loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.js +1 -12
- package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts +0 -6
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js +1 -48
- package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/hashline-read.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/hashline-read.js +3 -10
- package/packages/pi-coding-agent/dist/core/tools/hashline-read.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/read.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/read.js +4 -13
- package/packages/pi-coding-agent/dist/core/tools/read.js.map +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts +2 -2
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +1 -1
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +0 -4
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/remote-terminal.d.ts +0 -1
- package/packages/pi-coding-agent/dist/modes/rpc/remote-terminal.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/remote-terminal.js +0 -5
- package/packages/pi-coding-agent/dist/modes/rpc/remote-terminal.js.map +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +1 -38
- package/packages/pi-coding-agent/src/core/compaction/compaction.ts +1 -94
- package/packages/pi-coding-agent/src/core/exec.ts +1 -3
- package/packages/pi-coding-agent/src/core/extensions/index.ts +0 -4
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +0 -5
- package/packages/pi-coding-agent/src/core/index.ts +0 -6
- package/packages/pi-coding-agent/src/core/lsp/index.ts +0 -3
- package/packages/pi-coding-agent/src/core/lsp/lspmux.ts +0 -3
- package/packages/pi-coding-agent/src/core/messages.ts +2 -29
- package/packages/pi-coding-agent/src/core/model-resolver.ts +0 -1
- package/packages/pi-coding-agent/src/core/resource-loader.ts +1 -20
- package/packages/pi-coding-agent/src/core/retry-handler.ts +1 -52
- package/packages/pi-coding-agent/src/core/tools/hashline-read.ts +3 -11
- package/packages/pi-coding-agent/src/core/tools/read.ts +4 -14
- package/packages/pi-coding-agent/src/index.ts +0 -6
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +0 -7
- package/packages/pi-coding-agent/src/modes/rpc/remote-terminal.ts +0 -6
- package/packages/pi-tui/dist/terminal.d.ts +0 -2
- package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
- package/packages/pi-tui/dist/terminal.js +0 -9
- package/packages/pi-tui/dist/terminal.js.map +1 -1
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +0 -9
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/src/terminal.ts +0 -14
- package/packages/pi-tui/src/tui.ts +0 -8
- package/scripts/ensure-workspace-builds.cjs +14 -45
- package/src/resources/agents/researcher.md +1 -1
- package/src/resources/extensions/ask-user-questions.ts +3 -21
- package/src/resources/extensions/async-jobs/extension-manifest.json +1 -1
- package/src/resources/extensions/bg-shell/extension-manifest.json +1 -1
- package/src/resources/extensions/browser-tools/extension-manifest.json +1 -1
- package/src/resources/extensions/claude-code-cli/partial-builder.ts +6 -13
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +35 -63
- package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +0 -28
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +1 -108
- package/src/resources/extensions/context7/extension-manifest.json +1 -1
- package/src/resources/extensions/get-secrets-from-user.ts +5 -8
- package/src/resources/extensions/google-search/extension-manifest.json +1 -1
- package/src/resources/extensions/google-search/index.ts +1 -2
- package/src/resources/extensions/gsd/auto/loop-deps.ts +0 -1
- package/src/resources/extensions/gsd/auto/phases.ts +34 -43
- package/src/resources/extensions/gsd/auto-artifact-paths.ts +2 -2
- package/src/resources/extensions/gsd/auto-dashboard.ts +19 -37
- package/src/resources/extensions/gsd/auto-dispatch.ts +2 -18
- package/src/resources/extensions/gsd/auto-model-selection.ts +5 -26
- package/src/resources/extensions/gsd/auto-post-unit.ts +4 -18
- package/src/resources/extensions/gsd/auto-prompts.ts +1 -1
- package/src/resources/extensions/gsd/auto-recovery.ts +5 -12
- package/src/resources/extensions/gsd/auto-start.ts +26 -35
- package/src/resources/extensions/gsd/auto-worktree.ts +9 -190
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +0 -31
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +8 -85
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +1 -38
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +19 -31
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +11 -50
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +0 -75
- package/src/resources/extensions/gsd/captures.ts +3 -63
- package/src/resources/extensions/gsd/db-writer.ts +7 -140
- package/src/resources/extensions/gsd/doctor-git-checks.ts +0 -26
- package/src/resources/extensions/gsd/doctor-providers.ts +1 -2
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +4 -5
- package/src/resources/extensions/gsd/doctor.ts +1 -3
- package/src/resources/extensions/gsd/error-classifier.ts +11 -14
- package/src/resources/extensions/gsd/extension-manifest.json +1 -16
- package/src/resources/extensions/gsd/forensics.ts +20 -144
- package/src/resources/extensions/gsd/git-service.ts +3 -26
- package/src/resources/extensions/gsd/gitignore.ts +0 -33
- package/src/resources/extensions/gsd/gsd-db.ts +7 -43
- package/src/resources/extensions/gsd/guided-flow.ts +45 -114
- package/src/resources/extensions/gsd/health-widget-core.ts +0 -34
- package/src/resources/extensions/gsd/health-widget.ts +0 -17
- package/src/resources/extensions/gsd/index.ts +0 -1
- package/src/resources/extensions/gsd/memory-extractor.ts +0 -8
- package/src/resources/extensions/gsd/migrate-external.ts +1 -9
- package/src/resources/extensions/gsd/model-cost-table.ts +0 -19
- package/src/resources/extensions/gsd/model-router.ts +1 -35
- package/src/resources/extensions/gsd/native-git-bridge.ts +0 -17
- package/src/resources/extensions/gsd/notifications.ts +0 -16
- package/src/resources/extensions/gsd/parallel-eligibility.ts +2 -15
- package/src/resources/extensions/gsd/parallel-merge.ts +4 -87
- package/src/resources/extensions/gsd/parsers-legacy.ts +3 -22
- package/src/resources/extensions/gsd/paths.ts +0 -42
- package/src/resources/extensions/gsd/preferences-models.ts +1 -14
- package/src/resources/extensions/gsd/preferences-types.ts +1 -2
- package/src/resources/extensions/gsd/preferences.ts +15 -13
- package/src/resources/extensions/gsd/prompt-loader.ts +1 -4
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/complete-slice.md +2 -4
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +1 -1
- package/src/resources/extensions/gsd/prompts/discuss.md +1 -1
- package/src/resources/extensions/gsd/prompts/execute-task.md +1 -3
- package/src/resources/extensions/gsd/prompts/forensics.md +2 -2
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +0 -2
- package/src/resources/extensions/gsd/prompts/rethink.md +1 -1
- package/src/resources/extensions/gsd/prompts/triage-captures.md +0 -1
- package/src/resources/extensions/gsd/repo-identity.ts +11 -186
- package/src/resources/extensions/gsd/rethink.ts +0 -6
- package/src/resources/extensions/gsd/roadmap-slices.ts +4 -5
- package/src/resources/extensions/gsd/state.ts +32 -84
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +0 -29
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +1 -71
- package/src/resources/extensions/gsd/tests/captures.test.ts +0 -103
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +0 -27
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +0 -21
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +12 -7
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +5 -78
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +0 -29
- package/src/resources/extensions/gsd/tests/discuss-queued-milestones.test.ts +0 -40
- package/src/resources/extensions/gsd/tests/dist-redirect.mjs +1 -20
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +0 -117
- package/src/resources/extensions/gsd/tests/empty-db-reconciliation.test.ts +79 -0
- package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +0 -31
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +12 -125
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +0 -67
- package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +1 -111
- package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +0 -101
- package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +0 -59
- package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +0 -110
- package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +2 -85
- package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +0 -34
- package/src/resources/extensions/gsd/tests/model-router.test.ts +3 -68
- package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +0 -28
- package/src/resources/extensions/gsd/tests/notifications.test.ts +0 -45
- package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +1 -33
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +0 -29
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +0 -38
- package/src/resources/extensions/gsd/tests/reassess-handler.test.ts +0 -117
- package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +0 -97
- package/src/resources/extensions/gsd/tests/secure-env-collect.test.ts +0 -134
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +1 -2
- package/src/resources/extensions/gsd/tests/triage-resolution.test.ts +0 -8
- package/src/resources/extensions/gsd/tests/unit-ownership.test.ts +17 -100
- package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +1 -4
- package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +0 -48
- package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +0 -92
- package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +2 -4
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +1 -48
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +5 -29
- package/src/resources/extensions/gsd/tools/complete-task.ts +74 -36
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +1 -13
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +0 -36
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +2 -20
- package/src/resources/extensions/gsd/triage-resolution.ts +6 -23
- package/src/resources/extensions/gsd/types.ts +2 -4
- package/src/resources/extensions/gsd/undo.ts +2 -2
- package/src/resources/extensions/gsd/unit-ownership.ts +35 -206
- package/src/resources/extensions/gsd/verdict-parser.ts +6 -21
- package/src/resources/extensions/gsd/workflow-logger.ts +1 -3
- package/src/resources/extensions/gsd/workflow-manifest.ts +5 -22
- package/src/resources/extensions/gsd/workflow-projections.ts +64 -97
- package/src/resources/extensions/gsd/workflow-reconcile.ts +10 -39
- package/src/resources/extensions/gsd/workspace-index.ts +0 -30
- package/src/resources/extensions/gsd/worktree-manager.ts +1 -120
- package/src/resources/extensions/gsd/worktree-resolver.ts +3 -22
- package/src/resources/extensions/mcp-client/index.ts +7 -13
- package/src/resources/extensions/search-the-web/extension-manifest.json +1 -1
- package/src/resources/extensions/shared/interview-ui.ts +1 -12
- package/src/resources/skills/create-gsd-extension/SKILL.md +3 -5
- package/src/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +4 -5
- package/src/resources/skills/create-gsd-extension/workflows/add-capability.md +2 -2
- package/src/resources/skills/create-gsd-extension/workflows/create-extension.md +4 -4
- package/src/resources/skills/create-gsd-extension/workflows/debug-extension.md +3 -5
- package/dist/resources/extensions/gsd/milestone-validation-gates.js +0 -45
- package/dist/resources/extensions/ollama/index.js +0 -112
- package/dist/resources/extensions/ollama/model-capabilities.js +0 -115
- package/dist/resources/extensions/ollama/ollama-client.js +0 -168
- package/dist/resources/extensions/ollama/ollama-commands.js +0 -194
- package/dist/resources/extensions/ollama/ollama-discovery.js +0 -69
- package/dist/resources/extensions/ollama/ollama-tool.js +0 -184
- package/dist/resources/extensions/ollama/types.js +0 -2
- package/dist/startup-model-validation.d.ts +0 -39
- package/dist/startup-model-validation.js +0 -50
- package/dist/web/standalone/.next/static/chunks/6502.7593d7797a4b3999.js +0 -9
- package/dist/web/standalone/.next/static/css/f6e8833d46e738d8.css +0 -1
- package/packages/native/src/__tests__/module-compat.test.mjs +0 -91
- package/packages/pi-agent-core/src/agent-loop.test.ts +0 -45
- package/packages/pi-ai/dist/providers/anthropic-shared.test.d.ts +0 -2
- package/packages/pi-ai/dist/providers/anthropic-shared.test.d.ts.map +0 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.test.js +0 -25
- package/packages/pi-ai/dist/providers/anthropic-shared.test.js.map +0 -1
- package/packages/pi-ai/dist/utils/repair-tool-json.d.ts +0 -37
- package/packages/pi-ai/dist/utils/repair-tool-json.d.ts.map +0 -1
- package/packages/pi-ai/dist/utils/repair-tool-json.js +0 -75
- package/packages/pi-ai/dist/utils/repair-tool-json.js.map +0 -1
- package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.d.ts +0 -2
- package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.d.ts.map +0 -1
- package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js +0 -73
- package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js.map +0 -1
- package/packages/pi-ai/src/providers/anthropic-shared.test.ts +0 -29
- package/packages/pi-ai/src/utils/repair-tool-json.ts +0 -88
- package/packages/pi-ai/src/utils/tests/repair-tool-json.test.ts +0 -102
- package/packages/pi-coding-agent/dist/core/compaction/compaction.test.d.ts +0 -6
- package/packages/pi-coding-agent/dist/core/compaction/compaction.test.d.ts.map +0 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.test.js +0 -176
- package/packages/pi-coding-agent/dist/core/compaction/compaction.test.js.map +0 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.d.ts +0 -28
- package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.d.ts.map +0 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.js +0 -37
- package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.js.map +0 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.test.d.ts +0 -2
- package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.test.d.ts.map +0 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.test.js +0 -63
- package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.test.js.map +0 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-sort.d.ts +0 -19
- package/packages/pi-coding-agent/dist/core/extensions/extension-sort.d.ts.map +0 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-sort.js +0 -115
- package/packages/pi-coding-agent/dist/core/extensions/extension-sort.js.map +0 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-sort.test.d.ts +0 -2
- package/packages/pi-coding-agent/dist/core/extensions/extension-sort.test.d.ts.map +0 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-sort.test.js +0 -109
- package/packages/pi-coding-agent/dist/core/extensions/extension-sort.test.js.map +0 -1
- package/packages/pi-coding-agent/dist/core/image-overflow-recovery.d.ts +0 -44
- package/packages/pi-coding-agent/dist/core/image-overflow-recovery.d.ts.map +0 -1
- package/packages/pi-coding-agent/dist/core/image-overflow-recovery.js +0 -97
- package/packages/pi-coding-agent/dist/core/image-overflow-recovery.js.map +0 -1
- package/packages/pi-coding-agent/dist/core/image-overflow-recovery.test.d.ts +0 -2
- package/packages/pi-coding-agent/dist/core/image-overflow-recovery.test.d.ts.map +0 -1
- package/packages/pi-coding-agent/dist/core/image-overflow-recovery.test.js +0 -181
- package/packages/pi-coding-agent/dist/core/image-overflow-recovery.test.js.map +0 -1
- package/packages/pi-coding-agent/dist/core/messages.test.d.ts +0 -9
- package/packages/pi-coding-agent/dist/core/messages.test.d.ts.map +0 -1
- package/packages/pi-coding-agent/dist/core/messages.test.js +0 -86
- package/packages/pi-coding-agent/dist/core/messages.test.js.map +0 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.test.d.ts +0 -9
- package/packages/pi-coding-agent/dist/core/retry-handler.test.d.ts.map +0 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js +0 -193
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +0 -1
- package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.d.ts +0 -16
- package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.d.ts.map +0 -1
- package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js +0 -80
- package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js.map +0 -1
- package/packages/pi-coding-agent/src/core/compaction/compaction.test.ts +0 -236
- package/packages/pi-coding-agent/src/core/extensions/extension-manifest.test.ts +0 -77
- package/packages/pi-coding-agent/src/core/extensions/extension-manifest.ts +0 -62
- package/packages/pi-coding-agent/src/core/extensions/extension-sort.test.ts +0 -134
- package/packages/pi-coding-agent/src/core/extensions/extension-sort.ts +0 -137
- package/packages/pi-coding-agent/src/core/image-overflow-recovery.test.ts +0 -228
- package/packages/pi-coding-agent/src/core/image-overflow-recovery.ts +0 -118
- package/packages/pi-coding-agent/src/core/messages.test.ts +0 -114
- package/packages/pi-coding-agent/src/core/retry-handler.test.ts +0 -255
- package/packages/pi-coding-agent/src/core/tools/spawn-shell-windows.test.ts +0 -92
- package/src/resources/extensions/gsd/milestone-validation-gates.ts +0 -56
- package/src/resources/extensions/gsd/tests/auto-mode-interactive-guard.test.ts +0 -71
- package/src/resources/extensions/gsd/tests/cli-provider-rate-limit.test.ts +0 -47
- package/src/resources/extensions/gsd/tests/completion-hierarchy-guards.test.ts +0 -192
- package/src/resources/extensions/gsd/tests/db-path-worktree-symlink.test.ts +0 -131
- package/src/resources/extensions/gsd/tests/discord-invite-links.test.ts +0 -47
- package/src/resources/extensions/gsd/tests/discuss-empty-db-fallback.test.ts +0 -127
- package/src/resources/extensions/gsd/tests/dynamic-routing-default.test.ts +0 -20
- package/src/resources/extensions/gsd/tests/empty-content-abort-loop.test.ts +0 -74
- package/src/resources/extensions/gsd/tests/event-replay-idempotency.test.ts +0 -140
- package/src/resources/extensions/gsd/tests/forensics-context-persist.test.ts +0 -129
- package/src/resources/extensions/gsd/tests/forensics-db-completion.test.ts +0 -96
- package/src/resources/extensions/gsd/tests/gsdroot-worktree-detection.test.ts +0 -164
- package/src/resources/extensions/gsd/tests/guided-flow-dynamic-routing.test.ts +0 -135
- package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +0 -97
- package/src/resources/extensions/gsd/tests/hook-key-parsing.test.ts +0 -107
- package/src/resources/extensions/gsd/tests/integration/doctor-false-positives.test.ts +0 -243
- package/src/resources/extensions/gsd/tests/integration/gitignore-staging-2570.test.ts +0 -150
- package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +0 -959
- package/src/resources/extensions/gsd/tests/migrate-external-worktree.test.ts +0 -105
- package/src/resources/extensions/gsd/tests/milestone-status-authoritative.test.ts +0 -116
- package/src/resources/extensions/gsd/tests/parallel-commit-scope.test.ts +0 -159
- package/src/resources/extensions/gsd/tests/parallel-eligibility-ghost.test.ts +0 -150
- package/src/resources/extensions/gsd/tests/plan-milestone-title.test.ts +0 -70
- package/src/resources/extensions/gsd/tests/project-relocation-recovery.test.ts +0 -297
- package/src/resources/extensions/gsd/tests/prompt-loader-replacement.test.ts +0 -178
- package/src/resources/extensions/gsd/tests/prompt-tool-names.test.ts +0 -69
- package/src/resources/extensions/gsd/tests/queue-execution-guard.test.ts +0 -157
- package/src/resources/extensions/gsd/tests/quick-turn-end-cleanup.test.ts +0 -90
- package/src/resources/extensions/gsd/tests/reconciliation-edge-cases.test.ts +0 -162
- package/src/resources/extensions/gsd/tests/slice-disk-reconcile.test.ts +0 -233
- package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +0 -305
- package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +0 -405
- package/src/resources/extensions/gsd/tests/state-derivation-parity.test.ts +0 -257
- package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +0 -1628
- package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +0 -106
- package/src/resources/extensions/gsd/tests/stuck-detection-coverage.test.ts +0 -174
- package/src/resources/extensions/gsd/tests/summary-render-parity.test.ts +0 -221
- package/src/resources/extensions/gsd/tests/uat-stuck-loop-orphaned-worktree.test.ts +0 -289
- package/src/resources/extensions/gsd/tests/vacuum-recovery.test.ts +0 -154
- package/src/resources/extensions/gsd/tests/verdict-parser.test.ts +0 -156
- package/src/resources/extensions/gsd/tests/verification-operational-gate.test.ts +0 -82
- package/src/resources/extensions/gsd/tests/worktree-db-respawn-truncation.test.ts +0 -140
- package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +0 -101
- package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +0 -95
- package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +0 -55
- package/src/resources/extensions/ollama/index.ts +0 -130
- package/src/resources/extensions/ollama/model-capabilities.ts +0 -145
- package/src/resources/extensions/ollama/ollama-client.ts +0 -196
- package/src/resources/extensions/ollama/ollama-commands.ts +0 -248
- package/src/resources/extensions/ollama/ollama-discovery.ts +0 -106
- package/src/resources/extensions/ollama/ollama-tool.ts +0 -218
- package/src/resources/extensions/ollama/tests/model-capabilities.test.ts +0 -162
- package/src/resources/extensions/ollama/tests/ollama-client.test.ts +0 -38
- package/src/resources/extensions/ollama/tests/ollama-discovery.test.ts +0 -28
- package/src/resources/extensions/ollama/types.ts +0 -130
- package/src/resources/extensions/shared/tests/ask-user-freetext.test.ts +0 -156
- /package/dist/web/standalone/.next/static/{R0D4xaIPl5kg93edN7Oo0 → 5DLsjFHdSB6_a1EDQVjr7}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{R0D4xaIPl5kg93edN7Oo0 → 5DLsjFHdSB6_a1EDQVjr7}/_ssgManifest.js +0 -0
package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts
DELETED
|
@@ -1,959 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* state-machine-live-validation.test.ts — Live operational validation of the
|
|
3
|
-
* GSD state machine with real handlers, real DB, and real filesystem.
|
|
4
|
-
*
|
|
5
|
-
* Exercises every phase transition, completion guard, edge case, and reopen
|
|
6
|
-
* path end-to-end. This is NOT a unit test — it drives the actual tool handlers
|
|
7
|
-
* against a real temp directory with a real SQLite database.
|
|
8
|
-
*
|
|
9
|
-
* Findings reference: #3161 (state machine validation report)
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
// GSD State Machine Live Validation (#3161)
|
|
13
|
-
|
|
14
|
-
import { describe, test, beforeEach, afterEach } from "node:test";
|
|
15
|
-
import assert from "node:assert/strict";
|
|
16
|
-
import {
|
|
17
|
-
mkdtempSync,
|
|
18
|
-
mkdirSync,
|
|
19
|
-
writeFileSync,
|
|
20
|
-
readFileSync,
|
|
21
|
-
rmSync,
|
|
22
|
-
existsSync,
|
|
23
|
-
} from "node:fs";
|
|
24
|
-
import { tmpdir } from "node:os";
|
|
25
|
-
import { join } from "node:path";
|
|
26
|
-
|
|
27
|
-
// ── DB layer ──────────────────────────────────────────────────────────────
|
|
28
|
-
import {
|
|
29
|
-
openDatabase,
|
|
30
|
-
closeDatabase,
|
|
31
|
-
insertMilestone,
|
|
32
|
-
insertSlice,
|
|
33
|
-
insertTask,
|
|
34
|
-
getTask,
|
|
35
|
-
getSlice,
|
|
36
|
-
getMilestone,
|
|
37
|
-
getSliceTasks,
|
|
38
|
-
getMilestoneSlices,
|
|
39
|
-
updateTaskStatus,
|
|
40
|
-
updateSliceStatus,
|
|
41
|
-
updateMilestoneStatus,
|
|
42
|
-
} from "../../gsd-db.ts";
|
|
43
|
-
|
|
44
|
-
// ── Tool handlers ─────────────────────────────────────────────────────────
|
|
45
|
-
import { handleCompleteTask } from "../../tools/complete-task.ts";
|
|
46
|
-
import { handleCompleteSlice } from "../../tools/complete-slice.ts";
|
|
47
|
-
import { handleCompleteMilestone } from "../../tools/complete-milestone.ts";
|
|
48
|
-
import { handleReopenTask } from "../../tools/reopen-task.ts";
|
|
49
|
-
import { handleReopenSlice } from "../../tools/reopen-slice.ts";
|
|
50
|
-
|
|
51
|
-
// ── State derivation ──────────────────────────────────────────────────────
|
|
52
|
-
import {
|
|
53
|
-
deriveState,
|
|
54
|
-
deriveStateFromDb,
|
|
55
|
-
invalidateStateCache,
|
|
56
|
-
isGhostMilestone,
|
|
57
|
-
} from "../../state.ts";
|
|
58
|
-
|
|
59
|
-
// ── Status guards ─────────────────────────────────────────────────────────
|
|
60
|
-
import { isClosedStatus } from "../../status-guards.ts";
|
|
61
|
-
|
|
62
|
-
// ── Events ────────────────────────────────────────────────────────────────
|
|
63
|
-
import { readEvents } from "../../workflow-events.ts";
|
|
64
|
-
|
|
65
|
-
// ── Cache invalidation ───────────────────────────────────────────────────
|
|
66
|
-
import { invalidateAllCaches } from "../../cache.ts";
|
|
67
|
-
|
|
68
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
69
|
-
// Fixture Helpers
|
|
70
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
71
|
-
|
|
72
|
-
function makeTempDir(): string {
|
|
73
|
-
return mkdtempSync(join(tmpdir(), "gsd-live-validation-"));
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Create a realistic .gsd/ fixture with:
|
|
78
|
-
* - M001 milestone with ROADMAP, CONTEXT
|
|
79
|
-
* - S01 slice with PLAN (2 tasks T01, T02)
|
|
80
|
-
* - S02 slice with PLAN (1 task T01)
|
|
81
|
-
* - Task PLAN stubs for each task
|
|
82
|
-
* - REQUIREMENTS.md and DECISIONS.md
|
|
83
|
-
*/
|
|
84
|
-
function createFullFixture(): string {
|
|
85
|
-
const base = makeTempDir();
|
|
86
|
-
const gsdDir = join(base, ".gsd");
|
|
87
|
-
const m001Dir = join(gsdDir, "milestones", "M001");
|
|
88
|
-
const s01Dir = join(m001Dir, "slices", "S01");
|
|
89
|
-
const s01Tasks = join(s01Dir, "tasks");
|
|
90
|
-
const s02Dir = join(m001Dir, "slices", "S02");
|
|
91
|
-
const s02Tasks = join(s02Dir, "tasks");
|
|
92
|
-
|
|
93
|
-
mkdirSync(s01Tasks, { recursive: true });
|
|
94
|
-
mkdirSync(s02Tasks, { recursive: true });
|
|
95
|
-
|
|
96
|
-
// CONTEXT.md — needed to get past needs-discussion
|
|
97
|
-
writeFileSync(
|
|
98
|
-
join(m001Dir, "M001-CONTEXT.md"),
|
|
99
|
-
[
|
|
100
|
-
"# M001: Live Validation Milestone",
|
|
101
|
-
"",
|
|
102
|
-
"## Purpose",
|
|
103
|
-
"Validate the state machine end-to-end.",
|
|
104
|
-
].join("\n"),
|
|
105
|
-
);
|
|
106
|
-
|
|
107
|
-
// ROADMAP.md
|
|
108
|
-
writeFileSync(
|
|
109
|
-
join(m001Dir, "M001-ROADMAP.md"),
|
|
110
|
-
[
|
|
111
|
-
"# M001: Live Validation Milestone",
|
|
112
|
-
"",
|
|
113
|
-
"## Vision",
|
|
114
|
-
"Prove state machine correctness.",
|
|
115
|
-
"",
|
|
116
|
-
"## Success Criteria",
|
|
117
|
-
"- All operations succeed",
|
|
118
|
-
"",
|
|
119
|
-
"## Slices",
|
|
120
|
-
"",
|
|
121
|
-
"- [ ] **S01: First Feature** `risk:low` `depends:[]`",
|
|
122
|
-
" - After this: First feature proven.",
|
|
123
|
-
"",
|
|
124
|
-
"- [ ] **S02: Second Feature** `risk:low` `depends:[]`",
|
|
125
|
-
" - After this: Second feature proven.",
|
|
126
|
-
"",
|
|
127
|
-
"## Boundary Map",
|
|
128
|
-
"",
|
|
129
|
-
"| From | To | Produces | Consumes |",
|
|
130
|
-
"|------|----|----------|----------|",
|
|
131
|
-
"| S01 | terminal | feature-a | nothing |",
|
|
132
|
-
"| S02 | terminal | feature-b | nothing |",
|
|
133
|
-
].join("\n"),
|
|
134
|
-
);
|
|
135
|
-
|
|
136
|
-
// S01 PLAN
|
|
137
|
-
writeFileSync(
|
|
138
|
-
join(s01Dir, "S01-PLAN.md"),
|
|
139
|
-
[
|
|
140
|
-
"# S01: First Feature",
|
|
141
|
-
"",
|
|
142
|
-
"**Goal:** Implement first feature.",
|
|
143
|
-
"",
|
|
144
|
-
"## Tasks",
|
|
145
|
-
"",
|
|
146
|
-
"- [ ] **T01: Implementation** `est:30m`",
|
|
147
|
-
" - Do: Build it",
|
|
148
|
-
" - Verify: Run tests",
|
|
149
|
-
"",
|
|
150
|
-
"- [ ] **T02: Testing** `est:30m`",
|
|
151
|
-
" - Do: Write tests",
|
|
152
|
-
" - Verify: Run tests",
|
|
153
|
-
].join("\n"),
|
|
154
|
-
);
|
|
155
|
-
|
|
156
|
-
// S01 task plan stubs
|
|
157
|
-
writeFileSync(join(s01Tasks, "T01-PLAN.md"), "# T01 Plan\nImplement.\n");
|
|
158
|
-
writeFileSync(join(s01Tasks, "T02-PLAN.md"), "# T02 Plan\nTest.\n");
|
|
159
|
-
|
|
160
|
-
// S02 PLAN
|
|
161
|
-
writeFileSync(
|
|
162
|
-
join(s02Dir, "S02-PLAN.md"),
|
|
163
|
-
[
|
|
164
|
-
"# S02: Second Feature",
|
|
165
|
-
"",
|
|
166
|
-
"**Goal:** Implement second feature.",
|
|
167
|
-
"",
|
|
168
|
-
"## Tasks",
|
|
169
|
-
"",
|
|
170
|
-
"- [ ] **T01: Implementation** `est:30m`",
|
|
171
|
-
" - Do: Build it",
|
|
172
|
-
" - Verify: Run tests",
|
|
173
|
-
].join("\n"),
|
|
174
|
-
);
|
|
175
|
-
|
|
176
|
-
// S02 task plan stub
|
|
177
|
-
writeFileSync(join(s02Tasks, "T01-PLAN.md"), "# T01 Plan\nBuild.\n");
|
|
178
|
-
|
|
179
|
-
// REQUIREMENTS.md
|
|
180
|
-
writeFileSync(
|
|
181
|
-
join(gsdDir, "REQUIREMENTS.md"),
|
|
182
|
-
[
|
|
183
|
-
"# Requirements",
|
|
184
|
-
"",
|
|
185
|
-
"## Active",
|
|
186
|
-
"",
|
|
187
|
-
"| ID | Description | Owner |",
|
|
188
|
-
"|----|-------------|-------|",
|
|
189
|
-
"| R001 | Feature works | S01 |",
|
|
190
|
-
].join("\n"),
|
|
191
|
-
);
|
|
192
|
-
|
|
193
|
-
// DECISIONS.md
|
|
194
|
-
writeFileSync(
|
|
195
|
-
join(gsdDir, "DECISIONS.md"),
|
|
196
|
-
[
|
|
197
|
-
"# Decisions",
|
|
198
|
-
"",
|
|
199
|
-
"| ID | Decision | Choice | Rationale |",
|
|
200
|
-
"|----|----------|--------|-----------|",
|
|
201
|
-
].join("\n"),
|
|
202
|
-
);
|
|
203
|
-
|
|
204
|
-
return base;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
function makeTaskParams(
|
|
208
|
-
taskId: string,
|
|
209
|
-
sliceId: string,
|
|
210
|
-
milestoneId: string,
|
|
211
|
-
overrides?: Partial<Record<string, unknown>>,
|
|
212
|
-
): Record<string, unknown> {
|
|
213
|
-
return {
|
|
214
|
-
taskId,
|
|
215
|
-
sliceId,
|
|
216
|
-
milestoneId,
|
|
217
|
-
oneLiner: `Completed ${taskId}`,
|
|
218
|
-
narrative: `Implemented ${taskId} with full coverage.`,
|
|
219
|
-
verification: "All tests pass.",
|
|
220
|
-
keyFiles: ["src/feature.ts"],
|
|
221
|
-
keyDecisions: [],
|
|
222
|
-
deviations: "None.",
|
|
223
|
-
knownIssues: "None.",
|
|
224
|
-
blockerDiscovered: false,
|
|
225
|
-
verificationEvidence: [
|
|
226
|
-
{ command: "npm test", exitCode: 0, verdict: "pass", durationMs: 1000 },
|
|
227
|
-
],
|
|
228
|
-
...overrides,
|
|
229
|
-
};
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
function makeSliceParams(
|
|
233
|
-
sliceId: string,
|
|
234
|
-
milestoneId: string,
|
|
235
|
-
): Record<string, unknown> {
|
|
236
|
-
return {
|
|
237
|
-
sliceId,
|
|
238
|
-
milestoneId,
|
|
239
|
-
sliceTitle: `${sliceId} Feature`,
|
|
240
|
-
oneLiner: `${sliceId} proven`,
|
|
241
|
-
narrative: "All tasks completed.",
|
|
242
|
-
verification: "Tests pass.",
|
|
243
|
-
keyFiles: ["src/feature.ts"],
|
|
244
|
-
keyDecisions: [],
|
|
245
|
-
patternsEstablished: [],
|
|
246
|
-
observabilitySurfaces: [],
|
|
247
|
-
deviations: "None.",
|
|
248
|
-
knownLimitations: "None.",
|
|
249
|
-
followUps: "None.",
|
|
250
|
-
requirementsAdvanced: [],
|
|
251
|
-
requirementsValidated: [],
|
|
252
|
-
requirementsSurfaced: [],
|
|
253
|
-
requirementsInvalidated: [],
|
|
254
|
-
filesModified: [{ path: "src/feature.ts", description: "Feature" }],
|
|
255
|
-
uatContent: "Acceptance criteria met.",
|
|
256
|
-
provides: ["feature"],
|
|
257
|
-
requires: [],
|
|
258
|
-
affects: [],
|
|
259
|
-
drillDownPaths: [],
|
|
260
|
-
};
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
function makeMilestoneParams(milestoneId: string): Record<string, unknown> {
|
|
264
|
-
return {
|
|
265
|
-
milestoneId,
|
|
266
|
-
title: "Live Validation Milestone",
|
|
267
|
-
oneLiner: "Milestone proven end-to-end",
|
|
268
|
-
narrative: "All slices completed and verified.",
|
|
269
|
-
successCriteriaResults: "All criteria met.",
|
|
270
|
-
definitionOfDoneResults: "All items checked.",
|
|
271
|
-
requirementOutcomes: "All requirements satisfied.",
|
|
272
|
-
keyDecisions: ["Chose approach A"],
|
|
273
|
-
keyFiles: ["src/feature.ts"],
|
|
274
|
-
lessonsLearned: ["Integration testing is valuable"],
|
|
275
|
-
followUps: "None.",
|
|
276
|
-
deviations: "None.",
|
|
277
|
-
verificationPassed: true,
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
282
|
-
// Test Suite
|
|
283
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
284
|
-
|
|
285
|
-
describe("state-machine-live-validation", () => {
|
|
286
|
-
let base: string;
|
|
287
|
-
|
|
288
|
-
afterEach(() => {
|
|
289
|
-
closeDatabase();
|
|
290
|
-
if (base) rmSync(base, { recursive: true, force: true });
|
|
291
|
-
});
|
|
292
|
-
|
|
293
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
294
|
-
// PHASE 1: Full happy-path lifecycle
|
|
295
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
296
|
-
|
|
297
|
-
describe("happy path: full lifecycle M001 → complete", () => {
|
|
298
|
-
test("step 1: empty project derives pre-planning", async () => {
|
|
299
|
-
base = makeTempDir();
|
|
300
|
-
mkdirSync(join(base, ".gsd", "milestones"), { recursive: true });
|
|
301
|
-
const state = await deriveState(base);
|
|
302
|
-
assert.equal(state.phase, "pre-planning");
|
|
303
|
-
assert.equal(state.activeMilestone, null);
|
|
304
|
-
});
|
|
305
|
-
|
|
306
|
-
test("step 2: milestone with CONTEXT-DRAFT derives needs-discussion", async () => {
|
|
307
|
-
base = makeTempDir();
|
|
308
|
-
const mDir = join(base, ".gsd", "milestones", "M001");
|
|
309
|
-
mkdirSync(mDir, { recursive: true });
|
|
310
|
-
writeFileSync(join(mDir, "M001-CONTEXT-DRAFT.md"), "# Draft\nDraft context.\n");
|
|
311
|
-
invalidateStateCache();
|
|
312
|
-
const state = await deriveState(base);
|
|
313
|
-
assert.equal(state.phase, "needs-discussion");
|
|
314
|
-
assert.equal(state.activeMilestone?.id, "M001");
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
test("step 3: full fixture with ROADMAP+PLAN derives planning or executing", async () => {
|
|
318
|
-
base = createFullFixture();
|
|
319
|
-
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
320
|
-
invalidateStateCache();
|
|
321
|
-
const state = await deriveState(base);
|
|
322
|
-
// Without DB migration, filesystem path is used — should be planning or executing
|
|
323
|
-
assert.ok(
|
|
324
|
-
["planning", "executing", "pre-planning"].includes(state.phase),
|
|
325
|
-
`expected planning/executing/pre-planning, got: ${state.phase}`,
|
|
326
|
-
);
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
test("step 4: complete T01 in S01 — handler succeeds, DB reflects completion", async () => {
|
|
330
|
-
base = createFullFixture();
|
|
331
|
-
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
332
|
-
// Seed DB with hierarchy
|
|
333
|
-
insertMilestone({ id: "M001", title: "Live Validation", status: "active" });
|
|
334
|
-
insertSlice({ id: "S01", milestoneId: "M001", title: "First Feature", status: "in_progress" });
|
|
335
|
-
insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", title: "Implementation", status: "pending" });
|
|
336
|
-
insertTask({ id: "T02", sliceId: "S01", milestoneId: "M001", title: "Testing", status: "pending" });
|
|
337
|
-
|
|
338
|
-
const result = await handleCompleteTask(makeTaskParams("T01", "S01", "M001") as any, base);
|
|
339
|
-
assert.ok(!("error" in result), `expected success, got: ${JSON.stringify(result)}`);
|
|
340
|
-
|
|
341
|
-
// Verify DB state
|
|
342
|
-
const task = getTask("M001", "S01", "T01");
|
|
343
|
-
assert.ok(task, "T01 should exist in DB");
|
|
344
|
-
assert.ok(isClosedStatus(task!.status), `T01 status should be closed, got: ${task!.status}`);
|
|
345
|
-
|
|
346
|
-
// Verify SUMMARY.md written to disk
|
|
347
|
-
const summaryPath = join(base, ".gsd", "milestones", "M001", "slices", "S01", "tasks", "T01-SUMMARY.md");
|
|
348
|
-
assert.ok(existsSync(summaryPath), "T01-SUMMARY.md should exist on disk");
|
|
349
|
-
|
|
350
|
-
// Verify event log entry
|
|
351
|
-
const events = readEvents(join(base, ".gsd", "event-log.jsonl"));
|
|
352
|
-
const taskEvent = events.find(e => e.cmd === "complete-task" && (e.params as any).taskId === "T01");
|
|
353
|
-
assert.ok(taskEvent, "event log should contain complete-task for T01");
|
|
354
|
-
});
|
|
355
|
-
|
|
356
|
-
test("step 5: complete T02 in S01 — both tasks now done", async () => {
|
|
357
|
-
base = createFullFixture();
|
|
358
|
-
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
359
|
-
insertMilestone({ id: "M001", title: "Live Validation", status: "active" });
|
|
360
|
-
insertSlice({ id: "S01", milestoneId: "M001", title: "First Feature", status: "in_progress" });
|
|
361
|
-
insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", title: "Implementation", status: "complete" });
|
|
362
|
-
insertTask({ id: "T02", sliceId: "S01", milestoneId: "M001", title: "Testing", status: "pending" });
|
|
363
|
-
|
|
364
|
-
const result = await handleCompleteTask(makeTaskParams("T02", "S01", "M001") as any, base);
|
|
365
|
-
assert.ok(!("error" in result), `expected success, got: ${JSON.stringify(result)}`);
|
|
366
|
-
|
|
367
|
-
// Both tasks complete
|
|
368
|
-
const tasks = getSliceTasks("M001", "S01");
|
|
369
|
-
assert.equal(tasks.length, 2);
|
|
370
|
-
assert.ok(tasks.every(t => isClosedStatus(t.status)), "all tasks should be closed");
|
|
371
|
-
});
|
|
372
|
-
|
|
373
|
-
test("step 6: complete slice S01 — all tasks done, slice closes", async () => {
|
|
374
|
-
base = createFullFixture();
|
|
375
|
-
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
376
|
-
insertMilestone({ id: "M001", title: "Live Validation", status: "active" });
|
|
377
|
-
insertSlice({ id: "S01", milestoneId: "M001", title: "First Feature", status: "in_progress" });
|
|
378
|
-
insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", title: "Impl", status: "complete" });
|
|
379
|
-
insertTask({ id: "T02", sliceId: "S01", milestoneId: "M001", title: "Test", status: "complete" });
|
|
380
|
-
|
|
381
|
-
const result = await handleCompleteSlice(makeSliceParams("S01", "M001") as any, base);
|
|
382
|
-
assert.ok(!("error" in result), `expected success, got: ${JSON.stringify(result)}`);
|
|
383
|
-
|
|
384
|
-
const slice = getSlice("M001", "S01");
|
|
385
|
-
assert.ok(slice, "S01 should exist");
|
|
386
|
-
assert.ok(isClosedStatus(slice!.status), `S01 should be closed, got: ${slice!.status}`);
|
|
387
|
-
|
|
388
|
-
// SUMMARY.md on disk
|
|
389
|
-
const summaryPath = join(base, ".gsd", "milestones", "M001", "slices", "S01", "S01-SUMMARY.md");
|
|
390
|
-
assert.ok(existsSync(summaryPath), "S01-SUMMARY.md should exist");
|
|
391
|
-
});
|
|
392
|
-
|
|
393
|
-
test("step 7: complete S02 task + slice — both slices done", async () => {
|
|
394
|
-
base = createFullFixture();
|
|
395
|
-
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
396
|
-
insertMilestone({ id: "M001", title: "Live Validation", status: "active" });
|
|
397
|
-
insertSlice({ id: "S01", milestoneId: "M001", title: "First", status: "complete" });
|
|
398
|
-
insertSlice({ id: "S02", milestoneId: "M001", title: "Second", status: "in_progress" });
|
|
399
|
-
insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", title: "Impl", status: "complete" });
|
|
400
|
-
insertTask({ id: "T01", sliceId: "S02", milestoneId: "M001", title: "Impl", status: "pending" });
|
|
401
|
-
|
|
402
|
-
// Complete task
|
|
403
|
-
const taskResult = await handleCompleteTask(makeTaskParams("T01", "S02", "M001") as any, base);
|
|
404
|
-
assert.ok(!("error" in taskResult), `task: ${JSON.stringify(taskResult)}`);
|
|
405
|
-
|
|
406
|
-
// Complete slice
|
|
407
|
-
const sliceResult = await handleCompleteSlice(makeSliceParams("S02", "M001") as any, base);
|
|
408
|
-
assert.ok(!("error" in sliceResult), `slice: ${JSON.stringify(sliceResult)}`);
|
|
409
|
-
|
|
410
|
-
// Both slices complete
|
|
411
|
-
const slices = getMilestoneSlices("M001");
|
|
412
|
-
assert.ok(slices.length >= 2, "should have 2+ slices");
|
|
413
|
-
assert.ok(slices.every(s => isClosedStatus(s.status)), "all slices should be closed");
|
|
414
|
-
});
|
|
415
|
-
|
|
416
|
-
test("step 8: complete milestone M001 — full lifecycle done", async () => {
|
|
417
|
-
base = createFullFixture();
|
|
418
|
-
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
419
|
-
insertMilestone({ id: "M001", title: "Live Validation", status: "active" });
|
|
420
|
-
insertSlice({ id: "S01", milestoneId: "M001", title: "First", status: "complete" });
|
|
421
|
-
insertSlice({ id: "S02", milestoneId: "M001", title: "Second", status: "complete" });
|
|
422
|
-
insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", title: "Impl", status: "complete" });
|
|
423
|
-
insertTask({ id: "T02", sliceId: "S01", milestoneId: "M001", title: "Test", status: "complete" });
|
|
424
|
-
insertTask({ id: "T01", sliceId: "S02", milestoneId: "M001", title: "Impl", status: "complete" });
|
|
425
|
-
|
|
426
|
-
const result = await handleCompleteMilestone(makeMilestoneParams("M001") as any, base);
|
|
427
|
-
assert.ok(!("error" in result), `expected success, got: ${JSON.stringify(result)}`);
|
|
428
|
-
|
|
429
|
-
const milestone = getMilestone("M001");
|
|
430
|
-
assert.ok(milestone, "M001 should exist");
|
|
431
|
-
assert.ok(isClosedStatus(milestone!.status), `M001 should be closed, got: ${milestone!.status}`);
|
|
432
|
-
|
|
433
|
-
// SUMMARY.md on disk
|
|
434
|
-
const summaryPath = join(base, ".gsd", "milestones", "M001", "M001-SUMMARY.md");
|
|
435
|
-
assert.ok(existsSync(summaryPath), "M001-SUMMARY.md should exist");
|
|
436
|
-
});
|
|
437
|
-
});
|
|
438
|
-
|
|
439
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
440
|
-
// PHASE 2: Completion guard edge cases
|
|
441
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
442
|
-
|
|
443
|
-
describe("completion guards — edge cases", () => {
|
|
444
|
-
test("cannot complete task with empty taskId", async () => {
|
|
445
|
-
base = createFullFixture();
|
|
446
|
-
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
447
|
-
const result = await handleCompleteTask(makeTaskParams("", "S01", "M001") as any, base);
|
|
448
|
-
assert.ok("error" in result);
|
|
449
|
-
assert.match((result as any).error, /taskId is required/);
|
|
450
|
-
});
|
|
451
|
-
|
|
452
|
-
test("cannot complete task in closed milestone", async () => {
|
|
453
|
-
base = createFullFixture();
|
|
454
|
-
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
455
|
-
insertMilestone({ id: "M001", title: "Done", status: "complete" });
|
|
456
|
-
insertSlice({ id: "S01", milestoneId: "M001" });
|
|
457
|
-
insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "pending" });
|
|
458
|
-
|
|
459
|
-
const result = await handleCompleteTask(makeTaskParams("T01", "S01", "M001") as any, base);
|
|
460
|
-
assert.ok("error" in result);
|
|
461
|
-
assert.match((result as any).error, /closed milestone/);
|
|
462
|
-
});
|
|
463
|
-
|
|
464
|
-
test("cannot complete task in closed slice", async () => {
|
|
465
|
-
base = createFullFixture();
|
|
466
|
-
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
467
|
-
insertMilestone({ id: "M001", title: "Active", status: "active" });
|
|
468
|
-
insertSlice({ id: "S01", milestoneId: "M001", status: "complete" });
|
|
469
|
-
insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "pending" });
|
|
470
|
-
|
|
471
|
-
const result = await handleCompleteTask(makeTaskParams("T01", "S01", "M001") as any, base);
|
|
472
|
-
assert.ok("error" in result);
|
|
473
|
-
assert.match((result as any).error, /closed slice/);
|
|
474
|
-
});
|
|
475
|
-
|
|
476
|
-
test("double task completion returns error (H5-related)", async () => {
|
|
477
|
-
base = createFullFixture();
|
|
478
|
-
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
479
|
-
insertMilestone({ id: "M001", title: "Active", status: "active" });
|
|
480
|
-
insertSlice({ id: "S01", milestoneId: "M001", status: "in_progress" });
|
|
481
|
-
insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "complete" });
|
|
482
|
-
|
|
483
|
-
const result = await handleCompleteTask(makeTaskParams("T01", "S01", "M001") as any, base);
|
|
484
|
-
assert.ok("error" in result);
|
|
485
|
-
assert.match((result as any).error, /already complete/);
|
|
486
|
-
});
|
|
487
|
-
|
|
488
|
-
test("cannot complete slice with zero tasks — vacuous truth guard", async () => {
|
|
489
|
-
base = createFullFixture();
|
|
490
|
-
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
491
|
-
insertMilestone({ id: "M001", title: "Active", status: "active" });
|
|
492
|
-
insertSlice({ id: "S01", milestoneId: "M001", status: "in_progress" });
|
|
493
|
-
// No tasks inserted
|
|
494
|
-
|
|
495
|
-
const result = await handleCompleteSlice(makeSliceParams("S01", "M001") as any, base);
|
|
496
|
-
assert.ok("error" in result);
|
|
497
|
-
assert.match((result as any).error, /no tasks found/);
|
|
498
|
-
});
|
|
499
|
-
|
|
500
|
-
test("cannot complete slice with incomplete tasks", async () => {
|
|
501
|
-
base = createFullFixture();
|
|
502
|
-
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
503
|
-
insertMilestone({ id: "M001", title: "Active", status: "active" });
|
|
504
|
-
insertSlice({ id: "S01", milestoneId: "M001", status: "in_progress" });
|
|
505
|
-
insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "complete" });
|
|
506
|
-
insertTask({ id: "T02", sliceId: "S01", milestoneId: "M001", status: "pending" });
|
|
507
|
-
|
|
508
|
-
const result = await handleCompleteSlice(makeSliceParams("S01", "M001") as any, base);
|
|
509
|
-
assert.ok("error" in result);
|
|
510
|
-
assert.match((result as any).error, /incomplete tasks/);
|
|
511
|
-
});
|
|
512
|
-
|
|
513
|
-
test("double slice completion returns error", async () => {
|
|
514
|
-
base = createFullFixture();
|
|
515
|
-
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
516
|
-
insertMilestone({ id: "M001", title: "Active", status: "active" });
|
|
517
|
-
insertSlice({ id: "S01", milestoneId: "M001", status: "complete" });
|
|
518
|
-
insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "complete" });
|
|
519
|
-
|
|
520
|
-
const result = await handleCompleteSlice(makeSliceParams("S01", "M001") as any, base);
|
|
521
|
-
assert.ok("error" in result);
|
|
522
|
-
assert.match((result as any).error, /already complete/);
|
|
523
|
-
});
|
|
524
|
-
|
|
525
|
-
test("cannot complete milestone with zero slices", async () => {
|
|
526
|
-
base = createFullFixture();
|
|
527
|
-
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
528
|
-
insertMilestone({ id: "M001", title: "Active", status: "active" });
|
|
529
|
-
|
|
530
|
-
const result = await handleCompleteMilestone(makeMilestoneParams("M001") as any, base);
|
|
531
|
-
assert.ok("error" in result);
|
|
532
|
-
assert.match((result as any).error, /no slices found/);
|
|
533
|
-
});
|
|
534
|
-
|
|
535
|
-
test("cannot complete milestone with incomplete slices", async () => {
|
|
536
|
-
base = createFullFixture();
|
|
537
|
-
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
538
|
-
insertMilestone({ id: "M001", title: "Active", status: "active" });
|
|
539
|
-
insertSlice({ id: "S01", milestoneId: "M001", status: "complete" });
|
|
540
|
-
insertSlice({ id: "S02", milestoneId: "M001", status: "in_progress" });
|
|
541
|
-
insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "complete" });
|
|
542
|
-
insertTask({ id: "T01", sliceId: "S02", milestoneId: "M001", status: "pending" });
|
|
543
|
-
|
|
544
|
-
const result = await handleCompleteMilestone(makeMilestoneParams("M001") as any, base);
|
|
545
|
-
assert.ok("error" in result);
|
|
546
|
-
assert.match((result as any).error, /incomplete slices/);
|
|
547
|
-
});
|
|
548
|
-
|
|
549
|
-
test("cannot complete milestone with incomplete tasks in complete slice (deep check)", async () => {
|
|
550
|
-
base = createFullFixture();
|
|
551
|
-
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
552
|
-
insertMilestone({ id: "M001", title: "Active", status: "active" });
|
|
553
|
-
// Slice marked complete but task is still pending — simulates inconsistent state
|
|
554
|
-
insertSlice({ id: "S01", milestoneId: "M001", status: "complete" });
|
|
555
|
-
insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "pending" });
|
|
556
|
-
|
|
557
|
-
const result = await handleCompleteMilestone(makeMilestoneParams("M001") as any, base);
|
|
558
|
-
assert.ok("error" in result);
|
|
559
|
-
assert.match((result as any).error, /incomplete tasks/);
|
|
560
|
-
});
|
|
561
|
-
|
|
562
|
-
test("cannot complete milestone without verificationPassed=true", async () => {
|
|
563
|
-
base = createFullFixture();
|
|
564
|
-
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
565
|
-
insertMilestone({ id: "M001", title: "Active", status: "active" });
|
|
566
|
-
insertSlice({ id: "S01", milestoneId: "M001", status: "complete" });
|
|
567
|
-
insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "complete" });
|
|
568
|
-
|
|
569
|
-
const params = makeMilestoneParams("M001");
|
|
570
|
-
params.verificationPassed = false;
|
|
571
|
-
const result = await handleCompleteMilestone(params as any, base);
|
|
572
|
-
assert.ok("error" in result);
|
|
573
|
-
assert.match((result as any).error, /verification did not pass/);
|
|
574
|
-
});
|
|
575
|
-
|
|
576
|
-
test("double milestone completion returns error", async () => {
|
|
577
|
-
base = createFullFixture();
|
|
578
|
-
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
579
|
-
insertMilestone({ id: "M001", title: "Done", status: "complete" });
|
|
580
|
-
insertSlice({ id: "S01", milestoneId: "M001", status: "complete" });
|
|
581
|
-
insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "complete" });
|
|
582
|
-
|
|
583
|
-
const result = await handleCompleteMilestone(makeMilestoneParams("M001") as any, base);
|
|
584
|
-
assert.ok("error" in result);
|
|
585
|
-
assert.match((result as any).error, /already complete/);
|
|
586
|
-
});
|
|
587
|
-
});
|
|
588
|
-
|
|
589
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
590
|
-
// PHASE 3: Reopen operations
|
|
591
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
592
|
-
|
|
593
|
-
describe("reopen operations", () => {
|
|
594
|
-
test("reopen task: resets completed task to pending", async () => {
|
|
595
|
-
base = createFullFixture();
|
|
596
|
-
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
597
|
-
insertMilestone({ id: "M001", title: "Active", status: "active" });
|
|
598
|
-
insertSlice({ id: "S01", milestoneId: "M001", status: "in_progress" });
|
|
599
|
-
insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "complete" });
|
|
600
|
-
|
|
601
|
-
const result = await handleReopenTask(
|
|
602
|
-
{ milestoneId: "M001", sliceId: "S01", taskId: "T01", reason: "Need to redo" },
|
|
603
|
-
base,
|
|
604
|
-
);
|
|
605
|
-
assert.ok(!("error" in result), `expected success: ${JSON.stringify(result)}`);
|
|
606
|
-
|
|
607
|
-
const task = getTask("M001", "S01", "T01");
|
|
608
|
-
assert.equal(task!.status, "pending");
|
|
609
|
-
});
|
|
610
|
-
|
|
611
|
-
test("cannot reopen task that is not complete", async () => {
|
|
612
|
-
base = createFullFixture();
|
|
613
|
-
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
614
|
-
insertMilestone({ id: "M001", title: "Active", status: "active" });
|
|
615
|
-
insertSlice({ id: "S01", milestoneId: "M001", status: "in_progress" });
|
|
616
|
-
insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "pending" });
|
|
617
|
-
|
|
618
|
-
const result = await handleReopenTask(
|
|
619
|
-
{ milestoneId: "M001", sliceId: "S01", taskId: "T01" },
|
|
620
|
-
base,
|
|
621
|
-
);
|
|
622
|
-
assert.ok("error" in result);
|
|
623
|
-
assert.match((result as any).error, /not complete/);
|
|
624
|
-
});
|
|
625
|
-
|
|
626
|
-
test("cannot reopen task in closed slice — must reopen slice first", async () => {
|
|
627
|
-
base = createFullFixture();
|
|
628
|
-
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
629
|
-
insertMilestone({ id: "M001", title: "Active", status: "active" });
|
|
630
|
-
insertSlice({ id: "S01", milestoneId: "M001", status: "complete" });
|
|
631
|
-
insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "complete" });
|
|
632
|
-
|
|
633
|
-
const result = await handleReopenTask(
|
|
634
|
-
{ milestoneId: "M001", sliceId: "S01", taskId: "T01" },
|
|
635
|
-
base,
|
|
636
|
-
);
|
|
637
|
-
assert.ok("error" in result);
|
|
638
|
-
assert.match((result as any).error, /closed slice/);
|
|
639
|
-
});
|
|
640
|
-
|
|
641
|
-
test("cannot reopen task in closed milestone", async () => {
|
|
642
|
-
base = createFullFixture();
|
|
643
|
-
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
644
|
-
insertMilestone({ id: "M001", title: "Done", status: "complete" });
|
|
645
|
-
insertSlice({ id: "S01", milestoneId: "M001", status: "complete" });
|
|
646
|
-
insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "complete" });
|
|
647
|
-
|
|
648
|
-
const result = await handleReopenTask(
|
|
649
|
-
{ milestoneId: "M001", sliceId: "S01", taskId: "T01" },
|
|
650
|
-
base,
|
|
651
|
-
);
|
|
652
|
-
assert.ok("error" in result);
|
|
653
|
-
assert.match((result as any).error, /closed milestone/);
|
|
654
|
-
});
|
|
655
|
-
|
|
656
|
-
test("reopen slice: resets slice to in_progress and all tasks to pending", async () => {
|
|
657
|
-
base = createFullFixture();
|
|
658
|
-
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
659
|
-
insertMilestone({ id: "M001", title: "Active", status: "active" });
|
|
660
|
-
insertSlice({ id: "S01", milestoneId: "M001", status: "complete" });
|
|
661
|
-
insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "complete" });
|
|
662
|
-
insertTask({ id: "T02", sliceId: "S01", milestoneId: "M001", status: "complete" });
|
|
663
|
-
|
|
664
|
-
const result = await handleReopenSlice(
|
|
665
|
-
{ milestoneId: "M001", sliceId: "S01", reason: "Need rework" },
|
|
666
|
-
base,
|
|
667
|
-
);
|
|
668
|
-
assert.ok(!("error" in result), `expected success: ${JSON.stringify(result)}`);
|
|
669
|
-
assert.equal((result as any).tasksReset, 2);
|
|
670
|
-
|
|
671
|
-
// Verify slice state
|
|
672
|
-
const slice = getSlice("M001", "S01");
|
|
673
|
-
assert.equal(slice!.status, "in_progress");
|
|
674
|
-
|
|
675
|
-
// Verify all tasks reset to pending
|
|
676
|
-
const tasks = getSliceTasks("M001", "S01");
|
|
677
|
-
assert.ok(tasks.every(t => t.status === "pending"), "all tasks should be pending after slice reopen");
|
|
678
|
-
});
|
|
679
|
-
|
|
680
|
-
test("cannot reopen slice in closed milestone", async () => {
|
|
681
|
-
base = createFullFixture();
|
|
682
|
-
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
683
|
-
insertMilestone({ id: "M001", title: "Done", status: "complete" });
|
|
684
|
-
insertSlice({ id: "S01", milestoneId: "M001", status: "complete" });
|
|
685
|
-
|
|
686
|
-
const result = await handleReopenSlice(
|
|
687
|
-
{ milestoneId: "M001", sliceId: "S01" },
|
|
688
|
-
base,
|
|
689
|
-
);
|
|
690
|
-
assert.ok("error" in result);
|
|
691
|
-
assert.match((result as any).error, /closed milestone/);
|
|
692
|
-
});
|
|
693
|
-
|
|
694
|
-
test("no reopen-milestone tool exists — milestone completion is irrevocable (H5)", async () => {
|
|
695
|
-
// This test documents the H5 finding: there is no handleReopenMilestone function.
|
|
696
|
-
// A completed milestone can only be undone via direct DB manipulation.
|
|
697
|
-
base = createFullFixture();
|
|
698
|
-
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
699
|
-
insertMilestone({ id: "M001", title: "Done", status: "complete" });
|
|
700
|
-
|
|
701
|
-
const milestone = getMilestone("M001");
|
|
702
|
-
assert.ok(isClosedStatus(milestone!.status), "milestone is closed");
|
|
703
|
-
|
|
704
|
-
// The only escape is direct DB manipulation — no handler exists
|
|
705
|
-
updateMilestoneStatus("M001", "active", null);
|
|
706
|
-
const reopened = getMilestone("M001");
|
|
707
|
-
assert.equal(reopened!.status, "active", "direct DB manipulation can reopen, but no tool exposes this");
|
|
708
|
-
});
|
|
709
|
-
});
|
|
710
|
-
|
|
711
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
712
|
-
// PHASE 4: Phantom parents and auto-creation (H6)
|
|
713
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
714
|
-
|
|
715
|
-
describe("phantom parent auto-creation (H6)", () => {
|
|
716
|
-
test("completing task for non-existent milestone/slice auto-creates them", async () => {
|
|
717
|
-
base = createFullFixture();
|
|
718
|
-
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
719
|
-
// No milestone or slice pre-inserted — handler will auto-create
|
|
720
|
-
|
|
721
|
-
const result = await handleCompleteTask(makeTaskParams("T01", "S99", "M099") as any, base);
|
|
722
|
-
assert.ok(!("error" in result), `expected success: ${JSON.stringify(result)}`);
|
|
723
|
-
|
|
724
|
-
// Phantom milestone created
|
|
725
|
-
const milestone = getMilestone("M099");
|
|
726
|
-
assert.ok(milestone, "phantom milestone M099 should exist");
|
|
727
|
-
assert.equal(milestone!.title, "", "phantom milestone has empty title");
|
|
728
|
-
|
|
729
|
-
// Phantom slice created
|
|
730
|
-
const slice = getSlice("M099", "S99");
|
|
731
|
-
assert.ok(slice, "phantom slice S99 should exist");
|
|
732
|
-
});
|
|
733
|
-
|
|
734
|
-
test("completing slice for non-existent milestone auto-creates it", async () => {
|
|
735
|
-
base = createFullFixture();
|
|
736
|
-
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
737
|
-
// Insert task to satisfy completion guard
|
|
738
|
-
insertMilestone({ id: "M099" });
|
|
739
|
-
insertSlice({ id: "S99", milestoneId: "M099" });
|
|
740
|
-
insertTask({ id: "T01", sliceId: "S99", milestoneId: "M099", status: "complete" });
|
|
741
|
-
|
|
742
|
-
const result = await handleCompleteSlice(makeSliceParams("S99", "M099") as any, base);
|
|
743
|
-
assert.ok(!("error" in result), `expected success: ${JSON.stringify(result)}`);
|
|
744
|
-
});
|
|
745
|
-
});
|
|
746
|
-
|
|
747
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
748
|
-
// PHASE 5: State derivation consistency
|
|
749
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
750
|
-
|
|
751
|
-
describe("state derivation with live DB", () => {
|
|
752
|
-
test("deriveStateFromDb reflects task completion immediately", async () => {
|
|
753
|
-
base = createFullFixture();
|
|
754
|
-
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
755
|
-
insertMilestone({ id: "M001", title: "Active", status: "active" });
|
|
756
|
-
insertSlice({ id: "S01", milestoneId: "M001", title: "First", status: "in_progress" });
|
|
757
|
-
insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "pending" });
|
|
758
|
-
insertTask({ id: "T02", sliceId: "S01", milestoneId: "M001", status: "pending" });
|
|
759
|
-
|
|
760
|
-
invalidateStateCache();
|
|
761
|
-
const stateBefore = await deriveStateFromDb(base);
|
|
762
|
-
assert.equal(stateBefore.phase, "executing", `before: expected executing, got ${stateBefore.phase}`);
|
|
763
|
-
|
|
764
|
-
// Complete T01
|
|
765
|
-
updateTaskStatus("M001", "S01", "T01", "complete", new Date().toISOString());
|
|
766
|
-
invalidateStateCache();
|
|
767
|
-
const stateAfterT01 = await deriveStateFromDb(base);
|
|
768
|
-
// Still executing — T02 is pending
|
|
769
|
-
assert.equal(stateAfterT01.phase, "executing", `after T01: expected executing, got ${stateAfterT01.phase}`);
|
|
770
|
-
|
|
771
|
-
// Complete T02
|
|
772
|
-
updateTaskStatus("M001", "S01", "T02", "complete", new Date().toISOString());
|
|
773
|
-
invalidateStateCache();
|
|
774
|
-
const stateAfterT02 = await deriveStateFromDb(base);
|
|
775
|
-
// All tasks done → summarizing
|
|
776
|
-
assert.equal(stateAfterT02.phase, "summarizing", `after T02: expected summarizing, got ${stateAfterT02.phase}`);
|
|
777
|
-
});
|
|
778
|
-
|
|
779
|
-
test("deriveStateFromDb reflects slice completion → next slice or validating", async () => {
|
|
780
|
-
base = createFullFixture();
|
|
781
|
-
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
782
|
-
insertMilestone({ id: "M001", title: "Active", status: "active" });
|
|
783
|
-
insertSlice({ id: "S01", milestoneId: "M001", title: "First", status: "complete" });
|
|
784
|
-
insertSlice({ id: "S02", milestoneId: "M001", title: "Second", status: "in_progress" });
|
|
785
|
-
insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "complete" });
|
|
786
|
-
insertTask({ id: "T01", sliceId: "S02", milestoneId: "M001", status: "pending" });
|
|
787
|
-
|
|
788
|
-
invalidateStateCache();
|
|
789
|
-
const state = await deriveStateFromDb(base);
|
|
790
|
-
// S01 done, S02 has pending task → executing
|
|
791
|
-
assert.equal(state.phase, "executing", `expected executing for S02, got ${state.phase}`);
|
|
792
|
-
assert.equal(state.activeSlice?.id, "S02", "active slice should be S02");
|
|
793
|
-
});
|
|
794
|
-
|
|
795
|
-
test("deriveStateFromDb with all slices done → validating-milestone", async () => {
|
|
796
|
-
base = createFullFixture();
|
|
797
|
-
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
798
|
-
insertMilestone({ id: "M001", title: "Active", status: "active" });
|
|
799
|
-
insertSlice({ id: "S01", milestoneId: "M001", title: "First", status: "complete" });
|
|
800
|
-
insertSlice({ id: "S02", milestoneId: "M001", title: "Second", status: "complete" });
|
|
801
|
-
insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "complete" });
|
|
802
|
-
insertTask({ id: "T01", sliceId: "S02", milestoneId: "M001", status: "complete" });
|
|
803
|
-
|
|
804
|
-
invalidateStateCache();
|
|
805
|
-
const state = await deriveStateFromDb(base);
|
|
806
|
-
assert.equal(state.phase, "validating-milestone", `expected validating-milestone, got ${state.phase}`);
|
|
807
|
-
});
|
|
808
|
-
|
|
809
|
-
test("ghost milestone is skipped by deriveState", async () => {
|
|
810
|
-
base = makeTempDir();
|
|
811
|
-
const gsdDir = join(base, ".gsd", "milestones");
|
|
812
|
-
// M001 is ghost — empty dir
|
|
813
|
-
mkdirSync(join(gsdDir, "M001"), { recursive: true });
|
|
814
|
-
// M002 has content
|
|
815
|
-
mkdirSync(join(gsdDir, "M002"), { recursive: true });
|
|
816
|
-
writeFileSync(join(gsdDir, "M002", "M002-CONTEXT-DRAFT.md"), "# Draft\nContent.\n");
|
|
817
|
-
|
|
818
|
-
assert.ok(isGhostMilestone(base, "M001"), "M001 should be ghost");
|
|
819
|
-
assert.ok(!isGhostMilestone(base, "M002"), "M002 should not be ghost");
|
|
820
|
-
|
|
821
|
-
invalidateStateCache();
|
|
822
|
-
const state = await deriveState(base);
|
|
823
|
-
assert.equal(state.activeMilestone?.id, "M002", "should skip ghost M001 and use M002");
|
|
824
|
-
});
|
|
825
|
-
});
|
|
826
|
-
|
|
827
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
828
|
-
// PHASE 6: Event log integrity
|
|
829
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
830
|
-
|
|
831
|
-
describe("event log integrity across operations", () => {
|
|
832
|
-
test("full operation sequence produces correct event log", async () => {
|
|
833
|
-
base = createFullFixture();
|
|
834
|
-
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
835
|
-
insertMilestone({ id: "M001", title: "Active", status: "active" });
|
|
836
|
-
insertSlice({ id: "S01", milestoneId: "M001", title: "First", status: "in_progress" });
|
|
837
|
-
insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "pending" });
|
|
838
|
-
insertTask({ id: "T02", sliceId: "S01", milestoneId: "M001", status: "pending" });
|
|
839
|
-
|
|
840
|
-
// Complete T01
|
|
841
|
-
await handleCompleteTask(makeTaskParams("T01", "S01", "M001") as any, base);
|
|
842
|
-
// Complete T02
|
|
843
|
-
await handleCompleteTask(makeTaskParams("T02", "S01", "M001") as any, base);
|
|
844
|
-
// Complete S01
|
|
845
|
-
await handleCompleteSlice(makeSliceParams("S01", "M001") as any, base);
|
|
846
|
-
|
|
847
|
-
const events = readEvents(join(base, ".gsd", "event-log.jsonl"));
|
|
848
|
-
|
|
849
|
-
// Should have 3 events: 2 task completions + 1 slice completion
|
|
850
|
-
assert.ok(events.length >= 3, `expected ≥3 events, got ${events.length}`);
|
|
851
|
-
|
|
852
|
-
const taskEvents = events.filter(e => e.cmd === "complete-task");
|
|
853
|
-
assert.equal(taskEvents.length, 2, "2 task completion events");
|
|
854
|
-
|
|
855
|
-
const sliceEvents = events.filter(e => e.cmd === "complete-slice");
|
|
856
|
-
assert.equal(sliceEvents.length, 1, "1 slice completion event");
|
|
857
|
-
|
|
858
|
-
// Events are ordered chronologically
|
|
859
|
-
for (let i = 1; i < events.length; i++) {
|
|
860
|
-
assert.ok(
|
|
861
|
-
events[i]!.ts >= events[i - 1]!.ts,
|
|
862
|
-
`events should be chronologically ordered: ${events[i - 1]!.ts} <= ${events[i]!.ts}`,
|
|
863
|
-
);
|
|
864
|
-
}
|
|
865
|
-
|
|
866
|
-
// All events have hashes and session IDs
|
|
867
|
-
for (const event of events) {
|
|
868
|
-
assert.ok(event.hash, "event should have hash");
|
|
869
|
-
assert.ok(event.session_id, "event should have session_id");
|
|
870
|
-
}
|
|
871
|
-
});
|
|
872
|
-
|
|
873
|
-
test("reopen operations produce events", async () => {
|
|
874
|
-
base = createFullFixture();
|
|
875
|
-
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
876
|
-
insertMilestone({ id: "M001", title: "Active", status: "active" });
|
|
877
|
-
insertSlice({ id: "S01", milestoneId: "M001", status: "in_progress" });
|
|
878
|
-
insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "complete" });
|
|
879
|
-
|
|
880
|
-
await handleReopenTask(
|
|
881
|
-
{ milestoneId: "M001", sliceId: "S01", taskId: "T01", reason: "redo" },
|
|
882
|
-
base,
|
|
883
|
-
);
|
|
884
|
-
|
|
885
|
-
const events = readEvents(join(base, ".gsd", "event-log.jsonl"));
|
|
886
|
-
const reopenEvent = events.find(e => e.cmd === "reopen-task");
|
|
887
|
-
assert.ok(reopenEvent, "should have reopen-task event");
|
|
888
|
-
assert.equal((reopenEvent!.params as any).taskId, "T01");
|
|
889
|
-
assert.equal((reopenEvent!.params as any).reason, "redo");
|
|
890
|
-
});
|
|
891
|
-
});
|
|
892
|
-
|
|
893
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
894
|
-
// PHASE 7: Reopen-then-redo cycle
|
|
895
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
896
|
-
|
|
897
|
-
describe("reopen-then-redo cycle", () => {
|
|
898
|
-
test("complete → reopen → M12: stale SUMMARY causes immediate auto-reconcile", async () => {
|
|
899
|
-
// Finding M12: reopen-task does NOT delete the SUMMARY.md from disk.
|
|
900
|
-
// The reopen handler's own post-mutation hook calls renderAllProjections
|
|
901
|
-
// which triggers deriveStateFromDb, which sees the stale SUMMARY.md and
|
|
902
|
-
// auto-reconciles the task BACK to "complete" (#2514) within the same call.
|
|
903
|
-
//
|
|
904
|
-
// Result: the reopen is effectively a no-op when filesystem artifacts exist.
|
|
905
|
-
base = createFullFixture();
|
|
906
|
-
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
907
|
-
insertMilestone({ id: "M001", title: "Active", status: "active" });
|
|
908
|
-
insertSlice({ id: "S01", milestoneId: "M001", title: "First", status: "in_progress" });
|
|
909
|
-
insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "pending" });
|
|
910
|
-
|
|
911
|
-
// Complete — writes T01-SUMMARY.md to disk
|
|
912
|
-
const r1 = await handleCompleteTask(makeTaskParams("T01", "S01", "M001") as any, base);
|
|
913
|
-
assert.ok(!("error" in r1), `first complete: ${JSON.stringify(r1)}`);
|
|
914
|
-
|
|
915
|
-
const summaryPath = join(base, ".gsd", "milestones", "M001", "slices", "S01", "tasks", "T01-SUMMARY.md");
|
|
916
|
-
assert.ok(existsSync(summaryPath), "SUMMARY.md exists after completion");
|
|
917
|
-
|
|
918
|
-
// Reopen — handler sets DB to "pending" in transaction, but post-mutation
|
|
919
|
-
// hook triggers reconciler which immediately sets it back to "complete"
|
|
920
|
-
const r2 = await handleReopenTask({ milestoneId: "M001", sliceId: "S01", taskId: "T01" }, base);
|
|
921
|
-
assert.ok(!("error" in r2), `reopen handler succeeded: ${JSON.stringify(r2)}`);
|
|
922
|
-
|
|
923
|
-
// M12: After reopen completes, DB shows "complete" not "pending" because
|
|
924
|
-
// the reconciler auto-corrected it from the stale SUMMARY.md
|
|
925
|
-
const task = getTask("M001", "S01", "T01");
|
|
926
|
-
assert.equal(task!.status, "complete", "M12: reconciler overrides reopen — task is back to complete");
|
|
927
|
-
assert.ok(existsSync(summaryPath), "M12: SUMMARY.md was never cleaned up");
|
|
928
|
-
});
|
|
929
|
-
|
|
930
|
-
test("complete slice → reopen → M12: reconciler overrides task reset via stale SUMMARY", async () => {
|
|
931
|
-
// Same M12 pattern at the slice level: reopen-slice resets all tasks to
|
|
932
|
-
// "pending" in DB, but task SUMMARY.md artifacts remain on disk. The
|
|
933
|
-
// reopen handler's post-mutation hook triggers reconciler which sees the
|
|
934
|
-
// stale artifacts and auto-corrects tasks back to "complete".
|
|
935
|
-
base = createFullFixture();
|
|
936
|
-
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
937
|
-
insertMilestone({ id: "M001", title: "Active", status: "active" });
|
|
938
|
-
insertSlice({ id: "S01", milestoneId: "M001", title: "First", status: "in_progress" });
|
|
939
|
-
insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "pending" });
|
|
940
|
-
|
|
941
|
-
// Complete task + slice
|
|
942
|
-
await handleCompleteTask(makeTaskParams("T01", "S01", "M001") as any, base);
|
|
943
|
-
await handleCompleteSlice(makeSliceParams("S01", "M001") as any, base);
|
|
944
|
-
assert.ok(isClosedStatus(getSlice("M001", "S01")!.status));
|
|
945
|
-
|
|
946
|
-
// Reopen slice — transaction resets slice to in_progress and task to pending,
|
|
947
|
-
// but post-mutation hook triggers reconciler which sees stale SUMMARY.md
|
|
948
|
-
await handleReopenSlice({ milestoneId: "M001", sliceId: "S01" }, base);
|
|
949
|
-
|
|
950
|
-
// Slice status is correctly in_progress (no slice SUMMARY reconciliation)
|
|
951
|
-
assert.equal(getSlice("M001", "S01")!.status, "in_progress");
|
|
952
|
-
|
|
953
|
-
// M12: Task was reset to "pending" in the transaction, but reconciler
|
|
954
|
-
// already corrected it back to "complete" from the stale SUMMARY.md
|
|
955
|
-
const task = getTask("M001", "S01", "T01");
|
|
956
|
-
assert.equal(task!.status, "complete", "M12: reconciler overrides reopen — task back to complete");
|
|
957
|
-
});
|
|
958
|
-
});
|
|
959
|
-
});
|