gsd-pi 2.80.0-dev.c5f2443b3 → 2.80.0-dev.f2447468f
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 +46 -9
- package/dist/resources/extensions/gsd/planning-path-scope.js +26 -0
- package/dist/resources/extensions/gsd/pr-evidence.js +57 -16
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +7 -8
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +3 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +10 -2
- package/dist/resources/extensions/gsd/tools/plan-slice.js +9 -0
- package/dist/resources/extensions/gsd/tools/plan-task.js +9 -0
- package/dist/resources/extensions/gsd/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 +10 -10
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
- package/dist/web/standalone/.next/server/chunks/6897.js +3 -3
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/{8336.6f6f30e410419aff.js → 8336.631939fb583761fa.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/{webpack-d82dbee6356c1733.js → webpack-0481f1221120a7c6.js} +1 -1
- package/package.json +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/db-snapshot.d.ts +15 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.js +66 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.js +24 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +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/dist/resources/extensions/memory/storage-safety-guard.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js +10 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js +3 -2
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js.map +1 -1
- package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +87 -0
- package/packages/pi-coding-agent/src/core/db-snapshot.test.ts +32 -0
- package/packages/pi-coding-agent/src/core/db-snapshot.ts +66 -0
- package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +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/src/resources/extensions/memory/storage-safety-guard.test.ts +14 -0
- package/packages/pi-coding-agent/src/resources/extensions/memory/storage.ts +3 -2
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/__tests__/style.test.d.ts +2 -0
- package/packages/pi-tui/dist/__tests__/style.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/__tests__/style.test.js +63 -0
- package/packages/pi-tui/dist/__tests__/style.test.js.map +1 -0
- package/packages/pi-tui/dist/__tests__/tui.test.js +24 -3
- package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
- package/packages/pi-tui/dist/index.d.ts +1 -0
- package/packages/pi-tui/dist/index.d.ts.map +1 -1
- package/packages/pi-tui/dist/index.js +2 -0
- package/packages/pi-tui/dist/index.js.map +1 -1
- package/packages/pi-tui/dist/style.d.ts +41 -0
- package/packages/pi-tui/dist/style.d.ts.map +1 -0
- package/packages/pi-tui/dist/style.js +158 -0
- package/packages/pi-tui/dist/style.js.map +1 -0
- package/packages/pi-tui/dist/tui.d.ts +0 -1
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +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 +46 -9
- package/src/resources/extensions/gsd/planning-path-scope.ts +35 -0
- package/src/resources/extensions/gsd/pr-evidence.ts +63 -5
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +7 -8
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +3 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/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/plan-slice.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/pr-evidence-equivalence.test.ts +102 -0
- package/src/resources/extensions/gsd/tests/pr-evidence-hardening.test.ts +165 -0
- package/src/resources/extensions/gsd/tests/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 +38 -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/tools/plan-slice.ts +13 -0
- package/src/resources/extensions/gsd/tools/plan-task.ts +10 -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 → _67VlKGhH0VvTM6yfRGKl}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{bQDK5_LtkGVS64AirQgQG → _67VlKGhH0VvTM6yfRGKl}/_ssgManifest.js +0 -0
|
@@ -7,11 +7,12 @@ import { randomUUID } from "node:crypto";
|
|
|
7
7
|
|
|
8
8
|
import { verifyExpectedArtifact, hasImplementationArtifacts, resolveExpectedArtifactPath, diagnoseExpectedArtifact, buildLoopRemediationSteps, writeBlockerPlaceholder } from "../auto-recovery.ts";
|
|
9
9
|
import { resolveMilestoneFile } from "../paths.ts";
|
|
10
|
-
import { openDatabase, closeDatabase, insertMilestone, insertSlice, insertGateRow, insertTask } from "../gsd-db.ts";
|
|
10
|
+
import { openDatabase, closeDatabase, insertMilestone, insertSlice, insertGateRow, insertTask, getMilestoneCommitAttributionShas } from "../gsd-db.ts";
|
|
11
11
|
import { clearParseCache } from "../files.ts";
|
|
12
12
|
import { parseRoadmap } from "../parsers-legacy.ts";
|
|
13
13
|
import { invalidateAllCaches } from "../cache.ts";
|
|
14
14
|
import { deriveState, invalidateStateCache } from "../state.ts";
|
|
15
|
+
import { writeIntegrationBranch } from "../git-service.ts";
|
|
15
16
|
|
|
16
17
|
const tmpDirs: string[] = [];
|
|
17
18
|
|
|
@@ -735,6 +736,174 @@ test("hasImplementationArtifacts rejects milestone-scoped main history with only
|
|
|
735
736
|
}
|
|
736
737
|
});
|
|
737
738
|
|
|
739
|
+
test("hasImplementationArtifacts finds integration implementation-only commits when milestone branch diff is .gsd-only", () => {
|
|
740
|
+
const base = makeGitBase();
|
|
741
|
+
try {
|
|
742
|
+
mkdirSync(join(base, "src"), { recursive: true });
|
|
743
|
+
writeFileSync(join(base, "src", "feature.ts"), "export function feature() {}\n");
|
|
744
|
+
execFileSync("git", ["add", "src/feature.ts"], { cwd: base, stdio: "ignore" });
|
|
745
|
+
execFileSync("git", ["commit", "-m", "feat: add milestone feature\n\nGSD-Task: S01/T01"], { cwd: base, stdio: "ignore" });
|
|
746
|
+
|
|
747
|
+
mkdirSync(join(base, ".gsd"), { recursive: true });
|
|
748
|
+
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
749
|
+
insertMilestone({ id: "M001", title: "Milestone One", status: "active" });
|
|
750
|
+
insertSlice({
|
|
751
|
+
id: "S01",
|
|
752
|
+
milestoneId: "M001",
|
|
753
|
+
title: "Slice One",
|
|
754
|
+
status: "complete",
|
|
755
|
+
risk: "low",
|
|
756
|
+
depends: [],
|
|
757
|
+
});
|
|
758
|
+
insertTask({
|
|
759
|
+
id: "T01",
|
|
760
|
+
sliceId: "S01",
|
|
761
|
+
milestoneId: "M001",
|
|
762
|
+
title: "Task One",
|
|
763
|
+
status: "complete",
|
|
764
|
+
});
|
|
765
|
+
|
|
766
|
+
execFileSync("git", ["checkout", "-b", "milestone/M001"], { cwd: base, stdio: "ignore" });
|
|
767
|
+
writeIntegrationBranch(base, "M001", "main");
|
|
768
|
+
writeFileSync(join(base, ".gsd", "milestones", "M001", "M001-SUMMARY.md"), "# Milestone Summary\nDone.");
|
|
769
|
+
execFileSync("git", ["add", "."], { cwd: base, stdio: "ignore" });
|
|
770
|
+
execFileSync("git", ["commit", "-m", "chore: auto-commit after complete-milestone\n\nGSD-Unit: M001"], { cwd: base, stdio: "ignore" });
|
|
771
|
+
|
|
772
|
+
const result = hasImplementationArtifacts(base, "M001");
|
|
773
|
+
assert.equal(
|
|
774
|
+
result,
|
|
775
|
+
"present",
|
|
776
|
+
".gsd-only milestone closeout diffs should still honor implementation commits already on the integration branch",
|
|
777
|
+
);
|
|
778
|
+
} finally {
|
|
779
|
+
cleanup(base);
|
|
780
|
+
}
|
|
781
|
+
});
|
|
782
|
+
|
|
783
|
+
test("hasImplementationArtifacts backfills untagged main implementation commits from completed task file hints", () => {
|
|
784
|
+
const base = makeGitBase();
|
|
785
|
+
try {
|
|
786
|
+
mkdirSync(join(base, ".gsd"), { recursive: true });
|
|
787
|
+
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
788
|
+
insertMilestone({ id: "M001", title: "Milestone One", status: "active" });
|
|
789
|
+
insertSlice({
|
|
790
|
+
id: "S01",
|
|
791
|
+
milestoneId: "M001",
|
|
792
|
+
title: "Slice One",
|
|
793
|
+
status: "complete",
|
|
794
|
+
risk: "low",
|
|
795
|
+
depends: [],
|
|
796
|
+
});
|
|
797
|
+
insertTask({
|
|
798
|
+
id: "T01",
|
|
799
|
+
sliceId: "S01",
|
|
800
|
+
milestoneId: "M001",
|
|
801
|
+
title: "Task One",
|
|
802
|
+
status: "complete",
|
|
803
|
+
keyFiles: ["index.html", "style.css", "app.js"],
|
|
804
|
+
planning: { files: ["index.html", "style.css", "app.js"] },
|
|
805
|
+
});
|
|
806
|
+
|
|
807
|
+
writeFileSync(join(base, "index.html"), "<main></main>\n");
|
|
808
|
+
writeFileSync(join(base, "style.css"), "main { display: block; }\n");
|
|
809
|
+
writeFileSync(join(base, "app.js"), "document.body.dataset.ready = 'true';\n");
|
|
810
|
+
execFileSync("git", ["add", "index.html", "style.css", "app.js"], { cwd: base, stdio: "ignore" });
|
|
811
|
+
execFileSync("git", ["commit", "-m", "feat: add to-do app with CRUD and localStorage persistence"], { cwd: base, stdio: "ignore" });
|
|
812
|
+
const commitSha = execFileSync("git", ["rev-parse", "HEAD"], { cwd: base, encoding: "utf-8" }).trim();
|
|
813
|
+
|
|
814
|
+
const result = hasImplementationArtifacts(base, "M001");
|
|
815
|
+
assert.equal(
|
|
816
|
+
result,
|
|
817
|
+
"present",
|
|
818
|
+
"completed task file hints should repair prior untagged implementation commits on main",
|
|
819
|
+
);
|
|
820
|
+
assert.deepEqual(getMilestoneCommitAttributionShas("M001"), [commitSha]);
|
|
821
|
+
} finally {
|
|
822
|
+
cleanup(base);
|
|
823
|
+
}
|
|
824
|
+
});
|
|
825
|
+
|
|
826
|
+
test("hasImplementationArtifacts does not backfill untagged commits before milestone creation", () => {
|
|
827
|
+
const base = makeGitBase();
|
|
828
|
+
try {
|
|
829
|
+
writeFileSync(join(base, "app.js"), "document.body.dataset.ready = 'old';\n");
|
|
830
|
+
execFileSync("git", ["add", "app.js"], { cwd: base, stdio: "ignore" });
|
|
831
|
+
execFileSync("git", ["commit", "-m", "feat: old app work"], {
|
|
832
|
+
cwd: base,
|
|
833
|
+
stdio: "ignore",
|
|
834
|
+
env: {
|
|
835
|
+
...process.env,
|
|
836
|
+
GIT_AUTHOR_DATE: "2020-01-01T00:00:00Z",
|
|
837
|
+
GIT_COMMITTER_DATE: "2020-01-01T00:00:00Z",
|
|
838
|
+
},
|
|
839
|
+
});
|
|
840
|
+
|
|
841
|
+
mkdirSync(join(base, ".gsd"), { recursive: true });
|
|
842
|
+
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
843
|
+
insertMilestone({ id: "M001", title: "Milestone One", status: "active" });
|
|
844
|
+
insertSlice({
|
|
845
|
+
id: "S01",
|
|
846
|
+
milestoneId: "M001",
|
|
847
|
+
title: "Slice One",
|
|
848
|
+
status: "complete",
|
|
849
|
+
risk: "low",
|
|
850
|
+
depends: [],
|
|
851
|
+
});
|
|
852
|
+
insertTask({
|
|
853
|
+
id: "T01",
|
|
854
|
+
sliceId: "S01",
|
|
855
|
+
milestoneId: "M001",
|
|
856
|
+
title: "Task One",
|
|
857
|
+
status: "complete",
|
|
858
|
+
keyFiles: ["app.js"],
|
|
859
|
+
planning: { files: ["app.js"] },
|
|
860
|
+
});
|
|
861
|
+
|
|
862
|
+
const result = hasImplementationArtifacts(base, "M001");
|
|
863
|
+
assert.equal(result, "absent", "pre-milestone commits must not be attributed to the milestone");
|
|
864
|
+
assert.deepEqual(getMilestoneCommitAttributionShas("M001"), []);
|
|
865
|
+
} finally {
|
|
866
|
+
cleanup(base);
|
|
867
|
+
}
|
|
868
|
+
});
|
|
869
|
+
|
|
870
|
+
test("hasImplementationArtifacts does not backfill unrelated untagged implementation commits", () => {
|
|
871
|
+
const base = makeGitBase();
|
|
872
|
+
try {
|
|
873
|
+
mkdirSync(join(base, ".gsd"), { recursive: true });
|
|
874
|
+
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
875
|
+
insertMilestone({ id: "M001", title: "Milestone One", status: "active" });
|
|
876
|
+
insertSlice({
|
|
877
|
+
id: "S01",
|
|
878
|
+
milestoneId: "M001",
|
|
879
|
+
title: "Slice One",
|
|
880
|
+
status: "complete",
|
|
881
|
+
risk: "low",
|
|
882
|
+
depends: [],
|
|
883
|
+
});
|
|
884
|
+
insertTask({
|
|
885
|
+
id: "T01",
|
|
886
|
+
sliceId: "S01",
|
|
887
|
+
milestoneId: "M001",
|
|
888
|
+
title: "Task One",
|
|
889
|
+
status: "complete",
|
|
890
|
+
keyFiles: ["src/expected.ts"],
|
|
891
|
+
planning: { files: ["src/expected.ts"] },
|
|
892
|
+
});
|
|
893
|
+
|
|
894
|
+
mkdirSync(join(base, "src"), { recursive: true });
|
|
895
|
+
writeFileSync(join(base, "src", "unrelated.ts"), "export const unrelated = true;\n");
|
|
896
|
+
execFileSync("git", ["add", "src/unrelated.ts"], { cwd: base, stdio: "ignore" });
|
|
897
|
+
execFileSync("git", ["commit", "-m", "feat: unrelated work"], { cwd: base, stdio: "ignore" });
|
|
898
|
+
|
|
899
|
+
const result = hasImplementationArtifacts(base, "M001");
|
|
900
|
+
assert.equal(result, "absent", "backfill must require overlap with completed task file hints");
|
|
901
|
+
assert.deepEqual(getMilestoneCommitAttributionShas("M001"), []);
|
|
902
|
+
} finally {
|
|
903
|
+
cleanup(base);
|
|
904
|
+
}
|
|
905
|
+
});
|
|
906
|
+
|
|
738
907
|
test("hasImplementationArtifacts treats empty non-integration branch diff as absent (#4699)", () => {
|
|
739
908
|
const base = makeGitBase();
|
|
740
909
|
try {
|
|
@@ -131,7 +131,7 @@ test("postflightPopStash — restores stashed changes and emits info notificatio
|
|
|
131
131
|
run('git commit -m "simulate merge"', repo);
|
|
132
132
|
|
|
133
133
|
const postNotifications: Array<{ msg: string; level: string }> = [];
|
|
134
|
-
postflightPopStash(repo, "M004", (msg, level) => {
|
|
134
|
+
postflightPopStash(repo, "M004", preflight.stashMarker, (msg, level) => {
|
|
135
135
|
postNotifications.push({ msg, level });
|
|
136
136
|
});
|
|
137
137
|
|
|
@@ -171,7 +171,7 @@ test("preflight + merge + postflight round-trip preserves uncommitted changes",
|
|
|
171
171
|
run('git commit -m "feat: add feature"', repo);
|
|
172
172
|
|
|
173
173
|
// Postflight: pop stash
|
|
174
|
-
postflightPopStash(repo, "M005", () => {});
|
|
174
|
+
postflightPopStash(repo, "M005", preflight.stashMarker, () => {});
|
|
175
175
|
|
|
176
176
|
// README.md must still have our local content
|
|
177
177
|
const restored = readFileSync(join(repo, "README.md"), "utf-8");
|
|
@@ -184,3 +184,89 @@ test("preflight + merge + postflight round-trip preserves uncommitted changes",
|
|
|
184
184
|
try { rmSync(repo, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } catch { /* ignore */ }
|
|
185
185
|
}
|
|
186
186
|
});
|
|
187
|
+
|
|
188
|
+
test("postflightPopStash conflict warning names the exact stash ref", () => {
|
|
189
|
+
const repo = createTempRepo();
|
|
190
|
+
try {
|
|
191
|
+
writeFileSync(join(repo, "README.md"), "# local work\n");
|
|
192
|
+
const preflight = preflightCleanRoot(repo, "M005C", () => {});
|
|
193
|
+
assert.equal(preflight.stashPushed, true, "must have stashed");
|
|
194
|
+
|
|
195
|
+
writeFileSync(join(repo, "README.md"), "# merged work\n");
|
|
196
|
+
run("git add README.md", repo);
|
|
197
|
+
run('git commit -m "simulate conflicting merge"', repo);
|
|
198
|
+
|
|
199
|
+
const notifications: Array<{ msg: string; level: string }> = [];
|
|
200
|
+
postflightPopStash(repo, "M005C", preflight.stashMarker, (msg, level) => {
|
|
201
|
+
notifications.push({ msg, level });
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
const warning = notifications.find((n) => n.level === "warning")?.msg ?? "";
|
|
205
|
+
assert.match(warning, /git stash pop stash@\{\d+\}/);
|
|
206
|
+
assert.match(warning, /git stash apply stash@\{\d+\}/);
|
|
207
|
+
} finally {
|
|
208
|
+
try { rmSync(repo, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } catch { /* ignore */ }
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
test("postflightPopStash restores the matching GSD stash, not stash@{0}", () => {
|
|
213
|
+
const repo = createTempRepo();
|
|
214
|
+
try {
|
|
215
|
+
writeFileSync(join(repo, "README.md"), "# target stash\n");
|
|
216
|
+
const preflight = preflightCleanRoot(repo, "M006", () => {});
|
|
217
|
+
assert.equal(preflight.stashPushed, true, "must have stashed target change");
|
|
218
|
+
|
|
219
|
+
writeFileSync(join(repo, "other.txt"), "other stash\n");
|
|
220
|
+
run('git stash push --include-untracked -m "unrelated newer stash"', repo);
|
|
221
|
+
|
|
222
|
+
postflightPopStash(repo, "M006", preflight.stashMarker, () => {});
|
|
223
|
+
|
|
224
|
+
const content = readFileSync(join(repo, "README.md"), "utf-8");
|
|
225
|
+
assert.equal(content.replace(/\r\n/g, "\n"), "# target stash\n");
|
|
226
|
+
const stashList = run("git stash list", repo);
|
|
227
|
+
assert.ok(stashList.includes("unrelated newer stash"), "unrelated newer stash must remain");
|
|
228
|
+
assert.ok(!stashList.includes("gsd-preflight-stash [gsd-preflight-stash:M006"), "target stash should be consumed");
|
|
229
|
+
} finally {
|
|
230
|
+
try { rmSync(repo, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } catch { /* ignore */ }
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
test("postflightPopStash restores the exact preflight marker when another same-milestone stash exists", () => {
|
|
235
|
+
const repo = createTempRepo();
|
|
236
|
+
try {
|
|
237
|
+
writeFileSync(join(repo, "README.md"), "# target stash\n");
|
|
238
|
+
const preflight = preflightCleanRoot(repo, "M007", () => {});
|
|
239
|
+
assert.equal(preflight.stashPushed, true, "must have stashed target change");
|
|
240
|
+
assert.ok(preflight.stashMarker, "preflight must expose exact stash marker");
|
|
241
|
+
|
|
242
|
+
writeFileSync(join(repo, "same-milestone.txt"), "newer same milestone stash\n");
|
|
243
|
+
run('git stash push --include-untracked -m "gsd-preflight-stash [gsd-preflight-stash:M007:other]"', repo);
|
|
244
|
+
|
|
245
|
+
postflightPopStash(repo, "M007", preflight.stashMarker, () => {});
|
|
246
|
+
|
|
247
|
+
const content = readFileSync(join(repo, "README.md"), "utf-8");
|
|
248
|
+
assert.equal(content.replace(/\r\n/g, "\n"), "# target stash\n");
|
|
249
|
+
const stashList = run("git stash list", repo);
|
|
250
|
+
assert.ok(stashList.includes("gsd-preflight-stash:M007:other"), "newer same-milestone stash must remain");
|
|
251
|
+
assert.ok(!stashList.includes(preflight.stashMarker), "exact target stash should be consumed");
|
|
252
|
+
} finally {
|
|
253
|
+
try { rmSync(repo, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } catch { /* ignore */ }
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
test("postflightPopStash falls back to milestone marker prefix when exact marker is unavailable", () => {
|
|
258
|
+
const repo = createTempRepo();
|
|
259
|
+
try {
|
|
260
|
+
writeFileSync(join(repo, "README.md"), "# fallback stash\n");
|
|
261
|
+
run('git stash push --include-untracked -m "gsd-preflight-stash [gsd-preflight-stash:M008:fallback]"', repo);
|
|
262
|
+
|
|
263
|
+
postflightPopStash(repo, "M008", undefined, () => {});
|
|
264
|
+
|
|
265
|
+
const content = readFileSync(join(repo, "README.md"), "utf-8");
|
|
266
|
+
assert.equal(content.replace(/\r\n/g, "\n"), "# fallback stash\n");
|
|
267
|
+
const stashList = run("git stash list", repo);
|
|
268
|
+
assert.ok(!stashList.includes("gsd-preflight-stash:M008:fallback"), "fallback stash should be consumed");
|
|
269
|
+
} finally {
|
|
270
|
+
try { rmSync(repo, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } catch { /* ignore */ }
|
|
271
|
+
}
|
|
272
|
+
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// GSD2 commands-extract-learnings tests
|
|
1
2
|
import { describe, it, beforeEach, afterEach } from "node:test";
|
|
2
3
|
import assert from "node:assert/strict";
|
|
3
4
|
import { mkdirSync, writeFileSync, rmSync, readFileSync } from "node:fs";
|
|
@@ -484,6 +485,14 @@ describe("buildExtractionStepsBlock", () => {
|
|
|
484
485
|
assert.ok(/skip/i.test(block));
|
|
485
486
|
});
|
|
486
487
|
|
|
488
|
+
it("limits duplicate checks to one milestone-scoped memory query", () => {
|
|
489
|
+
const block = buildExtractionStepsBlock(ctx);
|
|
490
|
+
const memoryQueryMatches = block.match(/memory_query/g) ?? [];
|
|
491
|
+
assert.equal(memoryQueryMatches.length, 1);
|
|
492
|
+
assert.ok(block.includes("Do not re-read milestone artefacts or repeat memory queries category-by-category"));
|
|
493
|
+
assert.ok(!block.includes("Before each `capture_thought` call, optionally call `memory_query`"));
|
|
494
|
+
});
|
|
495
|
+
|
|
487
496
|
it("instructs capture_thought as the sole persistence path for Patterns, Lessons, and Decisions (ADR-013 step 6 cutover)", () => {
|
|
488
497
|
const block = buildExtractionStepsBlock(ctx);
|
|
489
498
|
// Each of the three persistence steps must call capture_thought.
|
|
@@ -372,7 +372,56 @@ describe("Custom engine loop integration", () => {
|
|
|
372
372
|
assert.ok(stopEntry?.includes("Workflow complete"), "Should stop with 'Workflow complete'");
|
|
373
373
|
});
|
|
374
374
|
|
|
375
|
-
it("
|
|
375
|
+
it("finalizes custom-engine complete turns and clears current turn state", async () => {
|
|
376
|
+
_resetPendingResolve();
|
|
377
|
+
|
|
378
|
+
const runDir = makeTmpDir();
|
|
379
|
+
const graph = makeGraph([
|
|
380
|
+
makeStep({ id: "step-a", status: "complete" }),
|
|
381
|
+
], "already-done");
|
|
382
|
+
writeGraph(runDir, graph);
|
|
383
|
+
writeDefinition(runDir, graph.steps, "already-done");
|
|
384
|
+
|
|
385
|
+
const ctx = makeMockCtx();
|
|
386
|
+
const pi = makeMockPi();
|
|
387
|
+
const s = makeLoopSession({
|
|
388
|
+
activeEngineId: "custom",
|
|
389
|
+
activeRunDir: runDir,
|
|
390
|
+
basePath: runDir,
|
|
391
|
+
});
|
|
392
|
+
const turnResults: Array<{ status: string; failureClass: string; error?: string }> = [];
|
|
393
|
+
const deps = makeMockDeps({
|
|
394
|
+
stopAuto: async (_ctx, _pi, reason) => {
|
|
395
|
+
deps.callLog.push(`stopAuto:${reason ?? "no-reason"}`);
|
|
396
|
+
s.active = false;
|
|
397
|
+
},
|
|
398
|
+
uokObserver: {
|
|
399
|
+
onTurnStart: () => {},
|
|
400
|
+
onTurnResult: (result) => {
|
|
401
|
+
deps.callLog.push(`turnResult:${result.status}`);
|
|
402
|
+
turnResults.push({
|
|
403
|
+
status: result.status,
|
|
404
|
+
failureClass: result.failureClass,
|
|
405
|
+
error: result.error,
|
|
406
|
+
});
|
|
407
|
+
},
|
|
408
|
+
onPhaseResult: () => {},
|
|
409
|
+
},
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
await autoLoop(ctx, pi, s, deps);
|
|
413
|
+
|
|
414
|
+
assert.deepEqual(turnResults, [{ status: "completed", failureClass: "none", error: undefined }]);
|
|
415
|
+
assert.ok(
|
|
416
|
+
deps.callLog.indexOf("turnResult:completed") < deps.callLog.indexOf("stopAuto:Workflow complete"),
|
|
417
|
+
`turn should finalize before stopAuto; log=${deps.callLog.join(",")}`,
|
|
418
|
+
);
|
|
419
|
+
assert.equal(s.currentTraceId, null);
|
|
420
|
+
assert.equal(s.currentTurnId, null);
|
|
421
|
+
assert.equal(pi.calls.length, 0, "complete workflow should not dispatch work");
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
it("stops blocked custom workflows and clears current turn state", async () => {
|
|
376
425
|
_resetPendingResolve();
|
|
377
426
|
|
|
378
427
|
const runDir = makeTmpDir();
|
|
@@ -390,13 +439,65 @@ describe("Custom engine loop integration", () => {
|
|
|
390
439
|
activeRunDir: runDir,
|
|
391
440
|
basePath: runDir,
|
|
392
441
|
});
|
|
393
|
-
const turnResults: Array<{ status: string }> = [];
|
|
442
|
+
const turnResults: Array<{ status: string; failureClass: string; error?: string }> = [];
|
|
394
443
|
const deps = makeMockDeps({
|
|
444
|
+
stopAuto: async (_ctx, _pi, reason) => {
|
|
445
|
+
deps.callLog.push(`stopAuto:${reason ?? "no-reason"}`);
|
|
446
|
+
s.active = false;
|
|
447
|
+
},
|
|
448
|
+
uokObserver: {
|
|
449
|
+
onTurnStart: () => {},
|
|
450
|
+
onTurnResult: (result) => {
|
|
451
|
+
turnResults.push({
|
|
452
|
+
status: result.status,
|
|
453
|
+
failureClass: result.failureClass,
|
|
454
|
+
error: result.error,
|
|
455
|
+
});
|
|
456
|
+
},
|
|
457
|
+
onPhaseResult: () => {},
|
|
458
|
+
},
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
await autoLoop(ctx, pi, s, deps);
|
|
462
|
+
|
|
463
|
+
assert.equal(turnResults.length, 1);
|
|
464
|
+
assert.equal(turnResults[0].status, "stopped");
|
|
465
|
+
assert.equal(turnResults[0].failureClass, "manual-attention");
|
|
466
|
+
assert.match(turnResults[0].error ?? "", /custom-engine-dispatch-stop/);
|
|
467
|
+
assert.equal(s.currentTraceId, null);
|
|
468
|
+
assert.equal(s.currentTurnId, null);
|
|
469
|
+
assert.equal(pi.calls.length, 0, "blocked workflow should not dispatch a custom step");
|
|
470
|
+
assert.match(
|
|
471
|
+
deps.callLog.find((e: string) => e.startsWith("stopAuto:")) ?? "",
|
|
472
|
+
/Workflow blocked: no pending steps are ready/,
|
|
473
|
+
);
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
it("finalizes the active turn when the session lock is lost", async () => {
|
|
477
|
+
_resetPendingResolve();
|
|
478
|
+
|
|
479
|
+
const ctx = makeMockCtx();
|
|
480
|
+
const pi = makeMockPi();
|
|
481
|
+
const s = makeLoopSession();
|
|
482
|
+
const turnResults: Array<{ status: string; failureClass: string; error?: string }> = [];
|
|
483
|
+
const deps = makeMockDeps({
|
|
484
|
+
validateSessionLock: () => ({
|
|
485
|
+
valid: false,
|
|
486
|
+
failureReason: "pid-mismatch",
|
|
487
|
+
expectedPid: 111,
|
|
488
|
+
existingPid: 222,
|
|
489
|
+
} as SessionLockStatus),
|
|
490
|
+
handleLostSessionLock: () => {
|
|
491
|
+
deps.callLog.push("handleLostSessionLock");
|
|
492
|
+
},
|
|
395
493
|
uokObserver: {
|
|
396
494
|
onTurnStart: () => {},
|
|
397
495
|
onTurnResult: (result) => {
|
|
398
|
-
turnResults.push({
|
|
399
|
-
|
|
496
|
+
turnResults.push({
|
|
497
|
+
status: result.status,
|
|
498
|
+
failureClass: result.failureClass,
|
|
499
|
+
error: result.error,
|
|
500
|
+
});
|
|
400
501
|
},
|
|
401
502
|
onPhaseResult: () => {},
|
|
402
503
|
},
|
|
@@ -404,10 +505,15 @@ describe("Custom engine loop integration", () => {
|
|
|
404
505
|
|
|
405
506
|
await autoLoop(ctx, pi, s, deps);
|
|
406
507
|
|
|
407
|
-
assert.deepEqual(turnResults, [{
|
|
508
|
+
assert.deepEqual(turnResults, [{
|
|
509
|
+
status: "stopped",
|
|
510
|
+
failureClass: "manual-attention",
|
|
511
|
+
error: "session-lock-lost",
|
|
512
|
+
}]);
|
|
408
513
|
assert.equal(s.currentTraceId, null);
|
|
409
514
|
assert.equal(s.currentTurnId, null);
|
|
410
|
-
assert.equal(pi.calls.length, 0, "
|
|
515
|
+
assert.equal(pi.calls.length, 0, "lost session lock must not dispatch work");
|
|
516
|
+
assert.ok(deps.callLog.includes("handleLostSessionLock"));
|
|
411
517
|
});
|
|
412
518
|
|
|
413
519
|
it("does not call runPreDispatch or runFinalize on the custom path", async () => {
|
|
@@ -193,7 +193,7 @@ describe("CustomWorkflowEngine.resolveDispatch", () => {
|
|
|
193
193
|
}
|
|
194
194
|
});
|
|
195
195
|
|
|
196
|
-
it("returns
|
|
196
|
+
it("returns stop with dependency details when pending steps are blocked", async () => {
|
|
197
197
|
const { engine } = setupEngine([
|
|
198
198
|
makeStep({ id: "a", dependsOn: ["b"] }),
|
|
199
199
|
makeStep({ id: "b", dependsOn: ["a"] }),
|
|
@@ -202,7 +202,45 @@ describe("CustomWorkflowEngine.resolveDispatch", () => {
|
|
|
202
202
|
const state = await engine.deriveState("/unused");
|
|
203
203
|
const dispatch = await engine.resolveDispatch(state, { basePath: "/unused" });
|
|
204
204
|
|
|
205
|
-
assert.
|
|
205
|
+
assert.equal(dispatch.action, "stop");
|
|
206
|
+
if (dispatch.action === "stop") {
|
|
207
|
+
assert.equal(dispatch.level, "error");
|
|
208
|
+
assert.match(dispatch.reason, /Workflow blocked/);
|
|
209
|
+
assert.match(dispatch.reason, /a waiting on b \(pending\)/);
|
|
210
|
+
assert.match(dispatch.reason, /b waiting on a \(pending\)/);
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it("reports missing dependencies when no pending step can run", async () => {
|
|
215
|
+
const { engine } = setupEngine([
|
|
216
|
+
makeStep({ id: "a", dependsOn: ["missing-step"] }),
|
|
217
|
+
]);
|
|
218
|
+
|
|
219
|
+
const state = await engine.deriveState("/unused");
|
|
220
|
+
const dispatch = await engine.resolveDispatch(state, { basePath: "/unused" });
|
|
221
|
+
|
|
222
|
+
assert.equal(dispatch.action, "stop");
|
|
223
|
+
if (dispatch.action === "stop") {
|
|
224
|
+
assert.equal(dispatch.level, "error");
|
|
225
|
+
assert.match(dispatch.reason, /a waiting on missing-step \(missing\)/);
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it("does not report expanded dependencies as blockers", async () => {
|
|
230
|
+
const { engine } = setupEngine([
|
|
231
|
+
makeStep({ id: "iter", status: "expanded" }),
|
|
232
|
+
makeStep({ id: "after", dependsOn: ["iter", "missing-step"] }),
|
|
233
|
+
]);
|
|
234
|
+
|
|
235
|
+
const state = await engine.deriveState("/unused");
|
|
236
|
+
const dispatch = await engine.resolveDispatch(state, { basePath: "/unused" });
|
|
237
|
+
|
|
238
|
+
assert.equal(dispatch.action, "stop");
|
|
239
|
+
if (dispatch.action === "stop") {
|
|
240
|
+
assert.equal(dispatch.level, "error");
|
|
241
|
+
assert.match(dispatch.reason, /after waiting on missing-step \(missing\)/);
|
|
242
|
+
assert.doesNotMatch(dispatch.reason, /iter \(expanded\)/);
|
|
243
|
+
}
|
|
206
244
|
});
|
|
207
245
|
|
|
208
246
|
it("respects dependency ordering", async () => {
|