gsd-pi 2.78.0 → 2.78.1-dev.9d08d820b
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/README.md +59 -23
- package/dist/bundled-resource-path.d.ts +7 -0
- package/dist/bundled-resource-path.js +34 -2
- package/dist/claude-cli-check.js +104 -33
- package/dist/cli-policy.d.ts +13 -0
- package/dist/cli-policy.js +17 -0
- package/dist/cli.js +95 -55
- package/dist/headless-query.d.ts +22 -0
- package/dist/headless-query.js +43 -8
- package/dist/headless.d.ts +10 -0
- package/dist/headless.js +16 -1
- package/dist/loader.js +9 -13
- package/dist/onboarding.d.ts +10 -0
- package/dist/onboarding.js +2 -2
- package/dist/provider-migrations.d.ts +2 -2
- package/dist/provider-migrations.js +5 -2
- package/dist/resource-loader.d.ts +5 -2
- package/dist/resource-loader.js +30 -13
- package/dist/resources/.managed-resources-content-hash +1 -0
- package/dist/resources/extensions/claude-code-cli/readiness.js +128 -32
- package/dist/resources/extensions/gsd/auto/loop.js +23 -0
- package/dist/resources/extensions/gsd/auto/phases.js +5 -13
- package/dist/resources/extensions/gsd/auto/run-unit.js +3 -1
- package/dist/resources/extensions/gsd/auto/session.js +5 -6
- package/dist/resources/extensions/gsd/auto-dashboard.js +3 -2
- package/dist/resources/extensions/gsd/auto-dispatch.js +18 -6
- package/dist/resources/extensions/gsd/auto-prompts.js +63 -2
- package/dist/resources/extensions/gsd/auto-recovery.js +43 -4
- package/dist/resources/extensions/gsd/auto-runtime-state.js +31 -0
- package/dist/resources/extensions/gsd/auto-start.js +1 -1
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +2 -2
- package/dist/resources/extensions/gsd/auto-worktree.js +60 -13
- package/dist/resources/extensions/gsd/auto.js +14 -5
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +14 -2
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +7 -5
- package/dist/resources/extensions/gsd/bootstrap/query-tools.js +2 -2
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +5 -4
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +100 -31
- package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +11 -6
- package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +22 -0
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +34 -8
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +121 -3
- package/dist/resources/extensions/gsd/commands/catalog.js +69 -5
- package/dist/resources/extensions/gsd/commands/handlers/core.js +22 -1
- package/dist/resources/extensions/gsd/commands-config.js +3 -2
- package/dist/resources/extensions/gsd/commands-extensions.js +46 -3
- package/dist/resources/extensions/gsd/commands-handlers.js +3 -2
- package/dist/resources/extensions/gsd/commands-mcp-status.js +3 -1
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +10 -1
- package/dist/resources/extensions/gsd/dashboard-overlay.js +1 -1
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +10 -0
- package/dist/resources/extensions/gsd/doctor-providers.js +2 -1
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +39 -1
- package/dist/resources/extensions/gsd/error-classifier.js +1 -1
- package/dist/resources/extensions/gsd/forensics.js +10 -8
- package/dist/resources/extensions/gsd/git-service.js +12 -5
- package/dist/resources/extensions/gsd/gsd-db.js +11 -2
- package/dist/resources/extensions/gsd/guided-flow.js +25 -24
- package/dist/resources/extensions/gsd/home-dir.js +16 -0
- package/dist/resources/extensions/gsd/key-manager.js +2 -1
- package/dist/resources/extensions/gsd/memory-store.js +66 -31
- package/dist/resources/extensions/gsd/migrate/command.js +3 -2
- package/dist/resources/extensions/gsd/milestone-id-reservation.js +36 -0
- package/dist/resources/extensions/gsd/model-router.js +114 -9
- package/dist/resources/extensions/gsd/native-git-bridge.js +7 -1
- package/dist/resources/extensions/gsd/preferences-models.js +91 -15
- package/dist/resources/extensions/gsd/preferences-types.js +2 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +32 -0
- package/dist/resources/extensions/gsd/preferences.js +5 -3
- package/dist/resources/extensions/gsd/prompt-loader.js +23 -12
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +10 -0
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +10 -0
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +10 -0
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +10 -0
- package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +9 -3
- package/dist/resources/extensions/gsd/state.js +42 -0
- package/dist/resources/extensions/gsd/templates/PREFERENCES.md +1 -0
- package/dist/resources/extensions/gsd/tools/memory-tools.js +18 -1
- package/dist/resources/extensions/gsd/unit-context-manifest.js +29 -4
- package/dist/resources/extensions/gsd/visualizer-overlay.js +1 -1
- package/dist/resources/extensions/gsd/watch/header-renderer.js +3 -1
- package/dist/resources/extensions/gsd/worktree-command.js +26 -46
- package/dist/resources/extensions/gsd/worktree-manager.js +20 -1
- package/dist/resources/extensions/gsd/worktree-resolver.js +4 -13
- package/dist/resources/extensions/gsd/worktree-root.js +124 -0
- package/dist/resources/extensions/gsd/worktree-session-state.js +33 -0
- package/dist/resources/extensions/gsd/worktree.js +4 -115
- package/dist/resources/extensions/mcp-client/index.js +6 -3
- package/dist/resources/extensions/ollama/index.js +15 -2
- package/dist/resources/extensions/ollama/model-capabilities.js +31 -0
- package/dist/resources/extensions/ollama/ollama-client.js +40 -4
- package/dist/resources/extensions/slash-commands/create-extension.js +36 -22
- package/dist/resources/extensions/subagent/index.js +324 -178
- package/dist/resources/skills/create-gsd-extension/SKILL.md +9 -5
- package/dist/resources/skills/create-gsd-extension/references/custom-commands.md +1 -1
- package/dist/resources/skills/create-gsd-extension/references/custom-rendering.md +5 -5
- package/dist/resources/skills/create-gsd-extension/references/custom-tools.md +4 -4
- package/dist/resources/skills/create-gsd-extension/references/custom-ui.md +6 -6
- package/dist/resources/skills/create-gsd-extension/references/events-reference.md +3 -3
- package/dist/resources/skills/create-gsd-extension/references/packaging-distribution.md +1 -1
- package/dist/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +3 -3
- package/dist/resources/skills/create-gsd-extension/workflows/create-extension.md +32 -12
- package/dist/rtk-shared.d.ts +3 -0
- package/dist/rtk-shared.js +17 -0
- package/dist/rtk.d.ts +2 -5
- package/dist/rtk.js +3 -20
- package/dist/runtime-checks.d.ts +27 -0
- package/dist/runtime-checks.js +38 -0
- 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 +4 -4
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +44 -4
- package/dist/web/standalone/.next/required-server-files.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +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/page.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
- 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 +3 -3
- 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/boot/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js +4 -2
- package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
- 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 +3 -3
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
- package/dist/web/standalone/.next/server/chunks/63.js +3 -3
- package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
- 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/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware.js +2 -2
- package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +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/server/webpack-runtime.js +1 -1
- package/dist/web/standalone/.next/static/chunks/2556.0527fea66e123b7f.js +1 -0
- package/dist/web/standalone/.next/static/chunks/2824.08296bc2f9654698.js +1 -0
- package/dist/web/standalone/.next/static/chunks/3026.3af53b279375f082.js +1 -0
- package/dist/web/standalone/.next/static/chunks/315.6f68ae79b67d25cf.js +1 -0
- package/dist/web/standalone/.next/static/chunks/3497.4bfc60a3b3dea717.js +1 -0
- package/dist/web/standalone/.next/static/chunks/5516.4a07c872b5c3a663.js +1 -0
- package/dist/web/standalone/.next/static/chunks/8336.31b019697882acfb.js +10 -0
- package/dist/web/standalone/.next/static/chunks/8845.c9702695e8c5a9c5.js +2 -0
- package/dist/web/standalone/.next/static/chunks/9058.01ef3a463bda88f1.js +20 -0
- package/dist/web/standalone/.next/static/chunks/9441.1081da1125d1764f.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/page-9bf2e0c50fb2ca05.js +1 -0
- package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
- package/dist/web/standalone/.next/static/chunks/webpack-f9f0dc45e4f3ac10.js +1 -0
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
- package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
- package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
- package/dist/web/standalone/package.json +2 -1
- package/dist/web/standalone/server.js +1 -1
- package/dist/worktree-cli.d.ts +1 -0
- package/dist/worktree-cli.js +9 -3
- package/dist/worktree-status-banner.d.ts +1 -0
- package/dist/worktree-status-banner.js +132 -0
- package/package.json +1 -3
- package/packages/daemon/package.json +2 -2
- package/packages/mcp-server/dist/alias-telemetry.d.ts +8 -0
- package/packages/mcp-server/dist/alias-telemetry.d.ts.map +1 -0
- package/packages/mcp-server/dist/alias-telemetry.js +30 -0
- package/packages/mcp-server/dist/alias-telemetry.js.map +1 -0
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +74 -46
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +2 -2
- package/packages/mcp-server/src/alias-telemetry.test.ts +78 -0
- package/packages/mcp-server/src/alias-telemetry.ts +30 -0
- package/packages/mcp-server/src/workflow-tools.test.ts +78 -0
- package/packages/mcp-server/src/workflow-tools.ts +93 -58
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/package.json +1 -1
- package/packages/native/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.cache-breakpoint.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/anthropic-shared.cache-breakpoint.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/anthropic-shared.cache-breakpoint.test.js +231 -0
- package/packages/pi-ai/dist/providers/anthropic-shared.cache-breakpoint.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.js +48 -19
- package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
- package/packages/pi-ai/dist/types.d.ts +13 -0
- package/packages/pi-ai/dist/types.d.ts.map +1 -1
- package/packages/pi-ai/dist/types.js.map +1 -1
- package/packages/pi-ai/dist/utils/repair-tool-json.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/repair-tool-json.js +24 -3
- package/packages/pi-ai/dist/utils/repair-tool-json.js.map +1 -1
- package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js +26 -0
- package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-ai/src/providers/anthropic-shared.cache-breakpoint.test.ts +289 -0
- package/packages/pi-ai/src/providers/anthropic-shared.ts +52 -20
- package/packages/pi-ai/src/types.ts +13 -0
- package/packages/pi-ai/src/utils/repair-tool-json.ts +24 -3
- package/packages/pi-ai/src/utils/tests/repair-tool-json.test.ts +32 -0
- 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 +6 -0
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/messages.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/messages.js +4 -0
- package/packages/pi-coding-agent/dist/core/messages.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +19 -2
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts +10 -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 +18 -0
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +13 -0
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +20 -16
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/token-telemetry.d.ts +37 -0
- package/packages/pi-coding-agent/dist/core/token-telemetry.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/token-telemetry.js +49 -0
- package/packages/pi-coding-agent/dist/core/token-telemetry.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js +133 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +14 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/tests/system-prompt-cache-stability.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-cache-stability.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-cache-stability.test.js +78 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-cache-stability.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/tests/token-telemetry.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/tests/token-telemetry.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/tests/token-telemetry.test.js +181 -0
- package/packages/pi-coding-agent/dist/tests/token-telemetry.test.js.map +1 -0
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +7 -0
- package/packages/pi-coding-agent/src/core/messages.ts +4 -0
- package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +32 -2
- package/packages/pi-coding-agent/src/core/model-registry.ts +21 -0
- package/packages/pi-coding-agent/src/core/system-prompt.ts +33 -15
- package/packages/pi-coding-agent/src/core/token-telemetry.ts +77 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.ts +212 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +17 -1
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +1 -1
- package/packages/pi-coding-agent/src/tests/system-prompt-cache-stability.test.ts +102 -0
- package/packages/pi-coding-agent/src/tests/token-telemetry.test.ts +200 -0
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/__tests__/autocomplete.test.js +17 -3
- package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
- package/packages/pi-tui/dist/components/__tests__/leak-fixes-runtime.test.d.ts +2 -0
- package/packages/pi-tui/dist/components/__tests__/leak-fixes-runtime.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/components/__tests__/leak-fixes-runtime.test.js +161 -0
- package/packages/pi-tui/dist/components/__tests__/leak-fixes-runtime.test.js.map +1 -0
- package/packages/pi-tui/package.json +1 -1
- package/packages/pi-tui/src/__tests__/autocomplete.test.ts +20 -3
- package/packages/pi-tui/src/components/__tests__/leak-fixes-runtime.test.ts +219 -0
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/packages/rpc-client/package.json +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/claude-code-cli/readiness.ts +130 -30
- package/src/resources/extensions/gsd/auto/loop.ts +24 -2
- package/src/resources/extensions/gsd/auto/phases.ts +6 -14
- package/src/resources/extensions/gsd/auto/run-unit.ts +3 -1
- package/src/resources/extensions/gsd/auto/session.ts +5 -6
- package/src/resources/extensions/gsd/auto/types.ts +1 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +3 -2
- package/src/resources/extensions/gsd/auto-dispatch.ts +18 -6
- package/src/resources/extensions/gsd/auto-prompts.ts +60 -2
- package/src/resources/extensions/gsd/auto-recovery.ts +46 -8
- package/src/resources/extensions/gsd/auto-runtime-state.ts +51 -0
- package/src/resources/extensions/gsd/auto-start.ts +1 -1
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +2 -4
- package/src/resources/extensions/gsd/auto-worktree.ts +82 -12
- package/src/resources/extensions/gsd/auto.ts +14 -4
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +15 -13
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +8 -7
- package/src/resources/extensions/gsd/bootstrap/query-tools.ts +2 -2
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +10 -9
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +108 -31
- package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +12 -6
- package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +20 -0
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +39 -8
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +141 -11
- package/src/resources/extensions/gsd/commands/catalog.ts +75 -5
- package/src/resources/extensions/gsd/commands/handlers/core.ts +22 -1
- package/src/resources/extensions/gsd/commands-config.ts +3 -2
- package/src/resources/extensions/gsd/commands-extensions.ts +43 -3
- package/src/resources/extensions/gsd/commands-handlers.ts +3 -2
- package/src/resources/extensions/gsd/commands-mcp-status.ts +3 -1
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +15 -1
- package/src/resources/extensions/gsd/dashboard-overlay.ts +1 -1
- package/src/resources/extensions/gsd/docs/preferences-reference.md +10 -0
- package/src/resources/extensions/gsd/doctor-providers.ts +2 -1
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +39 -1
- package/src/resources/extensions/gsd/doctor-types.ts +3 -1
- package/src/resources/extensions/gsd/error-classifier.ts +1 -1
- package/src/resources/extensions/gsd/forensics.ts +12 -7
- package/src/resources/extensions/gsd/git-service.ts +13 -5
- package/src/resources/extensions/gsd/gsd-db.ts +12 -2
- package/src/resources/extensions/gsd/guided-flow.ts +27 -26
- package/src/resources/extensions/gsd/home-dir.ts +19 -0
- package/src/resources/extensions/gsd/journal.ts +4 -1
- package/src/resources/extensions/gsd/key-manager.ts +2 -1
- package/src/resources/extensions/gsd/memory-store.ts +81 -28
- package/src/resources/extensions/gsd/migrate/command.ts +3 -2
- package/src/resources/extensions/gsd/milestone-id-reservation.ts +47 -0
- package/src/resources/extensions/gsd/model-router.ts +172 -9
- package/src/resources/extensions/gsd/native-git-bridge.ts +7 -1
- package/src/resources/extensions/gsd/preferences-models.ts +101 -15
- package/src/resources/extensions/gsd/preferences-types.ts +6 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +35 -0
- package/src/resources/extensions/gsd/preferences.ts +16 -2
- package/src/resources/extensions/gsd/prompt-loader.ts +26 -12
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +10 -0
- package/src/resources/extensions/gsd/prompts/complete-slice.md +10 -0
- package/src/resources/extensions/gsd/prompts/plan-slice.md +10 -0
- package/src/resources/extensions/gsd/prompts/refine-slice.md +10 -0
- package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +9 -3
- package/src/resources/extensions/gsd/state.ts +42 -0
- package/src/resources/extensions/gsd/templates/PREFERENCES.md +1 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +178 -1
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +58 -0
- package/src/resources/extensions/gsd/tests/auto-session-encapsulation.test.ts +24 -5
- package/src/resources/extensions/gsd/tests/auto-supervisor.test.mjs +21 -4
- package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/budget-prediction.test.ts +138 -211
- package/src/resources/extensions/gsd/tests/commands-extensions-version-compare.test.ts +58 -0
- package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +142 -59
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +7 -4
- package/src/resources/extensions/gsd/tests/completed-at-reconcile.test.ts +89 -32
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +41 -23
- package/src/resources/extensions/gsd/tests/db-path-worktree-symlink.test.ts +3 -43
- package/src/resources/extensions/gsd/tests/debug-logger.test.ts +5 -3
- package/src/resources/extensions/gsd/tests/deferred-milestone-dir-4996.test.ts +116 -0
- package/src/resources/extensions/gsd/tests/discuss-empty-db-fallback.test.ts +22 -87
- package/src/resources/extensions/gsd/tests/discuss-queued-milestones.test.ts +7 -118
- package/src/resources/extensions/gsd/tests/discuss-tool-scope-leak.test.ts +18 -60
- package/src/resources/extensions/gsd/tests/doctor-orphan-milestone-4996.test.ts +100 -0
- package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +14 -76
- package/src/resources/extensions/gsd/tests/ensure-preconditions-guard-4996.test.ts +93 -0
- package/src/resources/extensions/gsd/tests/false-degraded-mode-warning.test.ts +22 -83
- package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +1 -63
- package/src/resources/extensions/gsd/tests/find-missing-summaries-closed-runtime.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/forensics-stuck-loops.test.ts +26 -1
- package/src/resources/extensions/gsd/tests/gitignore-bg-shell-runtime.test.ts +63 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/gsd-no-project-error-runtime.test.ts +81 -0
- package/src/resources/extensions/gsd/tests/headless-answers.test.ts +14 -4
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +22 -12
- package/src/resources/extensions/gsd/tests/help-menu-coverage.test.ts +57 -0
- package/src/resources/extensions/gsd/tests/home-dir.test.ts +52 -0
- package/src/resources/extensions/gsd/tests/import-done-milestones-runtime.test.ts +145 -0
- package/src/resources/extensions/gsd/tests/init-prefs-routing.test.ts +64 -1
- package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +72 -1
- package/src/resources/extensions/gsd/tests/integration/token-savings.test.ts +0 -23
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +128 -0
- package/src/resources/extensions/gsd/tests/memory-tools.test.ts +33 -1
- package/src/resources/extensions/gsd/tests/merge-self-branch-guard.test.ts +124 -0
- package/src/resources/extensions/gsd/tests/milestone-id-gap-reuse-4996.test.ts +152 -0
- package/src/resources/extensions/gsd/tests/milestone-report-path.test.ts +18 -1
- package/src/resources/extensions/gsd/tests/model-router.test.ts +169 -8
- package/src/resources/extensions/gsd/tests/native-git-infra-errors.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +32 -43
- package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +4 -10
- package/src/resources/extensions/gsd/tests/preferences.test.ts +127 -0
- package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/quick-turn-end-cleanup.test.ts +6 -6
- package/src/resources/extensions/gsd/tests/register-hooks-compaction-checkpoint.test.ts +93 -0
- package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +168 -19
- package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +23 -1
- package/src/resources/extensions/gsd/tests/steer-worktree-path.test.ts +17 -1
- package/src/resources/extensions/gsd/tests/system-context-message-routing.test.ts +101 -0
- package/src/resources/extensions/gsd/tests/token-profile.test.ts +51 -4
- package/src/resources/extensions/gsd/tests/turn-epoch.test.ts +7 -16
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +38 -3
- package/src/resources/extensions/gsd/tests/unstructured-continue-context-injection.test.ts +5 -7
- package/src/resources/extensions/gsd/tests/uok-gitops-turn-action.test.ts +15 -1
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +6 -6
- package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +34 -33
- package/src/resources/extensions/gsd/tests/worktree.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +131 -1
- package/src/resources/extensions/gsd/tools/memory-tools.ts +17 -1
- package/src/resources/extensions/gsd/unit-context-manifest.ts +44 -12
- package/src/resources/extensions/gsd/visualizer-overlay.ts +1 -1
- package/src/resources/extensions/gsd/watch/header-renderer.ts +3 -1
- package/src/resources/extensions/gsd/workflow-logger.ts +1 -0
- package/src/resources/extensions/gsd/worktree-command.ts +31 -44
- package/src/resources/extensions/gsd/worktree-manager.ts +40 -1
- package/src/resources/extensions/gsd/worktree-resolver.ts +4 -14
- package/src/resources/extensions/gsd/worktree-root.ts +144 -0
- package/src/resources/extensions/gsd/worktree-session-state.ts +35 -0
- package/src/resources/extensions/gsd/worktree.ts +8 -119
- package/src/resources/extensions/mcp-client/index.ts +6 -3
- package/src/resources/extensions/mcp-client/tests/global-config.test.ts +91 -0
- package/src/resources/extensions/ollama/index.ts +16 -2
- package/src/resources/extensions/ollama/model-capabilities.ts +34 -0
- package/src/resources/extensions/ollama/ollama-client.ts +41 -4
- package/src/resources/extensions/ollama/tests/model-capabilities.test.ts +96 -0
- package/src/resources/extensions/ollama/tests/ollama-client-timeout-env.test.ts +147 -0
- package/src/resources/extensions/slash-commands/create-extension.ts +38 -24
- package/src/resources/extensions/subagent/index.ts +165 -7
- package/src/resources/skills/create-gsd-extension/SKILL.md +9 -5
- package/src/resources/skills/create-gsd-extension/references/custom-commands.md +1 -1
- package/src/resources/skills/create-gsd-extension/references/custom-rendering.md +5 -5
- package/src/resources/skills/create-gsd-extension/references/custom-tools.md +4 -4
- package/src/resources/skills/create-gsd-extension/references/custom-ui.md +6 -6
- package/src/resources/skills/create-gsd-extension/references/events-reference.md +3 -3
- package/src/resources/skills/create-gsd-extension/references/packaging-distribution.md +1 -1
- package/src/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +3 -3
- package/src/resources/skills/create-gsd-extension/templates/extension-skeleton.ts +2 -2
- package/src/resources/skills/create-gsd-extension/templates/stateful-tool-skeleton.ts +3 -3
- package/src/resources/skills/create-gsd-extension/templates/templates.test.ts +58 -0
- package/src/resources/skills/create-gsd-extension/workflows/create-extension.md +32 -12
- package/dist/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +0 -601
- package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +0 -651
- package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +0 -91
- package/dist/resources/extensions/gsd/tests/auto-supervisor.test.mjs +0 -53
- package/dist/resources/extensions/gsd/tests/dist-redirect.mjs +0 -112
- package/dist/resources/extensions/gsd/tests/resolve-ts-hooks.mjs +0 -23
- package/dist/resources/extensions/gsd/tests/resolve-ts.mjs +0 -5
- package/dist/resources/skills/github-workflows/references/gh/tests/__init__.py +0 -0
- package/dist/resources/skills/github-workflows/references/gh/tests/test_github_project_setup.py +0 -608
- package/dist/web/standalone/.next/static/chunks/2826.e9f5195e91f9cad2.js +0 -11
- package/dist/web/standalone/.next/static/chunks/3621.fc7480022c972438.js +0 -20
- package/dist/web/standalone/.next/static/chunks/app/page-151349214571e2b6.js +0 -1
- package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
- package/dist/web/standalone/.next/static/chunks/webpack-2e68521d7c82f7c2.js +0 -1
- package/src/resources/extensions/gsd/tests/copy-planning-artifacts-samepath.test.ts +0 -22
- package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +0 -47
- package/src/resources/extensions/gsd/tests/empty-content-abort-loop.test.ts +0 -75
- /package/dist/web/standalone/.next/static/{C1zT2kEfoLhDdbWPWKrXd → -Ukk6_YxRd4GY4iUOnRUE}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{C1zT2kEfoLhDdbWPWKrXd → -Ukk6_YxRd4GY4iUOnRUE}/_ssgManifest.js +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { test } from 'node:test';
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
3
|
|
|
4
|
-
import { closeDatabase, openDatabase } from '../gsd-db.ts';
|
|
4
|
+
import { _getAdapter, closeDatabase, openDatabase } from '../gsd-db.ts';
|
|
5
5
|
import { createMemory, supersedeMemory } from '../memory-store.ts';
|
|
6
6
|
import {
|
|
7
7
|
executeGsdGraph,
|
|
@@ -293,3 +293,35 @@ test('memory-tools: gsd_graph errors when DB is closed', () => {
|
|
|
293
293
|
assert.ok(result.isError);
|
|
294
294
|
assert.equal(result.details.error, 'db_unavailable');
|
|
295
295
|
});
|
|
296
|
+
|
|
297
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
298
|
+
// regression #4967 — capture_thought must surface real SQL errors
|
|
299
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
300
|
+
|
|
301
|
+
test('memory-tools: capture_thought surfaces underlying SQL error (regression #4967)', () => {
|
|
302
|
+
openDatabase(':memory:');
|
|
303
|
+
|
|
304
|
+
// Simulate the real-world failure mode where the memories table is gone.
|
|
305
|
+
// The original bug was a "database disk image is malformed" on the memory
|
|
306
|
+
// store; dropping the table produces a deterministic statement-time SQL
|
|
307
|
+
// error of the same shape — a thrown sqlite error during INSERT.
|
|
308
|
+
const adapter = _getAdapter()!;
|
|
309
|
+
adapter.prepare('DROP TABLE IF EXISTS memory_embeddings').run();
|
|
310
|
+
adapter.prepare('DROP TABLE IF EXISTS memories_fts').run();
|
|
311
|
+
adapter.prepare('DROP TABLE IF EXISTS memories').run();
|
|
312
|
+
|
|
313
|
+
const result = executeMemoryCapture({
|
|
314
|
+
category: 'gotcha',
|
|
315
|
+
content: 'should reveal the real reason',
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
assert.ok(result.isError, 'broken store should produce an error result');
|
|
319
|
+
assert.equal(result.details.operation, 'memory_capture');
|
|
320
|
+
|
|
321
|
+
const err = String(result.details.error ?? '');
|
|
322
|
+
assert.notEqual(err, 'create_failed', 'must not collapse to opaque create_failed');
|
|
323
|
+
assert.ok(err.length > 0, 'error detail must be populated');
|
|
324
|
+
assert.match(err, /memories|no such table/i, 'error must reference the underlying SQL fault');
|
|
325
|
+
|
|
326
|
+
closeDatabase();
|
|
327
|
+
});
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
// gsd-2 / merge-self-branch-guard.test.ts — regression for #5024
|
|
2
|
+
//
|
|
3
|
+
// mergeMilestoneToMain() must fail closed when the resolved integration
|
|
4
|
+
// branch is the same ref as the milestone branch. Stale or corrupt
|
|
5
|
+
// integration metadata (e.g. integrationBranch recorded as "milestone/<MID>")
|
|
6
|
+
// would otherwise let the squash merge resolve to a self-merge: the post-
|
|
7
|
+
// merge no-op safety check (#1792) compares main vs milestone and finds an
|
|
8
|
+
// empty diff (because they're the same ref), so the helper returns success
|
|
9
|
+
// for work that never landed on a distinct integration branch.
|
|
10
|
+
|
|
11
|
+
import test from "node:test";
|
|
12
|
+
import assert from "node:assert/strict";
|
|
13
|
+
import {
|
|
14
|
+
mkdtempSync,
|
|
15
|
+
mkdirSync,
|
|
16
|
+
rmSync,
|
|
17
|
+
existsSync,
|
|
18
|
+
realpathSync,
|
|
19
|
+
writeFileSync,
|
|
20
|
+
} from "node:fs";
|
|
21
|
+
import { join } from "node:path";
|
|
22
|
+
import { tmpdir } from "node:os";
|
|
23
|
+
import { execFileSync } from "node:child_process";
|
|
24
|
+
|
|
25
|
+
import { mergeMilestoneToMain } from "../auto-worktree.ts";
|
|
26
|
+
import { _resetServiceCache } from "../worktree.ts";
|
|
27
|
+
import { _clearGsdRootCache } from "../paths.ts";
|
|
28
|
+
|
|
29
|
+
function git(args: string[], cwd: string): string {
|
|
30
|
+
return execFileSync("git", args, { cwd, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }).trim();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function createTempRepo(): string {
|
|
34
|
+
const dir = realpathSync(mkdtempSync(join(tmpdir(), "merge-self-guard-")));
|
|
35
|
+
git(["init"], dir);
|
|
36
|
+
git(["config", "user.email", "test@test.com"], dir);
|
|
37
|
+
git(["config", "user.name", "Test"], dir);
|
|
38
|
+
writeFileSync(join(dir, "README.md"), "# test\n");
|
|
39
|
+
git(["add", "."], dir);
|
|
40
|
+
git(["commit", "-m", "init"], dir);
|
|
41
|
+
git(["branch", "-M", "main"], dir);
|
|
42
|
+
return dir;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function assertSelfMergeRefIsRejected(recordedIntegrationBranch: string): void {
|
|
46
|
+
const savedCwd = process.cwd();
|
|
47
|
+
let tempDir = "";
|
|
48
|
+
|
|
49
|
+
// Isolate from user's global preferences so prefs.main_branch can't
|
|
50
|
+
// override the corrupt-metadata path under test.
|
|
51
|
+
const originalHome = process.env.HOME;
|
|
52
|
+
const fakeHome = realpathSync(mkdtempSync(join(tmpdir(), "gsd-fake-home-")));
|
|
53
|
+
process.env.HOME = fakeHome;
|
|
54
|
+
_clearGsdRootCache();
|
|
55
|
+
_resetServiceCache();
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
tempDir = createTempRepo();
|
|
59
|
+
|
|
60
|
+
// Plant corrupt integration metadata: integrationBranch points at the
|
|
61
|
+
// milestone branch itself. Commit it so mergeMilestoneToMain's
|
|
62
|
+
// autoCommitDirtyState pre-step has nothing to capture and the
|
|
63
|
+
// postcondition (no new commits) cleanly reflects the guard.
|
|
64
|
+
const msDir = join(tempDir, ".gsd", "milestones", "M001");
|
|
65
|
+
mkdirSync(msDir, { recursive: true });
|
|
66
|
+
writeFileSync(
|
|
67
|
+
join(msDir, "M001-META.json"),
|
|
68
|
+
JSON.stringify({ integrationBranch: recordedIntegrationBranch }),
|
|
69
|
+
);
|
|
70
|
+
git(["add", "."], tempDir);
|
|
71
|
+
git(["commit", "-m", "chore: plant corrupt M001 meta"], tempDir);
|
|
72
|
+
|
|
73
|
+
// Create the milestone branch ref so any pre-guard branch operations
|
|
74
|
+
// wouldn't fail for unrelated reasons.
|
|
75
|
+
git(["branch", "milestone/M001"], tempDir);
|
|
76
|
+
|
|
77
|
+
const mainHeadBefore = git(["rev-parse", "main"], tempDir);
|
|
78
|
+
const milestoneHeadBefore = git(["rev-parse", "milestone/M001"], tempDir);
|
|
79
|
+
|
|
80
|
+
process.chdir(tempDir);
|
|
81
|
+
|
|
82
|
+
assert.throws(
|
|
83
|
+
() => mergeMilestoneToMain(tempDir, "M001", ""),
|
|
84
|
+
(err: unknown) => {
|
|
85
|
+
assert.ok(err instanceof Error, "expected an Error to be thrown");
|
|
86
|
+
assert.match(
|
|
87
|
+
err.message,
|
|
88
|
+
/self-merge|same ref/i,
|
|
89
|
+
"error message should explain the self-merge refusal",
|
|
90
|
+
);
|
|
91
|
+
return true;
|
|
92
|
+
},
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
// Postcondition: neither branch should have been advanced by a merge
|
|
96
|
+
// commit. The guard fires before checkout/merge, so both refs must be
|
|
97
|
+
// unchanged from their pre-call state.
|
|
98
|
+
const mainHeadAfter = git(["rev-parse", "main"], tempDir);
|
|
99
|
+
const milestoneHeadAfter = git(["rev-parse", "milestone/M001"], tempDir);
|
|
100
|
+
assert.equal(mainHeadAfter, mainHeadBefore, "main must not have advanced");
|
|
101
|
+
assert.equal(
|
|
102
|
+
milestoneHeadAfter,
|
|
103
|
+
milestoneHeadBefore,
|
|
104
|
+
"milestone branch must not have advanced",
|
|
105
|
+
);
|
|
106
|
+
} finally {
|
|
107
|
+
process.chdir(savedCwd);
|
|
108
|
+
process.env.HOME = originalHome;
|
|
109
|
+
_clearGsdRootCache();
|
|
110
|
+
_resetServiceCache();
|
|
111
|
+
if (tempDir && existsSync(tempDir)) {
|
|
112
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
113
|
+
}
|
|
114
|
+
rmSync(fakeHome, { recursive: true, force: true });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
test("mergeMilestoneToMain refuses exact milestone branch self-merge metadata (#5024)", () => {
|
|
119
|
+
assertSelfMergeRefIsRejected("milestone/M001");
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
test("mergeMilestoneToMain refuses refs/heads milestone branch self-merge metadata (#5024)", () => {
|
|
123
|
+
assertSelfMergeRefIsRejected("refs/heads/milestone/M001");
|
|
124
|
+
});
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// GSD Extension — Regression test for #4996: ghost milestone ID reuse
|
|
2
|
+
// Verifies that isReusableGhostMilestone correctly identifies reclaim-safe stub dirs,
|
|
3
|
+
// and that nextMilestoneIdReserved (guided-flow) prefers the lowest reusable ghost
|
|
4
|
+
// over max+1. Also covers the race-window regression: a queued DB row must NOT be reused.
|
|
5
|
+
|
|
6
|
+
import { describe, it, beforeEach, afterEach } from "node:test";
|
|
7
|
+
import assert from "node:assert/strict";
|
|
8
|
+
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
import { tmpdir } from "node:os";
|
|
11
|
+
|
|
12
|
+
import { isReusableGhostMilestone } from "../state.ts";
|
|
13
|
+
import { nextMilestoneIdReserved } from "../milestone-id-reservation.ts";
|
|
14
|
+
import {
|
|
15
|
+
openDatabase,
|
|
16
|
+
closeDatabase,
|
|
17
|
+
insertMilestone,
|
|
18
|
+
} from "../gsd-db.ts";
|
|
19
|
+
import { clearReservedMilestoneIds, findMilestoneIds } from "../milestone-ids.ts";
|
|
20
|
+
import { invalidateAllCaches } from "../cache.ts";
|
|
21
|
+
|
|
22
|
+
function makeBase(prefix = "gsd-gap-4996-"): string {
|
|
23
|
+
const base = mkdtempSync(join(tmpdir(), prefix));
|
|
24
|
+
mkdirSync(join(base, ".gsd", "milestones"), { recursive: true });
|
|
25
|
+
return base;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function stubDir(base: string, mid: string): void {
|
|
29
|
+
// Create an empty stub — the phantom pattern
|
|
30
|
+
mkdirSync(join(base, ".gsd", "milestones", mid, "slices"), { recursive: true });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function populateDir(base: string, mid: string): void {
|
|
34
|
+
mkdirSync(join(base, ".gsd", "milestones", mid), { recursive: true });
|
|
35
|
+
writeFileSync(join(base, ".gsd", "milestones", mid, `${mid}-CONTEXT.md`), `# ${mid} Context\n`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
describe("isReusableGhostMilestone (#4996)", () => {
|
|
39
|
+
let base: string;
|
|
40
|
+
|
|
41
|
+
afterEach(() => {
|
|
42
|
+
try { closeDatabase(); } catch { /* ignore */ }
|
|
43
|
+
try { invalidateAllCaches(); } catch { /* ignore */ }
|
|
44
|
+
try { rmSync(base, { recursive: true, force: true }); } catch { /* ignore */ }
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("(a) fails closed when the DB is unavailable", () => {
|
|
48
|
+
base = makeBase();
|
|
49
|
+
stubDir(base, "M003");
|
|
50
|
+
assert.equal(isReusableGhostMilestone(base, "M003"), false, "closed DB should block reusable-ghost claims");
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("(b) empty stub dir with an open DB and no DB row is reusable", () => {
|
|
54
|
+
base = makeBase();
|
|
55
|
+
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
56
|
+
stubDir(base, "M003");
|
|
57
|
+
assert.ok(isReusableGhostMilestone(base, "M003"), "empty stub with no DB row should be reusable");
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("(c) queued DB row with no content must NOT be reusable (race window regression)", () => {
|
|
61
|
+
base = makeBase();
|
|
62
|
+
stubDir(base, "M003");
|
|
63
|
+
const dbPath = join(base, ".gsd", "gsd.db");
|
|
64
|
+
openDatabase(dbPath);
|
|
65
|
+
insertMilestone({ id: "M003", status: "queued" });
|
|
66
|
+
// Even though no content files exist, the queued DB row means an in-flight discuss
|
|
67
|
+
// is reserving this ID — it must not be reclaimed.
|
|
68
|
+
assert.ok(!isReusableGhostMilestone(base, "M003"), "queued DB row must block reuse");
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("(d) populated milestone dir is not reusable", () => {
|
|
72
|
+
base = makeBase();
|
|
73
|
+
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
74
|
+
populateDir(base, "M001");
|
|
75
|
+
assert.ok(!isReusableGhostMilestone(base, "M001"), "populated dir must not be reusable");
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("(e) stub dir with worktree is not reusable (legitimate in-flight)", () => {
|
|
79
|
+
base = makeBase();
|
|
80
|
+
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
81
|
+
stubDir(base, "M003");
|
|
82
|
+
// Simulate an existing worktree
|
|
83
|
+
mkdirSync(join(base, ".gsd", "worktrees", "M003"), { recursive: true });
|
|
84
|
+
assert.ok(!isReusableGhostMilestone(base, "M003"), "dir with worktree must not be reusable");
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("(f) active DB row makes dir not reusable", () => {
|
|
88
|
+
base = makeBase();
|
|
89
|
+
stubDir(base, "M003");
|
|
90
|
+
const dbPath = join(base, ".gsd", "gsd.db");
|
|
91
|
+
openDatabase(dbPath);
|
|
92
|
+
insertMilestone({ id: "M003", status: "active" });
|
|
93
|
+
assert.ok(!isReusableGhostMilestone(base, "M003"), "active DB row must block reuse");
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
describe("primary regression: M003/M004 stubs returned as next ID (#4996)", () => {
|
|
98
|
+
let base: string;
|
|
99
|
+
|
|
100
|
+
beforeEach(() => {
|
|
101
|
+
clearReservedMilestoneIds();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
afterEach(() => {
|
|
105
|
+
try { closeDatabase(); } catch { /* ignore */ }
|
|
106
|
+
try { invalidateAllCaches(); } catch { /* ignore */ }
|
|
107
|
+
try { clearReservedMilestoneIds(); } catch { /* ignore */ }
|
|
108
|
+
try { rmSync(base, { recursive: true, force: true }); } catch { /* ignore */ }
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it("M001/M002 populated + M003/M004 stubs → isReusableGhostMilestone returns true for M003 and M004", () => {
|
|
112
|
+
base = makeBase();
|
|
113
|
+
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
114
|
+
populateDir(base, "M001");
|
|
115
|
+
populateDir(base, "M002");
|
|
116
|
+
stubDir(base, "M003");
|
|
117
|
+
stubDir(base, "M004");
|
|
118
|
+
|
|
119
|
+
assert.ok(isReusableGhostMilestone(base, "M003"), "M003 should be identified as reusable ghost");
|
|
120
|
+
assert.ok(isReusableGhostMilestone(base, "M004"), "M004 should be identified as reusable ghost");
|
|
121
|
+
assert.ok(!isReusableGhostMilestone(base, "M001"), "M001 should not be reusable");
|
|
122
|
+
assert.ok(!isReusableGhostMilestone(base, "M002"), "M002 should not be reusable");
|
|
123
|
+
|
|
124
|
+
const nextId = nextMilestoneIdReserved(findMilestoneIds(base), false, base);
|
|
125
|
+
assert.equal(nextId, "M003", "ID reservation should select the lowest reusable ghost");
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("when all dirs are populated, no ghost exists and the function returns false for all", () => {
|
|
129
|
+
base = makeBase();
|
|
130
|
+
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
131
|
+
populateDir(base, "M001");
|
|
132
|
+
populateDir(base, "M002");
|
|
133
|
+
|
|
134
|
+
assert.ok(!isReusableGhostMilestone(base, "M001"), "M001 is populated, not reusable");
|
|
135
|
+
assert.ok(!isReusableGhostMilestone(base, "M002"), "M002 is populated, not reusable");
|
|
136
|
+
|
|
137
|
+
const nextId = nextMilestoneIdReserved(findMilestoneIds(base), false, base);
|
|
138
|
+
assert.equal(nextId, "M003", "ID reservation should fall back to max+1 when no ghost is reusable");
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it("does not return an already-reserved reusable ghost twice", () => {
|
|
142
|
+
base = makeBase();
|
|
143
|
+
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
144
|
+
stubDir(base, "M001");
|
|
145
|
+
|
|
146
|
+
const firstId = nextMilestoneIdReserved(findMilestoneIds(base), false, base);
|
|
147
|
+
const secondId = nextMilestoneIdReserved(findMilestoneIds(base), false, base);
|
|
148
|
+
|
|
149
|
+
assert.equal(firstId, "M001", "first reservation should reuse the ghost");
|
|
150
|
+
assert.equal(secondId, "M002", "second reservation must skip the already-reserved ghost");
|
|
151
|
+
});
|
|
152
|
+
});
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import { describe, test } from "node:test";
|
|
11
11
|
import assert from "node:assert/strict";
|
|
12
12
|
|
|
13
|
-
import { _resolveReportBasePath } from "../auto/phases.ts";
|
|
13
|
+
import { _resolveDispatchGuardBasePath, _resolveReportBasePath } from "../auto/phases.ts";
|
|
14
14
|
|
|
15
15
|
describe("_resolveReportBasePath", () => {
|
|
16
16
|
test("uses originalBasePath when set (worktree scenario)", () => {
|
|
@@ -48,4 +48,21 @@ describe("_resolveReportBasePath", () => {
|
|
|
48
48
|
|
|
49
49
|
assert.equal(_resolveReportBasePath(session), "/home/user/repo");
|
|
50
50
|
});
|
|
51
|
+
|
|
52
|
+
test("uses GSD_PROJECT_ROOT for symlink-resolved worktree paths", () => {
|
|
53
|
+
const savedProjectRoot = process.env.GSD_PROJECT_ROOT;
|
|
54
|
+
process.env.GSD_PROJECT_ROOT = "/real/project";
|
|
55
|
+
try {
|
|
56
|
+
const session = {
|
|
57
|
+
originalBasePath: "",
|
|
58
|
+
basePath: "/Users/dev/.gsd/projects/abc123/worktrees/M001/slices/S01",
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
assert.equal(_resolveReportBasePath(session), "/real/project");
|
|
62
|
+
assert.equal(_resolveDispatchGuardBasePath(session), "/real/project");
|
|
63
|
+
} finally {
|
|
64
|
+
if (savedProjectRoot === undefined) delete process.env.GSD_PROJECT_ROOT;
|
|
65
|
+
else process.env.GSD_PROJECT_ROOT = savedProjectRoot;
|
|
66
|
+
}
|
|
67
|
+
});
|
|
51
68
|
});
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
resolveModelForComplexity,
|
|
6
6
|
escalateTier,
|
|
7
7
|
defaultRoutingConfig,
|
|
8
|
+
resolveModelForTier,
|
|
8
9
|
scoreModel,
|
|
9
10
|
computeTaskRequirements,
|
|
10
11
|
scoreEligibleModels,
|
|
@@ -248,6 +249,172 @@ test("#2192: known model is still downgraded normally", () => {
|
|
|
248
249
|
assert.notEqual(result.modelId, "claude-opus-4-6");
|
|
249
250
|
});
|
|
250
251
|
|
|
252
|
+
// ─── Cross-provider fallback ──────────────────────────────────────────────────
|
|
253
|
+
|
|
254
|
+
test("uses cross-provider equivalent when configured primary is unavailable", () => {
|
|
255
|
+
const config = { ...defaultRoutingConfig(), enabled: true };
|
|
256
|
+
// Profile default says claude-opus-4-6 for planning, but user is on GPT only
|
|
257
|
+
const result = resolveModelForComplexity(
|
|
258
|
+
makeClassification("heavy"),
|
|
259
|
+
{ primary: "claude-opus-4-6", fallbacks: [] },
|
|
260
|
+
config,
|
|
261
|
+
["gpt-4o", "gpt-4o-mini", "o1"],
|
|
262
|
+
);
|
|
263
|
+
// o1 is the heavy-tier GPT model — should be selected as cross-provider equivalent
|
|
264
|
+
assert.equal(result.modelId, "o1");
|
|
265
|
+
assert.equal(result.wasDowngraded, false);
|
|
266
|
+
assert.match(result.reason, /cross-provider/);
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
test("cross-provider: selects standard-tier equivalent when primary unavailable", () => {
|
|
270
|
+
const config = { ...defaultRoutingConfig(), enabled: true };
|
|
271
|
+
// Planning configured with Opus, but only GPT standard models available
|
|
272
|
+
const result = resolveModelForComplexity(
|
|
273
|
+
makeClassification("heavy"),
|
|
274
|
+
{ primary: "claude-opus-4-6", fallbacks: [] },
|
|
275
|
+
config,
|
|
276
|
+
["gpt-4o", "gpt-4o-mini"],
|
|
277
|
+
);
|
|
278
|
+
// gpt-4o is standard tier, not heavy — no heavy-tier model available
|
|
279
|
+
// Should fall back to gpt-4o (best available)
|
|
280
|
+
assert.ok(result.modelId === "gpt-4o" || result.modelId === "claude-opus-4-6");
|
|
281
|
+
assert.equal(result.wasDowngraded, false);
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
test("cross-provider: configured primary available by bare ID wins over equivalent", () => {
|
|
285
|
+
const config = { ...defaultRoutingConfig(), enabled: true };
|
|
286
|
+
// Provider-prefixed ID — bare match should find it
|
|
287
|
+
const result = resolveModelForComplexity(
|
|
288
|
+
makeClassification("heavy"),
|
|
289
|
+
{ primary: "claude-opus-4-6", fallbacks: [] },
|
|
290
|
+
config,
|
|
291
|
+
["anthropic/claude-opus-4-6", "o1"],
|
|
292
|
+
);
|
|
293
|
+
assert.equal(result.modelId, "claude-opus-4-6");
|
|
294
|
+
assert.equal(result.wasDowngraded, false);
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
// ─── resolveModelForTier (provider-agnostic tier resolution) ────────────────
|
|
298
|
+
|
|
299
|
+
test("resolveModelForTier: returns canonical Anthropic model when no available models", () => {
|
|
300
|
+
assert.equal(resolveModelForTier("heavy", []), "claude-opus-4-6");
|
|
301
|
+
assert.equal(resolveModelForTier("standard", []), "claude-sonnet-4-6");
|
|
302
|
+
assert.equal(resolveModelForTier("light", []), "claude-haiku-4-5");
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
test("resolveModelForTier: returns canonical model when it is available", () => {
|
|
306
|
+
assert.equal(
|
|
307
|
+
resolveModelForTier("heavy", ["claude-opus-4-6", "claude-sonnet-4-6"]),
|
|
308
|
+
"claude-opus-4-6",
|
|
309
|
+
);
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
test("resolveModelForTier: does not prefer canonical over cheaper same-tier model", () => {
|
|
313
|
+
const result = resolveModelForTier("light", ["claude-haiku-4-5", "gpt-4o-mini"]);
|
|
314
|
+
assert.equal(result, "gpt-4o-mini");
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
test("resolveModelForTier: honors configured tier_models pins", () => {
|
|
318
|
+
const config: DynamicRoutingConfig = {
|
|
319
|
+
...defaultRoutingConfig(),
|
|
320
|
+
tier_models: { light: "claude-haiku-4-5" },
|
|
321
|
+
};
|
|
322
|
+
const result = resolveModelForTier("light", ["claude-haiku-4-5", "gpt-4o-mini"], config);
|
|
323
|
+
assert.equal(result, "claude-haiku-4-5");
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
test("resolveModelForTier: picks cross-provider equivalent when Anthropic unavailable", () => {
|
|
327
|
+
// Only OpenAI models available
|
|
328
|
+
const result = resolveModelForTier("heavy", ["gpt-4o", "gpt-4o-mini", "o1"]);
|
|
329
|
+
// o1 is the heavy-tier model in the OpenAI lineup
|
|
330
|
+
assert.equal(result, "o1");
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
test("resolveModelForTier: picks standard-tier cross-provider model", () => {
|
|
334
|
+
const result = resolveModelForTier("standard", ["gpt-4o", "gpt-4o-mini"]);
|
|
335
|
+
assert.equal(result, "gpt-4o");
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
test("resolveModelForTier: picks light-tier cross-provider model", () => {
|
|
339
|
+
const result = resolveModelForTier("light", ["gpt-4o", "gpt-4o-mini"]);
|
|
340
|
+
assert.equal(result, "gpt-4o-mini");
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
test("resolveModelForTier: falls back to canonical when no tier match available", () => {
|
|
344
|
+
// Only unknown models available — getModelTier classifies unknowns as
|
|
345
|
+
// "standard", so a request for "heavy" finds no match and the canonical
|
|
346
|
+
// Anthropic ID is returned as a documented fallback.
|
|
347
|
+
const result = resolveModelForTier("heavy", ["some-custom-model"]);
|
|
348
|
+
assert.equal(result, "claude-opus-4-6");
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
test("resolveModelForTier: handles provider-prefixed available models", () => {
|
|
352
|
+
const result = resolveModelForTier("heavy", ["anthropic/claude-opus-4-6"]);
|
|
353
|
+
assert.equal(result, "claude-opus-4-6");
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
test("resolveModelForTier: picks Gemini models when only Google available", () => {
|
|
357
|
+
const result = resolveModelForTier("light", ["gemini-2.5-pro", "gemini-2.0-flash"]);
|
|
358
|
+
assert.equal(result, "gemini-2.0-flash");
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
// ─── Behavioral: profile defaults are provider-agnostic at runtime ──────────
|
|
362
|
+
|
|
363
|
+
test("resolveProfileDefaults: balanced with only OpenAI models returns OpenAI IDs", async () => {
|
|
364
|
+
const { resolveProfileDefaults } = await import("../preferences-models.js");
|
|
365
|
+
const defaults = resolveProfileDefaults("balanced", ["gpt-4o", "gpt-4o-mini"]);
|
|
366
|
+
assert.ok(defaults.models, "balanced should populate models");
|
|
367
|
+
// All slots must resolve to an available OpenAI ID — not a claude- canonical.
|
|
368
|
+
for (const [phase, modelId] of Object.entries(defaults.models!)) {
|
|
369
|
+
assert.ok(typeof modelId === "string" && modelId.length > 0, `${phase} should resolve to a model ID`);
|
|
370
|
+
assert.ok(
|
|
371
|
+
!String(modelId).startsWith("claude-"),
|
|
372
|
+
`${phase} resolved to ${modelId} but no claude-* model is available — should be OpenAI`,
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
test("resolveProfileDefaults: budget with only OpenAI models picks gpt-4o-mini for light slots", async () => {
|
|
378
|
+
const { resolveProfileDefaults } = await import("../preferences-models.js");
|
|
379
|
+
const defaults = resolveProfileDefaults("budget", ["gpt-4o", "gpt-4o-mini"]);
|
|
380
|
+
// light-tier slots in budget: research, execution_simple, completion, subagent
|
|
381
|
+
assert.equal(defaults.models?.research, "gpt-4o-mini");
|
|
382
|
+
assert.equal(defaults.models?.execution_simple, "gpt-4o-mini");
|
|
383
|
+
assert.equal(defaults.models?.completion, "gpt-4o-mini");
|
|
384
|
+
assert.equal(defaults.models?.subagent, "gpt-4o-mini");
|
|
385
|
+
// standard-tier slots: planning, execution
|
|
386
|
+
assert.equal(defaults.models?.planning, "gpt-4o");
|
|
387
|
+
assert.equal(defaults.models?.execution, "gpt-4o");
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
test("resolveProfileDefaults: honors dynamic routing tier_models pins", async () => {
|
|
391
|
+
const { resolveProfileDefaults } = await import("../preferences-models.js");
|
|
392
|
+
const defaults = resolveProfileDefaults(
|
|
393
|
+
"budget",
|
|
394
|
+
["claude-haiku-4-5", "gpt-4o-mini", "gpt-4o"],
|
|
395
|
+
{ ...defaultRoutingConfig(), tier_models: { light: "claude-haiku-4-5" } },
|
|
396
|
+
);
|
|
397
|
+
assert.equal(defaults.models?.research, "claude-haiku-4-5");
|
|
398
|
+
assert.equal(defaults.models?.execution_simple, "claude-haiku-4-5");
|
|
399
|
+
assert.equal(defaults.models?.completion, "claude-haiku-4-5");
|
|
400
|
+
assert.equal(defaults.models?.subagent, "claude-haiku-4-5");
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
test("resolveProfileDefaults: empty availableModelIds falls back to canonical Anthropic IDs", async () => {
|
|
404
|
+
const { resolveProfileDefaults } = await import("../preferences-models.js");
|
|
405
|
+
const defaults = resolveProfileDefaults("balanced", []);
|
|
406
|
+
// Documented fallback only — when registry is unavailable at bootstrap.
|
|
407
|
+
const planningModel = defaults.models?.planning;
|
|
408
|
+
assert.ok(typeof planningModel === "string" && planningModel.startsWith("claude-"));
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
test("resolveProfileDefaults: burn-max omits models so user choice is preserved", async () => {
|
|
412
|
+
const { resolveProfileDefaults } = await import("../preferences-models.js");
|
|
413
|
+
const defaults = resolveProfileDefaults("burn-max", ["gpt-4o"]);
|
|
414
|
+
assert.equal(defaults.models, undefined, "burn-max must not write model defaults");
|
|
415
|
+
assert.equal(defaults.dynamic_routing?.enabled, false);
|
|
416
|
+
});
|
|
417
|
+
|
|
251
418
|
// ─── Capability Scoring (ADR-004 Phase 2) ───────────────────────────────────
|
|
252
419
|
|
|
253
420
|
test("defaultRoutingConfig includes capability_routing: true", () => {
|
|
@@ -279,14 +446,8 @@ test("scoreModel computes weighted average of capability × requirement", () =>
|
|
|
279
446
|
assert.ok(Math.abs(score - 88.21) < 0.1, `score ${score} should be ~88.21`);
|
|
280
447
|
});
|
|
281
448
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
coding: 90, debugging: 80, research: 70,
|
|
285
|
-
reasoning: 85, speed: 50, longContext: 60, instruction: 75,
|
|
286
|
-
};
|
|
287
|
-
const score = scoreModel(caps, {});
|
|
288
|
-
assert.equal(score, 50);
|
|
289
|
-
});
|
|
449
|
+
// (Removed duplicate "scoreModel returns 50 for empty requirements" — the
|
|
450
|
+
// `describe("scoreModel")` block below has the same scenario.)
|
|
290
451
|
|
|
291
452
|
test("computeTaskRequirements returns base vector for known unit type", () => {
|
|
292
453
|
const reqs = computeTaskRequirements("execute-task");
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { chmodSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
|
|
7
|
+
import { git } from "./test-utils.ts";
|
|
8
|
+
import { GSD_GIT_ERROR } from "../errors.js";
|
|
9
|
+
|
|
10
|
+
test("nativeAddAllWithExclusions preserves infrastructure failures from git add", async () => {
|
|
11
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-native-git-infra-"));
|
|
12
|
+
const repo = join(base, "repo");
|
|
13
|
+
const bin = join(base, "bin");
|
|
14
|
+
mkdirSync(repo);
|
|
15
|
+
mkdirSync(bin);
|
|
16
|
+
|
|
17
|
+
const fakeGit = join(bin, "git");
|
|
18
|
+
writeFileSync(
|
|
19
|
+
fakeGit,
|
|
20
|
+
"#!/bin/sh\n" +
|
|
21
|
+
"echo 'fatal: ENFILE: file table overflow' >&2\n" +
|
|
22
|
+
"exit 1\n",
|
|
23
|
+
"utf-8",
|
|
24
|
+
);
|
|
25
|
+
chmodSync(fakeGit, 0o755);
|
|
26
|
+
|
|
27
|
+
const originalPath = process.env.PATH ?? "";
|
|
28
|
+
try {
|
|
29
|
+
git(repo, "init");
|
|
30
|
+
git(repo, "config", "user.email", "test@example.com");
|
|
31
|
+
git(repo, "config", "user.name", "Test User");
|
|
32
|
+
writeFileSync(join(repo, "README.md"), "# Test\n", "utf-8");
|
|
33
|
+
|
|
34
|
+
process.env.PATH = `${bin}:${originalPath}`;
|
|
35
|
+
const { nativeAddAllWithExclusions } = await import("../native-git-bridge.ts");
|
|
36
|
+
|
|
37
|
+
assert.throws(
|
|
38
|
+
() => nativeAddAllWithExclusions(repo, [".gsd/activity/"]),
|
|
39
|
+
(err) => {
|
|
40
|
+
const shaped = err as { code?: string; stderr?: string; message?: string };
|
|
41
|
+
assert.notEqual(shaped.code, GSD_GIT_ERROR);
|
|
42
|
+
assert.match(`${shaped.stderr ?? ""}${shaped.message ?? ""}`, /ENFILE/);
|
|
43
|
+
return true;
|
|
44
|
+
},
|
|
45
|
+
);
|
|
46
|
+
} finally {
|
|
47
|
+
process.env.PATH = originalPath;
|
|
48
|
+
rmSync(base, { recursive: true, force: true });
|
|
49
|
+
}
|
|
50
|
+
});
|
|
@@ -101,6 +101,14 @@ describe("auditOrphanedMilestoneBranches", () => {
|
|
|
101
101
|
result.warnings.some(w => w.includes("NOT merged")),
|
|
102
102
|
"should warn about unmerged branch",
|
|
103
103
|
);
|
|
104
|
+
assert.ok(
|
|
105
|
+
result.warnings.some(w => w.includes("/gsd doctor fix")),
|
|
106
|
+
`warning should suggest the real remediation command; got: ${JSON.stringify(result.warnings)}`,
|
|
107
|
+
);
|
|
108
|
+
assert.ok(
|
|
109
|
+
result.warnings.every(w => !w.includes("/gsd health --fix")),
|
|
110
|
+
`warning must not suggest the removed health --fix command; got: ${JSON.stringify(result.warnings)}`,
|
|
111
|
+
);
|
|
104
112
|
|
|
105
113
|
// Branch should still exist (data safety)
|
|
106
114
|
const branches = run("git branch --list milestone/M001", dir);
|