gsd-pi 2.74.0-dev.b741afb → 2.74.0-dev.ffbcc03
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/extensions/gsd/activity-log.js +16 -0
- package/dist/resources/extensions/gsd/auto/loop.js +147 -10
- package/dist/resources/extensions/gsd/auto/phases.js +113 -3
- package/dist/resources/extensions/gsd/auto/session.js +10 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +11 -1
- package/dist/resources/extensions/gsd/auto-model-selection.js +51 -5
- package/dist/resources/extensions/gsd/auto-post-unit.js +215 -8
- package/dist/resources/extensions/gsd/auto-recovery.js +24 -10
- package/dist/resources/extensions/gsd/auto-unit-closeout.js +18 -0
- package/dist/resources/extensions/gsd/auto-verification.js +100 -2
- package/dist/resources/extensions/gsd/auto.js +28 -2
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +10 -1
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +61 -9
- package/dist/resources/extensions/gsd/cache.js +16 -5
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +5 -0
- package/dist/resources/extensions/gsd/commands-extract-learnings.js +225 -0
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +1 -1
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +14 -1
- package/dist/resources/extensions/gsd/ecosystem/gsd-extension-api.js +144 -0
- package/dist/resources/extensions/gsd/ecosystem/loader.js +145 -0
- package/dist/resources/extensions/gsd/git-service.js +49 -1
- package/dist/resources/extensions/gsd/graph-context.js +98 -7
- package/dist/resources/extensions/gsd/gsd-db.js +260 -2
- package/dist/resources/extensions/gsd/guided-flow.js +24 -1
- package/dist/resources/extensions/gsd/init-wizard.js +1 -0
- package/dist/resources/extensions/gsd/journal.js +27 -0
- package/dist/resources/extensions/gsd/metrics.js +19 -0
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +33 -1
- package/dist/resources/extensions/gsd/preferences-models.js +20 -3
- package/dist/resources/extensions/gsd/preferences-types.js +1 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +108 -2
- package/dist/resources/extensions/gsd/preferences.js +26 -0
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +15 -30
- package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +12 -2
- package/dist/resources/extensions/gsd/templates/PREFERENCES.md +18 -0
- package/dist/resources/extensions/gsd/tools/complete-slice.js +5 -0
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +39 -4
- package/dist/resources/extensions/gsd/unit-ownership.js +1 -1
- package/dist/resources/extensions/gsd/uok/audit-toggle.js +7 -0
- package/dist/resources/extensions/gsd/uok/audit.js +40 -0
- package/dist/resources/extensions/gsd/uok/contracts.js +1 -0
- package/dist/resources/extensions/gsd/uok/execution-graph.js +179 -0
- package/dist/resources/extensions/gsd/uok/flags.js +29 -0
- package/dist/resources/extensions/gsd/uok/gate-runner.js +109 -0
- package/dist/resources/extensions/gsd/uok/gitops.js +53 -0
- package/dist/resources/extensions/gsd/uok/kernel.js +80 -0
- package/dist/resources/extensions/gsd/uok/loop-adapter.js +133 -0
- package/dist/resources/extensions/gsd/uok/model-policy.js +66 -0
- package/dist/resources/extensions/gsd/uok/plan-v2.js +132 -0
- package/dist/resources/extensions/gsd/workflow-logger.js +22 -0
- package/dist/resources/extensions/ttsr/ttsr-manager.js +3 -1
- 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 +9 -9
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- 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/api/terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/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 +9 -9
- 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-manifest.json +5 -5
- 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/package.json +1 -1
- package/packages/mcp-server/dist/readers/graph.d.ts +1 -1
- package/packages/mcp-server/dist/readers/graph.d.ts.map +1 -1
- package/packages/mcp-server/dist/readers/graph.js +107 -0
- package/packages/mcp-server/dist/readers/graph.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +88 -6
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/src/readers/graph.test.ts +178 -0
- package/packages/mcp-server/src/readers/graph.ts +148 -1
- package/packages/mcp-server/src/workflow-tools.ts +95 -10
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/index.d.ts +1 -9
- package/packages/pi-ai/dist/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/index.js +1 -9
- package/packages/pi-ai/dist/index.js.map +1 -1
- package/packages/pi-ai/dist/models/capability-patches.d.ts +19 -0
- package/packages/pi-ai/dist/models/capability-patches.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/capability-patches.js +36 -0
- package/packages/pi-ai/dist/models/capability-patches.js.map +1 -0
- package/packages/pi-ai/dist/{models.custom.d.ts → models/custom.d.ts} +1 -1
- package/packages/pi-ai/dist/models/custom.d.ts.map +1 -0
- package/packages/pi-ai/dist/{models.custom.js → models/custom.js} +4 -4
- package/packages/pi-ai/dist/models/custom.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/amazon-bedrock.d.ts +1482 -0
- package/packages/pi-ai/dist/models/generated/amazon-bedrock.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/amazon-bedrock.js +1484 -0
- package/packages/pi-ai/dist/models/generated/amazon-bedrock.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/anthropic.d.ts +377 -0
- package/packages/pi-ai/dist/models/generated/anthropic.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/anthropic.js +379 -0
- package/packages/pi-ai/dist/models/generated/anthropic.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/azure-openai-responses.d.ts +700 -0
- package/packages/pi-ai/dist/models/generated/azure-openai-responses.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/azure-openai-responses.js +702 -0
- package/packages/pi-ai/dist/models/generated/azure-openai-responses.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/cerebras.d.ts +71 -0
- package/packages/pi-ai/dist/models/generated/cerebras.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/cerebras.js +73 -0
- package/packages/pi-ai/dist/models/generated/cerebras.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/github-copilot.d.ts +590 -0
- package/packages/pi-ai/dist/models/generated/github-copilot.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/github-copilot.js +444 -0
- package/packages/pi-ai/dist/models/generated/github-copilot.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/google-antigravity.d.ts +156 -0
- package/packages/pi-ai/dist/models/generated/google-antigravity.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/google-antigravity.js +158 -0
- package/packages/pi-ai/dist/models/generated/google-antigravity.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/google-gemini-cli.d.ts +105 -0
- package/packages/pi-ai/dist/models/generated/google-gemini-cli.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/google-gemini-cli.js +107 -0
- package/packages/pi-ai/dist/models/generated/google-gemini-cli.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/google-vertex.d.ts +207 -0
- package/packages/pi-ai/dist/models/generated/google-vertex.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/google-vertex.js +209 -0
- package/packages/pi-ai/dist/models/generated/google-vertex.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/google.d.ts +462 -0
- package/packages/pi-ai/dist/models/generated/google.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/google.js +464 -0
- package/packages/pi-ai/dist/models/generated/google.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/groq.d.ts +309 -0
- package/packages/pi-ai/dist/models/generated/groq.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/groq.js +311 -0
- package/packages/pi-ai/dist/models/generated/groq.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/huggingface.d.ts +383 -0
- package/packages/pi-ai/dist/models/generated/huggingface.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/huggingface.js +347 -0
- package/packages/pi-ai/dist/models/generated/huggingface.js.map +1 -0
- package/packages/pi-ai/dist/{models.generated.d.ts → models/generated/index.d.ts} +1 -1
- package/packages/pi-ai/dist/{models.generated.d.ts.map → models/generated/index.d.ts.map} +1 -1
- package/packages/pi-ai/dist/models/generated/index.js +51 -0
- package/packages/pi-ai/dist/models/generated/index.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/kimi-coding.d.ts +37 -0
- package/packages/pi-ai/dist/models/generated/kimi-coding.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/kimi-coding.js +39 -0
- package/packages/pi-ai/dist/models/generated/kimi-coding.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/minimax-cn.d.ts +105 -0
- package/packages/pi-ai/dist/models/generated/minimax-cn.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/minimax-cn.js +107 -0
- package/packages/pi-ai/dist/models/generated/minimax-cn.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/minimax.d.ts +105 -0
- package/packages/pi-ai/dist/models/generated/minimax.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/minimax.js +107 -0
- package/packages/pi-ai/dist/models/generated/minimax.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/mistral.d.ts +445 -0
- package/packages/pi-ai/dist/models/generated/mistral.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/mistral.js +447 -0
- package/packages/pi-ai/dist/models/generated/mistral.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +139 -0
- package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/openai-codex.js +141 -0
- package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/openai.d.ts +700 -0
- package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/openai.js +702 -0
- package/packages/pi-ai/dist/models/generated/openai.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/opencode-go.d.ts +122 -0
- package/packages/pi-ai/dist/models/generated/opencode-go.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/opencode-go.js +124 -0
- package/packages/pi-ai/dist/models/generated/opencode-go.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/opencode.d.ts +530 -0
- package/packages/pi-ai/dist/models/generated/opencode.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/opencode.js +532 -0
- package/packages/pi-ai/dist/models/generated/opencode.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/openrouter.d.ts +4270 -0
- package/packages/pi-ai/dist/models/generated/openrouter.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/openrouter.js +4272 -0
- package/packages/pi-ai/dist/models/generated/openrouter.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.d.ts +2604 -0
- package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.js +2606 -0
- package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/xai.d.ts +411 -0
- package/packages/pi-ai/dist/models/generated/xai.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/xai.js +413 -0
- package/packages/pi-ai/dist/models/generated/xai.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/zai.d.ts +276 -0
- package/packages/pi-ai/dist/models/generated/zai.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/zai.js +239 -0
- package/packages/pi-ai/dist/models/generated/zai.js.map +1 -0
- package/packages/pi-ai/dist/models/index.d.ts +27 -0
- package/packages/pi-ai/dist/models/index.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/index.js +80 -0
- package/packages/pi-ai/dist/models/index.js.map +1 -0
- package/packages/pi-ai/dist/models.d.ts +1 -36
- package/packages/pi-ai/dist/models.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.test.js +1 -2
- package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
- package/packages/pi-ai/dist/models.js +3 -112
- package/packages/pi-ai/dist/models.js.map +1 -1
- package/packages/pi-ai/dist/models.test.js +6 -5
- package/packages/pi-ai/dist/models.test.js.map +1 -1
- package/packages/pi-ai/scripts/generate-models.ts +74 -40
- package/packages/pi-ai/src/index.ts +1 -9
- package/packages/pi-ai/src/models/capability-patches.ts +40 -0
- package/packages/pi-ai/src/{models.custom.ts → models/custom.ts} +4 -4
- package/packages/pi-ai/src/models/generated/amazon-bedrock.ts +1486 -0
- package/packages/pi-ai/src/models/generated/anthropic.ts +381 -0
- package/packages/pi-ai/src/models/generated/azure-openai-responses.ts +704 -0
- package/packages/pi-ai/src/models/generated/cerebras.ts +75 -0
- package/packages/pi-ai/src/models/generated/github-copilot.ts +446 -0
- package/packages/pi-ai/src/models/generated/google-antigravity.ts +160 -0
- package/packages/pi-ai/src/models/generated/google-gemini-cli.ts +109 -0
- package/packages/pi-ai/src/models/generated/google-vertex.ts +211 -0
- package/packages/pi-ai/src/models/generated/google.ts +466 -0
- package/packages/pi-ai/src/models/generated/groq.ts +313 -0
- package/packages/pi-ai/src/models/generated/huggingface.ts +349 -0
- package/packages/pi-ai/src/models/generated/index.ts +52 -0
- package/packages/pi-ai/src/models/generated/kimi-coding.ts +41 -0
- package/packages/pi-ai/src/models/generated/minimax-cn.ts +109 -0
- package/packages/pi-ai/src/models/generated/minimax.ts +109 -0
- package/packages/pi-ai/src/models/generated/mistral.ts +449 -0
- package/packages/pi-ai/src/models/generated/openai-codex.ts +143 -0
- package/packages/pi-ai/src/models/generated/openai.ts +704 -0
- package/packages/pi-ai/src/models/generated/opencode-go.ts +126 -0
- package/packages/pi-ai/src/models/generated/opencode.ts +534 -0
- package/packages/pi-ai/src/models/generated/openrouter.ts +4274 -0
- package/packages/pi-ai/src/models/generated/vercel-ai-gateway.ts +2608 -0
- package/packages/pi-ai/src/models/generated/xai.ts +415 -0
- package/packages/pi-ai/src/models/generated/zai.ts +241 -0
- package/packages/pi-ai/src/models/index.ts +106 -0
- package/packages/pi-ai/src/models.generated.test.ts +1 -2
- package/packages/pi-ai/src/models.test.ts +6 -5
- package/packages/pi-ai/src/models.ts +3 -153
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +8 -2
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +472 -0
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.js +52 -0
- package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +2 -2
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +11 -0
- 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/assistant-message.d.ts +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 +23 -9
- 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 +11 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +47 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +8 -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 +68 -8
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +22 -22
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.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 +232 -18
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js +38 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +14 -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 +70 -6
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +12 -6
- package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +612 -0
- package/packages/pi-coding-agent/src/core/model-registry-env-fallback.test.ts +59 -0
- package/packages/pi-coding-agent/src/core/model-registry.ts +2 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +19 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +25 -10
- package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +67 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +83 -7
- package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +23 -26
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +298 -41
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-ordering.test.ts +44 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +92 -6
- package/packages/pi-coding-agent/src/types/ambient-modules.d.ts +69 -0
- package/packages/pi-coding-agent/tsconfig.json +2 -2
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/src/resources/extensions/gsd/activity-log.ts +21 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +4 -0
- package/src/resources/extensions/gsd/auto/loop.ts +159 -10
- package/src/resources/extensions/gsd/auto/phases.ts +123 -3
- package/src/resources/extensions/gsd/auto/session.ts +10 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +16 -6
- package/src/resources/extensions/gsd/auto-model-selection.ts +66 -5
- package/src/resources/extensions/gsd/auto-post-unit.ts +226 -9
- package/src/resources/extensions/gsd/auto-recovery.ts +29 -9
- package/src/resources/extensions/gsd/auto-unit-closeout.ts +25 -1
- package/src/resources/extensions/gsd/auto-verification.ts +129 -2
- package/src/resources/extensions/gsd/auto.ts +34 -2
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +15 -1
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +72 -8
- package/src/resources/extensions/gsd/cache.ts +16 -5
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +5 -0
- package/src/resources/extensions/gsd/commands-extract-learnings.ts +304 -0
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +1 -1
- package/src/resources/extensions/gsd/docs/preferences-reference.md +14 -1
- package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +228 -0
- package/src/resources/extensions/gsd/ecosystem/loader.ts +201 -0
- package/src/resources/extensions/gsd/git-service.ts +68 -0
- package/src/resources/extensions/gsd/graph-context.ts +139 -12
- package/src/resources/extensions/gsd/gsd-db.ts +321 -3
- package/src/resources/extensions/gsd/guided-flow.ts +33 -1
- package/src/resources/extensions/gsd/init-wizard.ts +3 -2
- package/src/resources/extensions/gsd/journal.ts +30 -0
- package/src/resources/extensions/gsd/metrics.ts +26 -0
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +40 -1
- package/src/resources/extensions/gsd/preferences-models.ts +20 -3
- package/src/resources/extensions/gsd/preferences-types.ts +32 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +107 -2
- package/src/resources/extensions/gsd/preferences.ts +28 -0
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +15 -31
- package/src/resources/extensions/gsd/session-lock.ts +14 -2
- package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +20 -1
- package/src/resources/extensions/gsd/templates/PREFERENCES.md +18 -0
- package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +177 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +7 -3
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/auto-project-root-env.test.ts +7 -3
- package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +272 -0
- package/src/resources/extensions/gsd/tests/cold-resume-db-reopen.test.ts +6 -2
- package/src/resources/extensions/gsd/tests/commands-extract-learnings.test.ts +340 -0
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +10 -7
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -2
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -3
- package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +79 -1
- package/src/resources/extensions/gsd/tests/post-unit-state-rebuild.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +40 -1
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/token-profile.test.ts +8 -5
- package/src/resources/extensions/gsd/tests/uok-audit-unified.test.ts +101 -0
- package/src/resources/extensions/gsd/tests/uok-contracts.test.ts +85 -0
- package/src/resources/extensions/gsd/tests/uok-execution-graph.test.ts +69 -0
- package/src/resources/extensions/gsd/tests/uok-flags.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +70 -0
- package/src/resources/extensions/gsd/tests/uok-gitops-turn-action.test.ts +85 -0
- package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/uok-model-policy.test.ts +89 -0
- package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +167 -0
- package/src/resources/extensions/gsd/tests/uok-preferences.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +39 -0
- package/src/resources/extensions/gsd/tools/complete-slice.ts +9 -2
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +48 -3
- package/src/resources/extensions/gsd/types.ts +14 -1
- package/src/resources/extensions/gsd/unit-ownership.ts +2 -2
- package/src/resources/extensions/gsd/uok/audit-toggle.ts +9 -0
- package/src/resources/extensions/gsd/uok/audit.ts +51 -0
- package/src/resources/extensions/gsd/uok/contracts.ts +135 -0
- package/src/resources/extensions/gsd/uok/execution-graph.ts +241 -0
- package/src/resources/extensions/gsd/uok/flags.ts +45 -0
- package/src/resources/extensions/gsd/uok/gate-runner.ts +146 -0
- package/src/resources/extensions/gsd/uok/gitops.ts +75 -0
- package/src/resources/extensions/gsd/uok/kernel.ts +105 -0
- package/src/resources/extensions/gsd/uok/loop-adapter.ts +162 -0
- package/src/resources/extensions/gsd/uok/model-policy.ts +112 -0
- package/src/resources/extensions/gsd/uok/plan-v2.ts +156 -0
- package/src/resources/extensions/gsd/workflow-logger.ts +27 -1
- package/src/resources/extensions/ttsr/ttsr-manager.ts +10 -5
- package/packages/pi-ai/dist/models.custom.d.ts.map +0 -1
- package/packages/pi-ai/dist/models.custom.js.map +0 -1
- package/packages/pi-ai/dist/models.generated.js +0 -14343
- package/packages/pi-ai/dist/models.generated.js.map +0 -1
- package/packages/pi-ai/src/models.generated.ts +0 -14345
- /package/dist/web/standalone/.next/static/{XnHY5eXUsTCFmNodWHetD → kn6xzWKYnogsxp2b6RpDD}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{XnHY5eXUsTCFmNodWHetD → kn6xzWKYnogsxp2b6RpDD}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regression tests for PR #4288 — auto-retry bug, .mcp.json churn, and MCP
|
|
3
|
+
* worktree routing fixes.
|
|
4
|
+
*
|
|
5
|
+
* Covers four source-file changes:
|
|
6
|
+
* 1. src/resources/extensions/gsd/safety/evidence-collector.ts (functional)
|
|
7
|
+
* 2. src/resources/extensions/gsd/bootstrap/register-hooks.ts (source shape)
|
|
8
|
+
* 3. src/resources/extensions/gsd/auto-recovery.ts (source shape)
|
|
9
|
+
* 4. packages/mcp-server/src/workflow-tools.ts (source shape)
|
|
10
|
+
*
|
|
11
|
+
* Copyright (c) 2026 Jeremy McSpadden <jeremy@fluxlabs.net>
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { describe, it, beforeEach } from "node:test";
|
|
15
|
+
import assert from "node:assert/strict";
|
|
16
|
+
import { readFileSync } from "node:fs";
|
|
17
|
+
import { resolve } from "node:path";
|
|
18
|
+
|
|
19
|
+
import {
|
|
20
|
+
resetEvidence,
|
|
21
|
+
getEvidence,
|
|
22
|
+
recordToolCall,
|
|
23
|
+
recordToolResult,
|
|
24
|
+
type BashEvidence,
|
|
25
|
+
} from "../safety/evidence-collector.js";
|
|
26
|
+
|
|
27
|
+
// ─── 1. evidence-collector: functional ─────────────────────────────────────
|
|
28
|
+
|
|
29
|
+
describe("evidence-collector: toolCallId-based matching (A-3)", () => {
|
|
30
|
+
beforeEach(() => {
|
|
31
|
+
resetEvidence();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("records bash calls with their toolCallId at dispatch time", () => {
|
|
35
|
+
recordToolCall("tc-1", "bash", { command: "ls -la" });
|
|
36
|
+
recordToolCall("tc-2", "bash", { command: "git status" });
|
|
37
|
+
|
|
38
|
+
const entries = getEvidence();
|
|
39
|
+
assert.equal(entries.length, 2);
|
|
40
|
+
assert.equal(entries[0].toolCallId, "tc-1");
|
|
41
|
+
assert.equal(entries[1].toolCallId, "tc-2");
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("matches results to the correct entry by toolCallId, not insertion order", () => {
|
|
45
|
+
// Simulate two parallel bash calls dispatched in order tc-1, tc-2.
|
|
46
|
+
recordToolCall("tc-1", "bash", { command: "slow-thing" });
|
|
47
|
+
recordToolCall("tc-2", "bash", { command: "fast-thing" });
|
|
48
|
+
|
|
49
|
+
// Results arrive out of order: tc-2 first (fast), then tc-1 (slow).
|
|
50
|
+
// With the old empty-string-matching strategy, tc-2's result would be
|
|
51
|
+
// stapled to tc-1's entry because findLastUnresolved scanned backwards
|
|
52
|
+
// for empty ids. Now we match by id directly.
|
|
53
|
+
recordToolResult("tc-2", "bash", "Command exited with code 0\nfast-output", false);
|
|
54
|
+
recordToolResult("tc-1", "bash", "Command exited with code 1\nslow-failure", true);
|
|
55
|
+
|
|
56
|
+
const entries = getEvidence() as readonly BashEvidence[];
|
|
57
|
+
const tc1 = entries.find(e => e.toolCallId === "tc-1") as BashEvidence | undefined;
|
|
58
|
+
const tc2 = entries.find(e => e.toolCallId === "tc-2") as BashEvidence | undefined;
|
|
59
|
+
|
|
60
|
+
assert.ok(tc1, "tc-1 entry must exist");
|
|
61
|
+
assert.ok(tc2, "tc-2 entry must exist");
|
|
62
|
+
|
|
63
|
+
// The original command stays attached to the entry it was recorded with,
|
|
64
|
+
// and the result matches the id it was reported for.
|
|
65
|
+
assert.equal(tc1.command, "slow-thing");
|
|
66
|
+
assert.equal(tc1.exitCode, 1);
|
|
67
|
+
assert.ok(tc1.outputSnippet.includes("slow-failure"));
|
|
68
|
+
|
|
69
|
+
assert.equal(tc2.command, "fast-thing");
|
|
70
|
+
assert.equal(tc2.exitCode, 0);
|
|
71
|
+
assert.ok(tc2.outputSnippet.includes("fast-output"));
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("ignores results with unknown toolCallIds rather than corrupting nearby entries", () => {
|
|
75
|
+
recordToolCall("tc-1", "bash", { command: "real" });
|
|
76
|
+
recordToolResult("tc-UNKNOWN", "bash", "Command exited with code 0\n", false);
|
|
77
|
+
|
|
78
|
+
const entries = getEvidence() as readonly BashEvidence[];
|
|
79
|
+
assert.equal(entries.length, 1);
|
|
80
|
+
assert.equal(entries[0].toolCallId, "tc-1");
|
|
81
|
+
// tc-1 must be untouched — no result was reported for it.
|
|
82
|
+
assert.equal(entries[0].exitCode, -1);
|
|
83
|
+
assert.equal(entries[0].outputSnippet, "");
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("records write/edit entries with their toolCallId", () => {
|
|
87
|
+
recordToolCall("tc-write", "write", { file_path: "/tmp/a.md" });
|
|
88
|
+
recordToolCall("tc-edit", "edit", { file_path: "/tmp/b.md" });
|
|
89
|
+
|
|
90
|
+
const entries = getEvidence();
|
|
91
|
+
assert.equal(entries.length, 2);
|
|
92
|
+
assert.equal(entries[0].kind, "write");
|
|
93
|
+
assert.equal(entries[0].toolCallId, "tc-write");
|
|
94
|
+
assert.equal(entries[1].kind, "edit");
|
|
95
|
+
assert.equal(entries[1].toolCallId, "tc-edit");
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// ─── 2. register-hooks: MCP auto-prep gated inside auto-worktrees (A-1) ────
|
|
100
|
+
|
|
101
|
+
describe("register-hooks: skip prepareWorkflowMcpForProject inside auto-worktrees (A-1)", () => {
|
|
102
|
+
const src = readFileSync(
|
|
103
|
+
resolve(process.cwd(), "src", "resources", "extensions", "gsd", "bootstrap", "register-hooks.ts"),
|
|
104
|
+
"utf-8",
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
it("session_start hook is gated on isInAutoWorktree", () => {
|
|
108
|
+
const idx = src.indexOf('pi.on("session_start"');
|
|
109
|
+
assert.ok(idx !== -1, "session_start handler must exist");
|
|
110
|
+
const block = src.slice(idx, idx + 2500);
|
|
111
|
+
assert.ok(
|
|
112
|
+
block.includes("isInAutoWorktree"),
|
|
113
|
+
"session_start must consult isInAutoWorktree before preparing MCP",
|
|
114
|
+
);
|
|
115
|
+
assert.ok(
|
|
116
|
+
block.includes("prepareWorkflowMcpForProject"),
|
|
117
|
+
"session_start still prepares MCP for non-worktree paths",
|
|
118
|
+
);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("session_switch hook is gated on isInAutoWorktree", () => {
|
|
122
|
+
const idx = src.indexOf('pi.on("session_switch"');
|
|
123
|
+
assert.ok(idx !== -1, "session_switch handler must exist");
|
|
124
|
+
const block = src.slice(idx, idx + 2500);
|
|
125
|
+
assert.ok(
|
|
126
|
+
block.includes("isInAutoWorktree"),
|
|
127
|
+
"session_switch must consult isInAutoWorktree before preparing MCP",
|
|
128
|
+
);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it("tool_call hook forwards event.toolCallId into safetyRecordToolCall (A-3)", () => {
|
|
132
|
+
// Find the call site (skip the import line by looking for the opening paren).
|
|
133
|
+
const idx = src.indexOf("safetyRecordToolCall(");
|
|
134
|
+
assert.ok(idx !== -1, "safetyRecordToolCall call must exist");
|
|
135
|
+
const line = src.slice(idx, src.indexOf("\n", idx));
|
|
136
|
+
assert.ok(
|
|
137
|
+
line.includes("event.toolCallId"),
|
|
138
|
+
"safetyRecordToolCall must receive event.toolCallId as the first argument",
|
|
139
|
+
);
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
// ─── 3. auto-recovery: verify-fail instrumentation ─────────────────────────
|
|
144
|
+
|
|
145
|
+
describe("verifyExpectedArtifact: verify-fail exit-point logging (Phase B diag)", () => {
|
|
146
|
+
const src = readFileSync(
|
|
147
|
+
resolve(process.cwd(), "src", "resources", "extensions", "gsd", "auto-recovery.ts"),
|
|
148
|
+
"utf-8",
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
it("logs a verify-fail warning on the null-absPath exit", () => {
|
|
152
|
+
assert.ok(
|
|
153
|
+
src.includes('verify-fail ${unitType} ${unitId}: resolveExpectedArtifactPath returned null'),
|
|
154
|
+
"null-absPath branch must emit a diagnostic line",
|
|
155
|
+
);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it("logs a verify-fail warning on the existsSync-false exit", () => {
|
|
159
|
+
assert.ok(
|
|
160
|
+
src.includes("verify-fail ${unitType} ${unitId}: existsSync false"),
|
|
161
|
+
"existsSync-false branch must emit a diagnostic line",
|
|
162
|
+
);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it("logs a verify-fail warning on the plan-slice no-task-entry exit", () => {
|
|
166
|
+
assert.ok(
|
|
167
|
+
src.includes("verify-fail ${unitType} ${unitId}: plan has no task checkbox/heading"),
|
|
168
|
+
"plan-slice no-task branch must emit a diagnostic line",
|
|
169
|
+
);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it("plan-slice task-plan-files check fails fast on missing tasks dir (hardening)", () => {
|
|
173
|
+
// The original check silently passed when resolveTasksDir returned null.
|
|
174
|
+
// The new check returns false with a diagnostic, which is correct — if
|
|
175
|
+
// the tool successfully planned tasks, the tasks/ dir must exist.
|
|
176
|
+
const idx = src.indexOf('verify-fail ${unitType} ${unitId}: resolveTasksDir returned null');
|
|
177
|
+
assert.ok(
|
|
178
|
+
idx !== -1,
|
|
179
|
+
"resolveTasksDir-null branch must emit a diagnostic and return false",
|
|
180
|
+
);
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// ─── 4. workflow-tools (mcp-server): guard + optional projectDir + routing ─
|
|
185
|
+
|
|
186
|
+
describe("mcp-server workflow-tools: projectDir routing (Phase B root cause)", () => {
|
|
187
|
+
const src = readFileSync(
|
|
188
|
+
resolve(process.cwd(), "packages", "mcp-server", "src", "workflow-tools.ts"),
|
|
189
|
+
"utf-8",
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
it("projectDirParam is optional and documents the default", () => {
|
|
193
|
+
const idx = src.indexOf("const projectDirParam");
|
|
194
|
+
assert.ok(idx !== -1, "projectDirParam definition must exist");
|
|
195
|
+
const block = src.slice(idx, idx + 600);
|
|
196
|
+
assert.ok(
|
|
197
|
+
block.includes(".optional()"),
|
|
198
|
+
"projectDirParam must be optional so the agent stops deliberating",
|
|
199
|
+
);
|
|
200
|
+
assert.ok(
|
|
201
|
+
/Omit this field/i.test(block),
|
|
202
|
+
"description must tell the agent to omit the field",
|
|
203
|
+
);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it("parseWorkflowArgs defaults projectDir to process.cwd() when omitted", () => {
|
|
207
|
+
const idx = src.indexOf("function parseWorkflowArgs");
|
|
208
|
+
assert.ok(idx !== -1, "parseWorkflowArgs must exist");
|
|
209
|
+
const block = src.slice(idx, idx + 1500);
|
|
210
|
+
assert.ok(
|
|
211
|
+
block.includes("parsed.projectDir ?? process.cwd()"),
|
|
212
|
+
"parseWorkflowArgs must fall back to process.cwd() when projectDir is omitted",
|
|
213
|
+
);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it("validateProjectDir accepts external-state worktree paths via .gsd symlink target", () => {
|
|
217
|
+
const idx = src.indexOf("function validateProjectDir");
|
|
218
|
+
assert.ok(idx !== -1, "validateProjectDir must exist");
|
|
219
|
+
const block = src.slice(idx, idx + 2500);
|
|
220
|
+
assert.ok(
|
|
221
|
+
block.includes("resolveExternalStateRoot"),
|
|
222
|
+
"validateProjectDir must consult resolveExternalStateRoot for external-state layouts",
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
const helperIdx = src.indexOf("function resolveExternalStateRoot");
|
|
226
|
+
assert.ok(helperIdx !== -1, "resolveExternalStateRoot helper must exist");
|
|
227
|
+
const helperBlock = src.slice(helperIdx, helperIdx + 600);
|
|
228
|
+
assert.ok(
|
|
229
|
+
helperBlock.includes("realpathSync"),
|
|
230
|
+
"resolveExternalStateRoot must use realpathSync to follow the symlink",
|
|
231
|
+
);
|
|
232
|
+
assert.ok(
|
|
233
|
+
/join\([^)]*\.gsd/.test(helperBlock),
|
|
234
|
+
"resolveExternalStateRoot must resolve <allowedRoot>/.gsd",
|
|
235
|
+
);
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it("parseWorkflowArgs routes tool writes to the active worktree when one exists", () => {
|
|
239
|
+
// This is the Phase B root-cause fix: when the tool call is scoped to a
|
|
240
|
+
// milestone that has an auto-worktree at <projectRoot>/.gsd/worktrees/<MID>/,
|
|
241
|
+
// tool writes must go to the worktree .gsd rather than the shared project .gsd.
|
|
242
|
+
const parseIdx = src.indexOf("function parseWorkflowArgs");
|
|
243
|
+
const parseBlock = src.slice(parseIdx, parseIdx + 2500);
|
|
244
|
+
assert.ok(
|
|
245
|
+
parseBlock.includes("resolveActiveWorktreeBasePath"),
|
|
246
|
+
"parseWorkflowArgs must consult resolveActiveWorktreeBasePath",
|
|
247
|
+
);
|
|
248
|
+
assert.ok(
|
|
249
|
+
parseBlock.includes("extractMilestoneId"),
|
|
250
|
+
"parseWorkflowArgs must extract the milestoneId to locate the worktree",
|
|
251
|
+
);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it("resolveActiveWorktreeBasePath checks .git presence to avoid hijacking stray directories", () => {
|
|
255
|
+
const idx = src.indexOf("function resolveActiveWorktreeBasePath");
|
|
256
|
+
assert.ok(idx !== -1, "resolveActiveWorktreeBasePath helper must exist");
|
|
257
|
+
const block = src.slice(idx, idx + 1200);
|
|
258
|
+
assert.ok(
|
|
259
|
+
block.includes('existsSync(join(wtPath, ".git"))'),
|
|
260
|
+
"resolveActiveWorktreeBasePath must verify a .git file exists in the worktree",
|
|
261
|
+
);
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
it("extractMilestoneId handles camelCase, snake_case, and short aliases", () => {
|
|
265
|
+
const idx = src.indexOf("function extractMilestoneId");
|
|
266
|
+
assert.ok(idx !== -1, "extractMilestoneId helper must exist");
|
|
267
|
+
const block = src.slice(idx, idx + 600);
|
|
268
|
+
assert.ok(block.includes("milestoneId"), "must check milestoneId");
|
|
269
|
+
assert.ok(block.includes("milestone_id"), "must check milestone_id");
|
|
270
|
+
assert.ok(block.includes("mid"), "must check mid");
|
|
271
|
+
});
|
|
272
|
+
});
|
|
@@ -25,8 +25,12 @@ console.log("\n=== resume path refreshes resources and opens DB before rebuildSt
|
|
|
25
25
|
const resumeSectionStart = autoSrc.indexOf("if (s.paused) {", autoSrc.indexOf("// If resuming from paused state"));
|
|
26
26
|
assertTrue(resumeSectionStart > 0, "auto.ts has the paused-session resume block");
|
|
27
27
|
|
|
28
|
-
const
|
|
29
|
-
|
|
28
|
+
const resumeSectionEndCandidates = [
|
|
29
|
+
autoSrc.indexOf("await runAutoLoopWithUok(", resumeSectionStart),
|
|
30
|
+
autoSrc.indexOf("await autoLoop(", resumeSectionStart),
|
|
31
|
+
].filter((idx) => idx > resumeSectionStart);
|
|
32
|
+
const resumeSectionEnd = resumeSectionEndCandidates.length > 0 ? Math.min(...resumeSectionEndCandidates) : -1;
|
|
33
|
+
assertTrue(resumeSectionEnd > resumeSectionStart, "resume block reaches the dispatch loop");
|
|
30
34
|
|
|
31
35
|
const resumeSection = autoSrc.slice(resumeSectionStart, resumeSectionEnd);
|
|
32
36
|
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
import { describe, it, beforeEach, afterEach } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { mkdirSync, writeFileSync, rmSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import { randomUUID } from "node:crypto";
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
parseExtractLearningsArgs,
|
|
10
|
+
buildLearningsOutputPath,
|
|
11
|
+
resolvePhaseArtifacts,
|
|
12
|
+
buildExtractLearningsPrompt,
|
|
13
|
+
buildFrontmatter,
|
|
14
|
+
extractProjectName,
|
|
15
|
+
} from "../commands-extract-learnings.js";
|
|
16
|
+
|
|
17
|
+
// ─── parseExtractLearningsArgs ────────────────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
describe("parseExtractLearningsArgs", () => {
|
|
20
|
+
it("parses a milestone ID", () => {
|
|
21
|
+
const result = parseExtractLearningsArgs("M001");
|
|
22
|
+
assert.deepEqual(result, { milestoneId: "M001" });
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("returns null milestoneId for empty string", () => {
|
|
26
|
+
const result = parseExtractLearningsArgs("");
|
|
27
|
+
assert.deepEqual(result, { milestoneId: null });
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("returns null milestoneId for whitespace-only string", () => {
|
|
31
|
+
const result = parseExtractLearningsArgs(" ");
|
|
32
|
+
assert.deepEqual(result, { milestoneId: null });
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("trims whitespace from milestone ID", () => {
|
|
36
|
+
const result = parseExtractLearningsArgs(" M002 ");
|
|
37
|
+
assert.deepEqual(result, { milestoneId: "M002" });
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// ─── buildLearningsOutputPath ─────────────────────────────────────────────────
|
|
42
|
+
|
|
43
|
+
describe("buildLearningsOutputPath", () => {
|
|
44
|
+
it("builds the correct output path", () => {
|
|
45
|
+
const result = buildLearningsOutputPath("/base/.gsd/milestones/M001", "M001");
|
|
46
|
+
assert.equal(result, "/base/.gsd/milestones/M001/M001-LEARNINGS.md");
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("builds path for different milestone ID", () => {
|
|
50
|
+
const result = buildLearningsOutputPath("/project/.gsd/milestones/M005", "M005");
|
|
51
|
+
assert.equal(result, "/project/.gsd/milestones/M005/M005-LEARNINGS.md");
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// ─── resolvePhaseArtifacts ────────────────────────────────────────────────────
|
|
56
|
+
|
|
57
|
+
describe("resolvePhaseArtifacts", () => {
|
|
58
|
+
let tmpBase: string;
|
|
59
|
+
|
|
60
|
+
beforeEach(() => {
|
|
61
|
+
tmpBase = join(tmpdir(), `gsd-learnings-test-${randomUUID()}`);
|
|
62
|
+
mkdirSync(tmpBase, { recursive: true });
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
afterEach(() => {
|
|
66
|
+
rmSync(tmpBase, { recursive: true, force: true });
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("finds required PLAN and SUMMARY when both present", () => {
|
|
70
|
+
writeFileSync(join(tmpBase, "M001-PLAN.md"), "# M001 Plan content", "utf-8");
|
|
71
|
+
writeFileSync(join(tmpBase, "M001-SUMMARY.md"), "# M001 Summary content", "utf-8");
|
|
72
|
+
|
|
73
|
+
const result = resolvePhaseArtifacts(tmpBase, "M001");
|
|
74
|
+
assert.equal(result.plan, join(tmpBase, "M001-PLAN.md"));
|
|
75
|
+
assert.equal(result.summary, join(tmpBase, "M001-SUMMARY.md"));
|
|
76
|
+
assert.deepEqual(result.missingRequired, []);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("reports missing PLAN as missingRequired", () => {
|
|
80
|
+
writeFileSync(join(tmpBase, "M001-SUMMARY.md"), "# Summary", "utf-8");
|
|
81
|
+
|
|
82
|
+
const result = resolvePhaseArtifacts(tmpBase, "M001");
|
|
83
|
+
assert.ok(result.missingRequired.includes("M001-PLAN.md"));
|
|
84
|
+
assert.equal(result.plan, null);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("reports missing SUMMARY as missingRequired", () => {
|
|
88
|
+
writeFileSync(join(tmpBase, "M001-PLAN.md"), "# Plan", "utf-8");
|
|
89
|
+
|
|
90
|
+
const result = resolvePhaseArtifacts(tmpBase, "M001");
|
|
91
|
+
assert.ok(result.missingRequired.includes("M001-SUMMARY.md"));
|
|
92
|
+
assert.equal(result.summary, null);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("reports both required files missing when neither present", () => {
|
|
96
|
+
const result = resolvePhaseArtifacts(tmpBase, "M001");
|
|
97
|
+
assert.equal(result.missingRequired.length, 2);
|
|
98
|
+
assert.ok(result.missingRequired.includes("M001-PLAN.md"));
|
|
99
|
+
assert.ok(result.missingRequired.includes("M001-SUMMARY.md"));
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it("finds optional VERIFICATION when present", () => {
|
|
103
|
+
writeFileSync(join(tmpBase, "M001-PLAN.md"), "# Plan", "utf-8");
|
|
104
|
+
writeFileSync(join(tmpBase, "M001-SUMMARY.md"), "# Summary", "utf-8");
|
|
105
|
+
writeFileSync(join(tmpBase, "M001-VERIFICATION.md"), "# Verification", "utf-8");
|
|
106
|
+
|
|
107
|
+
const result = resolvePhaseArtifacts(tmpBase, "M001");
|
|
108
|
+
assert.equal(result.verification, join(tmpBase, "M001-VERIFICATION.md"));
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it("returns null for optional VERIFICATION when absent", () => {
|
|
112
|
+
writeFileSync(join(tmpBase, "M001-PLAN.md"), "# Plan", "utf-8");
|
|
113
|
+
writeFileSync(join(tmpBase, "M001-SUMMARY.md"), "# Summary", "utf-8");
|
|
114
|
+
|
|
115
|
+
const result = resolvePhaseArtifacts(tmpBase, "M001");
|
|
116
|
+
assert.equal(result.verification, null);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it("finds optional UAT when present", () => {
|
|
120
|
+
writeFileSync(join(tmpBase, "M001-PLAN.md"), "# Plan", "utf-8");
|
|
121
|
+
writeFileSync(join(tmpBase, "M001-SUMMARY.md"), "# Summary", "utf-8");
|
|
122
|
+
writeFileSync(join(tmpBase, "M001-UAT.md"), "# UAT", "utf-8");
|
|
123
|
+
|
|
124
|
+
const result = resolvePhaseArtifacts(tmpBase, "M001");
|
|
125
|
+
assert.equal(result.uat, join(tmpBase, "M001-UAT.md"));
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("returns null for optional UAT when absent, no error", () => {
|
|
129
|
+
writeFileSync(join(tmpBase, "M001-PLAN.md"), "# Plan", "utf-8");
|
|
130
|
+
writeFileSync(join(tmpBase, "M001-SUMMARY.md"), "# Summary", "utf-8");
|
|
131
|
+
|
|
132
|
+
const result = resolvePhaseArtifacts(tmpBase, "M001");
|
|
133
|
+
assert.equal(result.uat, null);
|
|
134
|
+
assert.deepEqual(result.missingRequired, []);
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// ─── buildExtractLearningsPrompt ──────────────────────────────────────────────
|
|
139
|
+
|
|
140
|
+
describe("buildExtractLearningsPrompt", () => {
|
|
141
|
+
it("includes milestoneId and outputPath", () => {
|
|
142
|
+
const result = buildExtractLearningsPrompt({
|
|
143
|
+
milestoneId: "M001",
|
|
144
|
+
milestoneName: "Test Milestone",
|
|
145
|
+
outputPath: "/project/.gsd/milestones/M001/M001-LEARNINGS.md",
|
|
146
|
+
relativeOutputPath: ".gsd/milestones/M001/M001-LEARNINGS.md",
|
|
147
|
+
planContent: "# Plan content",
|
|
148
|
+
summaryContent: "# Summary content",
|
|
149
|
+
verificationContent: null,
|
|
150
|
+
uatContent: null,
|
|
151
|
+
missingArtifacts: [],
|
|
152
|
+
projectName: "MyProject",
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
assert.ok(result.includes("M001"));
|
|
156
|
+
assert.ok(result.includes("/project/.gsd/milestones/M001/M001-LEARNINGS.md"));
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("includes all 4 learning categories", () => {
|
|
160
|
+
const result = buildExtractLearningsPrompt({
|
|
161
|
+
milestoneId: "M001",
|
|
162
|
+
milestoneName: "Test Milestone",
|
|
163
|
+
outputPath: "/out/M001-LEARNINGS.md",
|
|
164
|
+
relativeOutputPath: ".gsd/milestones/M001/M001-LEARNINGS.md",
|
|
165
|
+
planContent: "# Plan",
|
|
166
|
+
summaryContent: "# Summary",
|
|
167
|
+
verificationContent: null,
|
|
168
|
+
uatContent: null,
|
|
169
|
+
missingArtifacts: [],
|
|
170
|
+
projectName: "MyProject",
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
assert.ok(result.includes("Decisions"));
|
|
174
|
+
assert.ok(result.includes("Lessons"));
|
|
175
|
+
assert.ok(result.includes("Patterns"));
|
|
176
|
+
assert.ok(result.includes("Surprises"));
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it("includes plan and summary content", () => {
|
|
180
|
+
const result = buildExtractLearningsPrompt({
|
|
181
|
+
milestoneId: "M001",
|
|
182
|
+
milestoneName: "Test Milestone",
|
|
183
|
+
outputPath: "/out/M001-LEARNINGS.md",
|
|
184
|
+
relativeOutputPath: ".gsd/milestones/M001/M001-LEARNINGS.md",
|
|
185
|
+
planContent: "PLAN_CONTENT_UNIQUE_123",
|
|
186
|
+
summaryContent: "SUMMARY_CONTENT_UNIQUE_456",
|
|
187
|
+
verificationContent: null,
|
|
188
|
+
uatContent: null,
|
|
189
|
+
missingArtifacts: [],
|
|
190
|
+
projectName: "MyProject",
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
assert.ok(result.includes("PLAN_CONTENT_UNIQUE_123"));
|
|
194
|
+
assert.ok(result.includes("SUMMARY_CONTENT_UNIQUE_456"));
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it("includes optional artifacts when present", () => {
|
|
198
|
+
const result = buildExtractLearningsPrompt({
|
|
199
|
+
milestoneId: "M001",
|
|
200
|
+
milestoneName: "Test Milestone",
|
|
201
|
+
outputPath: "/out/M001-LEARNINGS.md",
|
|
202
|
+
relativeOutputPath: ".gsd/milestones/M001/M001-LEARNINGS.md",
|
|
203
|
+
planContent: "# Plan",
|
|
204
|
+
summaryContent: "# Summary",
|
|
205
|
+
verificationContent: "VERIFICATION_UNIQUE_789",
|
|
206
|
+
uatContent: "UAT_UNIQUE_012",
|
|
207
|
+
missingArtifacts: [],
|
|
208
|
+
projectName: "MyProject",
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
assert.ok(result.includes("VERIFICATION_UNIQUE_789"));
|
|
212
|
+
assert.ok(result.includes("UAT_UNIQUE_012"));
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it("lists missing artifacts when present", () => {
|
|
216
|
+
const result = buildExtractLearningsPrompt({
|
|
217
|
+
milestoneId: "M001",
|
|
218
|
+
milestoneName: "Test Milestone",
|
|
219
|
+
outputPath: "/out/M001-LEARNINGS.md",
|
|
220
|
+
relativeOutputPath: ".gsd/milestones/M001/M001-LEARNINGS.md",
|
|
221
|
+
planContent: "# Plan",
|
|
222
|
+
summaryContent: "# Summary",
|
|
223
|
+
verificationContent: null,
|
|
224
|
+
uatContent: null,
|
|
225
|
+
missingArtifacts: ["M001-VERIFICATION.md"],
|
|
226
|
+
projectName: "MyProject",
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
assert.ok(result.includes("M001-VERIFICATION.md"));
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// ─── buildFrontmatter ─────────────────────────────────────────────────────────
|
|
234
|
+
|
|
235
|
+
describe("buildFrontmatter", () => {
|
|
236
|
+
it("starts with --- and ends with ---", () => {
|
|
237
|
+
const result = buildFrontmatter({
|
|
238
|
+
milestoneId: "M001",
|
|
239
|
+
milestoneName: "Test Milestone",
|
|
240
|
+
projectName: "MyProject",
|
|
241
|
+
generatedAt: "2026-04-15T10:00:00Z",
|
|
242
|
+
counts: { decisions: 0, lessons: 0, patterns: 0, surprises: 0 },
|
|
243
|
+
missingArtifacts: [],
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
assert.ok(result.startsWith("---\n"));
|
|
247
|
+
assert.ok(result.endsWith("---"));
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it("includes required fields", () => {
|
|
251
|
+
const result = buildFrontmatter({
|
|
252
|
+
milestoneId: "M001",
|
|
253
|
+
milestoneName: "Test Milestone",
|
|
254
|
+
projectName: "MyProject",
|
|
255
|
+
generatedAt: "2026-04-15T10:00:00Z",
|
|
256
|
+
counts: { decisions: 3, lessons: 2, patterns: 1, surprises: 0 },
|
|
257
|
+
missingArtifacts: [],
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
assert.ok(result.includes("phase:"));
|
|
261
|
+
assert.ok(result.includes("phase_name:"));
|
|
262
|
+
assert.ok(result.includes("project:"));
|
|
263
|
+
assert.ok(result.includes("generated:"));
|
|
264
|
+
assert.ok(result.includes("counts:"));
|
|
265
|
+
assert.ok(result.includes("missing_artifacts:"));
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
it("includes milestoneId as phase value", () => {
|
|
269
|
+
const result = buildFrontmatter({
|
|
270
|
+
milestoneId: "M001",
|
|
271
|
+
milestoneName: "Auth System",
|
|
272
|
+
projectName: "MyApp",
|
|
273
|
+
generatedAt: "2026-04-15T10:00:00Z",
|
|
274
|
+
counts: { decisions: 0, lessons: 0, patterns: 0, surprises: 0 },
|
|
275
|
+
missingArtifacts: [],
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
assert.ok(result.includes("M001"));
|
|
279
|
+
assert.ok(result.includes("Auth System"));
|
|
280
|
+
assert.ok(result.includes("MyApp"));
|
|
281
|
+
assert.ok(result.includes("2026-04-15T10:00:00Z"));
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it("includes missing artifacts list", () => {
|
|
285
|
+
const result = buildFrontmatter({
|
|
286
|
+
milestoneId: "M001",
|
|
287
|
+
milestoneName: "Test",
|
|
288
|
+
projectName: "Proj",
|
|
289
|
+
generatedAt: "2026-04-15T10:00:00Z",
|
|
290
|
+
counts: { decisions: 0, lessons: 0, patterns: 0, surprises: 0 },
|
|
291
|
+
missingArtifacts: ["M001-VERIFICATION.md", "M001-UAT.md"],
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
assert.ok(result.includes("M001-VERIFICATION.md"));
|
|
295
|
+
assert.ok(result.includes("M001-UAT.md"));
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
// ─── extractProjectName ───────────────────────────────────────────────────────
|
|
300
|
+
|
|
301
|
+
describe("extractProjectName", () => {
|
|
302
|
+
let tmpBase: string;
|
|
303
|
+
|
|
304
|
+
beforeEach(() => {
|
|
305
|
+
tmpBase = join(tmpdir(), `gsd-projname-test-${randomUUID()}`);
|
|
306
|
+
mkdirSync(join(tmpBase, ".gsd"), { recursive: true });
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
afterEach(() => {
|
|
310
|
+
rmSync(tmpBase, { recursive: true, force: true });
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
it("reads name from PROJECT.md frontmatter", () => {
|
|
314
|
+
writeFileSync(
|
|
315
|
+
join(tmpBase, ".gsd", "PROJECT.md"),
|
|
316
|
+
"---\nname: My Cool Project\nversion: 1\n---\n# Project\n",
|
|
317
|
+
"utf-8",
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
const result = extractProjectName(tmpBase);
|
|
321
|
+
assert.equal(result, "My Cool Project");
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
it("falls back to directory name when PROJECT.md absent", () => {
|
|
325
|
+
const result = extractProjectName(tmpBase);
|
|
326
|
+
// Should return the last path segment of tmpBase
|
|
327
|
+
assert.equal(result, tmpBase.split("/").at(-1));
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
it("falls back to directory name when PROJECT.md has no name field", () => {
|
|
331
|
+
writeFileSync(
|
|
332
|
+
join(tmpBase, ".gsd", "PROJECT.md"),
|
|
333
|
+
"---\nversion: 1\n---\n# Project\n",
|
|
334
|
+
"utf-8",
|
|
335
|
+
);
|
|
336
|
+
|
|
337
|
+
const result = extractProjectName(tmpBase);
|
|
338
|
+
assert.equal(result, tmpBase.split("/").at(-1));
|
|
339
|
+
});
|
|
340
|
+
});
|
|
@@ -125,9 +125,9 @@ console.log('\n=== complete-slice: schema v6 migration ===');
|
|
|
125
125
|
|
|
126
126
|
const adapter = _getAdapter()!;
|
|
127
127
|
|
|
128
|
-
// Verify schema version is current (
|
|
128
|
+
// Verify schema version is current (v15 with UOK projection tables)
|
|
129
129
|
const versionRow = adapter.prepare('SELECT MAX(version) as v FROM schema_version').get();
|
|
130
|
-
assertEq(versionRow?.['v'],
|
|
130
|
+
assertEq(versionRow?.['v'], 15, 'schema version should be 15');
|
|
131
131
|
|
|
132
132
|
// Verify slices table has full_summary_md and full_uat_md columns
|
|
133
133
|
const cols = adapter.prepare("PRAGMA table_info(slices)").all();
|
|
@@ -109,9 +109,9 @@ console.log('\n=== complete-task: schema v5 migration ===');
|
|
|
109
109
|
|
|
110
110
|
const adapter = _getAdapter()!;
|
|
111
111
|
|
|
112
|
-
// Verify schema version is current (
|
|
112
|
+
// Verify schema version is current (v15 with UOK projection tables)
|
|
113
113
|
const versionRow = adapter.prepare('SELECT MAX(version) as v FROM schema_version').get();
|
|
114
|
-
assertEq(versionRow?.['v'],
|
|
114
|
+
assertEq(versionRow?.['v'], 15, 'schema version should be 15');
|
|
115
115
|
|
|
116
116
|
// Verify all 4 new tables exist
|
|
117
117
|
const tables = adapter.prepare(
|