gsd-pi 2.78.0 → 2.78.1-dev.8a893322c
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 +60 -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/google-search/index.js +2 -6
- 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 +112 -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 +45 -8
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +121 -3
- package/dist/resources/extensions/gsd/commands/catalog.js +76 -5
- package/dist/resources/extensions/gsd/commands/handlers/core.js +23 -1
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +8 -0
- 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/commands-worktree.js +309 -0
- 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 -9
- 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 +15 -15
- 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 +15 -15
- 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/welcome-screen.js +27 -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/google-search/index.ts +2 -9
- 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 +121 -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 +50 -8
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +141 -11
- package/src/resources/extensions/gsd/commands/catalog.ts +82 -5
- package/src/resources/extensions/gsd/commands/handlers/core.ts +23 -1
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +10 -0
- 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/commands-worktree.ts +383 -0
- 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/bundled-skill-triggers.test.ts +50 -27
- package/src/resources/extensions/gsd/tests/commands-extensions-version-compare.test.ts +58 -0
- package/src/resources/extensions/gsd/tests/commands-worktree-clean.test.ts +48 -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/google-search-stub.test.ts +25 -65
- 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/safety-harness-false-positives.test.ts +34 -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 -10
- 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 → QK8fABiGPmonfTgboN0Y9}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{C1zT2kEfoLhDdbWPWKrXd → QK8fABiGPmonfTgboN0Y9}/_ssgManifest.js +0 -0
|
@@ -12,7 +12,7 @@ import { tmpdir } from "node:os";
|
|
|
12
12
|
import { join } from "node:path";
|
|
13
13
|
|
|
14
14
|
import { mapInitPrefsToWizardShape } from "../init-wizard.ts";
|
|
15
|
-
import { writePreferencesFile } from "../commands-prefs-wizard.ts";
|
|
15
|
+
import { handlePrefsWizard, writePreferencesFile } from "../commands-prefs-wizard.ts";
|
|
16
16
|
|
|
17
17
|
test("mapInitPrefsToWizardShape — full roundtrip with all fields", () => {
|
|
18
18
|
const out = mapInitPrefsToWizardShape({
|
|
@@ -123,6 +123,69 @@ test("writePreferencesFile — falls back to default body for new files", async
|
|
|
123
123
|
}
|
|
124
124
|
});
|
|
125
125
|
|
|
126
|
+
test("handlePrefsWizard — Advanced config writes min_request_interval_ms", async () => {
|
|
127
|
+
const tmp = mkdtempSync(join(tmpdir(), "gsd-init-prefs-routing-"));
|
|
128
|
+
const path = join(tmp, "PREFERENCES.md");
|
|
129
|
+
|
|
130
|
+
try {
|
|
131
|
+
const selectResponses = [
|
|
132
|
+
"Advanced",
|
|
133
|
+
"(keep current)",
|
|
134
|
+
"(keep current)",
|
|
135
|
+
"(keep current)",
|
|
136
|
+
"(keep current)",
|
|
137
|
+
"(keep current)",
|
|
138
|
+
"(keep current)",
|
|
139
|
+
"(keep current)",
|
|
140
|
+
"── Save & Exit ──",
|
|
141
|
+
];
|
|
142
|
+
const inputResponses = ["250"];
|
|
143
|
+
const ctx = {
|
|
144
|
+
ui: {
|
|
145
|
+
notify: () => {},
|
|
146
|
+
select: async (_label: string, options: string[]) => {
|
|
147
|
+
const response = selectResponses.shift();
|
|
148
|
+
if (response === undefined) {
|
|
149
|
+
throw new Error(
|
|
150
|
+
`Unexpected extra select prompt in handlePrefsWizard flow: selectResponses queue exhausted for "${_label}" ` +
|
|
151
|
+
"(expected no additional select prompts)",
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
if (response === "Advanced") {
|
|
155
|
+
const advancedOption = options.find((option) => option.startsWith("Advanced"));
|
|
156
|
+
if (!advancedOption) {
|
|
157
|
+
throw new Error(`Expected an "Advanced" option in "${_label}" menu`);
|
|
158
|
+
}
|
|
159
|
+
return advancedOption;
|
|
160
|
+
}
|
|
161
|
+
return response;
|
|
162
|
+
},
|
|
163
|
+
input: async () => {
|
|
164
|
+
const response = inputResponses.shift();
|
|
165
|
+
if (response === undefined) {
|
|
166
|
+
throw new Error(
|
|
167
|
+
"Unexpected extra input prompt in handlePrefsWizard flow: inputResponses queue exhausted " +
|
|
168
|
+
"(expected no additional input prompts)",
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
return response;
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
waitForIdle: async () => {},
|
|
175
|
+
reload: async () => {},
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
await handlePrefsWizard(ctx as any, "project", {}, { pathOverride: path });
|
|
179
|
+
|
|
180
|
+
assert.equal(selectResponses.length, 0, "Expected all queued selectResponses to be consumed");
|
|
181
|
+
assert.equal(inputResponses.length, 0, "Expected all queued inputResponses to be consumed");
|
|
182
|
+
const content = readFileSync(path, "utf-8");
|
|
183
|
+
assert.match(content, /^min_request_interval_ms:\s*250$/m);
|
|
184
|
+
} finally {
|
|
185
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
|
|
126
189
|
// ─── Regression tests from #4457 codex adversarial review ──────────────────
|
|
127
190
|
|
|
128
191
|
test("init — Step 9b shape: 'not_yet' option is recognized as defer (#4457 review)", async () => {
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { describe, test, afterEach } from "node:test";
|
|
9
9
|
import assert from "node:assert/strict";
|
|
10
|
-
import { mkdtempSync, mkdirSync, writeFileSync, rmSync, existsSync, realpathSync } from "node:fs";
|
|
10
|
+
import { mkdtempSync, mkdirSync, writeFileSync, rmSync, existsSync, realpathSync, symlinkSync } from "node:fs";
|
|
11
11
|
import { join } from "node:path";
|
|
12
12
|
import { tmpdir } from "node:os";
|
|
13
13
|
import { execSync } from "node:child_process";
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
getAutoWorktreeOriginalBase,
|
|
22
22
|
getActiveAutoWorktreeContext,
|
|
23
23
|
syncGsdStateToWorktree,
|
|
24
|
+
_resetAutoWorktreeOriginalBaseForTests,
|
|
24
25
|
} from "../../auto-worktree.ts";
|
|
25
26
|
|
|
26
27
|
// Note: execSync is used intentionally in tests for git operations with
|
|
@@ -142,6 +143,54 @@ describe("auto-worktree lifecycle", () => {
|
|
|
142
143
|
teardownAutoWorktree(tempDir, "M003");
|
|
143
144
|
});
|
|
144
145
|
|
|
146
|
+
test("symlink-resolved auto worktree is detected after module state reset", () => {
|
|
147
|
+
tempDir = createTempRepo();
|
|
148
|
+
const savedGsdHome = process.env.GSD_HOME;
|
|
149
|
+
const fakeHome = realpathSync(mkdtempSync(join(tmpdir(), "auto-wt-home-")));
|
|
150
|
+
const storage = join(fakeHome, ".gsd", "projects", "abc123def456");
|
|
151
|
+
mkdirSync(join(storage, "milestones", "M001"), { recursive: true });
|
|
152
|
+
writeFileSync(join(storage, "milestones", "M001", "CONTEXT.md"), "# M001\n");
|
|
153
|
+
symlinkSync(storage, join(tempDir, ".gsd"));
|
|
154
|
+
process.env.GSD_HOME = join(fakeHome, ".gsd");
|
|
155
|
+
|
|
156
|
+
try {
|
|
157
|
+
const wtPath = createAutoWorktree(tempDir, "M001");
|
|
158
|
+
const realWtPath = realpathSync(wtPath);
|
|
159
|
+
assert.ok(realWtPath.startsWith(storage), "git registered the symlink-resolved worktree path");
|
|
160
|
+
|
|
161
|
+
_resetAutoWorktreeOriginalBaseForTests();
|
|
162
|
+
process.chdir(join(realWtPath, ".gsd", "milestones", "M001"));
|
|
163
|
+
|
|
164
|
+
assert.ok(isInAutoWorktree(tempDir), "structural detection works without module originalBase");
|
|
165
|
+
const resolved = getAutoWorktreePath(realWtPath, "M001");
|
|
166
|
+
assert.ok(resolved, "existing worktree is found when basePath is the worktree path");
|
|
167
|
+
assert.equal(realpathSync(resolved!), realWtPath);
|
|
168
|
+
assert.equal(existsSync(join(realWtPath, ".gsd", "worktrees", "M001")), false);
|
|
169
|
+
|
|
170
|
+
enterAutoWorktree(tempDir, "M001");
|
|
171
|
+
process.chdir(join(realWtPath, ".gsd", "milestones", "M001"));
|
|
172
|
+
assert.deepStrictEqual(
|
|
173
|
+
getActiveAutoWorktreeContext(),
|
|
174
|
+
{
|
|
175
|
+
originalBase: tempDir,
|
|
176
|
+
worktreeName: "M001",
|
|
177
|
+
branch: "milestone/M001",
|
|
178
|
+
},
|
|
179
|
+
"active context is detected from a symlink-resolved worktree cwd",
|
|
180
|
+
);
|
|
181
|
+
} finally {
|
|
182
|
+
process.chdir(tempDir);
|
|
183
|
+
try {
|
|
184
|
+
teardownAutoWorktree(tempDir, "M001");
|
|
185
|
+
} catch {
|
|
186
|
+
// Best-effort cleanup for partially-created temp worktrees.
|
|
187
|
+
}
|
|
188
|
+
if (savedGsdHome === undefined) delete process.env.GSD_HOME;
|
|
189
|
+
else process.env.GSD_HOME = savedGsdHome;
|
|
190
|
+
rmSync(fakeHome, { recursive: true, force: true });
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
|
|
145
194
|
test("coexistence with manual worktree", async () => {
|
|
146
195
|
tempDir = createTempRepo();
|
|
147
196
|
const msDir = join(tempDir, ".gsd", "milestones", "M003");
|
|
@@ -345,4 +394,26 @@ describe("auto-worktree lifecycle", () => {
|
|
|
345
394
|
teardownAutoWorktree(tempDir, "M003");
|
|
346
395
|
}
|
|
347
396
|
});
|
|
397
|
+
|
|
398
|
+
test("#2482: throws GSDError when repo has no commits", () => {
|
|
399
|
+
// Create a bare git init with no commits — HEAD is invalid
|
|
400
|
+
tempDir = realpathSync(mkdtempSync(join(tmpdir(), "auto-wt-empty-")));
|
|
401
|
+
run("git init", tempDir);
|
|
402
|
+
run("git config user.email test@test.com", tempDir);
|
|
403
|
+
run("git config user.name Test", tempDir);
|
|
404
|
+
|
|
405
|
+
assert.throws(
|
|
406
|
+
() => createAutoWorktree(tempDir, "M001"),
|
|
407
|
+
(err: unknown) => {
|
|
408
|
+
assert.ok(err instanceof Error, "should throw an Error");
|
|
409
|
+
assert.ok("code" in err, "should have a code property (GSDError)");
|
|
410
|
+
assert.strictEqual((err as { code: string }).code, "GSD_GIT_ERROR");
|
|
411
|
+
assert.ok(
|
|
412
|
+
err.message.includes("repository has no commits yet"),
|
|
413
|
+
`message should mention no commits, got: ${err.message}`,
|
|
414
|
+
);
|
|
415
|
+
return true;
|
|
416
|
+
},
|
|
417
|
+
);
|
|
418
|
+
});
|
|
348
419
|
});
|
|
@@ -338,27 +338,4 @@ console.log('\n=== token-savings: quality — correct scoping, no cross-contamin
|
|
|
338
338
|
rmSync(base, { recursive: true, force: true });
|
|
339
339
|
}
|
|
340
340
|
|
|
341
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
342
|
-
// Test: Fixture data realism — sufficient volume and distribution
|
|
343
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
344
|
-
|
|
345
|
-
console.log('\n=== token-savings: fixture data realism ===');
|
|
346
|
-
{
|
|
347
|
-
// Verify fixture generators produce sufficient volume
|
|
348
|
-
assert.ok(DECISIONS_COUNT >= 20, `decisions count ≥ 20 (actual: ${DECISIONS_COUNT})`);
|
|
349
|
-
assert.ok(REQUIREMENTS_COUNT >= 20, `requirements count ≥ 20 (actual: ${REQUIREMENTS_COUNT})`);
|
|
350
|
-
assert.ok(MILESTONES.length >= 3, `milestones ≥ 3 (actual: ${MILESTONES.length})`);
|
|
351
|
-
assert.ok(SLICE_ASSIGNMENTS.length >= 5, `slice assignments ≥ 5 (actual: ${SLICE_ASSIGNMENTS.length})`);
|
|
352
|
-
|
|
353
|
-
// Verify markdown content is substantial
|
|
354
|
-
assert.ok(decisionsMarkdown.length > 1000, `decisions markdown > 1000 chars (actual: ${decisionsMarkdown.length})`);
|
|
355
|
-
assert.ok(requirementsMarkdown.length > 1000, `requirements markdown > 1000 chars (actual: ${requirementsMarkdown.length})`);
|
|
356
|
-
|
|
357
|
-
// Verify content structure
|
|
358
|
-
assert.match(decisionsMarkdown, /\| D001 \|/, 'decisions markdown has D001');
|
|
359
|
-
assert.match(decisionsMarkdown, /\| D024 \|/, 'decisions markdown has D024');
|
|
360
|
-
assert.match(requirementsMarkdown, /### R001/, 'requirements markdown has R001');
|
|
361
|
-
assert.match(requirementsMarkdown, /### R021/, 'requirements markdown has R021');
|
|
362
|
-
}
|
|
363
|
-
|
|
364
341
|
// ─── Report ────────────────────────────────────────────────────────────────
|
|
@@ -4,6 +4,11 @@ import {
|
|
|
4
4
|
isDbAvailable,
|
|
5
5
|
_getAdapter,
|
|
6
6
|
} from '../gsd-db.ts';
|
|
7
|
+
import {
|
|
8
|
+
_resetLogs,
|
|
9
|
+
peekLogs,
|
|
10
|
+
setStderrLoggingEnabled,
|
|
11
|
+
} from '../workflow-logger.ts';
|
|
7
12
|
import {
|
|
8
13
|
getActiveMemories,
|
|
9
14
|
getActiveMemoriesRanked,
|
|
@@ -329,3 +334,126 @@ test('memory-store: schema includes memories table', () => {
|
|
|
329
334
|
|
|
330
335
|
closeDatabase();
|
|
331
336
|
});
|
|
337
|
+
|
|
338
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
339
|
+
// regression #4967 — createMemory must not silently swallow SQL errors
|
|
340
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
341
|
+
|
|
342
|
+
test('memory-store: createMemory throws on memory-table SQL errors (regression #4967)', () => {
|
|
343
|
+
openDatabase(':memory:');
|
|
344
|
+
|
|
345
|
+
const adapter = _getAdapter()!;
|
|
346
|
+
// Drop FTS + dependents first to satisfy SQLite's trigger ordering, then
|
|
347
|
+
// the base memories table. IF EXISTS makes setup robust against schema
|
|
348
|
+
// versions that may not have created every dependent (e.g. embeddings).
|
|
349
|
+
adapter.prepare('DROP TABLE IF EXISTS memory_embeddings').run();
|
|
350
|
+
adapter.prepare('DROP TABLE IF EXISTS memories_fts').run();
|
|
351
|
+
adapter.prepare('DROP TABLE IF EXISTS memories').run();
|
|
352
|
+
|
|
353
|
+
// Pre-fix behaviour: returns null and the caller has no idea why.
|
|
354
|
+
// Post-fix behaviour: throws so the caller can surface the real SQL message.
|
|
355
|
+
assert.throws(
|
|
356
|
+
() => createMemory({ category: 'gotcha', content: 'broken store' }),
|
|
357
|
+
/memories|no such table/i,
|
|
358
|
+
'createMemory must surface SQL errors instead of returning null',
|
|
359
|
+
);
|
|
360
|
+
|
|
361
|
+
closeDatabase();
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
test('memory-store: VACUUM retry rolls back partial memory and logs recovery', () => {
|
|
365
|
+
openDatabase(':memory:');
|
|
366
|
+
|
|
367
|
+
const adapter = _getAdapter()!;
|
|
368
|
+
const originalPrepareMethod = adapter.prepare;
|
|
369
|
+
const originalPrepare = adapter.prepare.bind(adapter);
|
|
370
|
+
const previousStderrLogging = setStderrLoggingEnabled(false);
|
|
371
|
+
const streamAny = process.stderr as unknown as {
|
|
372
|
+
write: (chunk: string | Uint8Array, ...rest: unknown[]) => boolean;
|
|
373
|
+
};
|
|
374
|
+
const originalStderrWrite = streamAny.write.bind(streamAny);
|
|
375
|
+
let selectFailures = 0;
|
|
376
|
+
let vacuumRuns = 0;
|
|
377
|
+
_resetLogs();
|
|
378
|
+
|
|
379
|
+
adapter.prepare = ((sql: string) => {
|
|
380
|
+
if (sql === 'SELECT seq FROM memories WHERE id = :id' && selectFailures === 0) {
|
|
381
|
+
const stmt = originalPrepare(sql);
|
|
382
|
+
return {
|
|
383
|
+
run: (...params: unknown[]) => stmt.run(...params),
|
|
384
|
+
get: (..._params: unknown[]) => {
|
|
385
|
+
selectFailures++;
|
|
386
|
+
throw new Error('database disk image is malformed');
|
|
387
|
+
},
|
|
388
|
+
all: (...params: unknown[]) => stmt.all(...params),
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
if (sql === 'VACUUM') {
|
|
393
|
+
const stmt = originalPrepare(sql);
|
|
394
|
+
return {
|
|
395
|
+
run: (...params: unknown[]) => {
|
|
396
|
+
vacuumRuns++;
|
|
397
|
+
return stmt.run(...params);
|
|
398
|
+
},
|
|
399
|
+
get: (...params: unknown[]) => stmt.get(...params),
|
|
400
|
+
all: (...params: unknown[]) => stmt.all(...params),
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
return originalPrepare(sql);
|
|
405
|
+
}) as typeof adapter.prepare;
|
|
406
|
+
streamAny.write = (): boolean => true;
|
|
407
|
+
|
|
408
|
+
try {
|
|
409
|
+
const id = createMemory({ category: 'gotcha', content: 'recover without duplicate' });
|
|
410
|
+
assert.equal(id, 'MEM001', 'retry should create a single first memory');
|
|
411
|
+
|
|
412
|
+
const rows = adapter.prepare('SELECT id FROM memories ORDER BY seq').all();
|
|
413
|
+
assert.deepStrictEqual(
|
|
414
|
+
rows.map((row) => row['id']),
|
|
415
|
+
['MEM001'],
|
|
416
|
+
'failed first attempt should not leave a live _TMP_ memory behind',
|
|
417
|
+
);
|
|
418
|
+
assert.equal(selectFailures, 1, 'test should simulate one malformed SELECT after INSERT');
|
|
419
|
+
assert.equal(vacuumRuns, 1, 'malformed recovery should run VACUUM once');
|
|
420
|
+
assert.ok(
|
|
421
|
+
peekLogs().some((entry) =>
|
|
422
|
+
entry.component === 'memory-store' &&
|
|
423
|
+
entry.message === 'recovered malformed memory store via VACUUM'
|
|
424
|
+
),
|
|
425
|
+
'successful VACUUM recovery should be emitted to the workflow logger',
|
|
426
|
+
);
|
|
427
|
+
} finally {
|
|
428
|
+
adapter.prepare = originalPrepareMethod;
|
|
429
|
+
streamAny.write = originalStderrWrite;
|
|
430
|
+
setStderrLoggingEnabled(previousStderrLogging);
|
|
431
|
+
_resetLogs();
|
|
432
|
+
closeDatabase();
|
|
433
|
+
}
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
test('memory-store: applyMemoryActions stays non-fatal when memory store is broken (regression #4967)', () => {
|
|
437
|
+
openDatabase(':memory:');
|
|
438
|
+
|
|
439
|
+
const adapter = _getAdapter()!;
|
|
440
|
+
// Drop FTS + dependents first to satisfy SQLite's trigger ordering, then
|
|
441
|
+
// the base memories table. IF EXISTS makes setup robust against schema
|
|
442
|
+
// versions that may not have created every dependent (e.g. embeddings).
|
|
443
|
+
adapter.prepare('DROP TABLE IF EXISTS memory_embeddings').run();
|
|
444
|
+
adapter.prepare('DROP TABLE IF EXISTS memories_fts').run();
|
|
445
|
+
adapter.prepare('DROP TABLE IF EXISTS memories').run();
|
|
446
|
+
|
|
447
|
+
// applyMemoryActions wraps createMemory in a transaction with an outer
|
|
448
|
+
// catch. Even with createMemory now throwing, applyMemoryActions must not
|
|
449
|
+
// crash the auto-mode flow that calls it (memory extraction is best-effort).
|
|
450
|
+
const actions: MemoryAction[] = [
|
|
451
|
+
{ action: 'CREATE', category: 'gotcha', content: 'inside-transaction call' },
|
|
452
|
+
];
|
|
453
|
+
assert.doesNotThrow(
|
|
454
|
+
() => applyMemoryActions(actions),
|
|
455
|
+
'applyMemoryActions must absorb thrown errors so callers continue',
|
|
456
|
+
);
|
|
457
|
+
|
|
458
|
+
closeDatabase();
|
|
459
|
+
});
|
|
@@ -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
|
+
});
|