gsd-pi 2.80.0-dev.c5f2443b3 → 2.80.0-dev.f55d16d13
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-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 +2 -2
- 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 +11 -11
- 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 +11 -11
- 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-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 +2 -2
- 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/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 → mPZbi5BH9dwokaPZlrYuQ}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{bQDK5_LtkGVS64AirQgQG → mPZbi5BH9dwokaPZlrYuQ}/_ssgManifest.js +0 -0
|
@@ -21,10 +21,34 @@ import { nativeHasChanges } from "./native-git-bridge.js";
|
|
|
21
21
|
export interface PreflightResult {
|
|
22
22
|
/** true when a stash was pushed and postflightPopStash should be called */
|
|
23
23
|
stashPushed: boolean;
|
|
24
|
+
/** Unique marker embedded in the stash message for targeted restoration */
|
|
25
|
+
stashMarker?: string;
|
|
24
26
|
/** human-readable summary of what happened (empty string for clean trees) */
|
|
25
27
|
summary: string;
|
|
26
28
|
}
|
|
27
29
|
|
|
30
|
+
function findPreflightStashRef(basePath: string, milestoneId: string, stashMarker?: string): string | null {
|
|
31
|
+
const markerPrefix = `gsd-preflight-stash:${milestoneId}:`;
|
|
32
|
+
let fallbackRef: string | null = null;
|
|
33
|
+
try {
|
|
34
|
+
const list = execFileSync("git", ["stash", "list", "--format=%gd%x00%s"], {
|
|
35
|
+
cwd: basePath,
|
|
36
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
37
|
+
encoding: "utf-8",
|
|
38
|
+
env: GIT_NO_PROMPT_ENV,
|
|
39
|
+
});
|
|
40
|
+
for (const line of list.split("\n")) {
|
|
41
|
+
const [ref, subject] = line.split("\x00");
|
|
42
|
+
if (!ref || !subject) continue;
|
|
43
|
+
if (stashMarker && subject.includes(stashMarker)) return ref;
|
|
44
|
+
if (!fallbackRef && subject.includes(markerPrefix)) fallbackRef = ref;
|
|
45
|
+
}
|
|
46
|
+
} catch (err) {
|
|
47
|
+
logWarning("preflight", `stash list failed before restore: ${err instanceof Error ? err.message : String(err)}`);
|
|
48
|
+
}
|
|
49
|
+
return fallbackRef;
|
|
50
|
+
}
|
|
51
|
+
|
|
28
52
|
/**
|
|
29
53
|
* Check the working tree for dirty files before a milestone merge.
|
|
30
54
|
*
|
|
@@ -62,7 +86,8 @@ export function preflightCleanRoot(
|
|
|
62
86
|
|
|
63
87
|
// Push the stash
|
|
64
88
|
try {
|
|
65
|
-
|
|
89
|
+
const stashMarker = `gsd-preflight-stash:${milestoneId}:${process.pid}:${Date.now()}:${process.hrtime.bigint().toString(36)}`;
|
|
90
|
+
execFileSync("git", ["stash", "push", "--include-untracked", "-m", `gsd-preflight-stash [${stashMarker}]`], {
|
|
66
91
|
cwd: basePath,
|
|
67
92
|
stdio: ["ignore", "pipe", "pipe"],
|
|
68
93
|
encoding: "utf-8",
|
|
@@ -70,6 +95,7 @@ export function preflightCleanRoot(
|
|
|
70
95
|
});
|
|
71
96
|
return {
|
|
72
97
|
stashPushed: true,
|
|
98
|
+
stashMarker,
|
|
73
99
|
summary: `Stashed uncommitted changes before merge (milestone ${milestoneId}).`,
|
|
74
100
|
};
|
|
75
101
|
} catch (err) {
|
|
@@ -91,10 +117,19 @@ export function preflightCleanRoot(
|
|
|
91
117
|
export function postflightPopStash(
|
|
92
118
|
basePath: string,
|
|
93
119
|
milestoneId: string,
|
|
120
|
+
stashMarker: string | undefined,
|
|
94
121
|
notify: (message: string, level: "info" | "warning" | "error") => void,
|
|
95
122
|
): void {
|
|
123
|
+
let stashRef: string | null = null;
|
|
96
124
|
try {
|
|
97
|
-
|
|
125
|
+
stashRef = findPreflightStashRef(basePath, milestoneId, stashMarker);
|
|
126
|
+
if (!stashRef) {
|
|
127
|
+
const msg = `No matching GSD preflight stash found for milestone ${milestoneId}; leaving stash list untouched.`;
|
|
128
|
+
logWarning("preflight", msg);
|
|
129
|
+
notify(msg, "warning");
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
execFileSync("git", ["stash", "pop", stashRef], {
|
|
98
133
|
cwd: basePath,
|
|
99
134
|
stdio: ["ignore", "pipe", "pipe"],
|
|
100
135
|
encoding: "utf-8",
|
|
@@ -104,7 +139,10 @@ export function postflightPopStash(
|
|
|
104
139
|
} catch (err) {
|
|
105
140
|
// Pop conflicts mean the merged code collides with the stashed changes.
|
|
106
141
|
// Log a warning — the user needs to resolve manually, but the merge succeeded.
|
|
107
|
-
const
|
|
142
|
+
const restoreHint = stashRef
|
|
143
|
+
? `Run "git stash pop ${stashRef}" or "git stash apply ${stashRef}" manually to restore the correct stash.`
|
|
144
|
+
: `Run "git stash list" to find the matching GSD preflight stash before restoring manually.`;
|
|
145
|
+
const msg = `git stash pop ${stashRef ?? ""}`.trim() + ` failed after merge of milestone ${milestoneId}: ${err instanceof Error ? err.message : String(err)}. ${restoreHint}`;
|
|
108
146
|
logWarning("preflight", msg);
|
|
109
147
|
notify(msg, "warning");
|
|
110
148
|
}
|
|
@@ -222,14 +222,19 @@ Using the \`write\` tool, persist the full structured report to
|
|
|
222
222
|
LEARNINGS.md is the full, cited audit trail. Write it first — subsequent steps
|
|
223
223
|
feed from its content.
|
|
224
224
|
|
|
225
|
-
### Step 3 —
|
|
225
|
+
### Step 3 — Run one bounded duplicate check
|
|
226
226
|
|
|
227
|
-
Before persisting
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
227
|
+
Before persisting extracted items in Steps 4–6, do at most one duplicate-check
|
|
228
|
+
pass for the durable Decisions, Lessons, and Patterns from this milestone. Use
|
|
229
|
+
the already-written LEARNINGS.md content and call \`memory_query\` once with a
|
|
230
|
+
compact keyword summary for the whole batch. If that result clearly shows a
|
|
231
|
+
semantically equivalent high-confidence memory for an item, mark only that item
|
|
232
|
+
as already captured and skip it in its respective persistence step.
|
|
233
|
+
|
|
234
|
+
Do not re-read milestone artefacts or repeat memory queries category-by-category
|
|
235
|
+
after this point. The memory store is the single source of truth for
|
|
236
|
+
cross-session durable knowledge — no other persistence call is part of this
|
|
237
|
+
flow.
|
|
233
238
|
|
|
234
239
|
### Step 4 — Persist Patterns via \`capture_thought\`
|
|
235
240
|
|
|
@@ -268,11 +273,11 @@ later projection back to a human-visible decisions register stays lossless
|
|
|
268
273
|
|
|
269
274
|
### Step 7 — Deduplication rule (applies to Steps 4, 5, 6)
|
|
270
275
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
over creating a second slightly-different row
|
|
275
|
-
signal.
|
|
276
|
+
Use only the duplicate-check result from Step 3. If that bounded check returned
|
|
277
|
+
a semantically equivalent memory at high confidence for an extracted item, skip
|
|
278
|
+
the capture entirely. Otherwise, persist the item once via \`capture_thought\`.
|
|
279
|
+
Prefer skipping a near-duplicate over creating a second slightly-different row
|
|
280
|
+
— redundancy degrades the signal.
|
|
276
281
|
|
|
277
282
|
### Step 8 — Surprises stay only in LEARNINGS.md
|
|
278
283
|
|
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
markStepActive,
|
|
30
30
|
markStepComplete,
|
|
31
31
|
expandIteration,
|
|
32
|
+
isTerminalStepStatus,
|
|
32
33
|
type WorkflowGraph,
|
|
33
34
|
} from "./graph.js";
|
|
34
35
|
import { injectContext } from "./context-injector.js";
|
|
@@ -40,6 +41,24 @@ import { withFileLock } from "./file-lock.js";
|
|
|
40
41
|
// Re-export for downstream consumers
|
|
41
42
|
export { readFrozenDefinition } from "./definition-io.js";
|
|
42
43
|
|
|
44
|
+
function formatBlockedWorkflowReason(graph: WorkflowGraph): string {
|
|
45
|
+
const statusById = new Map(graph.steps.map((step) => [step.id, step.status]));
|
|
46
|
+
const blockedSteps = graph.steps
|
|
47
|
+
.filter((step) => step.status === "pending")
|
|
48
|
+
.map((step) => {
|
|
49
|
+
const blockers = step.dependsOn
|
|
50
|
+
.filter((depId) => !isTerminalStepStatus(statusById.get(depId)))
|
|
51
|
+
.map((depId) => `${depId} (${statusById.get(depId) ?? "missing"})`);
|
|
52
|
+
return blockers.length > 0
|
|
53
|
+
? `${step.id} waiting on ${blockers.join(", ")}`
|
|
54
|
+
: `${step.id} has no runnable dependency path`;
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
return blockedSteps.length > 0
|
|
58
|
+
? `Workflow blocked: no pending steps are ready. Blocked steps: ${blockedSteps.join("; ")}`
|
|
59
|
+
: "Workflow blocked: no pending steps are ready.";
|
|
60
|
+
}
|
|
61
|
+
|
|
43
62
|
export class CustomWorkflowEngine implements WorkflowEngine {
|
|
44
63
|
readonly engineId = "custom";
|
|
45
64
|
private readonly runDir: string;
|
|
@@ -114,7 +133,11 @@ export class CustomWorkflowEngine implements WorkflowEngine {
|
|
|
114
133
|
(step) => step.status === "complete" || step.status === "expanded",
|
|
115
134
|
);
|
|
116
135
|
if (!allDone) {
|
|
117
|
-
return {
|
|
136
|
+
return {
|
|
137
|
+
action: "stop",
|
|
138
|
+
reason: formatBlockedWorkflowReason(graph),
|
|
139
|
+
level: "error",
|
|
140
|
+
};
|
|
118
141
|
}
|
|
119
142
|
return {
|
|
120
143
|
action: "stop",
|
|
@@ -323,6 +323,20 @@ export function createBaseSchemaObjects(db: DbAdapter, hooks: BaseSchemaHooks):
|
|
|
323
323
|
)
|
|
324
324
|
`);
|
|
325
325
|
|
|
326
|
+
db.exec(`
|
|
327
|
+
CREATE TABLE IF NOT EXISTS milestone_commit_attributions (
|
|
328
|
+
commit_sha TEXT NOT NULL,
|
|
329
|
+
milestone_id TEXT NOT NULL,
|
|
330
|
+
slice_id TEXT DEFAULT NULL,
|
|
331
|
+
task_id TEXT DEFAULT NULL,
|
|
332
|
+
source TEXT NOT NULL DEFAULT 'recorded',
|
|
333
|
+
confidence REAL NOT NULL DEFAULT 1.0,
|
|
334
|
+
files_json TEXT NOT NULL DEFAULT '[]',
|
|
335
|
+
created_at TEXT NOT NULL DEFAULT '',
|
|
336
|
+
PRIMARY KEY (commit_sha, milestone_id)
|
|
337
|
+
)
|
|
338
|
+
`);
|
|
339
|
+
|
|
326
340
|
db.exec(`
|
|
327
341
|
CREATE TABLE IF NOT EXISTS audit_events (
|
|
328
342
|
event_id TEXT PRIMARY KEY,
|
|
@@ -359,6 +373,7 @@ export function createBaseSchemaObjects(db: DbAdapter, hooks: BaseSchemaHooks):
|
|
|
359
373
|
db.exec("CREATE INDEX IF NOT EXISTS idx_gate_runs_turn ON gate_runs(trace_id, turn_id)");
|
|
360
374
|
db.exec("CREATE INDEX IF NOT EXISTS idx_gate_runs_lookup ON gate_runs(milestone_id, slice_id, task_id, gate_id)");
|
|
361
375
|
db.exec("CREATE INDEX IF NOT EXISTS idx_turn_git_tx_turn ON turn_git_transactions(trace_id, turn_id)");
|
|
376
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_milestone_commit_attr_milestone ON milestone_commit_attributions(milestone_id)");
|
|
362
377
|
db.exec("CREATE INDEX IF NOT EXISTS idx_audit_events_trace ON audit_events(trace_id, ts)");
|
|
363
378
|
db.exec("CREATE INDEX IF NOT EXISTS idx_audit_events_turn ON audit_events(trace_id, turn_id, ts)");
|
|
364
379
|
|
|
@@ -399,6 +399,23 @@ export function applyMigrationV23MilestoneQueue(db: DbAdapter): void {
|
|
|
399
399
|
ensureColumn(db, "milestones", "sequence", "ALTER TABLE milestones ADD COLUMN sequence INTEGER DEFAULT 0");
|
|
400
400
|
}
|
|
401
401
|
|
|
402
|
+
export function applyMigrationV26MilestoneCommitAttributions(db: DbAdapter): void {
|
|
403
|
+
db.exec(`
|
|
404
|
+
CREATE TABLE IF NOT EXISTS milestone_commit_attributions (
|
|
405
|
+
commit_sha TEXT NOT NULL,
|
|
406
|
+
milestone_id TEXT NOT NULL,
|
|
407
|
+
slice_id TEXT DEFAULT NULL,
|
|
408
|
+
task_id TEXT DEFAULT NULL,
|
|
409
|
+
source TEXT NOT NULL DEFAULT 'recorded',
|
|
410
|
+
confidence REAL NOT NULL DEFAULT 1.0,
|
|
411
|
+
files_json TEXT NOT NULL DEFAULT '[]',
|
|
412
|
+
created_at TEXT NOT NULL DEFAULT '',
|
|
413
|
+
PRIMARY KEY (commit_sha, milestone_id)
|
|
414
|
+
)
|
|
415
|
+
`);
|
|
416
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_milestone_commit_attr_milestone ON milestone_commit_attributions(milestone_id)");
|
|
417
|
+
}
|
|
418
|
+
|
|
402
419
|
export interface MigrationV22Hooks {
|
|
403
420
|
copyQualityGateRowsToRepairedTable(db: DbAdapter): void;
|
|
404
421
|
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* flow to show when entering a project directory.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { execFileSync } from "node:child_process";
|
|
9
10
|
import { existsSync, openSync, readSync, closeSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
10
11
|
import { dirname, join, parse as parsePath } from "node:path";
|
|
11
12
|
import { homedir } from "node:os";
|
|
@@ -72,6 +73,22 @@ export interface ProjectSignals {
|
|
|
72
73
|
verificationCommands: string[];
|
|
73
74
|
}
|
|
74
75
|
|
|
76
|
+
export type ProjectClassificationKind =
|
|
77
|
+
| "invalid-repo"
|
|
78
|
+
| "greenfield"
|
|
79
|
+
| "untyped-existing"
|
|
80
|
+
| "typed-existing";
|
|
81
|
+
|
|
82
|
+
export interface ProjectClassification {
|
|
83
|
+
kind: ProjectClassificationKind;
|
|
84
|
+
signals: ProjectSignals;
|
|
85
|
+
trackedFiles: string[];
|
|
86
|
+
untrackedFiles: string[];
|
|
87
|
+
contentFiles: string[];
|
|
88
|
+
markers: string[];
|
|
89
|
+
reason: string;
|
|
90
|
+
}
|
|
91
|
+
|
|
75
92
|
// ─── Project File Markers ───────────────────────────────────────────────────────
|
|
76
93
|
|
|
77
94
|
export const PROJECT_FILES = [
|
|
@@ -243,6 +260,7 @@ const TEST_MARKERS = [
|
|
|
243
260
|
const RECURSIVE_SCAN_IGNORED_DIRS = new Set([
|
|
244
261
|
".git",
|
|
245
262
|
".gsd",
|
|
263
|
+
".bg-shell",
|
|
246
264
|
".planning",
|
|
247
265
|
".plans",
|
|
248
266
|
".claude",
|
|
@@ -267,6 +285,8 @@ const RECURSIVE_SCAN_IGNORED_DIRS = new Set([
|
|
|
267
285
|
"out",
|
|
268
286
|
]) as ReadonlySet<string>;
|
|
269
287
|
|
|
288
|
+
const PROJECT_CONTENT_EXCLUDE_DIRS = RECURSIVE_SCAN_IGNORED_DIRS;
|
|
289
|
+
|
|
270
290
|
/** Project file markers safe to detect recursively via suffix matching. */
|
|
271
291
|
const ROOT_ONLY_PROJECT_FILES = new Set<string>([
|
|
272
292
|
".github/workflows",
|
|
@@ -536,6 +556,114 @@ export function detectProjectSignals(basePath: string): ProjectSignals {
|
|
|
536
556
|
};
|
|
537
557
|
}
|
|
538
558
|
|
|
559
|
+
function normalizeGitPath(file: string): string {
|
|
560
|
+
return file.replaceAll("\\", "/").replace(/^\.\//, "");
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
function isProjectContentFile(file: string): boolean {
|
|
564
|
+
const normalized = normalizeGitPath(file);
|
|
565
|
+
if (!normalized || normalized.endsWith("/")) return false;
|
|
566
|
+
if (normalized === ".gitignore" || normalized === ".gitattributes") return false;
|
|
567
|
+
const parts = normalized.split("/");
|
|
568
|
+
if (parts.some((part) => PROJECT_CONTENT_EXCLUDE_DIRS.has(part))) return false;
|
|
569
|
+
if (normalized.endsWith(".DS_Store")) return false;
|
|
570
|
+
return true;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
function runGitLines(basePath: string, args: string[]): string[] {
|
|
574
|
+
try {
|
|
575
|
+
const output = execFileSync("git", args, {
|
|
576
|
+
cwd: basePath,
|
|
577
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
578
|
+
encoding: "utf-8",
|
|
579
|
+
}).trim();
|
|
580
|
+
return output ? output.split("\n").map((line) => line.trim()).filter(Boolean) : [];
|
|
581
|
+
} catch {
|
|
582
|
+
return [];
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
function listTrackedProjectFiles(basePath: string): string[] {
|
|
587
|
+
return runGitLines(basePath, ["ls-files"])
|
|
588
|
+
.map(normalizeGitPath)
|
|
589
|
+
.filter(isProjectContentFile);
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
function listUntrackedProjectFiles(basePath: string): string[] {
|
|
593
|
+
return runGitLines(basePath, ["ls-files", "--others", "--exclude-standard"])
|
|
594
|
+
.map(normalizeGitPath)
|
|
595
|
+
.filter(isProjectContentFile);
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
function hasKnownProjectMarkers(basePath: string, signals: ProjectSignals): boolean {
|
|
599
|
+
if (signals.detectedFiles.length > 0) return true;
|
|
600
|
+
if (signals.xcodePlatforms.length > 0) return true;
|
|
601
|
+
return false;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* Classify repo presence separately from ecosystem/tooling markers.
|
|
606
|
+
*
|
|
607
|
+
* Known project files identify tooling. Git-tracked/non-ignored content
|
|
608
|
+
* identifies whether this is an existing project at all. This keeps small
|
|
609
|
+
* static or documentation repos from being mislabeled as greenfield.
|
|
610
|
+
*/
|
|
611
|
+
export function classifyProject(basePath: string): ProjectClassification {
|
|
612
|
+
const signals = detectProjectSignals(basePath);
|
|
613
|
+
const markers = [...signals.detectedFiles];
|
|
614
|
+
|
|
615
|
+
if (!signals.isGitRepo) {
|
|
616
|
+
return {
|
|
617
|
+
kind: "invalid-repo",
|
|
618
|
+
signals,
|
|
619
|
+
trackedFiles: [],
|
|
620
|
+
untrackedFiles: [],
|
|
621
|
+
contentFiles: [],
|
|
622
|
+
markers,
|
|
623
|
+
reason: "missing .git",
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
const trackedFiles = listTrackedProjectFiles(basePath);
|
|
628
|
+
const untrackedFiles = listUntrackedProjectFiles(basePath);
|
|
629
|
+
const contentFiles = [...new Set([...trackedFiles, ...untrackedFiles])];
|
|
630
|
+
const hasMarkers = hasKnownProjectMarkers(basePath, signals);
|
|
631
|
+
|
|
632
|
+
if (hasMarkers) {
|
|
633
|
+
return {
|
|
634
|
+
kind: "typed-existing",
|
|
635
|
+
signals,
|
|
636
|
+
trackedFiles,
|
|
637
|
+
untrackedFiles,
|
|
638
|
+
contentFiles,
|
|
639
|
+
markers,
|
|
640
|
+
reason: markers.length > 0 ? `detected markers: ${markers.join(", ")}` : "detected project structure",
|
|
641
|
+
};
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
if (contentFiles.length > 0) {
|
|
645
|
+
return {
|
|
646
|
+
kind: "untyped-existing",
|
|
647
|
+
signals,
|
|
648
|
+
trackedFiles,
|
|
649
|
+
untrackedFiles,
|
|
650
|
+
contentFiles,
|
|
651
|
+
markers,
|
|
652
|
+
reason: "project content exists but no recognized tooling markers were found",
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
return {
|
|
657
|
+
kind: "greenfield",
|
|
658
|
+
signals,
|
|
659
|
+
trackedFiles,
|
|
660
|
+
untrackedFiles,
|
|
661
|
+
contentFiles,
|
|
662
|
+
markers,
|
|
663
|
+
reason: "no tracked or non-ignored project content",
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
|
|
539
667
|
// ─── Xcode Platform Detection ───────────────────────────────────────────────────
|
|
540
668
|
|
|
541
669
|
/** Known SDKROOT values → canonical platform names. */
|
|
@@ -31,7 +31,7 @@ export interface GraphStep {
|
|
|
31
31
|
status: "pending" | "active" | "complete" | "expanded";
|
|
32
32
|
/** The prompt to dispatch for this step. */
|
|
33
33
|
prompt: string;
|
|
34
|
-
/** IDs of steps that must be
|
|
34
|
+
/** IDs of steps that must be terminal before this step can run. */
|
|
35
35
|
dependsOn: string[];
|
|
36
36
|
/** For iteration instances: ID of the parent step that was expanded. */
|
|
37
37
|
parentStepId?: string;
|
|
@@ -152,10 +152,17 @@ export function writeGraph(runDir: string, graph: WorkflowGraph): void {
|
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
/**
|
|
155
|
-
*
|
|
155
|
+
* Return whether a graph step status satisfies dependency edges.
|
|
156
|
+
*/
|
|
157
|
+
export function isTerminalStepStatus(status: GraphStep["status"] | undefined): boolean {
|
|
158
|
+
return status === "complete" || status === "expanded";
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Get the next pending step whose dependencies are all terminal.
|
|
156
163
|
*
|
|
157
164
|
* Returns the first step (in array order) with status "pending" where
|
|
158
|
-
* every step in its `dependsOn` list has status "complete".
|
|
165
|
+
* every step in its `dependsOn` list has status "complete" or "expanded".
|
|
159
166
|
*
|
|
160
167
|
* @param graph — the workflow graph to query
|
|
161
168
|
* @returns The next dispatchable step, or null if none available
|
|
@@ -165,8 +172,8 @@ export function getNextPendingStep(graph: WorkflowGraph): GraphStep | null {
|
|
|
165
172
|
|
|
166
173
|
for (const step of graph.steps) {
|
|
167
174
|
if (step.status !== "pending") continue;
|
|
168
|
-
const depsComplete = step.dependsOn.every(
|
|
169
|
-
(
|
|
175
|
+
const depsComplete = step.dependsOn.every((depId) =>
|
|
176
|
+
isTerminalStepStatus(statusMap.get(depId)),
|
|
170
177
|
);
|
|
171
178
|
if (depsComplete) return step;
|
|
172
179
|
}
|
|
@@ -77,6 +77,7 @@ import {
|
|
|
77
77
|
applyMigrationV21StructuredMemories,
|
|
78
78
|
applyMigrationV22QualityGateRepair,
|
|
79
79
|
applyMigrationV23MilestoneQueue,
|
|
80
|
+
applyMigrationV26MilestoneCommitAttributions,
|
|
80
81
|
} from "./db-migration-steps.js";
|
|
81
82
|
import { isMemoriesFtsAvailableSchema, tryCreateMemoriesFtsSchema } from "./db-memory-fts-schema.js";
|
|
82
83
|
import { createDbOpenState, type DbOpenPhase } from "./db-open-state.js";
|
|
@@ -105,7 +106,7 @@ const providerLoader = createSqliteProviderLoader({
|
|
|
105
106
|
writeStderr: (message: string) => process.stderr.write(message),
|
|
106
107
|
});
|
|
107
108
|
|
|
108
|
-
export const SCHEMA_VERSION =
|
|
109
|
+
export const SCHEMA_VERSION = 26;
|
|
109
110
|
|
|
110
111
|
function initSchema(db: DbAdapter, fileBacked: boolean): void {
|
|
111
112
|
if (fileBacked) db.exec("PRAGMA journal_mode=WAL");
|
|
@@ -329,6 +330,11 @@ function migrateSchema(db: DbAdapter): void {
|
|
|
329
330
|
recordSchemaVersion(db, 25);
|
|
330
331
|
}
|
|
331
332
|
|
|
333
|
+
if (currentVersion < 26) {
|
|
334
|
+
applyMigrationV26MilestoneCommitAttributions(db);
|
|
335
|
+
recordSchemaVersion(db, 26);
|
|
336
|
+
}
|
|
337
|
+
|
|
332
338
|
db.exec("COMMIT");
|
|
333
339
|
} catch (err) {
|
|
334
340
|
db.exec("ROLLBACK");
|
|
@@ -1349,6 +1355,45 @@ export function getSliceTasks(milestoneId: string, sliceId: string): TaskRow[] {
|
|
|
1349
1355
|
return rows.map(rowToTask);
|
|
1350
1356
|
}
|
|
1351
1357
|
|
|
1358
|
+
export function getCompletedMilestoneTaskFileHints(milestoneId: string): string[] {
|
|
1359
|
+
if (!currentDb) return [];
|
|
1360
|
+
const rows = currentDb.prepare(
|
|
1361
|
+
`SELECT files, key_files
|
|
1362
|
+
FROM tasks
|
|
1363
|
+
WHERE milestone_id = :mid AND status IN ('complete', 'done')`,
|
|
1364
|
+
).all({ ":mid": milestoneId }) as Array<Record<string, unknown>>;
|
|
1365
|
+
|
|
1366
|
+
const hints = new Set<string>();
|
|
1367
|
+
for (const row of rows) {
|
|
1368
|
+
for (const raw of [row["files"], row["key_files"]]) {
|
|
1369
|
+
for (const file of parseStringArrayColumn(raw)) {
|
|
1370
|
+
const normalized = normalizeRepoPath(file);
|
|
1371
|
+
if (normalized) hints.add(normalized);
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
return [...hints];
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1378
|
+
function parseStringArrayColumn(raw: unknown): string[] {
|
|
1379
|
+
if (Array.isArray(raw)) return raw.filter((entry): entry is string => typeof entry === "string");
|
|
1380
|
+
if (typeof raw !== "string") return [];
|
|
1381
|
+
const trimmed = raw.trim();
|
|
1382
|
+
if (!trimmed) return [];
|
|
1383
|
+
try {
|
|
1384
|
+
const parsed = JSON.parse(trimmed);
|
|
1385
|
+
if (Array.isArray(parsed)) return parsed.filter((entry): entry is string => typeof entry === "string");
|
|
1386
|
+
if (typeof parsed === "string") return [parsed];
|
|
1387
|
+
} catch {
|
|
1388
|
+
return trimmed.split(",");
|
|
1389
|
+
}
|
|
1390
|
+
return [];
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
function normalizeRepoPath(file: string): string {
|
|
1394
|
+
return file.trim().replace(/\\/g, "/").replace(/^\.\/+/, "");
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1352
1397
|
// ─── ADR-011 Phase 2 escalation helpers ──────────────────────────────────
|
|
1353
1398
|
|
|
1354
1399
|
/** Set pause-on-escalation state on a completed task. Mutually exclusive with awaiting_review. */
|
|
@@ -2073,6 +2118,9 @@ export function deleteMilestone(milestoneId: string): void {
|
|
|
2073
2118
|
currentDb!.prepare(
|
|
2074
2119
|
`DELETE FROM artifacts WHERE milestone_id = :mid`,
|
|
2075
2120
|
).run({ ":mid": milestoneId });
|
|
2121
|
+
currentDb!.prepare(
|
|
2122
|
+
`DELETE FROM milestone_commit_attributions WHERE milestone_id = :mid`,
|
|
2123
|
+
).run({ ":mid": milestoneId });
|
|
2076
2124
|
currentDb!.prepare(
|
|
2077
2125
|
`DELETE FROM milestone_leases WHERE milestone_id = :mid`,
|
|
2078
2126
|
).run({ ":mid": milestoneId });
|
|
@@ -2391,6 +2439,75 @@ export function upsertTurnGitTransaction(entry: {
|
|
|
2391
2439
|
});
|
|
2392
2440
|
}
|
|
2393
2441
|
|
|
2442
|
+
export function getMilestoneCommitAttributionShas(milestoneId: string): string[] {
|
|
2443
|
+
if (!currentDb) return [];
|
|
2444
|
+
const rows = currentDb.prepare(
|
|
2445
|
+
`SELECT commit_sha
|
|
2446
|
+
FROM milestone_commit_attributions
|
|
2447
|
+
WHERE milestone_id = :mid
|
|
2448
|
+
ORDER BY created_at, commit_sha`,
|
|
2449
|
+
).all({ ":mid": milestoneId }) as Array<Record<string, unknown>>;
|
|
2450
|
+
return rows
|
|
2451
|
+
.map((row) => typeof row["commit_sha"] === "string" ? row["commit_sha"] : "")
|
|
2452
|
+
.filter(Boolean);
|
|
2453
|
+
}
|
|
2454
|
+
|
|
2455
|
+
export function recordMilestoneCommitAttribution(entry: {
|
|
2456
|
+
commitSha: string;
|
|
2457
|
+
milestoneId: string;
|
|
2458
|
+
sliceId?: string;
|
|
2459
|
+
taskId?: string;
|
|
2460
|
+
source: "recorded" | "backfill";
|
|
2461
|
+
confidence: number;
|
|
2462
|
+
files: string[];
|
|
2463
|
+
createdAt: string;
|
|
2464
|
+
}): void {
|
|
2465
|
+
if (!currentDb) return;
|
|
2466
|
+
transaction(() => {
|
|
2467
|
+
currentDb!.prepare(
|
|
2468
|
+
`INSERT OR REPLACE INTO milestone_commit_attributions (
|
|
2469
|
+
commit_sha, milestone_id, slice_id, task_id, source, confidence, files_json, created_at
|
|
2470
|
+
) VALUES (
|
|
2471
|
+
:commit_sha, :milestone_id, :slice_id, :task_id, :source, :confidence, :files_json, :created_at
|
|
2472
|
+
)`,
|
|
2473
|
+
).run({
|
|
2474
|
+
":commit_sha": entry.commitSha,
|
|
2475
|
+
":milestone_id": entry.milestoneId,
|
|
2476
|
+
":slice_id": entry.sliceId ?? null,
|
|
2477
|
+
":task_id": entry.taskId ?? null,
|
|
2478
|
+
":source": entry.source,
|
|
2479
|
+
":confidence": entry.confidence,
|
|
2480
|
+
":files_json": JSON.stringify(entry.files),
|
|
2481
|
+
":created_at": entry.createdAt,
|
|
2482
|
+
});
|
|
2483
|
+
|
|
2484
|
+
currentDb!.prepare(
|
|
2485
|
+
`INSERT OR IGNORE INTO audit_events (
|
|
2486
|
+
event_id, trace_id, turn_id, caused_by, category, type, ts, payload_json
|
|
2487
|
+
) VALUES (
|
|
2488
|
+
:event_id, :trace_id, :turn_id, :caused_by, :category, :type, :ts, :payload_json
|
|
2489
|
+
)`,
|
|
2490
|
+
).run({
|
|
2491
|
+
":event_id": `milestone-commit-attribution:${entry.milestoneId}:${entry.commitSha}`,
|
|
2492
|
+
":trace_id": "milestone-commit-attribution",
|
|
2493
|
+
":turn_id": null,
|
|
2494
|
+
":caused_by": null,
|
|
2495
|
+
":category": "git",
|
|
2496
|
+
":type": "milestone-commit-attribution-recorded",
|
|
2497
|
+
":ts": entry.createdAt,
|
|
2498
|
+
":payload_json": JSON.stringify({
|
|
2499
|
+
commitSha: entry.commitSha,
|
|
2500
|
+
milestoneId: entry.milestoneId,
|
|
2501
|
+
sliceId: entry.sliceId ?? null,
|
|
2502
|
+
taskId: entry.taskId ?? null,
|
|
2503
|
+
source: entry.source,
|
|
2504
|
+
confidence: entry.confidence,
|
|
2505
|
+
files: entry.files,
|
|
2506
|
+
}),
|
|
2507
|
+
});
|
|
2508
|
+
});
|
|
2509
|
+
}
|
|
2510
|
+
|
|
2394
2511
|
export function insertAuditEvent(entry: {
|
|
2395
2512
|
eventId: string;
|
|
2396
2513
|
traceId: string;
|
|
@@ -2494,6 +2611,7 @@ export function clearEngineHierarchy(): void {
|
|
|
2494
2611
|
currentDb!.exec("DELETE FROM slice_dependencies");
|
|
2495
2612
|
currentDb!.exec("DELETE FROM assessments");
|
|
2496
2613
|
currentDb!.exec("DELETE FROM replan_history");
|
|
2614
|
+
currentDb!.exec("DELETE FROM milestone_commit_attributions");
|
|
2497
2615
|
currentDb!.exec("DELETE FROM tasks");
|
|
2498
2616
|
currentDb!.exec("DELETE FROM slices");
|
|
2499
2617
|
currentDb!.exec("DELETE FROM milestone_leases");
|
|
@@ -2064,8 +2064,8 @@ export async function showSmartEntry(
|
|
|
2064
2064
|
// standard wizard below.
|
|
2065
2065
|
{
|
|
2066
2066
|
const prefs = loadEffectiveGSDPreferences(basePath)?.preferences;
|
|
2067
|
-
const {
|
|
2068
|
-
if (
|
|
2067
|
+
const { shouldRunDeepProjectSetup } = await import("./auto-dispatch.js");
|
|
2068
|
+
if (shouldRunDeepProjectSetup(state, prefs, basePath)) {
|
|
2069
2069
|
await startDeepProjectSetupForeground(ctx, pi, basePath, stepMode);
|
|
2070
2070
|
return;
|
|
2071
2071
|
}
|