gsd-pi 2.80.0-dev.c5f2443b3 → 2.80.0-dev.fbe7c8c6f
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/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 +16 -9
- package/dist/resources/extensions/gsd/auto/phases.js +37 -30
- package/dist/resources/extensions/gsd/auto/run-unit.js +19 -15
- 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 +111 -1
- package/dist/resources/extensions/gsd/auto-recovery.js +154 -8
- package/dist/resources/extensions/gsd/auto-start.js +2 -3
- package/dist/resources/extensions/gsd/auto.js +9 -1
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +15 -1
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +11 -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/custom-workflow-engine.js +22 -2
- package/dist/resources/extensions/gsd/db-base-schema.js +14 -0
- package/dist/resources/extensions/gsd/db-migration-steps.js +16 -0
- package/dist/resources/extensions/gsd/detection.js +106 -0
- package/dist/resources/extensions/gsd/graph.js +9 -3
- package/dist/resources/extensions/gsd/gsd-db.js +102 -2
- package/dist/resources/extensions/gsd/guided-flow.js +33 -9
- package/dist/resources/extensions/gsd/pr-evidence.js +57 -16
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +7 -8
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +3 -1
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +10 -2
- package/dist/resources/extensions/gsd/working-output-messages.js +64 -0
- package/dist/resources/extensions/gsd/worktree-manager.js +16 -14
- 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 +13 -13
- 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 +13 -13
- 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 +10 -6
- package/packages/contracts/package.json +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/chat-controller-ordering.test.js +74 -0
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +2 -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 +14 -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 +97 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.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 +4 -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 +8 -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 +16 -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 +106 -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 +60 -1
- 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 +40 -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 +23 -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/src/core/chat-controller-ordering.test.ts +87 -0
- package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +108 -0
- package/packages/pi-coding-agent/src/core/extensions/runner.ts +16 -1
- package/packages/pi-coding-agent/src/core/model-registry.ts +4 -0
- package/packages/pi-coding-agent/src/core/settings-manager.ts +12 -0
- 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 +118 -17
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +43 -1
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +75 -1
- 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 +25 -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/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 +3 -8
- 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 +3 -8
- 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 +17 -10
- package/src/resources/extensions/gsd/auto/phases.ts +42 -28
- package/src/resources/extensions/gsd/auto/run-unit.ts +24 -14
- 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 +116 -1
- package/src/resources/extensions/gsd/auto-recovery.ts +153 -7
- package/src/resources/extensions/gsd/auto-start.ts +7 -6
- package/src/resources/extensions/gsd/auto.ts +12 -1
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +16 -1
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +17 -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/custom-workflow-engine.ts +24 -1
- package/src/resources/extensions/gsd/db-base-schema.ts +15 -0
- package/src/resources/extensions/gsd/db-migration-steps.ts +17 -0
- package/src/resources/extensions/gsd/detection.ts +128 -0
- package/src/resources/extensions/gsd/graph.ts +12 -5
- package/src/resources/extensions/gsd/gsd-db.ts +119 -1
- package/src/resources/extensions/gsd/guided-flow.ts +30 -9
- package/src/resources/extensions/gsd/pr-evidence.ts +63 -5
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +7 -8
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +3 -1
- 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 +84 -5
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +170 -1
- 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/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/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/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/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/smart-entry-complete.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +46 -2
- package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +1 -1
- 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-write-gate.test.ts +179 -0
- package/src/resources/extensions/gsd/working-output-messages.ts +120 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +15 -4
- package/packages/contracts/tsconfig.tsbuildinfo +0 -1
- /package/dist/web/standalone/.next/static/{bQDK5_LtkGVS64AirQgQG → yTuahMMuJzVnsov5PreWl}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{bQDK5_LtkGVS64AirQgQG → yTuahMMuJzVnsov5PreWl}/_ssgManifest.js +0 -0
|
@@ -16,6 +16,31 @@ import { execFileSync } from "node:child_process";
|
|
|
16
16
|
import { GIT_NO_PROMPT_ENV } from "./git-constants.js";
|
|
17
17
|
import { logWarning } from "./workflow-logger.js";
|
|
18
18
|
import { nativeHasChanges } from "./native-git-bridge.js";
|
|
19
|
+
function findPreflightStashRef(basePath, milestoneId, stashMarker) {
|
|
20
|
+
const markerPrefix = `gsd-preflight-stash:${milestoneId}:`;
|
|
21
|
+
let fallbackRef = null;
|
|
22
|
+
try {
|
|
23
|
+
const list = execFileSync("git", ["stash", "list", "--format=%gd%x00%s"], {
|
|
24
|
+
cwd: basePath,
|
|
25
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
26
|
+
encoding: "utf-8",
|
|
27
|
+
env: GIT_NO_PROMPT_ENV,
|
|
28
|
+
});
|
|
29
|
+
for (const line of list.split("\n")) {
|
|
30
|
+
const [ref, subject] = line.split("\x00");
|
|
31
|
+
if (!ref || !subject)
|
|
32
|
+
continue;
|
|
33
|
+
if (stashMarker && subject.includes(stashMarker))
|
|
34
|
+
return ref;
|
|
35
|
+
if (!fallbackRef && subject.includes(markerPrefix))
|
|
36
|
+
fallbackRef = ref;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
logWarning("preflight", `stash list failed before restore: ${err instanceof Error ? err.message : String(err)}`);
|
|
41
|
+
}
|
|
42
|
+
return fallbackRef;
|
|
43
|
+
}
|
|
19
44
|
/**
|
|
20
45
|
* Check the working tree for dirty files before a milestone merge.
|
|
21
46
|
*
|
|
@@ -47,7 +72,8 @@ export function preflightCleanRoot(basePath, milestoneId, notify) {
|
|
|
47
72
|
notify(warnMsg, "warning");
|
|
48
73
|
// Push the stash
|
|
49
74
|
try {
|
|
50
|
-
|
|
75
|
+
const stashMarker = `gsd-preflight-stash:${milestoneId}:${process.pid}:${Date.now()}:${process.hrtime.bigint().toString(36)}`;
|
|
76
|
+
execFileSync("git", ["stash", "push", "--include-untracked", "-m", `gsd-preflight-stash [${stashMarker}]`], {
|
|
51
77
|
cwd: basePath,
|
|
52
78
|
stdio: ["ignore", "pipe", "pipe"],
|
|
53
79
|
encoding: "utf-8",
|
|
@@ -55,6 +81,7 @@ export function preflightCleanRoot(basePath, milestoneId, notify) {
|
|
|
55
81
|
});
|
|
56
82
|
return {
|
|
57
83
|
stashPushed: true,
|
|
84
|
+
stashMarker,
|
|
58
85
|
summary: `Stashed uncommitted changes before merge (milestone ${milestoneId}).`,
|
|
59
86
|
};
|
|
60
87
|
}
|
|
@@ -73,9 +100,17 @@ export function preflightCleanRoot(basePath, milestoneId, notify) {
|
|
|
73
100
|
* Any pop error (e.g. conflict) is logged and notified but does NOT throw —
|
|
74
101
|
* the merge already completed successfully.
|
|
75
102
|
*/
|
|
76
|
-
export function postflightPopStash(basePath, milestoneId, notify) {
|
|
103
|
+
export function postflightPopStash(basePath, milestoneId, stashMarker, notify) {
|
|
104
|
+
let stashRef = null;
|
|
77
105
|
try {
|
|
78
|
-
|
|
106
|
+
stashRef = findPreflightStashRef(basePath, milestoneId, stashMarker);
|
|
107
|
+
if (!stashRef) {
|
|
108
|
+
const msg = `No matching GSD preflight stash found for milestone ${milestoneId}; leaving stash list untouched.`;
|
|
109
|
+
logWarning("preflight", msg);
|
|
110
|
+
notify(msg, "warning");
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
execFileSync("git", ["stash", "pop", stashRef], {
|
|
79
114
|
cwd: basePath,
|
|
80
115
|
stdio: ["ignore", "pipe", "pipe"],
|
|
81
116
|
encoding: "utf-8",
|
|
@@ -86,7 +121,10 @@ export function postflightPopStash(basePath, milestoneId, notify) {
|
|
|
86
121
|
catch (err) {
|
|
87
122
|
// Pop conflicts mean the merged code collides with the stashed changes.
|
|
88
123
|
// Log a warning — the user needs to resolve manually, but the merge succeeded.
|
|
89
|
-
const
|
|
124
|
+
const restoreHint = stashRef
|
|
125
|
+
? `Run "git stash pop ${stashRef}" or "git stash apply ${stashRef}" manually to restore the correct stash.`
|
|
126
|
+
: `Run "git stash list" to find the matching GSD preflight stash before restoring manually.`;
|
|
127
|
+
const msg = `git stash pop ${stashRef ?? ""}`.trim() + ` failed after merge of milestone ${milestoneId}: ${err instanceof Error ? err.message : String(err)}. ${restoreHint}`;
|
|
90
128
|
logWarning("preflight", msg);
|
|
91
129
|
notify(msg, "warning");
|
|
92
130
|
}
|
|
@@ -33,5 +33,10 @@ export async function handleGSDCommand(args, ctx, pi) {
|
|
|
33
33
|
}
|
|
34
34
|
if (handled)
|
|
35
35
|
return;
|
|
36
|
+
if (trimmed.includes(" ")) {
|
|
37
|
+
const { handleDo } = await import("../commands-do.js");
|
|
38
|
+
await handleDo(trimmed, ctx, pi);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
36
41
|
ctx.ui.notify(`Unknown: /gsd ${trimmed}. Run /gsd help for available commands.`, "warning");
|
|
37
42
|
}
|
|
@@ -114,14 +114,19 @@ Using the \`write\` tool, persist the full structured report to
|
|
|
114
114
|
LEARNINGS.md is the full, cited audit trail. Write it first — subsequent steps
|
|
115
115
|
feed from its content.
|
|
116
116
|
|
|
117
|
-
### Step 3 —
|
|
117
|
+
### Step 3 — Run one bounded duplicate check
|
|
118
118
|
|
|
119
|
-
Before persisting
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
119
|
+
Before persisting extracted items in Steps 4–6, do at most one duplicate-check
|
|
120
|
+
pass for the durable Decisions, Lessons, and Patterns from this milestone. Use
|
|
121
|
+
the already-written LEARNINGS.md content and call \`memory_query\` once with a
|
|
122
|
+
compact keyword summary for the whole batch. If that result clearly shows a
|
|
123
|
+
semantically equivalent high-confidence memory for an item, mark only that item
|
|
124
|
+
as already captured and skip it in its respective persistence step.
|
|
125
|
+
|
|
126
|
+
Do not re-read milestone artefacts or repeat memory queries category-by-category
|
|
127
|
+
after this point. The memory store is the single source of truth for
|
|
128
|
+
cross-session durable knowledge — no other persistence call is part of this
|
|
129
|
+
flow.
|
|
125
130
|
|
|
126
131
|
### Step 4 — Persist Patterns via \`capture_thought\`
|
|
127
132
|
|
|
@@ -160,11 +165,11 @@ later projection back to a human-visible decisions register stays lossless
|
|
|
160
165
|
|
|
161
166
|
### Step 7 — Deduplication rule (applies to Steps 4, 5, 6)
|
|
162
167
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
over creating a second slightly-different row
|
|
167
|
-
signal.
|
|
168
|
+
Use only the duplicate-check result from Step 3. If that bounded check returned
|
|
169
|
+
a semantically equivalent memory at high confidence for an extracted item, skip
|
|
170
|
+
the capture entirely. Otherwise, persist the item once via \`capture_thought\`.
|
|
171
|
+
Prefer skipping a near-duplicate over creating a second slightly-different row
|
|
172
|
+
— redundancy degrades the signal.
|
|
168
173
|
|
|
169
174
|
### Step 8 — Surprises stay only in LEARNINGS.md
|
|
170
175
|
|
|
@@ -13,13 +13,29 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import { readFileSync } from "node:fs";
|
|
15
15
|
import { join } from "node:path";
|
|
16
|
-
import { readGraph, writeGraph, getNextPendingStep, markStepActive, markStepComplete, expandIteration, } from "./graph.js";
|
|
16
|
+
import { readGraph, writeGraph, getNextPendingStep, markStepActive, markStepComplete, expandIteration, isTerminalStepStatus, } from "./graph.js";
|
|
17
17
|
import { injectContext } from "./context-injector.js";
|
|
18
18
|
import { readFrozenDefinition } from "./definition-io.js";
|
|
19
19
|
import { parseUnitId } from "./unit-id.js";
|
|
20
20
|
import { withFileLock } from "./file-lock.js";
|
|
21
21
|
// Re-export for downstream consumers
|
|
22
22
|
export { readFrozenDefinition } from "./definition-io.js";
|
|
23
|
+
function formatBlockedWorkflowReason(graph) {
|
|
24
|
+
const statusById = new Map(graph.steps.map((step) => [step.id, step.status]));
|
|
25
|
+
const blockedSteps = graph.steps
|
|
26
|
+
.filter((step) => step.status === "pending")
|
|
27
|
+
.map((step) => {
|
|
28
|
+
const blockers = step.dependsOn
|
|
29
|
+
.filter((depId) => !isTerminalStepStatus(statusById.get(depId)))
|
|
30
|
+
.map((depId) => `${depId} (${statusById.get(depId) ?? "missing"})`);
|
|
31
|
+
return blockers.length > 0
|
|
32
|
+
? `${step.id} waiting on ${blockers.join(", ")}`
|
|
33
|
+
: `${step.id} has no runnable dependency path`;
|
|
34
|
+
});
|
|
35
|
+
return blockedSteps.length > 0
|
|
36
|
+
? `Workflow blocked: no pending steps are ready. Blocked steps: ${blockedSteps.join("; ")}`
|
|
37
|
+
: "Workflow blocked: no pending steps are ready.";
|
|
38
|
+
}
|
|
23
39
|
export class CustomWorkflowEngine {
|
|
24
40
|
engineId = "custom";
|
|
25
41
|
runDir;
|
|
@@ -80,7 +96,11 @@ export class CustomWorkflowEngine {
|
|
|
80
96
|
if (!next) {
|
|
81
97
|
const allDone = graph.steps.every((step) => step.status === "complete" || step.status === "expanded");
|
|
82
98
|
if (!allDone) {
|
|
83
|
-
return {
|
|
99
|
+
return {
|
|
100
|
+
action: "stop",
|
|
101
|
+
reason: formatBlockedWorkflowReason(graph),
|
|
102
|
+
level: "error",
|
|
103
|
+
};
|
|
84
104
|
}
|
|
85
105
|
return {
|
|
86
106
|
action: "stop",
|
|
@@ -294,6 +294,19 @@ export function createBaseSchemaObjects(db, hooks) {
|
|
|
294
294
|
updated_at TEXT NOT NULL DEFAULT '',
|
|
295
295
|
PRIMARY KEY (trace_id, turn_id, stage)
|
|
296
296
|
)
|
|
297
|
+
`);
|
|
298
|
+
db.exec(`
|
|
299
|
+
CREATE TABLE IF NOT EXISTS milestone_commit_attributions (
|
|
300
|
+
commit_sha TEXT NOT NULL,
|
|
301
|
+
milestone_id TEXT NOT NULL,
|
|
302
|
+
slice_id TEXT DEFAULT NULL,
|
|
303
|
+
task_id TEXT DEFAULT NULL,
|
|
304
|
+
source TEXT NOT NULL DEFAULT 'recorded',
|
|
305
|
+
confidence REAL NOT NULL DEFAULT 1.0,
|
|
306
|
+
files_json TEXT NOT NULL DEFAULT '[]',
|
|
307
|
+
created_at TEXT NOT NULL DEFAULT '',
|
|
308
|
+
PRIMARY KEY (commit_sha, milestone_id)
|
|
309
|
+
)
|
|
297
310
|
`);
|
|
298
311
|
db.exec(`
|
|
299
312
|
CREATE TABLE IF NOT EXISTS audit_events (
|
|
@@ -329,6 +342,7 @@ export function createBaseSchemaObjects(db, hooks) {
|
|
|
329
342
|
db.exec("CREATE INDEX IF NOT EXISTS idx_gate_runs_turn ON gate_runs(trace_id, turn_id)");
|
|
330
343
|
db.exec("CREATE INDEX IF NOT EXISTS idx_gate_runs_lookup ON gate_runs(milestone_id, slice_id, task_id, gate_id)");
|
|
331
344
|
db.exec("CREATE INDEX IF NOT EXISTS idx_turn_git_tx_turn ON turn_git_transactions(trace_id, turn_id)");
|
|
345
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_milestone_commit_attr_milestone ON milestone_commit_attributions(milestone_id)");
|
|
332
346
|
db.exec("CREATE INDEX IF NOT EXISTS idx_audit_events_trace ON audit_events(trace_id, ts)");
|
|
333
347
|
db.exec("CREATE INDEX IF NOT EXISTS idx_audit_events_turn ON audit_events(trace_id, turn_id, ts)");
|
|
334
348
|
db.exec("CREATE VIEW IF NOT EXISTS active_decisions AS SELECT * FROM decisions WHERE superseded_by IS NULL");
|
|
@@ -363,6 +363,22 @@ export function applyMigrationV21StructuredMemories(db) {
|
|
|
363
363
|
export function applyMigrationV23MilestoneQueue(db) {
|
|
364
364
|
ensureColumn(db, "milestones", "sequence", "ALTER TABLE milestones ADD COLUMN sequence INTEGER DEFAULT 0");
|
|
365
365
|
}
|
|
366
|
+
export function applyMigrationV26MilestoneCommitAttributions(db) {
|
|
367
|
+
db.exec(`
|
|
368
|
+
CREATE TABLE IF NOT EXISTS milestone_commit_attributions (
|
|
369
|
+
commit_sha TEXT NOT NULL,
|
|
370
|
+
milestone_id TEXT NOT NULL,
|
|
371
|
+
slice_id TEXT DEFAULT NULL,
|
|
372
|
+
task_id TEXT DEFAULT NULL,
|
|
373
|
+
source TEXT NOT NULL DEFAULT 'recorded',
|
|
374
|
+
confidence REAL NOT NULL DEFAULT 1.0,
|
|
375
|
+
files_json TEXT NOT NULL DEFAULT '[]',
|
|
376
|
+
created_at TEXT NOT NULL DEFAULT '',
|
|
377
|
+
PRIMARY KEY (commit_sha, milestone_id)
|
|
378
|
+
)
|
|
379
|
+
`);
|
|
380
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_milestone_commit_attr_milestone ON milestone_commit_attributions(milestone_id)");
|
|
381
|
+
}
|
|
366
382
|
export function applyMigrationV22QualityGateRepair(db, hooks) {
|
|
367
383
|
const qgInfo = db.prepare("PRAGMA table_info(quality_gates)").all();
|
|
368
384
|
const taskIdCol = qgInfo.find((r) => r["name"] === "task_id");
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* Used by init-wizard.ts and guided-flow.ts to determine what onboarding
|
|
6
6
|
* flow to show when entering a project directory.
|
|
7
7
|
*/
|
|
8
|
+
import { execFileSync } from "node:child_process";
|
|
8
9
|
import { existsSync, openSync, readSync, closeSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
9
10
|
import { dirname, join, parse as parsePath } from "node:path";
|
|
10
11
|
import { homedir } from "node:os";
|
|
@@ -171,6 +172,7 @@ const TEST_MARKERS = [
|
|
|
171
172
|
const RECURSIVE_SCAN_IGNORED_DIRS = new Set([
|
|
172
173
|
".git",
|
|
173
174
|
".gsd",
|
|
175
|
+
".bg-shell",
|
|
174
176
|
".planning",
|
|
175
177
|
".plans",
|
|
176
178
|
".claude",
|
|
@@ -194,6 +196,7 @@ const RECURSIVE_SCAN_IGNORED_DIRS = new Set([
|
|
|
194
196
|
"DerivedData",
|
|
195
197
|
"out",
|
|
196
198
|
]);
|
|
199
|
+
const PROJECT_CONTENT_EXCLUDE_DIRS = RECURSIVE_SCAN_IGNORED_DIRS;
|
|
197
200
|
/** Project file markers safe to detect recursively via suffix matching. */
|
|
198
201
|
const ROOT_ONLY_PROJECT_FILES = new Set([
|
|
199
202
|
".github/workflows",
|
|
@@ -429,6 +432,109 @@ export function detectProjectSignals(basePath) {
|
|
|
429
432
|
verificationCommands,
|
|
430
433
|
};
|
|
431
434
|
}
|
|
435
|
+
function normalizeGitPath(file) {
|
|
436
|
+
return file.replaceAll("\\", "/").replace(/^\.\//, "");
|
|
437
|
+
}
|
|
438
|
+
function isProjectContentFile(file) {
|
|
439
|
+
const normalized = normalizeGitPath(file);
|
|
440
|
+
if (!normalized || normalized.endsWith("/"))
|
|
441
|
+
return false;
|
|
442
|
+
if (normalized === ".gitignore" || normalized === ".gitattributes")
|
|
443
|
+
return false;
|
|
444
|
+
const parts = normalized.split("/");
|
|
445
|
+
if (parts.some((part) => PROJECT_CONTENT_EXCLUDE_DIRS.has(part)))
|
|
446
|
+
return false;
|
|
447
|
+
if (normalized.endsWith(".DS_Store"))
|
|
448
|
+
return false;
|
|
449
|
+
return true;
|
|
450
|
+
}
|
|
451
|
+
function runGitLines(basePath, args) {
|
|
452
|
+
try {
|
|
453
|
+
const output = execFileSync("git", args, {
|
|
454
|
+
cwd: basePath,
|
|
455
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
456
|
+
encoding: "utf-8",
|
|
457
|
+
}).trim();
|
|
458
|
+
return output ? output.split("\n").map((line) => line.trim()).filter(Boolean) : [];
|
|
459
|
+
}
|
|
460
|
+
catch {
|
|
461
|
+
return [];
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
function listTrackedProjectFiles(basePath) {
|
|
465
|
+
return runGitLines(basePath, ["ls-files"])
|
|
466
|
+
.map(normalizeGitPath)
|
|
467
|
+
.filter(isProjectContentFile);
|
|
468
|
+
}
|
|
469
|
+
function listUntrackedProjectFiles(basePath) {
|
|
470
|
+
return runGitLines(basePath, ["ls-files", "--others", "--exclude-standard"])
|
|
471
|
+
.map(normalizeGitPath)
|
|
472
|
+
.filter(isProjectContentFile);
|
|
473
|
+
}
|
|
474
|
+
function hasKnownProjectMarkers(basePath, signals) {
|
|
475
|
+
if (signals.detectedFiles.length > 0)
|
|
476
|
+
return true;
|
|
477
|
+
if (signals.xcodePlatforms.length > 0)
|
|
478
|
+
return true;
|
|
479
|
+
return false;
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* Classify repo presence separately from ecosystem/tooling markers.
|
|
483
|
+
*
|
|
484
|
+
* Known project files identify tooling. Git-tracked/non-ignored content
|
|
485
|
+
* identifies whether this is an existing project at all. This keeps small
|
|
486
|
+
* static or documentation repos from being mislabeled as greenfield.
|
|
487
|
+
*/
|
|
488
|
+
export function classifyProject(basePath) {
|
|
489
|
+
const signals = detectProjectSignals(basePath);
|
|
490
|
+
const markers = [...signals.detectedFiles];
|
|
491
|
+
if (!signals.isGitRepo) {
|
|
492
|
+
return {
|
|
493
|
+
kind: "invalid-repo",
|
|
494
|
+
signals,
|
|
495
|
+
trackedFiles: [],
|
|
496
|
+
untrackedFiles: [],
|
|
497
|
+
contentFiles: [],
|
|
498
|
+
markers,
|
|
499
|
+
reason: "missing .git",
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
const trackedFiles = listTrackedProjectFiles(basePath);
|
|
503
|
+
const untrackedFiles = listUntrackedProjectFiles(basePath);
|
|
504
|
+
const contentFiles = [...new Set([...trackedFiles, ...untrackedFiles])];
|
|
505
|
+
const hasMarkers = hasKnownProjectMarkers(basePath, signals);
|
|
506
|
+
if (hasMarkers) {
|
|
507
|
+
return {
|
|
508
|
+
kind: "typed-existing",
|
|
509
|
+
signals,
|
|
510
|
+
trackedFiles,
|
|
511
|
+
untrackedFiles,
|
|
512
|
+
contentFiles,
|
|
513
|
+
markers,
|
|
514
|
+
reason: markers.length > 0 ? `detected markers: ${markers.join(", ")}` : "detected project structure",
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
if (contentFiles.length > 0) {
|
|
518
|
+
return {
|
|
519
|
+
kind: "untyped-existing",
|
|
520
|
+
signals,
|
|
521
|
+
trackedFiles,
|
|
522
|
+
untrackedFiles,
|
|
523
|
+
contentFiles,
|
|
524
|
+
markers,
|
|
525
|
+
reason: "project content exists but no recognized tooling markers were found",
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
return {
|
|
529
|
+
kind: "greenfield",
|
|
530
|
+
signals,
|
|
531
|
+
trackedFiles,
|
|
532
|
+
untrackedFiles,
|
|
533
|
+
contentFiles,
|
|
534
|
+
markers,
|
|
535
|
+
reason: "no tracked or non-ignored project content",
|
|
536
|
+
};
|
|
537
|
+
}
|
|
432
538
|
// ─── Xcode Platform Detection ───────────────────────────────────────────────────
|
|
433
539
|
/** Known SDKROOT values → canonical platform names. */
|
|
434
540
|
const SDKROOT_MAP = {
|
|
@@ -89,10 +89,16 @@ export function writeGraph(runDir, graph) {
|
|
|
89
89
|
renameSync(tmpPath, filePath);
|
|
90
90
|
}
|
|
91
91
|
/**
|
|
92
|
-
*
|
|
92
|
+
* Return whether a graph step status satisfies dependency edges.
|
|
93
|
+
*/
|
|
94
|
+
export function isTerminalStepStatus(status) {
|
|
95
|
+
return status === "complete" || status === "expanded";
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Get the next pending step whose dependencies are all terminal.
|
|
93
99
|
*
|
|
94
100
|
* Returns the first step (in array order) with status "pending" where
|
|
95
|
-
* every step in its `dependsOn` list has status "complete".
|
|
101
|
+
* every step in its `dependsOn` list has status "complete" or "expanded".
|
|
96
102
|
*
|
|
97
103
|
* @param graph — the workflow graph to query
|
|
98
104
|
* @returns The next dispatchable step, or null if none available
|
|
@@ -102,7 +108,7 @@ export function getNextPendingStep(graph) {
|
|
|
102
108
|
for (const step of graph.steps) {
|
|
103
109
|
if (step.status !== "pending")
|
|
104
110
|
continue;
|
|
105
|
-
const depsComplete = step.dependsOn.every((depId) => statusMap.get(depId)
|
|
111
|
+
const depsComplete = step.dependsOn.every((depId) => isTerminalStepStatus(statusMap.get(depId)));
|
|
106
112
|
if (depsComplete)
|
|
107
113
|
return step;
|
|
108
114
|
}
|
|
@@ -36,7 +36,7 @@ import { rowToActiveDecision, rowToActiveRequirement, rowToDecision, rowToRequir
|
|
|
36
36
|
import { rowToGate } from "./db-gate-rows.js";
|
|
37
37
|
import { rowToArtifact, rowToMilestone } from "./db-milestone-artifact-rows.js";
|
|
38
38
|
import { backupDatabaseBeforeMigration } from "./db-migration-backup.js";
|
|
39
|
-
import { applyMigrationV2Artifacts, applyMigrationV3Memories, applyMigrationV4DecisionMadeBy, applyMigrationV5HierarchyTables, applyMigrationV6SliceSummaries, applyMigrationV7Dependencies, applyMigrationV8PlanningFields, applyMigrationV9Ordering, applyMigrationV10ReplanTrigger, applyMigrationV11TaskPlanning, applyMigrationV12QualityGates, applyMigrationV13HotPathIndexes, applyMigrationV14SliceDependencies, applyMigrationV15AuditTables, applyMigrationV16EscalationSource, applyMigrationV17TaskEscalation, applyMigrationV18MemorySources, applyMigrationV19MemoryFts, applyMigrationV20MemoryRelations, applyMigrationV21StructuredMemories, applyMigrationV22QualityGateRepair, applyMigrationV23MilestoneQueue, } from "./db-migration-steps.js";
|
|
39
|
+
import { applyMigrationV2Artifacts, applyMigrationV3Memories, applyMigrationV4DecisionMadeBy, applyMigrationV5HierarchyTables, applyMigrationV6SliceSummaries, applyMigrationV7Dependencies, applyMigrationV8PlanningFields, applyMigrationV9Ordering, applyMigrationV10ReplanTrigger, applyMigrationV11TaskPlanning, applyMigrationV12QualityGates, applyMigrationV13HotPathIndexes, applyMigrationV14SliceDependencies, applyMigrationV15AuditTables, applyMigrationV16EscalationSource, applyMigrationV17TaskEscalation, applyMigrationV18MemorySources, applyMigrationV19MemoryFts, applyMigrationV20MemoryRelations, applyMigrationV21StructuredMemories, applyMigrationV22QualityGateRepair, applyMigrationV23MilestoneQueue, applyMigrationV26MilestoneCommitAttributions, } from "./db-migration-steps.js";
|
|
40
40
|
import { isMemoriesFtsAvailableSchema, tryCreateMemoriesFtsSchema } from "./db-memory-fts-schema.js";
|
|
41
41
|
import { createDbOpenState } from "./db-open-state.js";
|
|
42
42
|
import { createRuntimeKvTableV25 } from "./db-runtime-kv-schema.js";
|
|
@@ -52,7 +52,7 @@ const providerLoader = createSqliteProviderLoader({
|
|
|
52
52
|
nodeVersion: process.versions.node,
|
|
53
53
|
writeStderr: (message) => process.stderr.write(message),
|
|
54
54
|
});
|
|
55
|
-
export const SCHEMA_VERSION =
|
|
55
|
+
export const SCHEMA_VERSION = 26;
|
|
56
56
|
function initSchema(db, fileBacked) {
|
|
57
57
|
if (fileBacked)
|
|
58
58
|
db.exec("PRAGMA journal_mode=WAL");
|
|
@@ -246,6 +246,10 @@ function migrateSchema(db) {
|
|
|
246
246
|
createRuntimeKvTableV25(db);
|
|
247
247
|
recordSchemaVersion(db, 25);
|
|
248
248
|
}
|
|
249
|
+
if (currentVersion < 26) {
|
|
250
|
+
applyMigrationV26MilestoneCommitAttributions(db);
|
|
251
|
+
recordSchemaVersion(db, 26);
|
|
252
|
+
}
|
|
249
253
|
db.exec("COMMIT");
|
|
250
254
|
}
|
|
251
255
|
catch (err) {
|
|
@@ -1158,6 +1162,47 @@ export function getSliceTasks(milestoneId, sliceId) {
|
|
|
1158
1162
|
const rows = currentDb.prepare("SELECT * FROM tasks WHERE milestone_id = :mid AND slice_id = :sid ORDER BY sequence, id").all({ ":mid": milestoneId, ":sid": sliceId });
|
|
1159
1163
|
return rows.map(rowToTask);
|
|
1160
1164
|
}
|
|
1165
|
+
export function getCompletedMilestoneTaskFileHints(milestoneId) {
|
|
1166
|
+
if (!currentDb)
|
|
1167
|
+
return [];
|
|
1168
|
+
const rows = currentDb.prepare(`SELECT files, key_files
|
|
1169
|
+
FROM tasks
|
|
1170
|
+
WHERE milestone_id = :mid AND status IN ('complete', 'done')`).all({ ":mid": milestoneId });
|
|
1171
|
+
const hints = new Set();
|
|
1172
|
+
for (const row of rows) {
|
|
1173
|
+
for (const raw of [row["files"], row["key_files"]]) {
|
|
1174
|
+
for (const file of parseStringArrayColumn(raw)) {
|
|
1175
|
+
const normalized = normalizeRepoPath(file);
|
|
1176
|
+
if (normalized)
|
|
1177
|
+
hints.add(normalized);
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
return [...hints];
|
|
1182
|
+
}
|
|
1183
|
+
function parseStringArrayColumn(raw) {
|
|
1184
|
+
if (Array.isArray(raw))
|
|
1185
|
+
return raw.filter((entry) => typeof entry === "string");
|
|
1186
|
+
if (typeof raw !== "string")
|
|
1187
|
+
return [];
|
|
1188
|
+
const trimmed = raw.trim();
|
|
1189
|
+
if (!trimmed)
|
|
1190
|
+
return [];
|
|
1191
|
+
try {
|
|
1192
|
+
const parsed = JSON.parse(trimmed);
|
|
1193
|
+
if (Array.isArray(parsed))
|
|
1194
|
+
return parsed.filter((entry) => typeof entry === "string");
|
|
1195
|
+
if (typeof parsed === "string")
|
|
1196
|
+
return [parsed];
|
|
1197
|
+
}
|
|
1198
|
+
catch {
|
|
1199
|
+
return trimmed.split(",");
|
|
1200
|
+
}
|
|
1201
|
+
return [];
|
|
1202
|
+
}
|
|
1203
|
+
function normalizeRepoPath(file) {
|
|
1204
|
+
return file.trim().replace(/\\/g, "/").replace(/^\.\/+/, "");
|
|
1205
|
+
}
|
|
1161
1206
|
// ─── ADR-011 Phase 2 escalation helpers ──────────────────────────────────
|
|
1162
1207
|
/** Set pause-on-escalation state on a completed task. Mutually exclusive with awaiting_review. */
|
|
1163
1208
|
export function setTaskEscalationPending(milestoneId, sliceId, taskId, artifactPath) {
|
|
@@ -1735,6 +1780,7 @@ export function deleteMilestone(milestoneId) {
|
|
|
1735
1780
|
currentDb.prepare(`DELETE FROM replan_history WHERE milestone_id = :mid`).run({ ":mid": milestoneId });
|
|
1736
1781
|
currentDb.prepare(`DELETE FROM assessments WHERE milestone_id = :mid`).run({ ":mid": milestoneId });
|
|
1737
1782
|
currentDb.prepare(`DELETE FROM artifacts WHERE milestone_id = :mid`).run({ ":mid": milestoneId });
|
|
1783
|
+
currentDb.prepare(`DELETE FROM milestone_commit_attributions WHERE milestone_id = :mid`).run({ ":mid": milestoneId });
|
|
1738
1784
|
currentDb.prepare(`DELETE FROM milestone_leases WHERE milestone_id = :mid`).run({ ":mid": milestoneId });
|
|
1739
1785
|
currentDb.prepare(`DELETE FROM milestones WHERE id = :mid`).run({ ":mid": milestoneId });
|
|
1740
1786
|
});
|
|
@@ -1962,6 +2008,59 @@ export function upsertTurnGitTransaction(entry) {
|
|
|
1962
2008
|
":updated_at": entry.updatedAt,
|
|
1963
2009
|
});
|
|
1964
2010
|
}
|
|
2011
|
+
export function getMilestoneCommitAttributionShas(milestoneId) {
|
|
2012
|
+
if (!currentDb)
|
|
2013
|
+
return [];
|
|
2014
|
+
const rows = currentDb.prepare(`SELECT commit_sha
|
|
2015
|
+
FROM milestone_commit_attributions
|
|
2016
|
+
WHERE milestone_id = :mid
|
|
2017
|
+
ORDER BY created_at, commit_sha`).all({ ":mid": milestoneId });
|
|
2018
|
+
return rows
|
|
2019
|
+
.map((row) => typeof row["commit_sha"] === "string" ? row["commit_sha"] : "")
|
|
2020
|
+
.filter(Boolean);
|
|
2021
|
+
}
|
|
2022
|
+
export function recordMilestoneCommitAttribution(entry) {
|
|
2023
|
+
if (!currentDb)
|
|
2024
|
+
return;
|
|
2025
|
+
transaction(() => {
|
|
2026
|
+
currentDb.prepare(`INSERT OR REPLACE INTO milestone_commit_attributions (
|
|
2027
|
+
commit_sha, milestone_id, slice_id, task_id, source, confidence, files_json, created_at
|
|
2028
|
+
) VALUES (
|
|
2029
|
+
:commit_sha, :milestone_id, :slice_id, :task_id, :source, :confidence, :files_json, :created_at
|
|
2030
|
+
)`).run({
|
|
2031
|
+
":commit_sha": entry.commitSha,
|
|
2032
|
+
":milestone_id": entry.milestoneId,
|
|
2033
|
+
":slice_id": entry.sliceId ?? null,
|
|
2034
|
+
":task_id": entry.taskId ?? null,
|
|
2035
|
+
":source": entry.source,
|
|
2036
|
+
":confidence": entry.confidence,
|
|
2037
|
+
":files_json": JSON.stringify(entry.files),
|
|
2038
|
+
":created_at": entry.createdAt,
|
|
2039
|
+
});
|
|
2040
|
+
currentDb.prepare(`INSERT OR IGNORE INTO audit_events (
|
|
2041
|
+
event_id, trace_id, turn_id, caused_by, category, type, ts, payload_json
|
|
2042
|
+
) VALUES (
|
|
2043
|
+
:event_id, :trace_id, :turn_id, :caused_by, :category, :type, :ts, :payload_json
|
|
2044
|
+
)`).run({
|
|
2045
|
+
":event_id": `milestone-commit-attribution:${entry.milestoneId}:${entry.commitSha}`,
|
|
2046
|
+
":trace_id": "milestone-commit-attribution",
|
|
2047
|
+
":turn_id": null,
|
|
2048
|
+
":caused_by": null,
|
|
2049
|
+
":category": "git",
|
|
2050
|
+
":type": "milestone-commit-attribution-recorded",
|
|
2051
|
+
":ts": entry.createdAt,
|
|
2052
|
+
":payload_json": JSON.stringify({
|
|
2053
|
+
commitSha: entry.commitSha,
|
|
2054
|
+
milestoneId: entry.milestoneId,
|
|
2055
|
+
sliceId: entry.sliceId ?? null,
|
|
2056
|
+
taskId: entry.taskId ?? null,
|
|
2057
|
+
source: entry.source,
|
|
2058
|
+
confidence: entry.confidence,
|
|
2059
|
+
files: entry.files,
|
|
2060
|
+
}),
|
|
2061
|
+
});
|
|
2062
|
+
});
|
|
2063
|
+
}
|
|
1965
2064
|
export function insertAuditEvent(entry) {
|
|
1966
2065
|
if (!currentDb)
|
|
1967
2066
|
return;
|
|
@@ -2048,6 +2147,7 @@ export function clearEngineHierarchy() {
|
|
|
2048
2147
|
currentDb.exec("DELETE FROM slice_dependencies");
|
|
2049
2148
|
currentDb.exec("DELETE FROM assessments");
|
|
2050
2149
|
currentDb.exec("DELETE FROM replan_history");
|
|
2150
|
+
currentDb.exec("DELETE FROM milestone_commit_attributions");
|
|
2051
2151
|
currentDb.exec("DELETE FROM tasks");
|
|
2052
2152
|
currentDb.exec("DELETE FROM slices");
|
|
2053
2153
|
currentDb.exec("DELETE FROM milestone_leases");
|
|
@@ -1716,8 +1716,8 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
|
|
|
1716
1716
|
// standard wizard below.
|
|
1717
1717
|
{
|
|
1718
1718
|
const prefs = loadEffectiveGSDPreferences(basePath)?.preferences;
|
|
1719
|
-
const {
|
|
1720
|
-
if (
|
|
1719
|
+
const { shouldRunDeepProjectSetup } = await import("./auto-dispatch.js");
|
|
1720
|
+
if (shouldRunDeepProjectSetup(state, prefs, basePath)) {
|
|
1721
1721
|
await startDeepProjectSetupForeground(ctx, pi, basePath, stepMode);
|
|
1722
1722
|
return;
|
|
1723
1723
|
}
|
|
@@ -1780,16 +1780,24 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
|
|
|
1780
1780
|
title: "GSD — Get Shit Done",
|
|
1781
1781
|
summary: ["No active milestone."],
|
|
1782
1782
|
actions: [
|
|
1783
|
+
{
|
|
1784
|
+
id: "quick_task",
|
|
1785
|
+
label: "Quick task",
|
|
1786
|
+
description: "For small bounded work, run /gsd quick <task> or /gsd do <task>.",
|
|
1787
|
+
recommended: true,
|
|
1788
|
+
},
|
|
1783
1789
|
{
|
|
1784
1790
|
id: "new_milestone",
|
|
1785
1791
|
label: "Create next milestone",
|
|
1786
|
-
description: "Define
|
|
1787
|
-
recommended: true,
|
|
1792
|
+
description: "Define a larger body of work with planning artifacts.",
|
|
1788
1793
|
},
|
|
1789
1794
|
],
|
|
1790
1795
|
notYetMessage: "Run /gsd when ready.",
|
|
1791
1796
|
});
|
|
1792
|
-
if (choice === "
|
|
1797
|
+
if (choice === "quick_task") {
|
|
1798
|
+
ctx.ui.notify("Run /gsd quick <task> for small bounded work, or /gsd do <task> for natural-language routing.", "info");
|
|
1799
|
+
}
|
|
1800
|
+
else if (choice === "new_milestone") {
|
|
1793
1801
|
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode });
|
|
1794
1802
|
await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId, `New milestone ${nextId}.`, basePath), "gsd-run", ctx, "discuss-milestone");
|
|
1795
1803
|
}
|
|
@@ -1809,11 +1817,16 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
|
|
|
1809
1817
|
title: `GSD — ${milestoneId}: ${milestoneTitle}`,
|
|
1810
1818
|
summary: ["All milestones complete."],
|
|
1811
1819
|
actions: [
|
|
1820
|
+
{
|
|
1821
|
+
id: "quick_task",
|
|
1822
|
+
label: "Quick task",
|
|
1823
|
+
description: "Do a small bounded task without opening a milestone.",
|
|
1824
|
+
recommended: true,
|
|
1825
|
+
},
|
|
1812
1826
|
{
|
|
1813
1827
|
id: "new_milestone",
|
|
1814
1828
|
label: "Start new milestone",
|
|
1815
1829
|
description: "Define and plan the next milestone.",
|
|
1816
|
-
recommended: true,
|
|
1817
1830
|
},
|
|
1818
1831
|
{
|
|
1819
1832
|
id: "status",
|
|
@@ -1823,7 +1836,10 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
|
|
|
1823
1836
|
],
|
|
1824
1837
|
notYetMessage: "Run /gsd when ready.",
|
|
1825
1838
|
});
|
|
1826
|
-
if (choice === "
|
|
1839
|
+
if (choice === "quick_task") {
|
|
1840
|
+
ctx.ui.notify("Run /gsd quick <task> for small bounded work, or /gsd do <task> for natural-language routing.", "info");
|
|
1841
|
+
}
|
|
1842
|
+
else if (choice === "new_milestone") {
|
|
1827
1843
|
const milestoneIds = findMilestoneIds(basePath);
|
|
1828
1844
|
const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
|
|
1829
1845
|
const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds, basePath);
|
|
@@ -1916,13 +1932,18 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
|
|
|
1916
1932
|
const contextFile = resolveMilestoneFile(basePath, milestoneId, "CONTEXT");
|
|
1917
1933
|
const hasContext = !!(contextFile && await loadFile(contextFile));
|
|
1918
1934
|
const actions = [
|
|
1935
|
+
{
|
|
1936
|
+
id: "quick_task",
|
|
1937
|
+
label: "Quick task instead",
|
|
1938
|
+
description: "Use this when the work is small and should not become a milestone.",
|
|
1939
|
+
recommended: true,
|
|
1940
|
+
},
|
|
1919
1941
|
{
|
|
1920
1942
|
id: "plan",
|
|
1921
1943
|
label: "Create roadmap",
|
|
1922
1944
|
description: hasContext
|
|
1923
1945
|
? "Context captured. Decompose into slices with a boundary map."
|
|
1924
1946
|
: "Decompose the milestone into slices with a boundary map.",
|
|
1925
|
-
recommended: true,
|
|
1926
1947
|
},
|
|
1927
1948
|
...(!hasContext ? [{
|
|
1928
1949
|
id: "discuss",
|
|
@@ -1946,7 +1967,10 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
|
|
|
1946
1967
|
actions,
|
|
1947
1968
|
notYetMessage: "Run /gsd when ready.",
|
|
1948
1969
|
});
|
|
1949
|
-
if (choice === "
|
|
1970
|
+
if (choice === "quick_task") {
|
|
1971
|
+
ctx.ui.notify("Run /gsd quick <task> for small bounded work, or /gsd do <task> for natural-language routing.", "info");
|
|
1972
|
+
}
|
|
1973
|
+
else if (choice === "plan") {
|
|
1950
1974
|
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId, step: stepMode });
|
|
1951
1975
|
await dispatchWorkflow(pi, await buildPlanMilestonePrompt(milestoneId, milestoneTitle, basePath), "gsd-run", ctx, "plan-milestone");
|
|
1952
1976
|
}
|