gsd-pi 2.82.0-dev.725028083 → 2.82.0-dev.98ea09b1e
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -3
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +10 -1
- package/dist/resources/extensions/claude-code-cli/partial-builder.js +2 -1
- package/dist/resources/extensions/cmux/index.js +5 -0
- package/dist/resources/extensions/gsd/auto/infra-errors.js +9 -3
- package/dist/resources/extensions/gsd/auto/loop.js +5 -5
- package/dist/resources/extensions/gsd/auto/orchestrator.js +124 -6
- package/dist/resources/extensions/gsd/auto/phases.js +8 -1
- package/dist/resources/extensions/gsd/auto/workflow-memory-pressure.js +12 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +13 -6
- package/dist/resources/extensions/gsd/auto-model-selection.js +2 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +233 -127
- package/dist/resources/extensions/gsd/auto-prompts.js +2 -2
- package/dist/resources/extensions/gsd/auto-recovery.js +31 -1
- package/dist/resources/extensions/gsd/auto-start.js +85 -12
- package/dist/resources/extensions/gsd/auto-verification.js +28 -22
- package/dist/resources/extensions/gsd/auto-worktree.js +111 -1
- package/dist/resources/extensions/gsd/auto.js +158 -55
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +4 -1
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +9 -8
- package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +21 -9
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +16 -2
- package/dist/resources/extensions/gsd/clean-root-preflight.js +170 -8
- package/dist/resources/extensions/gsd/commands/catalog.js +4 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +37 -0
- package/dist/resources/extensions/gsd/commands-bootstrap.js +5 -0
- package/dist/resources/extensions/gsd/crash-recovery.js +31 -5
- package/dist/resources/extensions/gsd/db/unit-dispatches.js +3 -2
- package/dist/resources/extensions/gsd/dispatch-guard.js +2 -2
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +28 -11
- package/dist/resources/extensions/gsd/doctor.js +2 -28
- package/dist/resources/extensions/gsd/export-html.js +27 -425
- package/dist/resources/extensions/gsd/git-service.js +39 -1
- package/dist/resources/extensions/gsd/gsd-db.js +1 -0
- package/dist/resources/extensions/gsd/guided-flow.js +13 -6
- package/dist/resources/extensions/gsd/md-importer.js +1 -1
- package/dist/resources/extensions/gsd/migrate/command.js +5 -0
- package/dist/resources/extensions/gsd/migrate/parsers.js +10 -0
- package/dist/resources/extensions/gsd/migrate/preview.js +9 -0
- package/dist/resources/extensions/gsd/migrate/transformer.js +51 -4
- package/dist/resources/extensions/gsd/migrate/writer.js +11 -1
- package/dist/resources/extensions/gsd/migration-auto-check.js +12 -17
- package/dist/resources/extensions/gsd/milestone-actions.js +11 -4
- package/dist/resources/extensions/gsd/native-git-bridge.js +48 -12
- package/dist/resources/extensions/gsd/post-execution-checks.js +73 -2
- package/dist/resources/extensions/gsd/pre-execution-checks.js +28 -1
- package/dist/resources/extensions/gsd/prompt-loader.js +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
- package/dist/resources/extensions/gsd/prompts/discuss.md +9 -9
- package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
- package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -4
- package/dist/resources/extensions/gsd/prompts/queue.md +4 -4
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +2 -2
- package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
- package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +6 -1
- package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +9 -14
- package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +19 -24
- package/dist/resources/extensions/gsd/status-guards.js +4 -0
- package/dist/resources/extensions/gsd/templates/plan.md +8 -5
- package/dist/resources/extensions/gsd/templates/task-plan.md +4 -2
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -8
- package/dist/resources/extensions/gsd/tools/complete-slice.js +6 -8
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +7 -1
- package/dist/resources/extensions/gsd/tools/plan-slice.js +89 -14
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +119 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +32 -10
- package/dist/resources/extensions/gsd/validation.js +23 -1
- package/dist/resources/extensions/gsd/verification-gate.js +68 -7
- package/dist/resources/extensions/gsd/verification-verdict.js +26 -0
- package/dist/resources/extensions/gsd/workflow-projections.js +6 -8
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +54 -10
- package/dist/resources/extensions/shared/html-shell.js +388 -0
- package/dist/resources/extensions/subagent/index.js +448 -78
- package/dist/resources/extensions/subagent/launch.js +77 -0
- package/dist/resources/extensions/subagent/run-store.js +148 -0
- package/dist/resources/extensions/visual-brief/artifact-policy.js +29 -0
- package/dist/resources/extensions/visual-brief/extension-manifest.json +8 -0
- package/dist/resources/extensions/visual-brief/index.js +5 -0
- package/dist/resources/extensions/visual-brief/page-contract.js +124 -0
- package/dist/resources/extensions/visual-brief/prompts.js +140 -0
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +14 -14
- 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 +3 -3
- 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 +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page.js.nft.json +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 +4 -7
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -7
- 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 +4 -5
- 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 -5
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +4 -7
- 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 +4 -7
- 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 +4 -5
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -5
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +14 -14
- package/dist/web/standalone/.next/server/chunks/4266.js +2 -0
- 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/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/2973.33f26573894b6153.js +2 -0
- package/dist/web/standalone/.next/static/chunks/{8359.e059d86b255fce1c.js → 8359.7eb3bb8f8ecf4c01.js} +2 -2
- package/dist/web/standalone/.next/static/chunks/app/layout-8c10ec293ae0f1d5.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-de742b64187e13fe.js → webpack-9a4db269f9ed63ad.js} +1 -1
- package/dist/web/standalone/.next/static/css/746ee28c929d1880.css +1 -0
- package/package.json +4 -4
- package/packages/contracts/dist/rpc.test.js +7 -0
- package/packages/contracts/dist/rpc.test.js.map +1 -1
- package/packages/contracts/dist/workflow.d.ts +21 -0
- package/packages/contracts/dist/workflow.d.ts.map +1 -1
- package/packages/contracts/dist/workflow.js +24 -0
- package/packages/contracts/dist/workflow.js.map +1 -1
- package/packages/contracts/src/rpc.test.ts +8 -0
- package/packages/contracts/src/workflow.ts +24 -0
- package/packages/mcp-server/README.md +13 -4
- package/packages/mcp-server/dist/workflow-tools.d.ts +0 -3
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +80 -0
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/src/workflow-tools.test.ts +23 -1
- package/packages/mcp-server/src/workflow-tools.ts +168 -0
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/tsconfig.json +2 -1
- package/packages/native/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js +82 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.js +52 -0
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/simple-options.d.ts +2 -4
- package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.js +5 -6
- package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/simple-options.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/simple-options.test.js +50 -0
- package/packages/pi-ai/dist/providers/simple-options.test.js.map +1 -0
- package/packages/pi-ai/src/providers/openai-codex-responses.test.ts +63 -0
- package/packages/pi-ai/src/providers/openai-codex-responses.ts +91 -1
- package/packages/pi-ai/src/providers/simple-options.test.ts +60 -0
- package/packages/pi-ai/src/providers/simple-options.ts +5 -6
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js +66 -0
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session.js +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/src/core/agent-session-thinking-level.test.ts +79 -0
- package/packages/pi-coding-agent/src/core/agent-session.ts +1 -1
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +5 -0
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/src/tui.ts +6 -0
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
- package/src/resources/GSD-WORKFLOW.md +10 -1
- package/src/resources/extensions/claude-code-cli/partial-builder.ts +2 -1
- package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +19 -2
- package/src/resources/extensions/cmux/index.ts +6 -0
- package/src/resources/extensions/gsd/auto/contracts.ts +59 -16
- package/src/resources/extensions/gsd/auto/infra-errors.ts +9 -3
- package/src/resources/extensions/gsd/auto/loop.ts +8 -5
- package/src/resources/extensions/gsd/auto/orchestrator.ts +129 -6
- package/src/resources/extensions/gsd/auto/phases.ts +7 -1
- package/src/resources/extensions/gsd/auto/workflow-memory-pressure.ts +13 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +14 -6
- package/src/resources/extensions/gsd/auto-model-selection.ts +2 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +266 -139
- package/src/resources/extensions/gsd/auto-prompts.ts +2 -2
- package/src/resources/extensions/gsd/auto-recovery.ts +29 -0
- package/src/resources/extensions/gsd/auto-start.ts +92 -9
- package/src/resources/extensions/gsd/auto-verification.ts +36 -34
- package/src/resources/extensions/gsd/auto-worktree.ts +119 -1
- package/src/resources/extensions/gsd/auto.ts +167 -53
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +6 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +9 -8
- package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +19 -7
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +19 -3
- package/src/resources/extensions/gsd/clean-root-preflight.ts +174 -8
- package/src/resources/extensions/gsd/commands/catalog.ts +4 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +40 -0
- package/src/resources/extensions/gsd/commands-bootstrap.ts +10 -0
- package/src/resources/extensions/gsd/crash-recovery.ts +30 -4
- package/src/resources/extensions/gsd/db/unit-dispatches.ts +4 -3
- package/src/resources/extensions/gsd/dispatch-guard.ts +2 -2
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +25 -13
- package/src/resources/extensions/gsd/doctor.ts +2 -27
- package/src/resources/extensions/gsd/export-html.ts +27 -427
- package/src/resources/extensions/gsd/git-service.ts +45 -1
- package/src/resources/extensions/gsd/gsd-db.ts +3 -0
- package/src/resources/extensions/gsd/guided-flow.ts +14 -7
- package/src/resources/extensions/gsd/md-importer.ts +1 -1
- package/src/resources/extensions/gsd/migrate/command.ts +5 -0
- package/src/resources/extensions/gsd/migrate/parsers.ts +11 -0
- package/src/resources/extensions/gsd/migrate/preview.ts +10 -0
- package/src/resources/extensions/gsd/migrate/transformer.ts +58 -4
- package/src/resources/extensions/gsd/migrate/writer.ts +14 -1
- package/src/resources/extensions/gsd/migration-auto-check.ts +15 -23
- package/src/resources/extensions/gsd/milestone-actions.ts +10 -4
- package/src/resources/extensions/gsd/native-git-bridge.ts +54 -12
- package/src/resources/extensions/gsd/post-execution-checks.ts +87 -2
- package/src/resources/extensions/gsd/pre-execution-checks.ts +32 -1
- package/src/resources/extensions/gsd/prompt-loader.ts +1 -1
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
- package/src/resources/extensions/gsd/prompts/discuss.md +9 -9
- package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
- package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
- package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -4
- package/src/resources/extensions/gsd/prompts/queue.md +4 -4
- package/src/resources/extensions/gsd/prompts/refine-slice.md +2 -2
- package/src/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
- package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +8 -1
- package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +12 -15
- package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +17 -25
- package/src/resources/extensions/gsd/status-guards.ts +5 -0
- package/src/resources/extensions/gsd/templates/plan.md +8 -5
- package/src/resources/extensions/gsd/templates/task-plan.md +4 -2
- package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +116 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +487 -4
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +12 -11
- package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +12 -1
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +15 -1
- package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +69 -1
- package/src/resources/extensions/gsd/tests/brief-command.test.ts +89 -0
- package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +107 -2
- package/src/resources/extensions/gsd/tests/closeout-git-deferral.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +4 -1
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +5 -9
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +43 -2
- package/src/resources/extensions/gsd/tests/db-authority-regression.test.ts +208 -0
- package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +59 -2
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/evidence-cross-ref.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/export-html-enhancements.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/guided-discuss-project-prompt-rendering.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/guided-flow.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +6 -6
- package/src/resources/extensions/gsd/tests/hook-model-resolution.test.ts +5 -0
- package/src/resources/extensions/gsd/tests/infra-error.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/infra-errors-cooldown.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/integration/doctor-runtime.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +103 -1
- package/src/resources/extensions/gsd/tests/integration/migrate-command.test.ts +48 -3
- package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +5 -1
- package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +24 -1
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +26 -18
- package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +63 -2
- package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +121 -1
- package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +55 -1
- package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +225 -1
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +17 -0
- package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +79 -1
- package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +86 -0
- package/src/resources/extensions/gsd/tests/post-unit-git-failure.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/prompt-loader.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +46 -2
- package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +31 -1
- package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +119 -23
- package/src/resources/extensions/gsd/tests/stuck-state-via-db.test.ts +64 -1
- package/src/resources/extensions/gsd/tests/summary-render-parity.test.ts +7 -3
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +86 -7
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +110 -1
- package/src/resources/extensions/gsd/tests/verification-verdict.test.ts +78 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/workflow-memory-pressure.test.ts +21 -1
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-git-pathspec.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +64 -12
- package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +54 -0
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +8 -10
- package/src/resources/extensions/gsd/tools/complete-slice.ts +6 -8
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +5 -1
- package/src/resources/extensions/gsd/tools/plan-slice.ts +98 -12
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +135 -0
- package/src/resources/extensions/gsd/types.ts +1 -1
- package/src/resources/extensions/gsd/unit-context-manifest.ts +47 -11
- package/src/resources/extensions/gsd/validation.ts +23 -1
- package/src/resources/extensions/gsd/verification-gate.ts +78 -6
- package/src/resources/extensions/gsd/verification-verdict.ts +47 -0
- package/src/resources/extensions/gsd/workflow-projections.ts +6 -8
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +61 -10
- package/src/resources/extensions/shared/html-shell.ts +412 -0
- package/src/resources/extensions/subagent/index.ts +567 -103
- package/src/resources/extensions/subagent/launch.ts +131 -0
- package/src/resources/extensions/subagent/run-store.ts +218 -0
- package/src/resources/extensions/subagent/tests/launch.test.ts +115 -0
- package/src/resources/extensions/subagent/tests/run-store.test.ts +111 -0
- package/src/resources/extensions/visual-brief/artifact-policy.ts +41 -0
- package/src/resources/extensions/visual-brief/extension-manifest.json +8 -0
- package/src/resources/extensions/visual-brief/index.ts +8 -0
- package/src/resources/extensions/visual-brief/page-contract.ts +136 -0
- package/src/resources/extensions/visual-brief/prompts.ts +183 -0
- package/src/resources/extensions/visual-brief/tests/visual-brief.test.ts +212 -0
- package/dist/web/standalone/.next/server/chunks/5822.js +0 -2
- package/dist/web/standalone/.next/static/chunks/2556.0527fea66e123b7f.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +0 -1
- package/dist/web/standalone/.next/static/css/54ec2745c1da488b.css +0 -1
- package/dist/web/standalone/.next/static/css/de70bee13400563f.css +0 -1
- package/dist/web/standalone/.next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/747892c23ea88013-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/8d697b304b401681-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
- /package/dist/web/standalone/.next/static/{KDRTXR-22LPCsa80X9dey → euQ0CLP_v8V4e76Tu3odJ}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{KDRTXR-22LPCsa80X9dey → euQ0CLP_v8V4e76Tu3odJ}/_ssgManifest.js +0 -0
|
@@ -8,12 +8,14 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Design constraints (from Trek-e approval):
|
|
10
10
|
* - Warn the user before stashing (no silent surprises)
|
|
11
|
-
* - git stash push / git stash
|
|
12
|
-
* - Stash/
|
|
11
|
+
* - git stash push / git stash apply+drop for targeted restore
|
|
12
|
+
* - Stash/apply errors are logged but MUST NOT block the merge itself
|
|
13
13
|
* - Fast-path status check — clean trees pay no extra cost
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import { execFileSync } from "node:child_process";
|
|
17
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
18
|
+
import { join } from "node:path";
|
|
17
19
|
import { GIT_NO_PROMPT_ENV } from "./git-constants.js";
|
|
18
20
|
import { logWarning } from "./workflow-logger.js";
|
|
19
21
|
import { nativeHasChanges } from "./native-git-bridge.js";
|
|
@@ -32,6 +34,148 @@ export interface PostflightResult {
|
|
|
32
34
|
needsManualRecovery: boolean;
|
|
33
35
|
message: string;
|
|
34
36
|
stashRef?: string;
|
|
37
|
+
resolution?: "applied" | "already-present-dropped" | "already-present-preserved" | "manual-recovery";
|
|
38
|
+
collidedPaths?: string[];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function gitText(basePath: string, args: string[]): string {
|
|
42
|
+
return execFileSync("git", args, {
|
|
43
|
+
cwd: basePath,
|
|
44
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
45
|
+
encoding: "utf-8",
|
|
46
|
+
env: GIT_NO_PROMPT_ENV,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function gitBuffer(basePath: string, args: string[]): Buffer {
|
|
51
|
+
return execFileSync("git", args, {
|
|
52
|
+
cwd: basePath,
|
|
53
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
54
|
+
env: GIT_NO_PROMPT_ENV,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function errorText(err: unknown): string {
|
|
59
|
+
if (!err || typeof err !== "object") return String(err);
|
|
60
|
+
const parts: string[] = [];
|
|
61
|
+
const stderr = (err as { stderr?: unknown }).stderr;
|
|
62
|
+
const stdout = (err as { stdout?: unknown }).stdout;
|
|
63
|
+
for (const value of [stderr, stdout]) {
|
|
64
|
+
if (typeof value === "string") parts.push(value);
|
|
65
|
+
else if (value instanceof Uint8Array) parts.push(Buffer.from(value).toString("utf-8"));
|
|
66
|
+
}
|
|
67
|
+
parts.push(err instanceof Error ? err.message : String(err));
|
|
68
|
+
return parts.filter(Boolean).join("\n");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function parseAlreadyExistsNoCheckoutPaths(text: string): string[] {
|
|
72
|
+
const paths: string[] = [];
|
|
73
|
+
for (const line of text.split(/\r?\n/)) {
|
|
74
|
+
const match = /^(.+?) already exists, no checkout$/i.exec(line.trim());
|
|
75
|
+
if (match?.[1]) paths.push(match[1]);
|
|
76
|
+
}
|
|
77
|
+
return [...new Set(paths)];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function readZeroDelimitedPaths(output: string): string[] {
|
|
81
|
+
return output.split("\0").filter(Boolean);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function listStashUntrackedPaths(basePath: string, stashRef: string): string[] | null {
|
|
85
|
+
try {
|
|
86
|
+
const output = gitText(basePath, ["ls-tree", "-r", "-z", "--name-only", `${stashRef}^3`]);
|
|
87
|
+
return readZeroDelimitedPaths(output);
|
|
88
|
+
} catch {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function listStashTrackedPaths(basePath: string, stashRef: string): string[] | null {
|
|
94
|
+
try {
|
|
95
|
+
const output = gitText(basePath, ["diff", "--name-only", "-z", `${stashRef}^1`, stashRef]);
|
|
96
|
+
return readZeroDelimitedPaths(output);
|
|
97
|
+
} catch {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function isWorktreeClean(basePath: string): boolean | null {
|
|
103
|
+
try {
|
|
104
|
+
return gitText(basePath, ["status", "--porcelain"]).trim() === "";
|
|
105
|
+
} catch {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function stashBlobEqualsWorktreeFile(basePath: string, stashRef: string, path: string): boolean | null {
|
|
111
|
+
try {
|
|
112
|
+
const worktreePath = join(basePath, path);
|
|
113
|
+
if (!existsSync(worktreePath)) return false;
|
|
114
|
+
const worktreeContent = readFileSync(worktreePath);
|
|
115
|
+
const stashContent = gitBuffer(basePath, ["show", `${stashRef}^3:${path}`]);
|
|
116
|
+
return Buffer.compare(worktreeContent, stashContent) === 0;
|
|
117
|
+
} catch {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function reconcileAlreadyPresentUntrackedStash(
|
|
123
|
+
basePath: string,
|
|
124
|
+
milestoneId: string,
|
|
125
|
+
stashRef: string,
|
|
126
|
+
err: unknown,
|
|
127
|
+
): PostflightResult | null {
|
|
128
|
+
const text = errorText(err);
|
|
129
|
+
const collidedPaths = parseAlreadyExistsNoCheckoutPaths(text);
|
|
130
|
+
if (collidedPaths.length === 0) return null;
|
|
131
|
+
|
|
132
|
+
const untrackedPaths = listStashUntrackedPaths(basePath, stashRef);
|
|
133
|
+
if (!untrackedPaths || untrackedPaths.length === 0) return null;
|
|
134
|
+
|
|
135
|
+
const trackedPaths = listStashTrackedPaths(basePath, stashRef);
|
|
136
|
+
if (trackedPaths === null || trackedPaths.length > 0) return null;
|
|
137
|
+
|
|
138
|
+
const untrackedPathSet = new Set(untrackedPaths);
|
|
139
|
+
if (!collidedPaths.every((path) => untrackedPathSet.has(path))) return null;
|
|
140
|
+
if (!untrackedPaths.every((path) => existsSync(join(basePath, path)))) return null;
|
|
141
|
+
if (isWorktreeClean(basePath) !== true) return null;
|
|
142
|
+
|
|
143
|
+
const blobComparisons = untrackedPaths.map((path) => stashBlobEqualsWorktreeFile(basePath, stashRef, path));
|
|
144
|
+
if (blobComparisons.some((result) => result === null)) return null;
|
|
145
|
+
const allIdentical = blobComparisons.every(Boolean);
|
|
146
|
+
if (allIdentical) {
|
|
147
|
+
let dropped = true;
|
|
148
|
+
try {
|
|
149
|
+
execFileSync("git", ["stash", "drop", stashRef], {
|
|
150
|
+
cwd: basePath,
|
|
151
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
152
|
+
encoding: "utf-8",
|
|
153
|
+
env: GIT_NO_PROMPT_ENV,
|
|
154
|
+
});
|
|
155
|
+
} catch (err) {
|
|
156
|
+
dropped = false;
|
|
157
|
+
logWarning("preflight", `git stash drop ${stashRef} failed after identical preflight stash reconciliation: ${err instanceof Error ? err.message : String(err)}`);
|
|
158
|
+
}
|
|
159
|
+
return {
|
|
160
|
+
restored: true,
|
|
161
|
+
needsManualRecovery: false,
|
|
162
|
+
message: dropped
|
|
163
|
+
? `Preflight stash for milestone ${milestoneId} contained files already present after merge; identical stash dropped.`
|
|
164
|
+
: `Preflight stash for milestone ${milestoneId} contained files already present after merge, but ${stashRef} could not be dropped and remains as a backup.`,
|
|
165
|
+
stashRef,
|
|
166
|
+
resolution: dropped ? "already-present-dropped" : "already-present-preserved",
|
|
167
|
+
collidedPaths,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return {
|
|
172
|
+
restored: false,
|
|
173
|
+
needsManualRecovery: false,
|
|
174
|
+
message: `Preflight stash for milestone ${milestoneId} contained untracked files already present after merge. Keeping merged files and preserving ${stashRef} as a backup.`,
|
|
175
|
+
stashRef,
|
|
176
|
+
resolution: "already-present-preserved",
|
|
177
|
+
collidedPaths,
|
|
178
|
+
};
|
|
35
179
|
}
|
|
36
180
|
|
|
37
181
|
function findPreflightStashRef(basePath: string, milestoneId: string, stashMarker?: string): string | null {
|
|
@@ -141,27 +285,48 @@ export function postflightPopStash(
|
|
|
141
285
|
message: msg,
|
|
142
286
|
};
|
|
143
287
|
}
|
|
144
|
-
execFileSync("git", ["stash", "
|
|
288
|
+
execFileSync("git", ["stash", "apply", stashRef], {
|
|
145
289
|
cwd: basePath,
|
|
146
290
|
stdio: ["ignore", "pipe", "pipe"],
|
|
147
291
|
encoding: "utf-8",
|
|
148
292
|
env: GIT_NO_PROMPT_ENV,
|
|
149
293
|
});
|
|
294
|
+
let dropWarning: string | null = null;
|
|
295
|
+
try {
|
|
296
|
+
execFileSync("git", ["stash", "drop", stashRef], {
|
|
297
|
+
cwd: basePath,
|
|
298
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
299
|
+
encoding: "utf-8",
|
|
300
|
+
env: GIT_NO_PROMPT_ENV,
|
|
301
|
+
});
|
|
302
|
+
} catch (err) {
|
|
303
|
+
dropWarning = ` Stash was restored, but git stash drop ${stashRef} failed: ${err instanceof Error ? err.message : String(err)}.`;
|
|
304
|
+
logWarning("preflight", dropWarning.trim());
|
|
305
|
+
}
|
|
150
306
|
const msg = `Restored stashed changes after milestone ${milestoneId} merge.`;
|
|
151
|
-
notify(msg
|
|
307
|
+
notify(`${msg}${dropWarning ?? ""}`, dropWarning ? "warning" : "info");
|
|
152
308
|
return {
|
|
153
309
|
restored: true,
|
|
154
310
|
needsManualRecovery: false,
|
|
155
|
-
message: msg
|
|
311
|
+
message: `${msg}${dropWarning ?? ""}`,
|
|
156
312
|
stashRef,
|
|
313
|
+
resolution: "applied",
|
|
157
314
|
};
|
|
158
315
|
} catch (err) {
|
|
159
|
-
|
|
316
|
+
if (stashRef) {
|
|
317
|
+
const reconciled = reconcileAlreadyPresentUntrackedStash(basePath, milestoneId, stashRef, err);
|
|
318
|
+
if (reconciled) {
|
|
319
|
+
logWarning("preflight", reconciled.message);
|
|
320
|
+
notify(reconciled.message, reconciled.resolution === "already-present-preserved" ? "warning" : "info");
|
|
321
|
+
return reconciled;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
// Apply conflicts mean the merged code collides with the stashed changes.
|
|
160
325
|
// Log a warning — the user needs to resolve manually, but the merge succeeded.
|
|
161
326
|
const restoreHint = stashRef
|
|
162
|
-
? `Run "git stash
|
|
327
|
+
? `Run "git stash apply ${stashRef}" manually to restore the correct stash, then "git stash drop ${stashRef}" after recovery.`
|
|
163
328
|
: `Run "git stash list" to find the matching GSD preflight stash before restoring manually.`;
|
|
164
|
-
const msg = `git stash
|
|
329
|
+
const msg = `git stash apply ${stashRef ?? ""}`.trim() + ` failed after merge of milestone ${milestoneId}: ${err instanceof Error ? err.message : String(err)}. ${restoreHint}`;
|
|
165
330
|
logWarning("preflight", msg);
|
|
166
331
|
notify(msg, "warning");
|
|
167
332
|
return {
|
|
@@ -169,6 +334,7 @@ export function postflightPopStash(
|
|
|
169
334
|
needsManualRecovery: true,
|
|
170
335
|
message: msg,
|
|
171
336
|
...(stashRef ? { stashRef } : {}),
|
|
337
|
+
resolution: "manual-recovery",
|
|
172
338
|
};
|
|
173
339
|
}
|
|
174
340
|
}
|
|
@@ -3,6 +3,7 @@ import { join, resolve } from "node:path";
|
|
|
3
3
|
|
|
4
4
|
import { loadRegistry } from "../workflow-templates.js";
|
|
5
5
|
import { gsdHome } from "../gsd-home.js";
|
|
6
|
+
import { VISUAL_BRIEF_MODES } from "../../visual-brief/prompts.js";
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
export interface GsdCommandDefinition {
|
|
@@ -13,7 +14,7 @@ export interface GsdCommandDefinition {
|
|
|
13
14
|
type CompletionMap = Record<string, readonly GsdCommandDefinition[]>;
|
|
14
15
|
|
|
15
16
|
export const GSD_COMMAND_DESCRIPTION =
|
|
16
|
-
"GSD — Get Shit Done: /gsd help|start|templates|next|auto|stop|pause|status|widget|visualize|queue|quick|discuss|capture|triage|dispatch|history|undo|undo-task|reset-slice|rate|skip|export|cleanup|model|mode|prefs|config|keys|hooks|run-hook|skill-health|doctor|debug|logs|forensics|changelog|migrate|remote|steer|knowledge|new-milestone|new-project|parallel|cmux|park|unpark|init|setup|onboarding|inspect|extensions|update|fast|mcp|rethink|workflow|codebase|notifications|ship|do|session-report|backlog|pr-branch|add-tests|scan|language|worktree|eval-review";
|
|
17
|
+
"GSD — Get Shit Done: /gsd help|start|templates|next|auto|stop|pause|status|widget|visualize|brief|queue|quick|discuss|capture|triage|dispatch|history|undo|undo-task|reset-slice|rate|skip|export|cleanup|model|mode|prefs|config|keys|hooks|run-hook|skill-health|doctor|debug|logs|forensics|changelog|migrate|remote|steer|knowledge|new-milestone|new-project|parallel|cmux|park|unpark|init|setup|onboarding|inspect|extensions|update|fast|mcp|rethink|workflow|codebase|notifications|ship|do|session-report|backlog|pr-branch|add-tests|scan|language|worktree|eval-review";
|
|
17
18
|
|
|
18
19
|
export const TOP_LEVEL_SUBCOMMANDS: readonly GsdCommandDefinition[] = [
|
|
19
20
|
{ cmd: "help", desc: "Categorized command reference with descriptions" },
|
|
@@ -24,6 +25,7 @@ export const TOP_LEVEL_SUBCOMMANDS: readonly GsdCommandDefinition[] = [
|
|
|
24
25
|
{ cmd: "status", desc: "Progress dashboard" },
|
|
25
26
|
{ cmd: "widget", desc: "Cycle widget: full → small → min → off" },
|
|
26
27
|
{ cmd: "visualize", desc: "Open 10-tab workflow visualizer (progress, timeline, deps, metrics, health, agent, changes, knowledge, captures, export)" },
|
|
28
|
+
{ cmd: "brief", desc: "Generate a visual HTML brief: diagram, plan, diff review, recap, table, or slides" },
|
|
27
29
|
{ cmd: "queue", desc: "Queue and reorder future milestones" },
|
|
28
30
|
{ cmd: "quick", desc: "Execute a quick task without full planning overhead" },
|
|
29
31
|
{ cmd: "discuss", desc: "Discuss architecture and decisions" },
|
|
@@ -88,6 +90,7 @@ export const TOP_LEVEL_SUBCOMMANDS: readonly GsdCommandDefinition[] = [
|
|
|
88
90
|
];
|
|
89
91
|
|
|
90
92
|
const NESTED_COMPLETIONS: CompletionMap = {
|
|
93
|
+
brief: VISUAL_BRIEF_MODES.map((mode) => ({ cmd: mode.mode, desc: mode.description })),
|
|
91
94
|
auto: [
|
|
92
95
|
{ cmd: "--verbose", desc: "Show detailed execution output" },
|
|
93
96
|
{ cmd: "--debug", desc: "Enable debug logging" },
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ExtensionAPI, ExtensionCommandContext, ExtensionContext } from "@gsd/pi-coding-agent";
|
|
2
2
|
import type { Model } from "@gsd/pi-ai";
|
|
3
3
|
import type { GSDState } from "../../types.js";
|
|
4
|
+
import { createRequire } from "node:module";
|
|
4
5
|
|
|
5
6
|
import { computeProgressScore, formatProgressLine } from "../../progress-score.js";
|
|
6
7
|
import { loadEffectiveGSDPreferences, getGlobalGSDPreferencesPath, getProjectGSDPreferencesPath } from "../../preferences.js";
|
|
@@ -11,6 +12,8 @@ import { handleCmux } from "../../commands-cmux.js";
|
|
|
11
12
|
import { setSessionModelOverride } from "../../session-model-override.js";
|
|
12
13
|
import { projectRoot } from "../context.js";
|
|
13
14
|
import { formattedShortcutPair } from "../../shortcut-defs.js";
|
|
15
|
+
import { getVisualBriefOutputDir } from "../../../visual-brief/artifact-policy.js";
|
|
16
|
+
import { buildVisualBriefPrompt, parseVisualBriefArgs, VISUAL_BRIEF_USAGE } from "../../../visual-brief/prompts.js";
|
|
14
17
|
|
|
15
18
|
export function showHelp(ctx: ExtensionCommandContext, args = ""): void {
|
|
16
19
|
const summaryLines = [
|
|
@@ -27,6 +30,7 @@ export function showHelp(ctx: ExtensionCommandContext, args = ""): void {
|
|
|
27
30
|
` /gsd parallel watch Parallel monitor (${formattedShortcutPair("parallel")})`,
|
|
28
31
|
` /gsd notifications Notification history (${formattedShortcutPair("notifications")})`,
|
|
29
32
|
" /gsd visualize Interactive 10-tab TUI",
|
|
33
|
+
" /gsd brief <mode> Visual HTML brief (diagram, plan, diff, recap, table, slides)",
|
|
30
34
|
" /gsd queue Show queued/dispatched units",
|
|
31
35
|
"",
|
|
32
36
|
"COURSE CORRECTION",
|
|
@@ -75,6 +79,7 @@ export function showHelp(ctx: ExtensionCommandContext, args = ""): void {
|
|
|
75
79
|
` /gsd parallel watch Open parallel worker monitor (${formattedShortcutPair("parallel")})`,
|
|
76
80
|
" /gsd widget Cycle status widget [full|small|min|off]",
|
|
77
81
|
" /gsd visualize Interactive 10-tab TUI (progress, timeline, deps, metrics, health, agent, changes, knowledge, captures, export)",
|
|
82
|
+
" /gsd brief <mode> Generate a visual HTML brief [diagram|plan|diff|recap|table|slides] [topic] [--slides]",
|
|
78
83
|
" /gsd queue Show queued/dispatched units and execution order",
|
|
79
84
|
" /gsd history View execution history [--cost] [--phase] [--model] [N]",
|
|
80
85
|
" /gsd changelog Show categorized release notes [version]",
|
|
@@ -203,6 +208,37 @@ export async function handleVisualize(ctx: ExtensionCommandContext): Promise<voi
|
|
|
203
208
|
}
|
|
204
209
|
}
|
|
205
210
|
|
|
211
|
+
export async function handleBrief(args: string, ctx: ExtensionCommandContext, pi?: ExtensionAPI): Promise<void> {
|
|
212
|
+
const request = parseVisualBriefArgs(args);
|
|
213
|
+
if (!request) {
|
|
214
|
+
ctx.ui.notify(VISUAL_BRIEF_USAGE, "info");
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (!pi?.sendUserMessage) {
|
|
219
|
+
ctx.ui.notify("Visual brief generation is unavailable in this context.", "warning");
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const outputDir = getVisualBriefOutputDir();
|
|
224
|
+
const version = resolveGsdVersion();
|
|
225
|
+
pi.sendUserMessage(buildVisualBriefPrompt(request, { outputDir, version }));
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const briefRequire = createRequire(import.meta.url);
|
|
229
|
+
|
|
230
|
+
function resolveGsdVersion(): string | undefined {
|
|
231
|
+
const envVersion = process.env.GSD_VERSION?.trim();
|
|
232
|
+
if (envVersion) return envVersion;
|
|
233
|
+
try {
|
|
234
|
+
const pkg = briefRequire("../../../../../../package.json") as { version?: unknown };
|
|
235
|
+
const fromPkg = typeof pkg.version === "string" ? pkg.version.trim() : "";
|
|
236
|
+
return fromPkg || undefined;
|
|
237
|
+
} catch {
|
|
238
|
+
return undefined;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
206
242
|
export async function handleSetup(args: string, ctx: ExtensionCommandContext, pi?: ExtensionAPI): Promise<void> {
|
|
207
243
|
const { detectProjectState, hasGlobalSetup } = await import("../../detection.js");
|
|
208
244
|
const { isOnboardingComplete, readOnboardingRecord } = await import("../../onboarding-state.js");
|
|
@@ -429,6 +465,10 @@ export async function handleCoreCommand(
|
|
|
429
465
|
await handleVisualize(ctx);
|
|
430
466
|
return true;
|
|
431
467
|
}
|
|
468
|
+
if (trimmed === "brief" || trimmed.startsWith("brief ")) {
|
|
469
|
+
await handleBrief(trimmed.replace(/^brief\s*/, "").trim(), ctx, pi);
|
|
470
|
+
return true;
|
|
471
|
+
}
|
|
432
472
|
if (trimmed === "widget" || trimmed.startsWith("widget ")) {
|
|
433
473
|
const { cycleWidgetMode, setWidgetMode, getWidgetMode } = await import("../../auto-dashboard.js");
|
|
434
474
|
const arg = trimmed.replace(/^widget\s*/, "").trim();
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { importExtensionModule, type ExtensionAPI, type ExtensionCommandContext } from "@gsd/pi-coding-agent";
|
|
2
|
+
import { VISUAL_BRIEF_MODES } from "../visual-brief/prompts.js";
|
|
2
3
|
|
|
3
4
|
const TOP_LEVEL_SUBCOMMANDS = [
|
|
4
5
|
{ cmd: "help", desc: "Categorized command reference with descriptions" },
|
|
@@ -8,6 +9,7 @@ const TOP_LEVEL_SUBCOMMANDS = [
|
|
|
8
9
|
{ cmd: "pause", desc: "Pause auto-mode (preserves state, /gsd auto to resume)" },
|
|
9
10
|
{ cmd: "status", desc: "Progress dashboard" },
|
|
10
11
|
{ cmd: "visualize", desc: "Open workflow visualizer" },
|
|
12
|
+
{ cmd: "brief", desc: "Generate a visual HTML brief" },
|
|
11
13
|
{ cmd: "queue", desc: "Queue and reorder future milestones" },
|
|
12
14
|
{ cmd: "quick", desc: "Execute a quick task without full planning overhead" },
|
|
13
15
|
{ cmd: "discuss", desc: "Discuss architecture and decisions" },
|
|
@@ -87,6 +89,14 @@ function getGsdArgumentCompletions(prefix: string) {
|
|
|
87
89
|
], "next");
|
|
88
90
|
}
|
|
89
91
|
|
|
92
|
+
if (parts[0] === "brief" && parts.length <= 2) {
|
|
93
|
+
return filterStartsWith(
|
|
94
|
+
partial,
|
|
95
|
+
VISUAL_BRIEF_MODES.map((mode) => ({ cmd: mode.mode, desc: mode.description })),
|
|
96
|
+
"brief",
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
90
100
|
if ((parts[0] === "new-project" || parts[0] === "new-milestone") && parts.length <= 2) {
|
|
91
101
|
return filterStartsWith(partial, [
|
|
92
102
|
{ cmd: "--deep", desc: "Enable deep planning mode (staged project-level discovery)" },
|
|
@@ -30,9 +30,10 @@ import { join } from "node:path";
|
|
|
30
30
|
import {
|
|
31
31
|
findStaleWorkerForProject,
|
|
32
32
|
getAllAutoWorkers,
|
|
33
|
+
markWorkerCrashed,
|
|
33
34
|
type AutoWorkerRow,
|
|
34
35
|
} from "./db/auto-workers.js";
|
|
35
|
-
import {
|
|
36
|
+
import { markLatestActiveForWorkerCanceled, type DispatchStatus } from "./db/unit-dispatches.js";
|
|
36
37
|
import { getRuntimeKv, setRuntimeKv, deleteRuntimeKv } from "./db/runtime-kv.js";
|
|
37
38
|
import { _getAdapter, isDbAvailable } from "./gsd-db.js";
|
|
38
39
|
import { gsdRoot, normalizeRealPath } from "./paths.js";
|
|
@@ -56,6 +57,15 @@ function lockPath(basePath: string): string {
|
|
|
56
57
|
return join(gsdRoot(basePath), effectiveLockFile());
|
|
57
58
|
}
|
|
58
59
|
|
|
60
|
+
function clearLegacyLockFile(basePath: string): void {
|
|
61
|
+
try {
|
|
62
|
+
const p = lockPath(basePath);
|
|
63
|
+
if (existsSync(p)) unlinkSync(p);
|
|
64
|
+
} catch {
|
|
65
|
+
// Best-effort.
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
59
69
|
function readLegacyLock(basePath: string): LockData | null {
|
|
60
70
|
try {
|
|
61
71
|
const p = lockPath(basePath);
|
|
@@ -204,18 +214,34 @@ export function writeLock(
|
|
|
204
214
|
* stale session-file pointer.
|
|
205
215
|
*/
|
|
206
216
|
export function clearLock(basePath: string): void {
|
|
217
|
+
clearLegacyLockFile(basePath);
|
|
218
|
+
|
|
219
|
+
if (!isDbAvailable()) return;
|
|
207
220
|
try {
|
|
208
|
-
const
|
|
209
|
-
|
|
221
|
+
const projectRoot = normalizeRealPath(basePath);
|
|
222
|
+
const worker = findActiveWorkerForCurrentProcess(projectRoot);
|
|
223
|
+
if (!worker) return;
|
|
224
|
+
deleteRuntimeKv("worker", worker.worker_id, SESSION_FILE_KV_KEY);
|
|
210
225
|
} catch {
|
|
211
226
|
// Best-effort.
|
|
212
227
|
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Clear a stale DB-backed worker lock after readCrashLock/findStaleWorkerForProject
|
|
232
|
+
* has identified a dead worker. Unlike clearLock(), this targets the stale
|
|
233
|
+
* worker row instead of the current process's active worker.
|
|
234
|
+
*/
|
|
235
|
+
export function clearStaleWorkerLock(basePath: string): void {
|
|
236
|
+
clearLegacyLockFile(basePath);
|
|
213
237
|
|
|
214
238
|
if (!isDbAvailable()) return;
|
|
215
239
|
try {
|
|
216
240
|
const projectRoot = normalizeRealPath(basePath);
|
|
217
|
-
const worker =
|
|
241
|
+
const worker = findStaleWorkerForProject(projectRoot);
|
|
218
242
|
if (!worker) return;
|
|
243
|
+
markLatestActiveForWorkerCanceled(worker.worker_id, "crash-recovered");
|
|
244
|
+
markWorkerCrashed(worker.worker_id);
|
|
219
245
|
deleteRuntimeKv("worker", worker.worker_id, SESSION_FILE_KV_KEY);
|
|
220
246
|
} catch {
|
|
221
247
|
// Best-effort.
|
|
@@ -524,17 +524,18 @@ export function getRecentUnitKeysForProjectRoot(
|
|
|
524
524
|
if (!isDbAvailable()) return [];
|
|
525
525
|
const db = _getAdapter()!;
|
|
526
526
|
const rows = db.prepare(
|
|
527
|
-
`SELECT ud.unit_id
|
|
527
|
+
`SELECT ud.unit_type, ud.unit_id
|
|
528
528
|
FROM unit_dispatches ud
|
|
529
529
|
INNER JOIN workers w ON w.worker_id = ud.worker_id
|
|
530
530
|
WHERE w.project_root_realpath = :project_root_realpath
|
|
531
|
+
AND w.status != 'crashed'
|
|
531
532
|
ORDER BY ud.started_at DESC, ud.id DESC
|
|
532
533
|
LIMIT :limit`,
|
|
533
534
|
).all({
|
|
534
535
|
":project_root_realpath": projectRootRealpath,
|
|
535
536
|
":limit": limit,
|
|
536
|
-
}) as Array<{ unit_id: string }>;
|
|
537
|
-
return rows.reverse().map((r) => ({ key: r.unit_id }));
|
|
537
|
+
}) as Array<{ unit_type: string; unit_id: string }>;
|
|
538
|
+
return rows.reverse().map((r) => ({ key: `${r.unit_type}/${r.unit_id}` }));
|
|
538
539
|
}
|
|
539
540
|
|
|
540
541
|
/**
|
|
@@ -5,7 +5,7 @@ import { findMilestoneIds } from "./guided-flow.js";
|
|
|
5
5
|
import { parseUnitId } from "./unit-id.js";
|
|
6
6
|
import { isDbAvailable, getMilestoneSlices, getMilestone } from "./gsd-db.js";
|
|
7
7
|
import { parseRoadmap } from "./parsers-legacy.js";
|
|
8
|
-
import { isClosedStatus } from "./status-guards.js";
|
|
8
|
+
import { isClosedStatus, isSkippedForDispatch } from "./status-guards.js";
|
|
9
9
|
import { classifyMilestoneSummaryContent } from "./milestone-summary-classifier.js";
|
|
10
10
|
import { readFileSync } from "node:fs";
|
|
11
11
|
|
|
@@ -58,7 +58,7 @@ export function getPriorSliceCompletionBlocker(
|
|
|
58
58
|
// DB-backed projects must not treat SUMMARY.md as authoritative.
|
|
59
59
|
if (isDbAvailable()) {
|
|
60
60
|
const milestoneRow = getMilestone(mid);
|
|
61
|
-
if (milestoneRow &&
|
|
61
|
+
if (milestoneRow && isSkippedForDispatch(milestoneRow.status)) continue;
|
|
62
62
|
} else {
|
|
63
63
|
const summaryPath = resolveMilestoneFile(base, mid, "SUMMARY");
|
|
64
64
|
let summaryContent: string | null = null;
|
|
@@ -7,7 +7,7 @@ import { milestonesDir, gsdRoot, resolveGsdRootFile } from "./paths.js";
|
|
|
7
7
|
import { deriveState, isGhostMilestone, isReusableGhostMilestone } from "./state.js";
|
|
8
8
|
import { saveFile } from "./files.js";
|
|
9
9
|
import { nativeIsRepo, nativeForEachRef, nativeUpdateRef } from "./native-git-bridge.js";
|
|
10
|
-
import { readCrashLock, isLockProcessAlive,
|
|
10
|
+
import { readCrashLock, isLockProcessAlive, clearStaleWorkerLock } from "./crash-recovery.js";
|
|
11
11
|
import { getActiveAutoWorkers } from "./db/auto-workers.js";
|
|
12
12
|
import { normalizeRealPath } from "./paths.js";
|
|
13
13
|
import { ensureGitignore, isGsdGitignored } from "./gitignore.js";
|
|
@@ -56,7 +56,7 @@ export async function checkRuntimeHealth(
|
|
|
56
56
|
});
|
|
57
57
|
|
|
58
58
|
if (shouldFix("stale_crash_lock")) {
|
|
59
|
-
|
|
59
|
+
clearStaleWorkerLock(basePath);
|
|
60
60
|
fixesApplied.push("cleared stale auto-mode worker state");
|
|
61
61
|
}
|
|
62
62
|
}
|
|
@@ -80,17 +80,29 @@ export async function checkRuntimeHealth(
|
|
|
80
80
|
// heartbeat for this project?" — readCrashLock returns null for
|
|
81
81
|
// healthy live workers (it surfaces stale ones only), so we must
|
|
82
82
|
// consult getActiveAutoWorkers directly.
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
83
|
+
let lockHolderAlive = false;
|
|
84
|
+
try {
|
|
85
|
+
const projectRoot = normalizeRealPath(basePath);
|
|
86
|
+
for (const worker of getActiveAutoWorkers()) {
|
|
87
|
+
if (worker.project_root_realpath !== projectRoot) continue;
|
|
88
|
+
try {
|
|
89
|
+
if (isLockProcessAlive({
|
|
90
|
+
pid: worker.pid,
|
|
91
|
+
startedAt: worker.started_at,
|
|
92
|
+
unitType: "starting",
|
|
93
|
+
unitId: "bootstrap",
|
|
94
|
+
unitStartedAt: worker.started_at,
|
|
95
|
+
})) {
|
|
96
|
+
lockHolderAlive = true;
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
} catch {
|
|
100
|
+
// Ignore malformed worker rows or transient PID probe failures.
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
} catch {
|
|
104
|
+
// If worker lookup fails, continue with the stranded lock diagnosis.
|
|
105
|
+
}
|
|
94
106
|
if (!lockHolderAlive) {
|
|
95
107
|
issues.push({
|
|
96
108
|
severity: "error",
|
|
@@ -16,6 +16,7 @@ import type { RoadmapSliceEntry } from "./types.js";
|
|
|
16
16
|
import { checkGitHealth, checkRuntimeHealth, checkGlobalHealth, checkEngineHealth } from "./doctor-checks.js";
|
|
17
17
|
import { checkEnvironmentHealth } from "./doctor-environment.js";
|
|
18
18
|
import { runProviderChecks } from "./doctor-providers.js";
|
|
19
|
+
import { validateTitle } from "./validation.js";
|
|
19
20
|
|
|
20
21
|
// ── Re-exports ─────────────────────────────────────────────────────────────
|
|
21
22
|
// All public types and functions from extracted modules are re-exported here
|
|
@@ -25,33 +26,7 @@ export { summarizeDoctorIssues, filterDoctorIssues, formatDoctorReport, formatDo
|
|
|
25
26
|
export { runEnvironmentChecks, runFullEnvironmentChecks, formatEnvironmentReport, type EnvironmentCheckResult } from "./doctor-environment.js";
|
|
26
27
|
export { computeProgressScore, computeProgressScoreWithContext, formatProgressLine, formatProgressReport, type ProgressScore, type ProgressLevel } from "./progress-score.js";
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
* Characters that are used as delimiters in GSD state management documents
|
|
30
|
-
* and should not appear in milestone or slice titles.
|
|
31
|
-
*
|
|
32
|
-
* - "\u2014" (em dash, U+2014): used as a display separator in STATE.md and other docs.
|
|
33
|
-
* A title containing "\u2014" makes the separator ambiguous, corrupting state display
|
|
34
|
-
* and confusing the LLM agent that reads and writes these files.
|
|
35
|
-
* - "\u2013" (en dash, U+2013): visually similar to em dash; same ambiguity risk.
|
|
36
|
-
* - "/" (forward slash, U+002F): used as the path separator in unit IDs (M001/S01)
|
|
37
|
-
* and git branch names (gsd/M001/S01). A slash in a title can break path resolution.
|
|
38
|
-
*/
|
|
39
|
-
const TITLE_DELIMITER_RE = /[\u2014\u2013\/]/; // em dash, en dash, forward slash
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Check whether a milestone or slice title contains characters that conflict
|
|
43
|
-
* with GSD's state document delimiter conventions.
|
|
44
|
-
* Returns a human-readable description of the problem, or null if the title is safe.
|
|
45
|
-
*/
|
|
46
|
-
export function validateTitle(title: string): string | null {
|
|
47
|
-
if (TITLE_DELIMITER_RE.test(title)) {
|
|
48
|
-
const found: string[] = [];
|
|
49
|
-
if (/[\u2014\u2013]/.test(title)) found.push("em/en dash (\u2014 or \u2013)");
|
|
50
|
-
if (/\//.test(title)) found.push("forward slash (/)");
|
|
51
|
-
return `title contains ${found.join(" and ")}, which conflict with GSD state document delimiters`;
|
|
52
|
-
}
|
|
53
|
-
return null;
|
|
54
|
-
}
|
|
29
|
+
export { validateTitle } from "./validation.js";
|
|
55
30
|
|
|
56
31
|
function validatePreferenceShape(preferences: GSDPreferences): string[] {
|
|
57
32
|
const issues: string[] = [];
|