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
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
// gsd-2 (GSD2) + db migration `:memory:` integration tests
|
|
2
|
+
//
|
|
3
|
+
// Covers the gap left by the FakeAdapter unit tests for the gsd-db split
|
|
4
|
+
// (PR #5308): those assert SQL strings, not that DDL actually executes.
|
|
5
|
+
// These tests open a real node:sqlite `:memory:` database, run the schema
|
|
6
|
+
// helpers, and verify the resulting schema via PRAGMA introspection.
|
|
7
|
+
|
|
8
|
+
import { describe, test } from "node:test";
|
|
9
|
+
import assert from "node:assert/strict";
|
|
10
|
+
import { createRequire } from "node:module";
|
|
11
|
+
|
|
12
|
+
import { createDbAdapter, type DbAdapter } from "../db-adapter.ts";
|
|
13
|
+
import { createBaseSchemaObjects } from "../db-base-schema.ts";
|
|
14
|
+
import { columnExists } from "../db-schema-metadata.ts";
|
|
15
|
+
import {
|
|
16
|
+
applyMigrationV2Artifacts,
|
|
17
|
+
applyMigrationV3Memories,
|
|
18
|
+
applyMigrationV4DecisionMadeBy,
|
|
19
|
+
applyMigrationV5HierarchyTables,
|
|
20
|
+
applyMigrationV6SliceSummaries,
|
|
21
|
+
applyMigrationV7Dependencies,
|
|
22
|
+
applyMigrationV8PlanningFields,
|
|
23
|
+
applyMigrationV9Ordering,
|
|
24
|
+
applyMigrationV10ReplanTrigger,
|
|
25
|
+
applyMigrationV11TaskPlanning,
|
|
26
|
+
applyMigrationV12QualityGates,
|
|
27
|
+
applyMigrationV13HotPathIndexes,
|
|
28
|
+
applyMigrationV22QualityGateRepair,
|
|
29
|
+
} from "../db-migration-steps.ts";
|
|
30
|
+
|
|
31
|
+
const _require = createRequire(import.meta.url);
|
|
32
|
+
|
|
33
|
+
interface ColumnInfo {
|
|
34
|
+
name: string;
|
|
35
|
+
type: string;
|
|
36
|
+
notnull: number;
|
|
37
|
+
dflt_value: unknown;
|
|
38
|
+
pk: number;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function openMemoryAdapter(): { adapter: DbAdapter; close: () => void } {
|
|
42
|
+
const sqlite = _require("node:sqlite") as { DatabaseSync: new (path: string) => unknown };
|
|
43
|
+
const raw = new sqlite.DatabaseSync(":memory:");
|
|
44
|
+
const adapter = createDbAdapter(raw);
|
|
45
|
+
return {
|
|
46
|
+
adapter,
|
|
47
|
+
close: () => adapter.close(),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function tableInfo(db: DbAdapter, table: string): ColumnInfo[] {
|
|
52
|
+
return db.prepare(`PRAGMA table_info(${table})`).all() as unknown as ColumnInfo[];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function columnNames(db: DbAdapter, table: string): string[] {
|
|
56
|
+
return tableInfo(db, table).map((c) => c.name);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function tableExists(db: DbAdapter, table: string): boolean {
|
|
60
|
+
return !!db
|
|
61
|
+
.prepare("SELECT 1 as present FROM sqlite_master WHERE type='table' AND name=?")
|
|
62
|
+
.get(table);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function indexExists(db: DbAdapter, name: string): boolean {
|
|
66
|
+
return !!db
|
|
67
|
+
.prepare("SELECT 1 as present FROM sqlite_master WHERE type='index' AND name=?")
|
|
68
|
+
.get(name);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function viewExists(db: DbAdapter, name: string): boolean {
|
|
72
|
+
return !!db
|
|
73
|
+
.prepare("SELECT 1 as present FROM sqlite_master WHERE type='view' AND name=?")
|
|
74
|
+
.get(name);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
describe("db base schema bring-up against :memory: sqlite", () => {
|
|
78
|
+
test("createBaseSchemaObjects executes all DDL without throwing", () => {
|
|
79
|
+
const { adapter, close } = openMemoryAdapter();
|
|
80
|
+
try {
|
|
81
|
+
assert.doesNotThrow(() => {
|
|
82
|
+
createBaseSchemaObjects(adapter, {
|
|
83
|
+
tryCreateMemoriesFts: () => true,
|
|
84
|
+
ensureVerificationEvidenceDedupIndex: () => {},
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
} finally {
|
|
88
|
+
close();
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test("base schema produces all expected tables, indexes, and views", () => {
|
|
93
|
+
const { adapter, close } = openMemoryAdapter();
|
|
94
|
+
try {
|
|
95
|
+
createBaseSchemaObjects(adapter, {
|
|
96
|
+
tryCreateMemoriesFts: () => true,
|
|
97
|
+
ensureVerificationEvidenceDedupIndex: () => {},
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const expectedTables = [
|
|
101
|
+
"schema_version",
|
|
102
|
+
"decisions",
|
|
103
|
+
"requirements",
|
|
104
|
+
"artifacts",
|
|
105
|
+
"memories",
|
|
106
|
+
"memory_processed_units",
|
|
107
|
+
"memory_sources",
|
|
108
|
+
"memory_embeddings",
|
|
109
|
+
"memory_relations",
|
|
110
|
+
"milestones",
|
|
111
|
+
"slices",
|
|
112
|
+
"tasks",
|
|
113
|
+
"verification_evidence",
|
|
114
|
+
"replan_history",
|
|
115
|
+
"assessments",
|
|
116
|
+
"quality_gates",
|
|
117
|
+
"slice_dependencies",
|
|
118
|
+
"gate_runs",
|
|
119
|
+
"turn_git_transactions",
|
|
120
|
+
"audit_events",
|
|
121
|
+
"audit_turn_index",
|
|
122
|
+
];
|
|
123
|
+
for (const t of expectedTables) {
|
|
124
|
+
assert.ok(tableExists(adapter, t), `expected table ${t} to exist`);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const expectedIndexes = [
|
|
128
|
+
"idx_memories_active",
|
|
129
|
+
"idx_replan_history_milestone",
|
|
130
|
+
"idx_tasks_active",
|
|
131
|
+
"idx_slices_active",
|
|
132
|
+
"idx_milestones_status",
|
|
133
|
+
"idx_quality_gates_pending",
|
|
134
|
+
"idx_verification_evidence_task",
|
|
135
|
+
"idx_slice_deps_target",
|
|
136
|
+
"idx_gate_runs_turn",
|
|
137
|
+
"idx_gate_runs_lookup",
|
|
138
|
+
"idx_turn_git_tx_turn",
|
|
139
|
+
"idx_audit_events_trace",
|
|
140
|
+
"idx_audit_events_turn",
|
|
141
|
+
];
|
|
142
|
+
for (const i of expectedIndexes) {
|
|
143
|
+
assert.ok(indexExists(adapter, i), `expected index ${i}`);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
for (const v of ["active_decisions", "active_requirements", "active_memories"]) {
|
|
147
|
+
assert.ok(viewExists(adapter, v), `expected view ${v}`);
|
|
148
|
+
}
|
|
149
|
+
} finally {
|
|
150
|
+
close();
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
test("base schema decisions table has the documented column shape", () => {
|
|
155
|
+
const { adapter, close } = openMemoryAdapter();
|
|
156
|
+
try {
|
|
157
|
+
createBaseSchemaObjects(adapter, {
|
|
158
|
+
tryCreateMemoriesFts: () => true,
|
|
159
|
+
ensureVerificationEvidenceDedupIndex: () => {},
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
const cols = tableInfo(adapter, "decisions");
|
|
163
|
+
const byName = new Map(cols.map((c) => [c.name, c]));
|
|
164
|
+
|
|
165
|
+
const seq = byName.get("seq");
|
|
166
|
+
assert.ok(seq, "decisions.seq column missing");
|
|
167
|
+
assert.equal(seq!.type, "INTEGER");
|
|
168
|
+
assert.equal(seq!.pk, 1, "seq should be primary key");
|
|
169
|
+
|
|
170
|
+
const id = byName.get("id");
|
|
171
|
+
assert.ok(id);
|
|
172
|
+
assert.equal(id!.type, "TEXT");
|
|
173
|
+
assert.equal(id!.notnull, 1);
|
|
174
|
+
|
|
175
|
+
const madeBy = byName.get("made_by");
|
|
176
|
+
assert.ok(madeBy, "decisions.made_by missing (V4 migration column)");
|
|
177
|
+
assert.equal(madeBy!.notnull, 1);
|
|
178
|
+
|
|
179
|
+
const source = byName.get("source");
|
|
180
|
+
assert.ok(source, "decisions.source missing (V16 migration column)");
|
|
181
|
+
assert.equal(source!.notnull, 1);
|
|
182
|
+
} finally {
|
|
183
|
+
close();
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
test("base schema tasks table promotes composite primary key correctly", () => {
|
|
188
|
+
const { adapter, close } = openMemoryAdapter();
|
|
189
|
+
try {
|
|
190
|
+
createBaseSchemaObjects(adapter, {
|
|
191
|
+
tryCreateMemoriesFts: () => true,
|
|
192
|
+
ensureVerificationEvidenceDedupIndex: () => {},
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
const cols = tableInfo(adapter, "tasks");
|
|
196
|
+
const pkCols = cols.filter((c) => c.pk > 0).sort((a, b) => a.pk - b.pk).map((c) => c.name);
|
|
197
|
+
assert.deepEqual(pkCols, ["milestone_id", "slice_id", "id"]);
|
|
198
|
+
} finally {
|
|
199
|
+
close();
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
describe("db migration steps end-to-end against :memory: sqlite", () => {
|
|
205
|
+
// Drive a fresh DB from V1 baseline up to V13 so each high-risk migration
|
|
206
|
+
// sees a realistic schema (not the FakeAdapter no-op surface).
|
|
207
|
+
function runUpToV13(adapter: DbAdapter): void {
|
|
208
|
+
adapter.exec(`
|
|
209
|
+
CREATE TABLE schema_version (
|
|
210
|
+
version INTEGER NOT NULL,
|
|
211
|
+
applied_at TEXT NOT NULL
|
|
212
|
+
)
|
|
213
|
+
`);
|
|
214
|
+
adapter.exec(`
|
|
215
|
+
CREATE TABLE decisions (
|
|
216
|
+
seq INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
217
|
+
id TEXT NOT NULL UNIQUE,
|
|
218
|
+
when_context TEXT NOT NULL DEFAULT '',
|
|
219
|
+
scope TEXT NOT NULL DEFAULT '',
|
|
220
|
+
decision TEXT NOT NULL DEFAULT '',
|
|
221
|
+
choice TEXT NOT NULL DEFAULT '',
|
|
222
|
+
rationale TEXT NOT NULL DEFAULT '',
|
|
223
|
+
revisable TEXT NOT NULL DEFAULT '',
|
|
224
|
+
superseded_by TEXT DEFAULT NULL
|
|
225
|
+
)
|
|
226
|
+
`);
|
|
227
|
+
adapter.exec(`
|
|
228
|
+
CREATE TABLE requirements (
|
|
229
|
+
id TEXT PRIMARY KEY,
|
|
230
|
+
class TEXT NOT NULL DEFAULT '',
|
|
231
|
+
status TEXT NOT NULL DEFAULT '',
|
|
232
|
+
description TEXT NOT NULL DEFAULT '',
|
|
233
|
+
why TEXT NOT NULL DEFAULT '',
|
|
234
|
+
source TEXT NOT NULL DEFAULT '',
|
|
235
|
+
primary_owner TEXT NOT NULL DEFAULT '',
|
|
236
|
+
supporting_slices TEXT NOT NULL DEFAULT '',
|
|
237
|
+
validation TEXT NOT NULL DEFAULT '',
|
|
238
|
+
notes TEXT NOT NULL DEFAULT '',
|
|
239
|
+
full_content TEXT NOT NULL DEFAULT '',
|
|
240
|
+
superseded_by TEXT DEFAULT NULL
|
|
241
|
+
)
|
|
242
|
+
`);
|
|
243
|
+
adapter.exec("CREATE VIEW active_decisions AS SELECT * FROM decisions WHERE superseded_by IS NULL");
|
|
244
|
+
adapter.exec("CREATE VIEW active_requirements AS SELECT * FROM requirements WHERE superseded_by IS NULL");
|
|
245
|
+
|
|
246
|
+
applyMigrationV2Artifacts(adapter);
|
|
247
|
+
applyMigrationV3Memories(adapter);
|
|
248
|
+
applyMigrationV4DecisionMadeBy(adapter);
|
|
249
|
+
applyMigrationV5HierarchyTables(adapter);
|
|
250
|
+
applyMigrationV6SliceSummaries(adapter);
|
|
251
|
+
applyMigrationV7Dependencies(adapter);
|
|
252
|
+
applyMigrationV8PlanningFields(adapter);
|
|
253
|
+
applyMigrationV9Ordering(adapter);
|
|
254
|
+
applyMigrationV10ReplanTrigger(adapter);
|
|
255
|
+
applyMigrationV11TaskPlanning(adapter);
|
|
256
|
+
applyMigrationV12QualityGates(adapter);
|
|
257
|
+
applyMigrationV13HotPathIndexes(adapter, () => {});
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
test("V8 PlanningFields adds every promised ALTER column without throwing", () => {
|
|
261
|
+
const { adapter, close } = openMemoryAdapter();
|
|
262
|
+
try {
|
|
263
|
+
runUpToV13(adapter);
|
|
264
|
+
|
|
265
|
+
assert.ok(columnExists(adapter, "milestones", "vision"));
|
|
266
|
+
assert.ok(columnExists(adapter, "milestones", "verification_uat"));
|
|
267
|
+
assert.ok(columnExists(adapter, "milestones", "definition_of_done"));
|
|
268
|
+
assert.ok(columnExists(adapter, "milestones", "boundary_map_markdown"));
|
|
269
|
+
|
|
270
|
+
assert.ok(columnExists(adapter, "slices", "goal"));
|
|
271
|
+
assert.ok(columnExists(adapter, "slices", "proof_level"));
|
|
272
|
+
assert.ok(columnExists(adapter, "slices", "observability_impact"));
|
|
273
|
+
|
|
274
|
+
assert.ok(columnExists(adapter, "tasks", "estimate"));
|
|
275
|
+
assert.ok(columnExists(adapter, "tasks", "files"));
|
|
276
|
+
assert.ok(columnExists(adapter, "tasks", "expected_output"));
|
|
277
|
+
|
|
278
|
+
assert.ok(tableExists(adapter, "replan_history"));
|
|
279
|
+
assert.ok(tableExists(adapter, "assessments"));
|
|
280
|
+
} finally {
|
|
281
|
+
close();
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
test("V13 HotPathIndexes succeeds when prior migrations have run (ordering)", () => {
|
|
286
|
+
const { adapter, close } = openMemoryAdapter();
|
|
287
|
+
try {
|
|
288
|
+
runUpToV13(adapter);
|
|
289
|
+
|
|
290
|
+
for (const i of [
|
|
291
|
+
"idx_tasks_active",
|
|
292
|
+
"idx_slices_active",
|
|
293
|
+
"idx_milestones_status",
|
|
294
|
+
"idx_quality_gates_pending",
|
|
295
|
+
"idx_verification_evidence_task",
|
|
296
|
+
]) {
|
|
297
|
+
assert.ok(indexExists(adapter, i), `expected index ${i} after V13`);
|
|
298
|
+
}
|
|
299
|
+
} finally {
|
|
300
|
+
close();
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
test("V13 HotPathIndexes throws if quality_gates table does not yet exist (ordering guard)", () => {
|
|
305
|
+
const { adapter, close } = openMemoryAdapter();
|
|
306
|
+
try {
|
|
307
|
+
adapter.exec("CREATE TABLE schema_version (version INTEGER NOT NULL, applied_at TEXT NOT NULL)");
|
|
308
|
+
assert.throws(
|
|
309
|
+
() => applyMigrationV13HotPathIndexes(adapter, () => {}),
|
|
310
|
+
/no such table/i,
|
|
311
|
+
);
|
|
312
|
+
} finally {
|
|
313
|
+
close();
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
test("V22 QualityGateRepair rebuilds quality_gates with task_id NOT NULL and preserves indexes", () => {
|
|
318
|
+
const { adapter, close } = openMemoryAdapter();
|
|
319
|
+
try {
|
|
320
|
+
runUpToV13(adapter);
|
|
321
|
+
|
|
322
|
+
adapter.exec("DROP INDEX IF EXISTS idx_quality_gates_pending");
|
|
323
|
+
adapter.exec("DROP TABLE quality_gates");
|
|
324
|
+
adapter.exec(`
|
|
325
|
+
CREATE TABLE quality_gates (
|
|
326
|
+
milestone_id TEXT NOT NULL,
|
|
327
|
+
slice_id TEXT NOT NULL,
|
|
328
|
+
gate_id TEXT NOT NULL,
|
|
329
|
+
task_id TEXT DEFAULT '',
|
|
330
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
331
|
+
verdict TEXT NOT NULL DEFAULT '',
|
|
332
|
+
rationale TEXT NOT NULL DEFAULT '',
|
|
333
|
+
findings TEXT NOT NULL DEFAULT '',
|
|
334
|
+
evaluated_at TEXT DEFAULT NULL,
|
|
335
|
+
PRIMARY KEY (milestone_id, slice_id, gate_id, task_id),
|
|
336
|
+
FOREIGN KEY (milestone_id, slice_id) REFERENCES slices(milestone_id, id)
|
|
337
|
+
)
|
|
338
|
+
`);
|
|
339
|
+
|
|
340
|
+
const before = tableInfo(adapter, "quality_gates").find((c) => c.name === "task_id");
|
|
341
|
+
assert.ok(before);
|
|
342
|
+
assert.equal(before!.notnull, 0, "pre-repair fixture should have nullable task_id");
|
|
343
|
+
|
|
344
|
+
let copyCalled = 0;
|
|
345
|
+
applyMigrationV22QualityGateRepair(adapter, {
|
|
346
|
+
copyQualityGateRowsToRepairedTable: () => {
|
|
347
|
+
copyCalled += 1;
|
|
348
|
+
},
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
assert.equal(copyCalled, 1, "repair branch should invoke the row-copy hook exactly once");
|
|
352
|
+
|
|
353
|
+
const after = tableInfo(adapter, "quality_gates").find((c) => c.name === "task_id");
|
|
354
|
+
assert.ok(after);
|
|
355
|
+
assert.equal(after!.notnull, 1, "post-repair task_id must be NOT NULL");
|
|
356
|
+
|
|
357
|
+
assert.ok(columnExists(adapter, "quality_gates", "scope"));
|
|
358
|
+
assert.ok(columnExists(adapter, "assessments", "scope"));
|
|
359
|
+
|
|
360
|
+
assert.ok(indexExists(adapter, "idx_quality_gates_pending"));
|
|
361
|
+
|
|
362
|
+
assert.equal(tableExists(adapter, "quality_gates_new"), false);
|
|
363
|
+
|
|
364
|
+
assert.deepEqual(columnNames(adapter, "quality_gates"), [
|
|
365
|
+
"milestone_id",
|
|
366
|
+
"slice_id",
|
|
367
|
+
"gate_id",
|
|
368
|
+
"scope",
|
|
369
|
+
"task_id",
|
|
370
|
+
"status",
|
|
371
|
+
"verdict",
|
|
372
|
+
"rationale",
|
|
373
|
+
"findings",
|
|
374
|
+
"evaluated_at",
|
|
375
|
+
]);
|
|
376
|
+
} finally {
|
|
377
|
+
close();
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
test("V22 is a no-op on already-repaired quality_gates", () => {
|
|
382
|
+
const { adapter, close } = openMemoryAdapter();
|
|
383
|
+
try {
|
|
384
|
+
runUpToV13(adapter);
|
|
385
|
+
|
|
386
|
+
let copyCalled = 0;
|
|
387
|
+
applyMigrationV22QualityGateRepair(adapter, {
|
|
388
|
+
copyQualityGateRowsToRepairedTable: () => {
|
|
389
|
+
copyCalled += 1;
|
|
390
|
+
},
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
assert.equal(copyCalled, 0, "no-op when task_id is already NOT NULL");
|
|
394
|
+
assert.ok(columnExists(adapter, "quality_gates", "scope"));
|
|
395
|
+
} finally {
|
|
396
|
+
close();
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
describe("db provider happy path against :memory: sqlite", () => {
|
|
402
|
+
test("createDbAdapter wraps node:sqlite and supports exec/prepare/close", () => {
|
|
403
|
+
const sqlite = _require("node:sqlite") as { DatabaseSync: new (path: string) => unknown };
|
|
404
|
+
const raw = new sqlite.DatabaseSync(":memory:");
|
|
405
|
+
const adapter = createDbAdapter(raw);
|
|
406
|
+
|
|
407
|
+
assert.doesNotThrow(() => adapter.exec("CREATE TABLE t (id INTEGER PRIMARY KEY, v TEXT)"));
|
|
408
|
+
|
|
409
|
+
const insert = adapter.prepare("INSERT INTO t (id, v) VALUES (?, ?)");
|
|
410
|
+
insert.run(1, "alpha");
|
|
411
|
+
insert.run(2, "beta");
|
|
412
|
+
|
|
413
|
+
const selectOne = adapter.prepare("SELECT v FROM t WHERE id = ?");
|
|
414
|
+
const row = selectOne.get(1);
|
|
415
|
+
assert.deepEqual(row, { v: "alpha" });
|
|
416
|
+
|
|
417
|
+
const selectAll = adapter.prepare("SELECT id, v FROM t ORDER BY id");
|
|
418
|
+
const rows = selectAll.all();
|
|
419
|
+
assert.equal(rows.length, 2);
|
|
420
|
+
assert.equal(rows[0]["v"], "alpha");
|
|
421
|
+
assert.equal(rows[1]["v"], "beta");
|
|
422
|
+
|
|
423
|
+
const selectAgain = adapter.prepare("SELECT v FROM t WHERE id = ?");
|
|
424
|
+
assert.deepEqual(selectAgain.get(2), { v: "beta" });
|
|
425
|
+
|
|
426
|
+
assert.doesNotThrow(() => adapter.close());
|
|
427
|
+
});
|
|
428
|
+
});
|
|
@@ -106,10 +106,10 @@ describe("db-schema-metadata", () => {
|
|
|
106
106
|
test("records schema version rows with timestamps", () => {
|
|
107
107
|
const db = new FakeAdapter();
|
|
108
108
|
|
|
109
|
-
recordSchemaVersion(db,
|
|
109
|
+
recordSchemaVersion(db, 26);
|
|
110
110
|
|
|
111
111
|
assert.equal(db.runCalls.length, 1);
|
|
112
|
-
assert.equal((db.runCalls[0][0] as Record<string, unknown>)[":version"],
|
|
112
|
+
assert.equal((db.runCalls[0][0] as Record<string, unknown>)[":version"], 26);
|
|
113
113
|
assert.equal(typeof (db.runCalls[0][0] as Record<string, unknown>)[":applied_at"], "string");
|
|
114
114
|
});
|
|
115
115
|
});
|
|
@@ -11,12 +11,14 @@
|
|
|
11
11
|
import test from "node:test";
|
|
12
12
|
import assert from "node:assert/strict";
|
|
13
13
|
import { mkdirSync, writeFileSync, rmSync, existsSync } from "node:fs";
|
|
14
|
+
import { execFileSync } from "node:child_process";
|
|
14
15
|
import { join } from "node:path";
|
|
15
16
|
import { tmpdir } from "node:os";
|
|
16
17
|
import {
|
|
17
18
|
detectProjectState,
|
|
18
19
|
detectV1Planning,
|
|
19
20
|
detectProjectSignals,
|
|
21
|
+
classifyProject,
|
|
20
22
|
scanProjectFiles,
|
|
21
23
|
} from "../detection.ts";
|
|
22
24
|
|
|
@@ -37,6 +39,18 @@ function cleanup(dir: string): void {
|
|
|
37
39
|
}
|
|
38
40
|
}
|
|
39
41
|
|
|
42
|
+
function git(dir: string, args: string[]): void {
|
|
43
|
+
execFileSync("git", args, { cwd: dir, stdio: "ignore" });
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function makeGitRepo(prefix: string): string {
|
|
47
|
+
const dir = makeTempDir(prefix);
|
|
48
|
+
git(dir, ["init"]);
|
|
49
|
+
git(dir, ["config", "user.email", "test@example.com"]);
|
|
50
|
+
git(dir, ["config", "user.name", "Test User"]);
|
|
51
|
+
return dir;
|
|
52
|
+
}
|
|
53
|
+
|
|
40
54
|
// ─── detectProjectState ─────────────────────────────────────────────────────────
|
|
41
55
|
|
|
42
56
|
test("detectProjectState: empty directory returns state=none", (t) => {
|
|
@@ -49,6 +63,132 @@ test("detectProjectState: empty directory returns state=none", (t) => {
|
|
|
49
63
|
assert.equal(result.v2, undefined);
|
|
50
64
|
});
|
|
51
65
|
|
|
66
|
+
test("classifyProject: no git repo is invalid", (t) => {
|
|
67
|
+
const dir = makeTempDir("classify-invalid");
|
|
68
|
+
t.after(() => cleanup(dir));
|
|
69
|
+
|
|
70
|
+
const classification = classifyProject(dir);
|
|
71
|
+
assert.equal(classification.kind, "invalid-repo");
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test("classifyProject: empty git repo is greenfield", (t) => {
|
|
75
|
+
const dir = makeGitRepo("classify-greenfield");
|
|
76
|
+
t.after(() => cleanup(dir));
|
|
77
|
+
|
|
78
|
+
const classification = classifyProject(dir);
|
|
79
|
+
assert.equal(classification.kind, "greenfield");
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test("classifyProject: nested empty git repo does not inherit ancestor markers", (t) => {
|
|
83
|
+
const parent = makeGitRepo("classify-parent-marker");
|
|
84
|
+
t.after(() => cleanup(parent));
|
|
85
|
+
|
|
86
|
+
writeFileSync(join(parent, "package.json"), JSON.stringify({ name: "parent" }), "utf-8");
|
|
87
|
+
git(parent, ["add", "package.json"]);
|
|
88
|
+
git(parent, ["commit", "-m", "add parent marker"]);
|
|
89
|
+
const child = join(parent, "nested");
|
|
90
|
+
mkdirSync(child, { recursive: true });
|
|
91
|
+
git(child, ["init"]);
|
|
92
|
+
git(child, ["config", "user.email", "test@example.com"]);
|
|
93
|
+
git(child, ["config", "user.name", "Test User"]);
|
|
94
|
+
|
|
95
|
+
const classification = classifyProject(child);
|
|
96
|
+
assert.equal(classification.kind, "greenfield");
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test("classifyProject: tracked static HTML is existing untyped content", (t) => {
|
|
100
|
+
const dir = makeGitRepo("classify-index");
|
|
101
|
+
t.after(() => cleanup(dir));
|
|
102
|
+
|
|
103
|
+
writeFileSync(join(dir, "index.html"), "<main></main>\n", "utf-8");
|
|
104
|
+
git(dir, ["add", "index.html"]);
|
|
105
|
+
git(dir, ["commit", "-m", "add static page"]);
|
|
106
|
+
|
|
107
|
+
const classification = classifyProject(dir);
|
|
108
|
+
assert.equal(classification.kind, "untyped-existing");
|
|
109
|
+
assert.deepEqual(classification.contentFiles, ["index.html"]);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test("classifyProject: README-only repo is existing untyped content", (t) => {
|
|
113
|
+
const dir = makeGitRepo("classify-readme");
|
|
114
|
+
t.after(() => cleanup(dir));
|
|
115
|
+
|
|
116
|
+
writeFileSync(join(dir, "README.md"), "# docs\n", "utf-8");
|
|
117
|
+
git(dir, ["add", "README.md"]);
|
|
118
|
+
git(dir, ["commit", "-m", "add docs"]);
|
|
119
|
+
|
|
120
|
+
const classification = classifyProject(dir);
|
|
121
|
+
assert.equal(classification.kind, "untyped-existing");
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test("classifyProject: src-only content is untyped existing, not typed marker", (t) => {
|
|
125
|
+
const dir = makeGitRepo("classify-src-only");
|
|
126
|
+
t.after(() => cleanup(dir));
|
|
127
|
+
|
|
128
|
+
mkdirSync(join(dir, "src"), { recursive: true });
|
|
129
|
+
writeFileSync(join(dir, "src", "index.txt"), "content\n", "utf-8");
|
|
130
|
+
git(dir, ["add", "src/index.txt"]);
|
|
131
|
+
git(dir, ["commit", "-m", "add source content"]);
|
|
132
|
+
|
|
133
|
+
const classification = classifyProject(dir);
|
|
134
|
+
assert.equal(classification.kind, "untyped-existing");
|
|
135
|
+
assert.deepEqual(classification.contentFiles, ["src/index.txt"]);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
test("classifyProject: nested untracked files count as project content", (t) => {
|
|
139
|
+
const dir = makeGitRepo("classify-untracked-nested");
|
|
140
|
+
t.after(() => cleanup(dir));
|
|
141
|
+
|
|
142
|
+
mkdirSync(join(dir, "docs"), { recursive: true });
|
|
143
|
+
writeFileSync(join(dir, "docs", "index.html"), "<main></main>\n", "utf-8");
|
|
144
|
+
|
|
145
|
+
const classification = classifyProject(dir);
|
|
146
|
+
assert.equal(classification.kind, "untyped-existing");
|
|
147
|
+
assert.deepEqual(classification.untrackedFiles, ["docs/index.html"]);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
test("classifyProject: known markers produce typed existing project", (t) => {
|
|
151
|
+
const dir = makeGitRepo("classify-typed");
|
|
152
|
+
t.after(() => cleanup(dir));
|
|
153
|
+
|
|
154
|
+
writeFileSync(join(dir, "package.json"), JSON.stringify({ name: "typed" }), "utf-8");
|
|
155
|
+
git(dir, ["add", "package.json"]);
|
|
156
|
+
git(dir, ["commit", "-m", "add package"]);
|
|
157
|
+
|
|
158
|
+
const classification = classifyProject(dir);
|
|
159
|
+
assert.equal(classification.kind, "typed-existing");
|
|
160
|
+
assert.ok(classification.markers.includes("package.json"));
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
test("classifyProject: ignored build/cache-only files do not count as content", (t) => {
|
|
164
|
+
const dir = makeGitRepo("classify-ignored");
|
|
165
|
+
t.after(() => cleanup(dir));
|
|
166
|
+
|
|
167
|
+
writeFileSync(join(dir, ".gitignore"), "dist/\n.cache/\n", "utf-8");
|
|
168
|
+
git(dir, ["add", ".gitignore"]);
|
|
169
|
+
git(dir, ["commit", "-m", "ignore generated files"]);
|
|
170
|
+
mkdirSync(join(dir, "dist"), { recursive: true });
|
|
171
|
+
writeFileSync(join(dir, "dist", "bundle.js"), "generated\n", "utf-8");
|
|
172
|
+
mkdirSync(join(dir, ".cache"), { recursive: true });
|
|
173
|
+
writeFileSync(join(dir, ".cache", "x"), "cache\n", "utf-8");
|
|
174
|
+
|
|
175
|
+
const classification = classifyProject(dir);
|
|
176
|
+
assert.equal(classification.kind, "greenfield");
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
test("classifyProject: generated framework/cache dirs do not count as content", (t) => {
|
|
180
|
+
const dir = makeGitRepo("classify-generated-dirs");
|
|
181
|
+
t.after(() => cleanup(dir));
|
|
182
|
+
|
|
183
|
+
mkdirSync(join(dir, ".next", "server"), { recursive: true });
|
|
184
|
+
writeFileSync(join(dir, ".next", "server", "page.js"), "generated\n", "utf-8");
|
|
185
|
+
mkdirSync(join(dir, ".venv", "lib"), { recursive: true });
|
|
186
|
+
writeFileSync(join(dir, ".venv", "lib", "site.py"), "generated\n", "utf-8");
|
|
187
|
+
|
|
188
|
+
const classification = classifyProject(dir);
|
|
189
|
+
assert.equal(classification.kind, "greenfield");
|
|
190
|
+
});
|
|
191
|
+
|
|
52
192
|
test("detectProjectState: directory with .gsd/milestones/M001 returns v2-gsd", (t) => {
|
|
53
193
|
const dir = makeTempDir("v2-gsd");
|
|
54
194
|
t.after(() => cleanup(dir));
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
## TL;DR
|
|
2
|
+
|
|
3
|
+
**What:** Ship milestone M001 - Authentication
|
|
4
|
+
**Why:** Users need to authenticate before accessing protected resources.
|
|
5
|
+
**How:** Added password hash check and session token issuance.
|
|
6
|
+
|
|
7
|
+
## What
|
|
8
|
+
|
|
9
|
+
### S01
|
|
10
|
+
Implemented login flow.
|
|
11
|
+
|
|
12
|
+
## Why
|
|
13
|
+
|
|
14
|
+
Users need to authenticate before accessing protected resources.
|
|
15
|
+
|
|
16
|
+
## How
|
|
17
|
+
|
|
18
|
+
Added password hash check and session token issuance.
|
|
19
|
+
|
|
20
|
+
## Linked Issue
|
|
21
|
+
|
|
22
|
+
Closes #123
|
|
23
|
+
|
|
24
|
+
## Roadmap
|
|
25
|
+
|
|
26
|
+
- [x] **S01: Login**
|
|
27
|
+
|
|
28
|
+
## Metrics
|
|
29
|
+
|
|
30
|
+
- **Units executed:** 3
|
|
31
|
+
|
|
32
|
+
## Tests Run
|
|
33
|
+
|
|
34
|
+
- npm test
|
|
35
|
+
- npm run typecheck:extensions
|
|
36
|
+
|
|
37
|
+
## Change Type
|
|
38
|
+
|
|
39
|
+
- [x] `feat` - New feature or capability
|
|
40
|
+
- [ ] `fix` - Bug fix
|
|
41
|
+
- [ ] `refactor` - Code restructuring
|
|
42
|
+
- [ ] `test` - Adding or updating tests
|
|
43
|
+
- [ ] `docs` - Documentation only
|
|
44
|
+
- [ ] `chore` - Build, CI, or tooling changes
|
|
45
|
+
|
|
46
|
+
## Rollback And Compatibility
|
|
47
|
+
|
|
48
|
+
- Revert the merge commit.
|
|
49
|
+
|
|
50
|
+
## AI Assistance Disclosure
|
|
51
|
+
|
|
52
|
+
This PR was prepared with AI assistance.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
## TL;DR
|
|
2
|
+
|
|
3
|
+
**What:** Ship milestone M001 - Authentication
|
|
4
|
+
**Why:** Milestone work is complete and ready for review.
|
|
5
|
+
**How:** Generated from GSD evidence and local workflow artifacts.
|
|
6
|
+
|
|
7
|
+
## What
|
|
8
|
+
|
|
9
|
+
Milestone M001 completed.
|
|
10
|
+
|
|
11
|
+
## Why
|
|
12
|
+
|
|
13
|
+
Milestone work is complete and ready for review.
|
|
14
|
+
|
|
15
|
+
## How
|
|
16
|
+
|
|
17
|
+
Generated from GSD evidence and local workflow artifacts.
|
|
18
|
+
|
|
19
|
+
## Linked Issue
|
|
20
|
+
|
|
21
|
+
Not specified. Add an issue link before marking this PR ready if CONTRIBUTING.md requires one.
|
|
22
|
+
|
|
23
|
+
## Tests Run
|
|
24
|
+
|
|
25
|
+
- Not specified. Add exact verification commands before requesting review.
|
|
26
|
+
|
|
27
|
+
## Change Type
|
|
28
|
+
|
|
29
|
+
- [x] `feat` - New feature or capability
|
|
30
|
+
- [ ] `fix` - Bug fix
|
|
31
|
+
- [ ] `refactor` - Code restructuring
|
|
32
|
+
- [ ] `test` - Adding or updating tests
|
|
33
|
+
- [ ] `docs` - Documentation only
|
|
34
|
+
- [ ] `chore` - Build, CI, or tooling changes
|
|
35
|
+
|
|
36
|
+
## Rollback And Compatibility
|
|
37
|
+
|
|
38
|
+
- No behavior-changing rollback notes recorded.
|
|
39
|
+
|
|
40
|
+
## AI Assistance Disclosure
|
|
41
|
+
|
|
42
|
+
This PR was prepared with AI assistance.
|