gsd-pi 2.80.0-dev.c5f2443b3 → 2.80.0-dev.cf9433f56
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 -2
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +2 -2
- package/dist/resources/extensions/github-sync/templates.js +39 -8
- package/dist/resources/extensions/gsd/auto/loop.js +48 -10
- package/dist/resources/extensions/gsd/auto/phases.js +66 -45
- package/dist/resources/extensions/gsd/auto/resolve.js +17 -0
- package/dist/resources/extensions/gsd/auto/run-unit.js +32 -16
- package/dist/resources/extensions/gsd/auto-dashboard.js +51 -15
- package/dist/resources/extensions/gsd/auto-dispatch.js +10 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +10 -10
- package/dist/resources/extensions/gsd/auto-prompts.js +124 -2
- package/dist/resources/extensions/gsd/auto-recovery.js +197 -9
- package/dist/resources/extensions/gsd/auto-start.js +2 -3
- package/dist/resources/extensions/gsd/auto-supervisor.js +8 -1
- package/dist/resources/extensions/gsd/auto-timeout-recovery.js +2 -2
- package/dist/resources/extensions/gsd/auto.js +77 -5
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +36 -3
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +27 -20
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +32 -1
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +129 -1
- package/dist/resources/extensions/gsd/clean-root-preflight.js +42 -4
- package/dist/resources/extensions/gsd/commands/dispatcher.js +5 -0
- package/dist/resources/extensions/gsd/commands-extract-learnings.js +17 -12
- package/dist/resources/extensions/gsd/context-budget.js +37 -2
- package/dist/resources/extensions/gsd/crash-recovery.js +56 -10
- package/dist/resources/extensions/gsd/custom-workflow-engine.js +22 -2
- package/dist/resources/extensions/gsd/db/unit-dispatches.js +39 -0
- package/dist/resources/extensions/gsd/db-base-schema.js +18 -2
- package/dist/resources/extensions/gsd/db-migration-steps.js +22 -0
- package/dist/resources/extensions/gsd/detection.js +106 -0
- package/dist/resources/extensions/gsd/git-service.js +36 -4
- package/dist/resources/extensions/gsd/graph.js +9 -3
- package/dist/resources/extensions/gsd/gsd-db.js +146 -13
- package/dist/resources/extensions/gsd/guided-flow.js +82 -16
- package/dist/resources/extensions/gsd/memory-store.js +69 -12
- package/dist/resources/extensions/gsd/migrate/command.js +40 -1
- package/dist/resources/extensions/gsd/migration-auto-check.js +87 -0
- package/dist/resources/extensions/gsd/planning-path-scope.js +26 -0
- package/dist/resources/extensions/gsd/pr-evidence.js +57 -16
- package/dist/resources/extensions/gsd/pre-execution-checks.js +7 -0
- package/dist/resources/extensions/gsd/prompt-loader.js +28 -2
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +19 -19
- package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +3 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -5
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
- package/dist/resources/extensions/gsd/quick.js +34 -2
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +10 -2
- package/dist/resources/extensions/gsd/tools/context-mode-tool-result.js +15 -0
- package/dist/resources/extensions/gsd/tools/exec-search-tool.js +5 -0
- package/dist/resources/extensions/gsd/tools/exec-tool.js +3 -15
- package/dist/resources/extensions/gsd/tools/memory-tools.js +1 -0
- package/dist/resources/extensions/gsd/tools/plan-slice.js +9 -0
- package/dist/resources/extensions/gsd/tools/plan-task.js +9 -0
- package/dist/resources/extensions/gsd/tools/resume-tool.js +5 -0
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +1 -1
- package/dist/resources/extensions/gsd/unit-context-composer.js +12 -3
- package/dist/resources/extensions/gsd/unit-runtime.js +22 -0
- package/dist/resources/extensions/gsd/working-output-messages.js +64 -0
- package/dist/resources/extensions/gsd/worktree-manager.js +16 -14
- package/dist/resources/extensions/gsd/worktree-resolver.js +33 -17
- 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 +10 -10
- 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/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
- package/dist/web/standalone/.next/server/chunks/6897.js +3 -3
- 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 +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/{8336.6f6f30e410419aff.js → 8336.631939fb583761fa.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/{webpack-d82dbee6356c1733.js → webpack-0481f1221120a7c6.js} +1 -1
- package/package.json +12 -8
- package/packages/contracts/package.json +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +22 -17
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/src/workflow-tools.test.ts +75 -2
- package/packages/mcp-server/src/workflow-tools.ts +30 -16
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/models/fake-model.d.ts +12 -0
- package/packages/pi-ai/dist/models/fake-model.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/fake-model.js +27 -0
- package/packages/pi-ai/dist/models/fake-model.js.map +1 -0
- package/packages/pi-ai/dist/models/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/index.js +8 -0
- package/packages/pi-ai/dist/models/index.js.map +1 -1
- package/packages/pi-ai/dist/providers/fake.d.ts +42 -0
- package/packages/pi-ai/dist/providers/fake.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/fake.js +319 -0
- package/packages/pi-ai/dist/providers/fake.js.map +1 -0
- package/packages/pi-ai/dist/providers/register-builtins.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/register-builtins.js +24 -0
- package/packages/pi-ai/dist/providers/register-builtins.js.map +1 -1
- package/packages/pi-ai/src/models/fake-model.ts +30 -0
- package/packages/pi-ai/src/models/index.ts +9 -0
- package/packages/pi-ai/src/providers/fake.ts +376 -0
- package/packages/pi-ai/src/providers/register-builtins.ts +23 -0
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +32 -0
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +8 -0
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +76 -0
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +11 -0
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js +9 -0
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js +103 -0
- package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts +15 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.js +66 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.js +24 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.js +17 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +99 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +7 -0
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +5 -0
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +24 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +33 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/slash-commands.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/slash-commands.js +1 -0
- package/packages/pi-coding-agent/dist/core/slash-commands.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.js +6 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +54 -15
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts +26 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js +112 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js +51 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +10 -9
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +3 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +11 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js +7 -6
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +17 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +109 -17
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.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 +69 -2
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +93 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +3 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +26 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js +20 -0
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.js +79 -0
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.d.ts +12 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.js +13 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +18 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +36 -27
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.d.ts +11 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.js +18 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js +48 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js +10 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js +3 -2
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js.map +1 -1
- package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +36 -0
- package/packages/pi-coding-agent/src/core/agent-session.ts +8 -0
- package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +89 -0
- package/packages/pi-coding-agent/src/core/compaction/compaction.ts +18 -0
- package/packages/pi-coding-agent/src/core/compaction-threshold.test.ts +121 -0
- package/packages/pi-coding-agent/src/core/db-snapshot.test.ts +32 -0
- package/packages/pi-coding-agent/src/core/db-snapshot.ts +66 -0
- package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +110 -0
- package/packages/pi-coding-agent/src/core/extensions/runner.ts +19 -1
- package/packages/pi-coding-agent/src/core/extensions/types.ts +7 -0
- package/packages/pi-coding-agent/src/core/model-registry.ts +4 -0
- package/packages/pi-coding-agent/src/core/settings-manager.ts +51 -1
- package/packages/pi-coding-agent/src/core/slash-commands.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.ts +7 -5
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +78 -15
- package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.test.ts +59 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.ts +160 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +10 -9
- package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +15 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.ts +10 -9
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +122 -17
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +99 -1
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +92 -3
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +28 -0
- package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.test.ts +95 -0
- package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.ts +24 -1
- package/packages/pi-coding-agent/src/modes/interactive/theme/theme-schema.ts +13 -0
- package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +32 -2
- package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +36 -27
- package/packages/pi-coding-agent/src/modes/interactive/tui-mode.test.ts +65 -0
- package/packages/pi-coding-agent/src/modes/interactive/tui-mode.ts +29 -0
- package/packages/pi-coding-agent/src/resources/extensions/memory/storage-safety-guard.test.ts +14 -0
- package/packages/pi-coding-agent/src/resources/extensions/memory/storage.ts +3 -2
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/__tests__/style.test.d.ts +2 -0
- package/packages/pi-tui/dist/__tests__/style.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/__tests__/style.test.js +63 -0
- package/packages/pi-tui/dist/__tests__/style.test.js.map +1 -0
- package/packages/pi-tui/dist/__tests__/tui.test.js +24 -3
- package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
- package/packages/pi-tui/dist/index.d.ts +1 -0
- package/packages/pi-tui/dist/index.d.ts.map +1 -1
- package/packages/pi-tui/dist/index.js +2 -0
- package/packages/pi-tui/dist/index.js.map +1 -1
- package/packages/pi-tui/dist/style.d.ts +41 -0
- package/packages/pi-tui/dist/style.d.ts.map +1 -0
- package/packages/pi-tui/dist/style.js +158 -0
- package/packages/pi-tui/dist/style.js.map +1 -0
- package/packages/pi-tui/dist/tui.d.ts +0 -1
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +21 -16
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/src/__tests__/style.test.ts +76 -0
- package/packages/pi-tui/src/__tests__/tui.test.ts +29 -3
- package/packages/pi-tui/src/index.ts +9 -0
- package/packages/pi-tui/src/style.ts +225 -0
- package/packages/pi-tui/src/tui.ts +23 -16
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/pkg/dist/modes/interactive/theme/theme-schema.d.ts +12 -0
- package/pkg/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/theme-schema.js +13 -0
- package/pkg/dist/modes/interactive/theme/theme-schema.js.map +1 -1
- package/pkg/dist/modes/interactive/theme/theme.d.ts +1 -1
- package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/theme.js +18 -1
- package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
- package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/themes.js +36 -27
- package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
- package/src/resources/GSD-WORKFLOW.md +2 -2
- package/src/resources/extensions/github-sync/templates.ts +38 -8
- package/src/resources/extensions/github-sync/tests/inline-code.test.ts +66 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
- package/src/resources/extensions/gsd/auto/loop.ts +67 -18
- package/src/resources/extensions/gsd/auto/phases.ts +77 -48
- package/src/resources/extensions/gsd/auto/resolve.ts +23 -1
- package/src/resources/extensions/gsd/auto/run-unit.ts +42 -15
- package/src/resources/extensions/gsd/auto-dashboard.ts +57 -8
- package/src/resources/extensions/gsd/auto-dispatch.ts +17 -0
- package/src/resources/extensions/gsd/auto-post-unit.ts +10 -10
- package/src/resources/extensions/gsd/auto-prompts.ts +133 -2
- package/src/resources/extensions/gsd/auto-recovery.ts +207 -7
- package/src/resources/extensions/gsd/auto-start.ts +7 -6
- package/src/resources/extensions/gsd/auto-supervisor.ts +7 -0
- package/src/resources/extensions/gsd/auto-timeout-recovery.ts +2 -2
- package/src/resources/extensions/gsd/auto.ts +92 -4
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +37 -2
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +27 -19
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +39 -1
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +135 -1
- package/src/resources/extensions/gsd/clean-root-preflight.ts +41 -3
- package/src/resources/extensions/gsd/commands/dispatcher.ts +6 -0
- package/src/resources/extensions/gsd/commands-extract-learnings.ts +17 -12
- package/src/resources/extensions/gsd/context-budget.ts +44 -2
- package/src/resources/extensions/gsd/crash-recovery.ts +67 -10
- package/src/resources/extensions/gsd/custom-workflow-engine.ts +24 -1
- package/src/resources/extensions/gsd/db/unit-dispatches.ts +41 -0
- package/src/resources/extensions/gsd/db-base-schema.ts +19 -2
- package/src/resources/extensions/gsd/db-migration-steps.ts +25 -0
- package/src/resources/extensions/gsd/detection.ts +128 -0
- package/src/resources/extensions/gsd/git-service.ts +46 -8
- package/src/resources/extensions/gsd/graph.ts +12 -5
- package/src/resources/extensions/gsd/gsd-db.ts +168 -13
- package/src/resources/extensions/gsd/guided-flow.ts +98 -16
- package/src/resources/extensions/gsd/memory-store.ts +77 -12
- package/src/resources/extensions/gsd/migrate/command.ts +47 -1
- package/src/resources/extensions/gsd/migration-auto-check.ts +129 -0
- package/src/resources/extensions/gsd/planning-path-scope.ts +35 -0
- package/src/resources/extensions/gsd/pr-evidence.ts +63 -5
- package/src/resources/extensions/gsd/pre-execution-checks.ts +7 -0
- package/src/resources/extensions/gsd/preferences-types.ts +1 -1
- package/src/resources/extensions/gsd/prompt-loader.ts +27 -2
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +19 -19
- package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +3 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/quick-task.md +1 -5
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
- package/src/resources/extensions/gsd/quick.ts +37 -2
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +11 -2
- package/src/resources/extensions/gsd/tests/auto-abort-pause-regression.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +33 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +155 -5
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +56 -13
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +184 -2
- package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +88 -2
- package/src/resources/extensions/gsd/tests/commands-extract-learnings.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +14 -1
- package/src/resources/extensions/gsd/tests/context-budget.test.ts +10 -1
- package/src/resources/extensions/gsd/tests/crash-handler-secondary.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +112 -6
- package/src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts +40 -2
- package/src/resources/extensions/gsd/tests/db-migration-steps.integration.test.ts +428 -0
- package/src/resources/extensions/gsd/tests/db-schema-metadata.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/detection.test.ts +140 -0
- package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +313 -0
- package/src/resources/extensions/gsd/tests/exec-history.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/fixtures/pr-body/commands-ship-basic.md +52 -0
- package/src/resources/extensions/gsd/tests/fixtures/pr-body/commands-ship-empty-optionals.md +42 -0
- package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-no-blockers.md +55 -0
- package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-with-blockers.md +60 -0
- package/src/resources/extensions/gsd/tests/graph-operations.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/has-pending-deep-stage.test.ts +33 -1
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +234 -0
- package/src/resources/extensions/gsd/tests/memory-decay-factor.test.ts +90 -0
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +127 -0
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/pr-evidence-equivalence.test.ts +102 -0
- package/src/resources/extensions/gsd/tests/pr-evidence-hardening.test.ts +165 -0
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/prompt-path-audit.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/quick-external-gsd.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/right-sized-workflow-prompts.test.ts +192 -0
- package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +29 -0
- package/src/resources/extensions/gsd/tests/schema-v27-v28-sequence.test.ts +156 -0
- package/src/resources/extensions/gsd/tests/signal-handlers.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +49 -1
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +101 -2
- package/src/resources/extensions/gsd/tests/status-db-open.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +136 -4
- package/src/resources/extensions/gsd/tests/unit-dispatches.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/working-output-messages.test.ts +93 -0
- package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +37 -6
- package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +9 -2
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +63 -1
- package/src/resources/extensions/gsd/tests/worktree-write-gate.test.ts +179 -0
- package/src/resources/extensions/gsd/tools/context-mode-tool-result.ts +25 -0
- package/src/resources/extensions/gsd/tools/exec-search-tool.ts +7 -7
- package/src/resources/extensions/gsd/tools/exec-tool.ts +4 -23
- package/src/resources/extensions/gsd/tools/memory-tools.ts +1 -0
- package/src/resources/extensions/gsd/tools/plan-slice.ts +13 -0
- package/src/resources/extensions/gsd/tools/plan-task.ts +10 -0
- package/src/resources/extensions/gsd/tools/resume-tool.ts +7 -7
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +1 -1
- package/src/resources/extensions/gsd/unit-context-composer.ts +19 -4
- package/src/resources/extensions/gsd/unit-runtime.ts +25 -0
- package/src/resources/extensions/gsd/working-output-messages.ts +120 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +15 -4
- package/src/resources/extensions/gsd/worktree-resolver.ts +36 -15
- package/packages/contracts/tsconfig.tsbuildinfo +0 -1
- /package/dist/web/standalone/.next/static/{bQDK5_LtkGVS64AirQgQG → -5nHJWzSdG-WkPMul_khA}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{bQDK5_LtkGVS64AirQgQG → -5nHJWzSdG-WkPMul_khA}/_ssgManifest.js +0 -0
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* Auto-mode Dashboard — progress widget rendering, elapsed time formatting,
|
|
3
|
-
* unit description helpers, and slice progress caching.
|
|
4
|
-
*
|
|
5
|
-
* Pure functions that accept specific parameters — no module-level globals
|
|
6
|
-
* or AutoContext dependency. State accessors are passed as callbacks.
|
|
7
|
-
*/
|
|
1
|
+
// GSD-2 + src/resources/extensions/gsd/auto-dashboard.ts - Auto-mode progress widget rendering and dashboard helpers.
|
|
8
2
|
import { getCurrentBranch } from "./worktree.js";
|
|
9
3
|
import { getActiveHook } from "./post-unit-hooks.js";
|
|
10
4
|
import { getLedger, getProjectTotals } from "./metrics.js";
|
|
@@ -25,6 +19,7 @@ import { formatRtkSavingsLabel, getRtkSessionSavings, } from "../shared/rtk-sess
|
|
|
25
19
|
import { logWarning } from "./workflow-logger.js";
|
|
26
20
|
import { formattedShortcutPair } from "./shortcut-defs.js";
|
|
27
21
|
import { homedir } from "node:os";
|
|
22
|
+
import { readUnitRuntimeRecord } from "./unit-runtime.js";
|
|
28
23
|
// ─── UAT Slice Extraction ─────────────────────────────────────────────────────
|
|
29
24
|
/**
|
|
30
25
|
* Extract the target slice ID from a run-uat unit ID (e.g. "M001/S01" → "S01").
|
|
@@ -165,6 +160,30 @@ export function formatWidgetTokens(count) {
|
|
|
165
160
|
return `${(count / 1000000).toFixed(1)}M`;
|
|
166
161
|
return `${Math.round(count / 1000000)}M`;
|
|
167
162
|
}
|
|
163
|
+
export function formatRuntimeHealthSignal(record, now = Date.now()) {
|
|
164
|
+
if (!record)
|
|
165
|
+
return null;
|
|
166
|
+
const idleMs = Math.max(0, now - record.lastProgressAt);
|
|
167
|
+
const idleMinutes = Math.floor(idleMs / 60_000);
|
|
168
|
+
if ((record.recoveryAttempts ?? 0) > 0 || record.phase === "recovered" || record.lastProgressKind.includes("recovery")) {
|
|
169
|
+
return {
|
|
170
|
+
level: "yellow",
|
|
171
|
+
summary: "Recovering",
|
|
172
|
+
detail: `retry ${record.recoveryAttempts ?? 1} after ${record.lastRecoveryReason ?? "idle"} stall`,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
if (record.progressCount === 0 && idleMs >= 60_000) {
|
|
176
|
+
return {
|
|
177
|
+
level: "yellow",
|
|
178
|
+
summary: "Waiting on provider",
|
|
179
|
+
detail: `no output for ${idleMinutes}m`,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
export function shouldRenderRoadmapProgress(progress) {
|
|
185
|
+
return !!progress && progress.total > 0;
|
|
186
|
+
}
|
|
168
187
|
// ─── ETA Estimation ──────────────────────────────────────────────────────────
|
|
169
188
|
/**
|
|
170
189
|
* Estimate remaining time based on average unit duration from the metrics ledger.
|
|
@@ -499,6 +518,7 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
|
|
|
499
518
|
let cachedLines;
|
|
500
519
|
let cachedWidth;
|
|
501
520
|
let cachedRtkLabel;
|
|
521
|
+
let cachedRuntimeRecord = null;
|
|
502
522
|
const refreshRtkLabel = () => {
|
|
503
523
|
try {
|
|
504
524
|
const sessionId = ctx.sessionManager.getSessionId();
|
|
@@ -510,7 +530,16 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
|
|
|
510
530
|
cachedRtkLabel = null;
|
|
511
531
|
}
|
|
512
532
|
};
|
|
533
|
+
const refreshRuntimeRecord = () => {
|
|
534
|
+
try {
|
|
535
|
+
cachedRuntimeRecord = readUnitRuntimeRecord(accessors.getBasePath(), unitType, unitId);
|
|
536
|
+
}
|
|
537
|
+
catch {
|
|
538
|
+
cachedRuntimeRecord = null;
|
|
539
|
+
}
|
|
540
|
+
};
|
|
513
541
|
refreshRtkLabel();
|
|
542
|
+
refreshRuntimeRecord();
|
|
514
543
|
const pulseTimer = setInterval(() => {
|
|
515
544
|
pulseBright = !pulseBright;
|
|
516
545
|
cachedLines = undefined;
|
|
@@ -526,6 +555,7 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
|
|
|
526
555
|
updateSliceProgressCache(accessors.getBasePath(), mid.id, slice?.id);
|
|
527
556
|
}
|
|
528
557
|
refreshRtkLabel();
|
|
558
|
+
refreshRuntimeRecord();
|
|
529
559
|
cachedLines = undefined;
|
|
530
560
|
}
|
|
531
561
|
catch (err) { /* non-fatal */
|
|
@@ -555,13 +585,16 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
|
|
|
555
585
|
const modeTag = accessors.isStepMode() ? "NEXT" : "AUTO";
|
|
556
586
|
// Health indicator in header
|
|
557
587
|
const score = computeProgressScore();
|
|
558
|
-
const
|
|
559
|
-
|
|
588
|
+
const runtimeSignal = formatRuntimeHealthSignal(cachedRuntimeRecord);
|
|
589
|
+
const healthLevel = runtimeSignal?.level ?? score.level;
|
|
590
|
+
const healthSummary = runtimeSignal?.summary ?? score.summary;
|
|
591
|
+
const healthColor = healthLevel === "green" ? "success"
|
|
592
|
+
: healthLevel === "yellow" ? "warning"
|
|
560
593
|
: "error";
|
|
561
|
-
const healthIcon =
|
|
562
|
-
:
|
|
594
|
+
const healthIcon = healthLevel === "green" ? GLYPH.statusActive
|
|
595
|
+
: healthLevel === "yellow" ? "!"
|
|
563
596
|
: "x";
|
|
564
|
-
const healthStr = ` ${theme.fg(healthColor, healthIcon)} ${theme.fg(healthColor,
|
|
597
|
+
const healthStr = ` ${theme.fg(healthColor, healthIcon)} ${theme.fg(healthColor, healthSummary)}`;
|
|
565
598
|
const headerLeft = `${pad}${dot} ${theme.fg("accent", theme.bold("GSD"))} ${theme.fg("success", modeTag)}${healthStr}`;
|
|
566
599
|
// ETA in header right, after elapsed
|
|
567
600
|
const eta = estimateTimeRemaining();
|
|
@@ -573,7 +606,10 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
|
|
|
573
606
|
: "";
|
|
574
607
|
lines.push(rightAlign(headerLeft, headerRight, width));
|
|
575
608
|
// Show health signal details when degraded (yellow/red)
|
|
576
|
-
if (
|
|
609
|
+
if (runtimeSignal?.detail && widgetMode !== "min") {
|
|
610
|
+
lines.push(`${pad} ${theme.fg("dim", runtimeSignal.detail)}`);
|
|
611
|
+
}
|
|
612
|
+
else if (score.level !== "green" && score.signals.length > 0 && widgetMode !== "min") {
|
|
577
613
|
// Show up to 3 most relevant signals in compact form
|
|
578
614
|
const topSignals = score.signals
|
|
579
615
|
.filter(s => s.kind === "negative")
|
|
@@ -645,7 +681,7 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
|
|
|
645
681
|
lines.push(rightAlign(actionLeft, theme.fg("dim", phaseLabel), width));
|
|
646
682
|
// Progress bar
|
|
647
683
|
const roadmapSlices = mid ? getRoadmapSlicesSync() : null;
|
|
648
|
-
if (roadmapSlices) {
|
|
684
|
+
if (shouldRenderRoadmapProgress(roadmapSlices)) {
|
|
649
685
|
const { done, total, activeSliceTasks } = roadmapSlices;
|
|
650
686
|
const barWidth = Math.max(6, Math.min(18, Math.floor(width * 0.25)));
|
|
651
687
|
const pct = total > 0 ? done / total : 0;
|
|
@@ -706,7 +742,7 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
|
|
|
706
742
|
? Math.floor(width * (width >= 100 ? 0.45 : 0.50))
|
|
707
743
|
: width;
|
|
708
744
|
const leftLines = [];
|
|
709
|
-
if (roadmapSlices) {
|
|
745
|
+
if (shouldRenderRoadmapProgress(roadmapSlices)) {
|
|
710
746
|
const { done, total, activeSliceTasks } = roadmapSlices;
|
|
711
747
|
const barWidth = Math.max(6, Math.min(18, Math.floor(leftColWidth * 0.4)));
|
|
712
748
|
const pct = total > 0 ? done / total : 0;
|
|
@@ -93,6 +93,16 @@ export function hasPendingDeepStage(prefs, basePath) {
|
|
|
93
93
|
const gate = getDeepStageGate(prefs, basePath);
|
|
94
94
|
return gate.status === "pending" || gate.status === "blocked";
|
|
95
95
|
}
|
|
96
|
+
export function shouldRunDeepProjectSetup(state, prefs, basePath, options = {}) {
|
|
97
|
+
if (options.hasSurvivorBranch === true)
|
|
98
|
+
return false;
|
|
99
|
+
if (state.phase !== "pre-planning" &&
|
|
100
|
+
state.phase !== "needs-discussion" &&
|
|
101
|
+
state.phase !== "planning") {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
return hasPendingDeepStage(prefs, basePath);
|
|
105
|
+
}
|
|
96
106
|
function missingSliceStop(mid, phase) {
|
|
97
107
|
return {
|
|
98
108
|
action: "stop",
|
|
@@ -25,7 +25,7 @@ import { verifyExpectedArtifact, resolveExpectedArtifactPath, writeBlockerPlaceh
|
|
|
25
25
|
import { regenerateIfMissing } from "./workflow-projections.js";
|
|
26
26
|
import { syncStateToProjectRoot } from "./auto-worktree.js";
|
|
27
27
|
import { normalizeWorktreePathForCompare } from "./worktree-root.js";
|
|
28
|
-
import { isDbAvailable, getTask, getSlice, getMilestone, updateTaskStatus, _getAdapter } from "./gsd-db.js";
|
|
28
|
+
import { isDbAvailable, getTask, getSlice, getMilestone, updateTaskStatus, _getAdapter, getVerificationEvidence } from "./gsd-db.js";
|
|
29
29
|
import { renderPlanCheckboxes } from "./markdown-renderer.js";
|
|
30
30
|
import { consumeSignal } from "./session-status-io.js";
|
|
31
31
|
import { checkPostUnitHooks, isRetryPending, consumeRetryTrigger, persistHookState, resolveHookArtifactPath, } from "./post-unit-hooks.js";
|
|
@@ -719,21 +719,21 @@ export async function postUnitPreVerification(pctx, opts) {
|
|
|
719
719
|
}
|
|
720
720
|
}
|
|
721
721
|
// Evidence cross-reference (execute-task only)
|
|
722
|
-
//
|
|
723
|
-
//
|
|
724
|
-
//
|
|
725
|
-
// we can still detect units that claimed success but ran no commands.
|
|
722
|
+
// Only compare against concrete command evidence persisted by the task
|
|
723
|
+
// completion tool. A prose Verify field can be satisfied later by the
|
|
724
|
+
// host verification gate, so it is not enough to accuse the unit.
|
|
726
725
|
if (safetyConfig.evidence_cross_reference && s.currentUnit.type === "execute-task") {
|
|
727
726
|
try {
|
|
728
727
|
const actual = getEvidence();
|
|
729
728
|
const bashCalls = actual.filter(e => e.kind === "bash");
|
|
730
|
-
// If the task is marked complete but zero bash commands were run,
|
|
731
|
-
// it's suspicious — the LLM may have fabricated results.
|
|
732
729
|
if (sMid && sSid && sTid && isDbAvailable()) {
|
|
733
730
|
const taskRow = getTask(sMid, sSid, sTid);
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
731
|
+
const claimedCommands = getVerificationEvidence(sMid, sSid, sTid)
|
|
732
|
+
.map((row) => row.command)
|
|
733
|
+
.filter((command) => typeof command === "string" && command.trim().length > 0);
|
|
734
|
+
if (taskRow?.status === "complete" && claimedCommands.length > 0 && bashCalls.length === 0) {
|
|
735
|
+
logWarning("safety", "task claimed verification command evidence but no execution tool calls were recorded");
|
|
736
|
+
ctx.ui.notify(`Safety: task ${sTid} claimed command evidence but no execution tool calls were recorded`, "warning");
|
|
737
737
|
}
|
|
738
738
|
}
|
|
739
739
|
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* utility.
|
|
7
7
|
*/
|
|
8
8
|
import { loadFile, parseContinue, parseSummary, loadActiveOverrides, formatOverridesSection, parseTaskPlanFile } from "./files.js";
|
|
9
|
-
import { hasVerdict, getUatType } from "./verdict-parser.js";
|
|
9
|
+
import { hasVerdict, getUatType, extractVerdict } from "./verdict-parser.js";
|
|
10
10
|
import { loadPrompt, inlineTemplate } from "./prompt-loader.js";
|
|
11
11
|
import { resolveMilestoneFile, resolveSliceFile, resolveSlicePath, resolveTasksDir, resolveTaskFiles, resolveTaskFile, relMilestoneFile, relSliceFile, relSlicePath, relMilestonePath, resolveGsdRootFile, relGsdRootFile, resolveRuntimeFile, } from "./paths.js";
|
|
12
12
|
import { resolveSkillDiscoveryMode, resolveInlineLevel, loadEffectiveGSDPreferences, resolveAllSkillReferences } from "./preferences.js";
|
|
@@ -21,10 +21,12 @@ import { assertGateCoverage, getGatesForTurn, } from "./gate-registry.js";
|
|
|
21
21
|
import { formatDecisionsCompact, formatRequirementsCompact } from "./structured-data-formatter.js";
|
|
22
22
|
import { readPhaseAnchor, formatAnchorForPrompt } from "./phase-anchor.js";
|
|
23
23
|
import { composeContextModeInstructions, composeInlinedContext } from "./unit-context-composer.js";
|
|
24
|
+
import { readCompactionSnapshot } from "./compaction-snapshot.js";
|
|
24
25
|
import { logWarning } from "./workflow-logger.js";
|
|
25
26
|
import { inlineGraphSubgraph } from "./graph-context.js";
|
|
26
27
|
import { buildExtractionStepsBlock } from "./commands-extract-learnings.js";
|
|
27
28
|
import { resolveSkillManifest, warnIfManifestHasMissingSkills } from "./skill-manifest.js";
|
|
29
|
+
import { classifyProject } from "./detection.js";
|
|
28
30
|
// ─── Preamble Cap ─────────────────────────────────────────────────────────────
|
|
29
31
|
/**
|
|
30
32
|
* Historical static ceiling for the preamble cap. Kept as an upper bound even
|
|
@@ -62,6 +64,104 @@ function resolvePromptBudgets() {
|
|
|
62
64
|
function resolveSummaryBudgetChars() {
|
|
63
65
|
return resolvePromptBudgets().summaryBudgetChars;
|
|
64
66
|
}
|
|
67
|
+
function formatProjectClassificationForPlanning(classification) {
|
|
68
|
+
const sampleFiles = classification.contentFiles.slice(0, 8);
|
|
69
|
+
const sample = sampleFiles.length > 0 ? sampleFiles.map((file) => `\`${file}\``).join(", ") : "(none)";
|
|
70
|
+
const lines = [
|
|
71
|
+
"### Project Classification",
|
|
72
|
+
"",
|
|
73
|
+
`- **Kind:** ${classification.kind}`,
|
|
74
|
+
`- **Content files:** ${classification.contentFiles.length}`,
|
|
75
|
+
`- **Sample files:** ${sample}`,
|
|
76
|
+
`- **Reason:** ${classification.reason}`,
|
|
77
|
+
"",
|
|
78
|
+
];
|
|
79
|
+
if (classification.kind === "untyped-existing") {
|
|
80
|
+
if (classification.contentFiles.length <= 2) {
|
|
81
|
+
lines.push("**Workflow sizing:** This is a tiny existing untyped project. Prefer exactly one slice unless the milestone request clearly spans multiple independent user-visible capabilities.");
|
|
82
|
+
}
|
|
83
|
+
else if (classification.contentFiles.length <= 5) {
|
|
84
|
+
lines.push("**Workflow sizing:** This is a small existing untyped project. Prefer 1-2 slices unless the milestone request clearly spans multiple independent user-visible capabilities.");
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
lines.push("**Workflow sizing:** Existing untyped project. Use generic file-level workflow guidance and size slices by real capability boundaries, not by missing tooling markers.");
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
else if (classification.kind === "greenfield") {
|
|
91
|
+
lines.push("**Workflow sizing:** No project content exists yet. Use normal greenfield sizing for the requested scope.");
|
|
92
|
+
}
|
|
93
|
+
else if (classification.kind === "typed-existing") {
|
|
94
|
+
lines.push("**Workflow sizing:** Known project markers exist. Use normal ecosystem-aware planning guidance.");
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
lines.push("**Workflow sizing:** Invalid repository state. Planning should surface this as a blocker rather than inventing project structure.");
|
|
98
|
+
}
|
|
99
|
+
return lines.join("\n");
|
|
100
|
+
}
|
|
101
|
+
function normalizeArtifactRef(value) {
|
|
102
|
+
return value.trim().replace(/^[-\s]+/, "").replace(/^["'`]+|["'`]+$/g, "").replaceAll("\\", "/").replace(/^\.\//, "");
|
|
103
|
+
}
|
|
104
|
+
function parseCoveredArtifacts(validationContent) {
|
|
105
|
+
const covered = new Set();
|
|
106
|
+
const lines = validationContent.split(/\r?\n/);
|
|
107
|
+
let inCoveredArtifacts = false;
|
|
108
|
+
for (const line of lines) {
|
|
109
|
+
if (/^\s*covered[-_]?artifacts\s*:/i.test(line)) {
|
|
110
|
+
inCoveredArtifacts = true;
|
|
111
|
+
const inline = line.split(/covered[-_]?artifacts\s*:/i)[1]?.trim();
|
|
112
|
+
if (inline && inline !== "[]") {
|
|
113
|
+
inline.replace(/^\[|\]$/g, "").split(",").map(normalizeArtifactRef).filter(Boolean).forEach((item) => covered.add(item));
|
|
114
|
+
}
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
if (!inCoveredArtifacts)
|
|
118
|
+
continue;
|
|
119
|
+
if (/^\S/.test(line) && !/^\s*-/.test(line))
|
|
120
|
+
break;
|
|
121
|
+
const item = line.match(/^\s*-\s*(.+)$/)?.[1];
|
|
122
|
+
if (item)
|
|
123
|
+
covered.add(normalizeArtifactRef(item));
|
|
124
|
+
}
|
|
125
|
+
return covered;
|
|
126
|
+
}
|
|
127
|
+
function isValidationFreshOrApplicable(validationContent, currentArtifacts) {
|
|
128
|
+
if (!validationContent)
|
|
129
|
+
return false;
|
|
130
|
+
if (!/validation_metadata:/i.test(validationContent))
|
|
131
|
+
return false;
|
|
132
|
+
const coveredArtifacts = parseCoveredArtifacts(validationContent);
|
|
133
|
+
if (coveredArtifacts.size === 0)
|
|
134
|
+
return false;
|
|
135
|
+
return currentArtifacts
|
|
136
|
+
.map(normalizeArtifactRef)
|
|
137
|
+
.filter(Boolean)
|
|
138
|
+
.every((artifact) => coveredArtifacts.has(artifact));
|
|
139
|
+
}
|
|
140
|
+
function formatCloseoutReviewInstructions(validationContent, validationRel, currentArtifacts) {
|
|
141
|
+
const verdict = validationContent ? extractVerdict(validationContent) : null;
|
|
142
|
+
const validationFresh = isValidationFreshOrApplicable(validationContent, currentArtifacts);
|
|
143
|
+
if (verdict === "pass" && validationFresh) {
|
|
144
|
+
return [
|
|
145
|
+
"### Passing Validation Artifact",
|
|
146
|
+
"",
|
|
147
|
+
`A passing validation artifact is present at \`${validationRel}\`. Treat it as authoritative for success criteria, requirement coverage, verification classes, and cross-slice integration.`,
|
|
148
|
+
"",
|
|
149
|
+
"Do not delegate fresh reviewer/security/tester audits and do not redo the validation evidence review unless the artifact is internally inconsistent with the inlined summaries. Focus this unit on final milestone narrative, learnings, PROJECT/requirements updates, and `gsd_complete_milestone`.",
|
|
150
|
+
].join("\n");
|
|
151
|
+
}
|
|
152
|
+
if (verdict) {
|
|
153
|
+
return [
|
|
154
|
+
"### Validation Requires Attention",
|
|
155
|
+
"",
|
|
156
|
+
`A validation artifact is present at \`${validationRel}\` with verdict \`${verdict}\`, but it is missing freshness metadata or does not cover current milestone artifacts. Do not treat the milestone as complete unless the issues are resolved and evidence supports completion.`,
|
|
157
|
+
].join("\n");
|
|
158
|
+
}
|
|
159
|
+
return [
|
|
160
|
+
"### No Passing Validation Artifact",
|
|
161
|
+
"",
|
|
162
|
+
`No passing validation artifact was found at \`${validationRel}\`. Use the full closeout review path before completion.`,
|
|
163
|
+
].join("\n");
|
|
164
|
+
}
|
|
65
165
|
function capPreamble(preamble) {
|
|
66
166
|
// Cap inlined context at min(historical 30K ceiling, scaled inline budget).
|
|
67
167
|
// The ceiling preserves pre-fix behavior for large-window users; the scaled
|
|
@@ -79,8 +179,19 @@ function renderContextModeForPrompt(unitType, base, renderMode = "standalone") {
|
|
|
79
179
|
renderMode,
|
|
80
180
|
});
|
|
81
181
|
}
|
|
82
|
-
function
|
|
182
|
+
function renderContextModeBlockForPrompt(unitType, base, renderMode = "standalone") {
|
|
83
183
|
const contextMode = renderContextModeForPrompt(unitType, base, renderMode);
|
|
184
|
+
if (!contextMode)
|
|
185
|
+
return "";
|
|
186
|
+
if (renderMode === "nested")
|
|
187
|
+
return contextMode;
|
|
188
|
+
const snapshot = readCompactionSnapshot(base);
|
|
189
|
+
if (!snapshot?.trim())
|
|
190
|
+
return contextMode;
|
|
191
|
+
return `${contextMode}\n\n## Context Snapshot\nSource: \`.gsd/last-snapshot.md\`\n\n${snapshot.trimEnd()}`;
|
|
192
|
+
}
|
|
193
|
+
function prependContextModeToBlock(unitType, base, block, renderMode = "standalone") {
|
|
194
|
+
const contextMode = renderContextModeBlockForPrompt(unitType, base, renderMode);
|
|
84
195
|
if (!contextMode)
|
|
85
196
|
return block;
|
|
86
197
|
if (!block.trim())
|
|
@@ -1465,6 +1576,7 @@ export async function buildPlanMilestonePrompt(mid, midTitle, base, level) {
|
|
|
1465
1576
|
const researchAnchor = readPhaseAnchor(base, mid, "research-milestone");
|
|
1466
1577
|
if (researchAnchor)
|
|
1467
1578
|
inlined.push(formatAnchorForPrompt(researchAnchor));
|
|
1579
|
+
inlined.push(formatProjectClassificationForPlanning(classifyProject(base)));
|
|
1468
1580
|
inlined.push(await inlineFile(contextPath, contextRel, "Milestone Context"));
|
|
1469
1581
|
const researchInline = await inlineFileOptional(researchPath, researchRel, "Milestone Research");
|
|
1470
1582
|
if (researchInline)
|
|
@@ -2017,6 +2129,9 @@ export async function buildCompleteMilestonePrompt(mid, midTitle, base, level) {
|
|
|
2017
2129
|
const inlineLevel = level ?? resolveInlineLevel();
|
|
2018
2130
|
const roadmapPath = resolveMilestoneFile(base, mid, "ROADMAP");
|
|
2019
2131
|
const roadmapRel = relMilestoneFile(base, mid, "ROADMAP");
|
|
2132
|
+
const validationPath = resolveMilestoneFile(base, mid, "VALIDATION");
|
|
2133
|
+
const validationRel = relMilestoneFile(base, mid, "VALIDATION");
|
|
2134
|
+
const validationContent = validationPath ? await loadFile(validationPath) : null;
|
|
2020
2135
|
const inlined = [];
|
|
2021
2136
|
inlined.push(await inlineFile(roadmapPath, roadmapRel, "Milestone Roadmap"));
|
|
2022
2137
|
// Inline all slice summaries (deduplicated by slice ID)
|
|
@@ -2056,6 +2171,13 @@ export async function buildCompleteMilestonePrompt(mid, midTitle, base, level) {
|
|
|
2056
2171
|
const pathList = summaryRelPaths.map(p => `- \`${p}\``).join("\n");
|
|
2057
2172
|
inlined.push(`### On-demand Slice Summaries\n\nExcerpted above. Read the full file for any slice when the excerpt's section heads don't carry enough narrative for the milestone summary you're drafting:\n\n${pathList}`);
|
|
2058
2173
|
}
|
|
2174
|
+
const validationContext = [
|
|
2175
|
+
formatCloseoutReviewInstructions(validationContent, validationRel, [validationRel, roadmapRel, ...summaryRelPaths]),
|
|
2176
|
+
];
|
|
2177
|
+
if (validationContent) {
|
|
2178
|
+
validationContext.push(`### Milestone Validation\nSource: \`${validationRel}\`\n\n${validationContent.trim()}`);
|
|
2179
|
+
}
|
|
2180
|
+
inlined.unshift(...validationContext);
|
|
2059
2181
|
// Inline root GSD files (skip for minimal — completion can read these if needed)
|
|
2060
2182
|
if (inlineLevel !== "minimal") {
|
|
2061
2183
|
const requirementsInline = await inlineRequirementsFromDb(base, mid, undefined, inlineLevel);
|
|
@@ -12,7 +12,7 @@ import { appendEvent } from "./workflow-events.js";
|
|
|
12
12
|
import { atomicWriteSync } from "./atomic-write.js";
|
|
13
13
|
import { clearParseCache } from "./files.js";
|
|
14
14
|
import { parseRoadmap as parseLegacyRoadmap, parsePlan as parseLegacyPlan } from "./parsers-legacy.js";
|
|
15
|
-
import { isDbAvailable, getTask, getSlice, getSliceTasks, getPendingGates, updateTaskStatus, updateSliceStatus, insertSlice, getMilestone, refreshOpenDatabaseFromDisk } from "./gsd-db.js";
|
|
15
|
+
import { isDbAvailable, getTask, getSlice, getSliceTasks, getPendingGates, updateTaskStatus, updateSliceStatus, insertSlice, getMilestone, refreshOpenDatabaseFromDisk, getCompletedMilestoneTaskFileHints, getMilestoneCommitAttributionShas, recordMilestoneCommitAttribution } from "./gsd-db.js";
|
|
16
16
|
import { isValidationTerminal } from "./state.js";
|
|
17
17
|
import { getErrorMessage } from "./error-utils.js";
|
|
18
18
|
import { logWarning, logError } from "./workflow-logger.js";
|
|
@@ -30,7 +30,49 @@ import { getProjectResearchStatus } from "./project-research-policy.js";
|
|
|
30
30
|
// Re-export so existing consumers of auto-recovery.ts keep working.
|
|
31
31
|
export { resolveExpectedArtifactPath, diagnoseExpectedArtifact };
|
|
32
32
|
export { classifyMilestoneSummaryContent, } from "./milestone-summary-classifier.js";
|
|
33
|
-
|
|
33
|
+
export function refreshRecoveryDbForArtifact(unitType, unitId) {
|
|
34
|
+
if (unitType !== "plan-slice" && unitType !== "execute-task")
|
|
35
|
+
return { ok: true };
|
|
36
|
+
if (!isDbAvailable())
|
|
37
|
+
return { ok: true };
|
|
38
|
+
if (!refreshOpenDatabaseFromDisk()) {
|
|
39
|
+
return {
|
|
40
|
+
ok: false,
|
|
41
|
+
fatal: unitType === "execute-task",
|
|
42
|
+
reason: `${unitType}-db-refresh-failed`,
|
|
43
|
+
message: `Stuck recovery found ${unitType} ${unitId} artifacts, but the DB refresh failed.`,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
if (unitType !== "execute-task")
|
|
47
|
+
return { ok: true };
|
|
48
|
+
const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
|
|
49
|
+
if (!mid || !sid || !tid) {
|
|
50
|
+
return {
|
|
51
|
+
ok: false,
|
|
52
|
+
fatal: true,
|
|
53
|
+
reason: "execute-task-invalid-unit-id",
|
|
54
|
+
message: `Stuck recovery found execute-task ${unitId} artifacts, but the unit id could not be parsed for DB verification.`,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
const task = getTask(mid, sid, tid);
|
|
58
|
+
if (!task) {
|
|
59
|
+
return {
|
|
60
|
+
ok: false,
|
|
61
|
+
fatal: true,
|
|
62
|
+
reason: "execute-task-artifact-db-missing",
|
|
63
|
+
message: `Stuck recovery found execute-task ${unitId} artifacts, but no matching DB task row exists after refresh.`,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
if (!isClosedStatus(task.status)) {
|
|
67
|
+
return {
|
|
68
|
+
ok: false,
|
|
69
|
+
fatal: true,
|
|
70
|
+
reason: "execute-task-artifact-db-mismatch",
|
|
71
|
+
message: `Stuck recovery found execute-task ${unitId} artifacts, but the DB task status is still '${task.status}' after refresh.`,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return { ok: true };
|
|
75
|
+
}
|
|
34
76
|
function hasCapturedWorkflowPrefs(base) {
|
|
35
77
|
const prefsPath = resolveExpectedArtifactPath("workflow-preferences", "WORKFLOW-PREFS", base);
|
|
36
78
|
if (!prefsPath || !existsSync(prefsPath))
|
|
@@ -110,17 +152,32 @@ export function hasImplementationArtifacts(basePath, milestoneId) {
|
|
|
110
152
|
// milestone commits instead of treating the self-diff as proof of no work.
|
|
111
153
|
if (changedFiles.length === 0) {
|
|
112
154
|
if (milestoneId && currentBranch === integrationBranch) {
|
|
113
|
-
const
|
|
114
|
-
if (!
|
|
155
|
+
const milestoneEvidence = getChangedFilesFromMilestoneEvidence(basePath, milestoneId);
|
|
156
|
+
if (!milestoneEvidence.ok)
|
|
115
157
|
return "unknown";
|
|
116
|
-
if (
|
|
117
|
-
return classifyImplementationFiles(
|
|
158
|
+
if (milestoneEvidence.matched)
|
|
159
|
+
return classifyImplementationFiles(milestoneEvidence.files);
|
|
118
160
|
}
|
|
119
161
|
if (currentBranch && currentBranch !== "HEAD")
|
|
120
162
|
return "absent";
|
|
121
163
|
return "unknown";
|
|
122
164
|
}
|
|
123
|
-
|
|
165
|
+
const branchClassification = classifyImplementationFiles(changedFiles);
|
|
166
|
+
if (branchClassification === "present")
|
|
167
|
+
return "present";
|
|
168
|
+
// A completing milestone branch can have a non-empty diff containing only
|
|
169
|
+
// .gsd/ closeout files after implementation commits already landed on the
|
|
170
|
+
// recorded integration branch. In that topology, the branch diff alone is
|
|
171
|
+
// insufficient; use the same milestone-tagged evidence fallback as the
|
|
172
|
+
// self-diff retry path before declaring the milestone implementation-free.
|
|
173
|
+
if (milestoneId) {
|
|
174
|
+
const milestoneEvidence = getChangedFilesFromMilestoneEvidence(basePath, milestoneId);
|
|
175
|
+
if (!milestoneEvidence.ok)
|
|
176
|
+
return "unknown";
|
|
177
|
+
if (milestoneEvidence.matched)
|
|
178
|
+
return classifyImplementationFiles(milestoneEvidence.files);
|
|
179
|
+
}
|
|
180
|
+
return "absent";
|
|
124
181
|
}
|
|
125
182
|
catch (e) {
|
|
126
183
|
// Non-fatal — if git operations fail, return unknown so callers can decide
|
|
@@ -148,6 +205,9 @@ function classifyImplementationFiles(files) {
|
|
|
148
205
|
function isImplementationPath(file) {
|
|
149
206
|
return !file.startsWith(".gsd/") && !file.startsWith(".gsd\\");
|
|
150
207
|
}
|
|
208
|
+
function normalizeRepoPath(file) {
|
|
209
|
+
return file.trim().replace(/\\/g, "/").replace(/^\.\/+/, "");
|
|
210
|
+
}
|
|
151
211
|
/**
|
|
152
212
|
* Detect the main/master branch name.
|
|
153
213
|
*/
|
|
@@ -217,7 +277,7 @@ function getChangedFilesFromMilestoneTaggedCommits(basePath, milestoneId) {
|
|
|
217
277
|
]);
|
|
218
278
|
if (!scoped.ok)
|
|
219
279
|
return scoped;
|
|
220
|
-
if (scoped.matched)
|
|
280
|
+
if (scoped.matched && classifyImplementationFiles(scoped.files) === "present")
|
|
221
281
|
return scoped;
|
|
222
282
|
// Fallback (#5033): when .gsd/ is gitignored / external / untracked, the
|
|
223
283
|
// path-scoped scan matches no commits even though GSD-tagged commits
|
|
@@ -228,9 +288,137 @@ function getChangedFilesFromMilestoneTaggedCommits(basePath, milestoneId) {
|
|
|
228
288
|
// Intentionally unbounded — symmetric with the primary scan, and avoids
|
|
229
289
|
// reintroducing the rolling-depth failure class removed in #4699 where
|
|
230
290
|
// milestone evidence aged out behind unrelated activity.
|
|
231
|
-
|
|
291
|
+
const unscoped = scanGsdTaggedCommits(basePath, milestoneId, [
|
|
232
292
|
"log", "--format=%H%x1f%B%x1e", "HEAD",
|
|
233
293
|
]);
|
|
294
|
+
if (!unscoped.ok)
|
|
295
|
+
return scoped.matched ? scoped : unscoped;
|
|
296
|
+
if (!unscoped.matched)
|
|
297
|
+
return scoped;
|
|
298
|
+
return {
|
|
299
|
+
ok: true,
|
|
300
|
+
matched: true,
|
|
301
|
+
files: [...new Set([...scoped.files, ...unscoped.files])],
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
function getChangedFilesFromMilestoneEvidence(basePath, milestoneId) {
|
|
305
|
+
const tagged = getChangedFilesFromMilestoneTaggedCommits(basePath, milestoneId);
|
|
306
|
+
if (!tagged.ok)
|
|
307
|
+
return tagged;
|
|
308
|
+
if (tagged.matched && classifyImplementationFiles(tagged.files) === "present")
|
|
309
|
+
return tagged;
|
|
310
|
+
const attributed = getChangedFilesFromAttributedMilestoneCommits(basePath, milestoneId);
|
|
311
|
+
if (!attributed.ok)
|
|
312
|
+
return tagged.matched ? tagged : attributed;
|
|
313
|
+
if (attributed.matched && classifyImplementationFiles(attributed.files) === "present")
|
|
314
|
+
return attributed;
|
|
315
|
+
const backfilled = backfillChangedFilesFromUntaggedMilestoneCommits(basePath, milestoneId);
|
|
316
|
+
if (!backfilled.ok)
|
|
317
|
+
return tagged.matched ? tagged : attributed.matched ? attributed : backfilled;
|
|
318
|
+
if (!backfilled.matched) {
|
|
319
|
+
if (tagged.matched)
|
|
320
|
+
return tagged;
|
|
321
|
+
return attributed.matched ? attributed : backfilled;
|
|
322
|
+
}
|
|
323
|
+
return {
|
|
324
|
+
ok: true,
|
|
325
|
+
matched: true,
|
|
326
|
+
files: [...new Set([...tagged.files, ...attributed.files, ...backfilled.files])],
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
function getChangedFilesFromAttributedMilestoneCommits(basePath, milestoneId) {
|
|
330
|
+
try {
|
|
331
|
+
const shas = getMilestoneCommitAttributionShas(milestoneId);
|
|
332
|
+
if (shas.length === 0)
|
|
333
|
+
return { ok: true, matched: false, files: [] };
|
|
334
|
+
const files = new Set();
|
|
335
|
+
let matched = false;
|
|
336
|
+
for (const sha of shas) {
|
|
337
|
+
if (!isFullCommitSha(sha))
|
|
338
|
+
continue;
|
|
339
|
+
const commitFiles = getChangedFilesForCommit(basePath, sha);
|
|
340
|
+
if (commitFiles.length === 0)
|
|
341
|
+
continue;
|
|
342
|
+
matched = true;
|
|
343
|
+
for (const file of commitFiles)
|
|
344
|
+
files.add(file);
|
|
345
|
+
}
|
|
346
|
+
return { ok: true, matched, files: [...files] };
|
|
347
|
+
}
|
|
348
|
+
catch (e) {
|
|
349
|
+
logWarning("recovery", `milestone attribution scan failed: ${e.message}`);
|
|
350
|
+
return { ok: false, matched: false, files: [] };
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
function backfillChangedFilesFromUntaggedMilestoneCommits(basePath, milestoneId) {
|
|
354
|
+
try {
|
|
355
|
+
const milestone = getMilestone(milestoneId);
|
|
356
|
+
const milestoneStartedAt = milestone?.created_at ? Math.floor(Date.parse(milestone.created_at) / 1000) * 1000 : NaN;
|
|
357
|
+
if (!Number.isFinite(milestoneStartedAt))
|
|
358
|
+
return { ok: true, matched: false, files: [] };
|
|
359
|
+
const taskFileHints = getCompletedMilestoneTaskFileHints(milestoneId);
|
|
360
|
+
if (taskFileHints.length === 0)
|
|
361
|
+
return { ok: true, matched: false, files: [] };
|
|
362
|
+
const hintSet = new Set(taskFileHints.map(normalizeRepoPath).filter(Boolean));
|
|
363
|
+
if (hintSet.size === 0)
|
|
364
|
+
return { ok: true, matched: false, files: [] };
|
|
365
|
+
const records = getCommitRecords(basePath);
|
|
366
|
+
const files = new Set();
|
|
367
|
+
let matched = false;
|
|
368
|
+
for (const record of records) {
|
|
369
|
+
if (!isFullCommitSha(record.hash))
|
|
370
|
+
continue;
|
|
371
|
+
if (Date.parse(record.committedAt) < milestoneStartedAt)
|
|
372
|
+
continue;
|
|
373
|
+
if (record.parents.trim().split(/\s+/).filter(Boolean).length > 1)
|
|
374
|
+
continue;
|
|
375
|
+
if (commitMessageHasGsdTrailer(record.message))
|
|
376
|
+
continue;
|
|
377
|
+
const commitFiles = getChangedFilesForCommit(basePath, record.hash);
|
|
378
|
+
const implementationFiles = commitFiles.map(normalizeRepoPath).filter(isImplementationPath);
|
|
379
|
+
if (implementationFiles.length === 0)
|
|
380
|
+
continue;
|
|
381
|
+
if (!implementationFiles.some((file) => hintSet.has(file)))
|
|
382
|
+
continue;
|
|
383
|
+
matched = true;
|
|
384
|
+
for (const file of implementationFiles)
|
|
385
|
+
files.add(file);
|
|
386
|
+
recordMilestoneCommitAttribution({
|
|
387
|
+
commitSha: record.hash,
|
|
388
|
+
milestoneId,
|
|
389
|
+
source: "backfill",
|
|
390
|
+
confidence: 0.8,
|
|
391
|
+
files: implementationFiles,
|
|
392
|
+
createdAt: new Date().toISOString(),
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
return { ok: true, matched, files: [...files] };
|
|
396
|
+
}
|
|
397
|
+
catch (e) {
|
|
398
|
+
logWarning("recovery", `milestone attribution backfill failed: ${e.message}`);
|
|
399
|
+
return { ok: false, matched: false, files: [] };
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
function getCommitRecords(basePath) {
|
|
403
|
+
const logOutput = execFileSync("git", ["log", "--format=%H%x1f%P%x1f%cI%x1f%B%x1e", "HEAD"], {
|
|
404
|
+
cwd: basePath,
|
|
405
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
406
|
+
encoding: "utf-8",
|
|
407
|
+
});
|
|
408
|
+
return logOutput
|
|
409
|
+
.split("\x1e")
|
|
410
|
+
.map((record) => record.trim())
|
|
411
|
+
.filter(Boolean)
|
|
412
|
+
.flatMap((record) => {
|
|
413
|
+
const parts = record.split("\x1f");
|
|
414
|
+
if (parts.length < 4)
|
|
415
|
+
return [];
|
|
416
|
+
const [hash, parents, committedAt, ...messageParts] = parts;
|
|
417
|
+
return [{ hash: hash.trim(), parents: parents.trim(), committedAt: committedAt.trim(), message: messageParts.join("\x1f") }];
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
function isFullCommitSha(value) {
|
|
421
|
+
return /^[0-9a-f]{40}$/i.test(value);
|
|
234
422
|
}
|
|
235
423
|
function scanGsdTaggedCommits(basePath, milestoneId, gitArgs) {
|
|
236
424
|
try {
|
|
@@ -487,9 +487,8 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
487
487
|
hasSurvivorBranch = false;
|
|
488
488
|
}
|
|
489
489
|
const effectivePrefs = loadEffectiveGSDPreferences(base)?.preferences;
|
|
490
|
-
const
|
|
491
|
-
|
|
492
|
-
: false;
|
|
490
|
+
const { shouldRunDeepProjectSetup } = await import("./auto-dispatch.js");
|
|
491
|
+
const deepProjectStagePending = shouldRunDeepProjectSetup(state, effectivePrefs, base, { hasSurvivorBranch });
|
|
493
492
|
if (deepProjectStagePending) {
|
|
494
493
|
// Deep project-level setup runs before the first milestone exists. Let
|
|
495
494
|
// the auto loop dispatch workflow-preferences / project / requirements
|