gsd-pi 2.57.0 → 2.58.0-dev.778d6ac
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 +1 -1
- package/dist/cli.js +49 -35
- package/dist/headless-ui.d.ts +17 -0
- package/dist/headless-ui.js +97 -3
- package/dist/headless.js +67 -6
- package/dist/help-text.js +1 -0
- package/dist/onboarding.js +44 -0
- package/dist/resource-loader.js +16 -1
- package/dist/resources/agents/researcher.md +1 -1
- package/dist/resources/extensions/ask-user-questions.js +16 -3
- package/dist/resources/extensions/async-jobs/extension-manifest.json +1 -1
- package/dist/resources/extensions/bg-shell/extension-manifest.json +1 -1
- package/dist/resources/extensions/browser-tools/extension-manifest.json +1 -1
- package/dist/resources/extensions/claude-code-cli/partial-builder.js +14 -6
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +59 -36
- package/dist/resources/extensions/context7/extension-manifest.json +1 -1
- package/dist/resources/extensions/get-secrets-from-user.js +8 -5
- package/dist/resources/extensions/google-search/extension-manifest.json +1 -1
- package/dist/resources/extensions/google-search/index.js +2 -1
- package/dist/resources/extensions/gsd/auto/infra-errors.js +4 -0
- package/dist/resources/extensions/gsd/auto/phases.js +25 -21
- package/dist/resources/extensions/gsd/auto-artifact-paths.js +2 -2
- package/dist/resources/extensions/gsd/auto-dashboard.js +37 -20
- package/dist/resources/extensions/gsd/auto-dispatch.js +20 -5
- package/dist/resources/extensions/gsd/auto-model-selection.js +26 -3
- package/dist/resources/extensions/gsd/auto-post-unit.js +16 -4
- package/dist/resources/extensions/gsd/auto-prompts.js +1 -1
- package/dist/resources/extensions/gsd/auto-recovery.js +13 -5
- package/dist/resources/extensions/gsd/auto-start.js +35 -22
- package/dist/resources/extensions/gsd/auto-worktree.js +203 -14
- package/dist/resources/extensions/gsd/auto.js +4 -0
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +32 -0
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +82 -9
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +32 -1
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +33 -18
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +44 -11
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +67 -0
- package/dist/resources/extensions/gsd/captures.js +56 -4
- package/dist/resources/extensions/gsd/db-writer.js +116 -8
- package/dist/resources/extensions/gsd/dispatch-guard.js +11 -1
- package/dist/resources/extensions/gsd/doctor-git-checks.js +28 -0
- package/dist/resources/extensions/gsd/doctor-providers.js +2 -1
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +5 -4
- package/dist/resources/extensions/gsd/doctor.js +3 -1
- package/dist/resources/extensions/gsd/error-classifier.js +13 -10
- package/dist/resources/extensions/gsd/extension-manifest.json +16 -1
- package/dist/resources/extensions/gsd/forensics.js +123 -20
- package/dist/resources/extensions/gsd/git-service.js +23 -1
- package/dist/resources/extensions/gsd/gitignore.js +33 -0
- package/dist/resources/extensions/gsd/gsd-db.js +44 -10
- package/dist/resources/extensions/gsd/guided-flow.js +106 -44
- package/dist/resources/extensions/gsd/health-widget-core.js +31 -0
- package/dist/resources/extensions/gsd/health-widget.js +17 -0
- package/dist/resources/extensions/gsd/index.js +1 -1
- package/dist/resources/extensions/gsd/memory-extractor.js +7 -0
- package/dist/resources/extensions/gsd/migrate-external.js +8 -1
- package/dist/resources/extensions/gsd/milestone-validation-gates.js +45 -0
- package/dist/resources/extensions/gsd/model-cost-table.js +18 -0
- package/dist/resources/extensions/gsd/model-router.js +35 -1
- package/dist/resources/extensions/gsd/native-git-bridge.js +17 -0
- package/dist/resources/extensions/gsd/notifications.js +16 -1
- package/dist/resources/extensions/gsd/parallel-eligibility.js +13 -2
- package/dist/resources/extensions/gsd/parallel-merge.js +78 -5
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +23 -6
- package/dist/resources/extensions/gsd/parsers-legacy.js +20 -3
- package/dist/resources/extensions/gsd/paths.js +43 -0
- package/dist/resources/extensions/gsd/preferences-models.js +14 -1
- package/dist/resources/extensions/gsd/preferences-types.js +2 -1
- package/dist/resources/extensions/gsd/preferences.js +42 -31
- package/dist/resources/extensions/gsd/prompt-loader.js +4 -1
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +4 -2
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +1 -1
- package/dist/resources/extensions/gsd/prompts/discuss.md +1 -1
- package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -1
- package/dist/resources/extensions/gsd/prompts/forensics.md +2 -2
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +2 -0
- package/dist/resources/extensions/gsd/prompts/rethink.md +1 -1
- package/dist/resources/extensions/gsd/prompts/triage-captures.md +1 -0
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
- package/dist/resources/extensions/gsd/repo-identity.js +205 -11
- package/dist/resources/extensions/gsd/rethink.js +5 -0
- package/dist/resources/extensions/gsd/roadmap-slices.js +5 -4
- package/dist/resources/extensions/gsd/state.js +85 -27
- package/dist/resources/extensions/gsd/tests/dist-redirect.mjs +20 -1
- package/dist/resources/extensions/gsd/tools/complete-task.js +34 -71
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +12 -2
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +29 -1
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +18 -3
- package/dist/resources/extensions/gsd/triage-resolution.js +22 -7
- package/dist/resources/extensions/gsd/undo.js +2 -2
- package/dist/resources/extensions/gsd/unit-ownership.js +164 -33
- package/dist/resources/extensions/gsd/verdict-parser.js +20 -8
- package/dist/resources/extensions/gsd/workflow-manifest.js +24 -5
- package/dist/resources/extensions/gsd/workflow-projections.js +95 -63
- package/dist/resources/extensions/gsd/workflow-reconcile.js +35 -5
- package/dist/resources/extensions/gsd/workspace-index.js +24 -0
- package/dist/resources/extensions/gsd/worktree-manager.js +105 -1
- package/dist/resources/extensions/gsd/worktree-resolver.js +20 -3
- package/dist/resources/extensions/mcp-client/index.js +11 -7
- package/dist/resources/extensions/ollama/index.js +112 -0
- package/dist/resources/extensions/ollama/model-capabilities.js +115 -0
- package/dist/resources/extensions/ollama/ollama-client.js +168 -0
- package/dist/resources/extensions/ollama/ollama-commands.js +194 -0
- package/dist/resources/extensions/ollama/ollama-discovery.js +69 -0
- package/dist/resources/extensions/ollama/ollama-tool.js +184 -0
- package/dist/resources/extensions/ollama/types.js +2 -0
- package/dist/resources/extensions/search-the-web/extension-manifest.json +1 -1
- package/dist/resources/extensions/shared/interview-ui.js +11 -1
- package/dist/resources/skills/create-gsd-extension/SKILL.md +5 -3
- package/dist/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +5 -4
- package/dist/resources/skills/create-gsd-extension/workflows/add-capability.md +2 -2
- package/dist/resources/skills/create-gsd-extension/workflows/create-extension.md +4 -4
- package/dist/resources/skills/create-gsd-extension/workflows/debug-extension.md +5 -3
- package/dist/startup-model-validation.d.ts +39 -0
- package/dist/startup-model-validation.js +50 -0
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
- 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 +1 -1
- 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 +2 -2
- 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 +4 -4
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -4
- 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 +4 -4
- 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 +2 -2
- 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/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 +2 -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 +5 -5
- 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 +5 -5
- 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 +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- 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 +12 -12
- package/dist/web/standalone/.next/server/chunks/2229.js +2 -2
- package/dist/web/standalone/.next/server/chunks/7471.js +3 -3
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/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 +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/6502.7593d7797a4b3999.js +9 -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-0c485498795110d6.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-4332cbd5dd1be584.js → webpack-a1c1e452c6b32d04.js} +1 -1
- package/dist/web/standalone/.next/static/css/f6e8833d46e738d8.css +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/server.js +1 -1
- package/dist/web-mode.js +2 -1
- package/package.json +2 -2
- package/packages/daemon/src/cli.ts +49 -0
- package/packages/daemon/src/daemon.test.ts +104 -1
- package/packages/daemon/src/daemon.ts +24 -1
- package/packages/daemon/src/discord-bot.ts +73 -3
- package/packages/daemon/src/event-bridge.ts +15 -9
- package/packages/daemon/src/event-formatter.ts +30 -2
- package/packages/daemon/src/index.ts +9 -0
- package/packages/daemon/src/launchd.test.ts +356 -0
- package/packages/daemon/src/launchd.ts +242 -0
- package/packages/daemon/src/message-batcher.test.ts +2 -2
- package/packages/daemon/src/message-batcher.ts +9 -3
- package/packages/daemon/src/orchestrator.test.ts +1 -0
- package/packages/daemon/src/orchestrator.ts +106 -2
- package/packages/native/dist/ast/index.js +9 -5
- package/packages/native/dist/ast/types.js +2 -1
- package/packages/native/dist/clipboard/index.js +12 -7
- package/packages/native/dist/clipboard/types.js +2 -1
- package/packages/native/dist/diff/index.js +12 -7
- package/packages/native/dist/diff/types.js +2 -1
- package/packages/native/dist/fd/index.js +6 -3
- package/packages/native/dist/fd/types.js +2 -1
- package/packages/native/dist/glob/index.js +9 -5
- package/packages/native/dist/glob/types.js +2 -1
- package/packages/native/dist/grep/index.js +9 -5
- package/packages/native/dist/grep/types.js +2 -1
- package/packages/native/dist/gsd-parser/index.js +18 -11
- package/packages/native/dist/gsd-parser/types.js +2 -1
- package/packages/native/dist/highlight/index.js +12 -7
- package/packages/native/dist/highlight/types.js +2 -1
- package/packages/native/dist/html/index.js +6 -3
- package/packages/native/dist/html/types.js +2 -1
- package/packages/native/dist/image/index.js +10 -5
- package/packages/native/dist/image/types.js +7 -4
- package/packages/native/dist/index.js +70 -17
- package/packages/native/dist/json-parse/index.js +13 -8
- package/packages/native/dist/native.js +47 -10
- package/packages/native/dist/ps/index.js +15 -9
- package/packages/native/dist/ps/types.js +2 -1
- package/packages/native/dist/stream-process/index.js +12 -7
- package/packages/native/dist/text/index.js +24 -14
- package/packages/native/dist/text/types.js +5 -2
- package/packages/native/dist/truncate/index.js +12 -7
- package/packages/native/dist/ttsr/index.js +12 -7
- package/packages/native/dist/ttsr/types.js +2 -1
- package/packages/native/dist/xxhash/index.js +9 -5
- package/packages/native/package.json +19 -19
- package/packages/native/src/__tests__/module-compat.test.mjs +91 -0
- package/packages/native/src/native.ts +9 -8
- package/packages/pi-agent-core/dist/agent-loop.js +3 -2
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/dist/proxy.d.ts +1 -1
- package/packages/pi-agent-core/dist/proxy.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/proxy.js.map +1 -1
- package/packages/pi-agent-core/src/agent-loop.test.ts +45 -0
- package/packages/pi-agent-core/src/agent-loop.ts +3 -2
- package/packages/pi-agent-core/src/proxy.ts +1 -1
- package/packages/pi-ai/dist/env-api-keys.js +1 -0
- package/packages/pi-ai/dist/env-api-keys.js.map +1 -1
- package/packages/pi-ai/dist/index.d.ts +1 -0
- package/packages/pi-ai/dist/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/index.js +1 -0
- package/packages/pi-ai/dist/index.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.js +19 -2
- package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/anthropic-shared.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/anthropic-shared.test.js +25 -0
- package/packages/pi-ai/dist/providers/anthropic-shared.test.js.map +1 -0
- package/packages/pi-ai/dist/types.d.ts +3 -3
- 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/json-parse.d.ts +3 -0
- package/packages/pi-ai/dist/utils/json-parse.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/json-parse.js +24 -1
- package/packages/pi-ai/dist/utils/json-parse.js.map +1 -1
- package/packages/pi-ai/dist/utils/repair-tool-json.d.ts +37 -0
- package/packages/pi-ai/dist/utils/repair-tool-json.d.ts.map +1 -0
- package/packages/pi-ai/dist/utils/repair-tool-json.js +75 -0
- package/packages/pi-ai/dist/utils/repair-tool-json.js.map +1 -0
- package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.d.ts +2 -0
- package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js +73 -0
- package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js.map +1 -0
- package/packages/pi-ai/src/env-api-keys.ts +1 -0
- package/packages/pi-ai/src/index.ts +1 -0
- package/packages/pi-ai/src/providers/anthropic-shared.test.ts +29 -0
- package/packages/pi-ai/src/providers/anthropic-shared.ts +17 -2
- package/packages/pi-ai/src/types.ts +3 -2
- package/packages/pi-ai/src/utils/json-parse.ts +28 -1
- package/packages/pi-ai/src/utils/repair-tool-json.ts +88 -0
- package/packages/pi-ai/src/utils/tests/repair-tool-json.test.ts +102 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +4 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +31 -0
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +17 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js +62 -2
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.test.d.ts +6 -0
- package/packages/pi-coding-agent/dist/core/compaction/compaction.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/compaction/compaction.test.js +176 -0
- package/packages/pi-coding-agent/dist/core/compaction/compaction.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/exec.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/exec.js +3 -1
- package/packages/pi-coding-agent/dist/core/exec.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.d.ts +28 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.js +37 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.test.js +63 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-sort.d.ts +19 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-sort.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-sort.js +115 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-sort.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-sort.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-sort.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-sort.test.js +109 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-sort.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/index.d.ts +4 -0
- package/packages/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/index.js +2 -0
- package/packages/pi-coding-agent/dist/core/extensions/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +5 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +5 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/image-overflow-recovery.d.ts +44 -0
- package/packages/pi-coding-agent/dist/core/image-overflow-recovery.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/image-overflow-recovery.js +97 -0
- package/packages/pi-coding-agent/dist/core/image-overflow-recovery.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/image-overflow-recovery.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/image-overflow-recovery.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/image-overflow-recovery.test.js +181 -0
- package/packages/pi-coding-agent/dist/core/image-overflow-recovery.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/core/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/index.js +1 -1
- package/packages/pi-coding-agent/dist/core/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/index.js +3 -0
- package/packages/pi-coding-agent/dist/core/lsp/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/lspmux.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/lspmux.js +3 -0
- package/packages/pi-coding-agent/dist/core/lsp/lspmux.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 +31 -2
- package/packages/pi-coding-agent/dist/core/messages.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/messages.test.d.ts +9 -0
- package/packages/pi-coding-agent/dist/core/messages.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/messages.test.js +86 -0
- package/packages/pi-coding-agent/dist/core/messages.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js +1 -0
- package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.d.ts +10 -0
- package/packages/pi-coding-agent/dist/core/resource-loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.js +12 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts +6 -0
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js +48 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.test.d.ts +9 -0
- package/packages/pi-coding-agent/dist/core/retry-handler.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js +193 -0
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/tools/hashline-read.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/hashline-read.js +10 -3
- package/packages/pi-coding-agent/dist/core/tools/hashline-read.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/read.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/read.js +13 -4
- package/packages/pi-coding-agent/dist/core/tools/read.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.d.ts +16 -0
- package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js +80 -0
- package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/index.d.ts +2 -2
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +1 -1
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +4 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/remote-terminal.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/rpc/remote-terminal.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/remote-terminal.js +5 -0
- package/packages/pi-coding-agent/dist/modes/rpc/remote-terminal.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +38 -1
- package/packages/pi-coding-agent/src/core/compaction/compaction.test.ts +236 -0
- package/packages/pi-coding-agent/src/core/compaction/compaction.ts +94 -1
- package/packages/pi-coding-agent/src/core/exec.ts +3 -1
- package/packages/pi-coding-agent/src/core/extensions/extension-manifest.test.ts +77 -0
- package/packages/pi-coding-agent/src/core/extensions/extension-manifest.ts +62 -0
- package/packages/pi-coding-agent/src/core/extensions/extension-sort.test.ts +134 -0
- package/packages/pi-coding-agent/src/core/extensions/extension-sort.ts +137 -0
- package/packages/pi-coding-agent/src/core/extensions/index.ts +4 -0
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +5 -0
- package/packages/pi-coding-agent/src/core/image-overflow-recovery.test.ts +228 -0
- package/packages/pi-coding-agent/src/core/image-overflow-recovery.ts +118 -0
- package/packages/pi-coding-agent/src/core/index.ts +6 -0
- package/packages/pi-coding-agent/src/core/lsp/index.ts +3 -0
- package/packages/pi-coding-agent/src/core/lsp/lspmux.ts +3 -0
- package/packages/pi-coding-agent/src/core/messages.test.ts +114 -0
- package/packages/pi-coding-agent/src/core/messages.ts +29 -2
- package/packages/pi-coding-agent/src/core/model-resolver.ts +1 -0
- package/packages/pi-coding-agent/src/core/resource-loader.ts +20 -1
- package/packages/pi-coding-agent/src/core/retry-handler.test.ts +255 -0
- package/packages/pi-coding-agent/src/core/retry-handler.ts +52 -1
- package/packages/pi-coding-agent/src/core/tools/hashline-read.ts +11 -3
- package/packages/pi-coding-agent/src/core/tools/read.ts +14 -4
- package/packages/pi-coding-agent/src/core/tools/spawn-shell-windows.test.ts +92 -0
- package/packages/pi-coding-agent/src/index.ts +6 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +7 -0
- package/packages/pi-coding-agent/src/modes/rpc/remote-terminal.ts +6 -0
- package/packages/pi-tui/dist/terminal.d.ts +2 -0
- package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
- package/packages/pi-tui/dist/terminal.js +9 -0
- package/packages/pi-tui/dist/terminal.js.map +1 -1
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +9 -0
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/src/terminal.ts +14 -0
- package/packages/pi-tui/src/tui.ts +8 -0
- package/pkg/package.json +1 -1
- package/scripts/ensure-workspace-builds.cjs +45 -14
- package/src/resources/agents/researcher.md +1 -1
- package/src/resources/extensions/ask-user-questions.ts +21 -3
- package/src/resources/extensions/async-jobs/extension-manifest.json +1 -1
- package/src/resources/extensions/bg-shell/extension-manifest.json +1 -1
- package/src/resources/extensions/browser-tools/extension-manifest.json +1 -1
- package/src/resources/extensions/claude-code-cli/partial-builder.ts +13 -6
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +63 -35
- package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +28 -0
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +108 -1
- package/src/resources/extensions/context7/extension-manifest.json +1 -1
- package/src/resources/extensions/get-secrets-from-user.ts +8 -5
- package/src/resources/extensions/google-search/extension-manifest.json +1 -1
- package/src/resources/extensions/google-search/index.ts +2 -1
- package/src/resources/extensions/gsd/auto/infra-errors.ts +3 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
- package/src/resources/extensions/gsd/auto/phases.ts +43 -34
- package/src/resources/extensions/gsd/auto-artifact-paths.ts +2 -2
- package/src/resources/extensions/gsd/auto-dashboard.ts +37 -19
- package/src/resources/extensions/gsd/auto-dispatch.ts +21 -5
- package/src/resources/extensions/gsd/auto-model-selection.ts +26 -5
- package/src/resources/extensions/gsd/auto-post-unit.ts +18 -4
- package/src/resources/extensions/gsd/auto-prompts.ts +1 -1
- package/src/resources/extensions/gsd/auto-recovery.ts +12 -5
- package/src/resources/extensions/gsd/auto-start.ts +35 -26
- package/src/resources/extensions/gsd/auto-worktree.ts +197 -11
- package/src/resources/extensions/gsd/auto.ts +5 -0
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +31 -0
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +87 -9
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +38 -1
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +31 -19
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +50 -11
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +75 -0
- package/src/resources/extensions/gsd/captures.ts +63 -3
- package/src/resources/extensions/gsd/db-writer.ts +140 -7
- package/src/resources/extensions/gsd/dispatch-guard.ts +12 -1
- package/src/resources/extensions/gsd/doctor-git-checks.ts +26 -0
- package/src/resources/extensions/gsd/doctor-providers.ts +2 -1
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +5 -4
- package/src/resources/extensions/gsd/doctor.ts +3 -1
- package/src/resources/extensions/gsd/error-classifier.ts +14 -11
- package/src/resources/extensions/gsd/extension-manifest.json +16 -1
- package/src/resources/extensions/gsd/forensics.ts +144 -20
- package/src/resources/extensions/gsd/git-service.ts +26 -3
- package/src/resources/extensions/gsd/gitignore.ts +33 -0
- package/src/resources/extensions/gsd/gsd-db.ts +49 -8
- package/src/resources/extensions/gsd/guided-flow.ts +114 -45
- package/src/resources/extensions/gsd/health-widget-core.ts +34 -0
- package/src/resources/extensions/gsd/health-widget.ts +17 -0
- package/src/resources/extensions/gsd/index.ts +1 -0
- package/src/resources/extensions/gsd/memory-extractor.ts +8 -0
- package/src/resources/extensions/gsd/migrate-external.ts +9 -1
- package/src/resources/extensions/gsd/milestone-validation-gates.ts +56 -0
- package/src/resources/extensions/gsd/model-cost-table.ts +19 -0
- package/src/resources/extensions/gsd/model-router.ts +35 -1
- package/src/resources/extensions/gsd/native-git-bridge.ts +17 -0
- package/src/resources/extensions/gsd/notifications.ts +16 -0
- package/src/resources/extensions/gsd/parallel-eligibility.ts +15 -2
- package/src/resources/extensions/gsd/parallel-merge.ts +87 -4
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +23 -6
- package/src/resources/extensions/gsd/parsers-legacy.ts +22 -3
- package/src/resources/extensions/gsd/paths.ts +42 -0
- package/src/resources/extensions/gsd/preferences-models.ts +14 -1
- package/src/resources/extensions/gsd/preferences-types.ts +2 -1
- package/src/resources/extensions/gsd/preferences.ts +45 -29
- package/src/resources/extensions/gsd/prompt-loader.ts +4 -1
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/complete-slice.md +4 -2
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +1 -1
- package/src/resources/extensions/gsd/prompts/discuss.md +1 -1
- package/src/resources/extensions/gsd/prompts/execute-task.md +3 -1
- package/src/resources/extensions/gsd/prompts/forensics.md +2 -2
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +2 -0
- package/src/resources/extensions/gsd/prompts/rethink.md +1 -1
- package/src/resources/extensions/gsd/prompts/triage-captures.md +1 -0
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
- package/src/resources/extensions/gsd/repo-identity.ts +186 -11
- package/src/resources/extensions/gsd/rethink.ts +6 -0
- package/src/resources/extensions/gsd/roadmap-slices.ts +5 -4
- package/src/resources/extensions/gsd/state.ts +84 -32
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/auto-mode-interactive-guard.test.ts +71 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +71 -1
- package/src/resources/extensions/gsd/tests/captures.test.ts +103 -0
- package/src/resources/extensions/gsd/tests/cli-provider-rate-limit.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/completion-hierarchy-guards.test.ts +192 -0
- package/src/resources/extensions/gsd/tests/db-path-worktree-symlink.test.ts +131 -0
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +7 -12
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +78 -5
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +29 -0
- package/src/resources/extensions/gsd/tests/discord-invite-links.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/discuss-empty-db-fallback.test.ts +127 -0
- package/src/resources/extensions/gsd/tests/discuss-queued-milestones.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/dist-redirect.mjs +20 -1
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +117 -0
- package/src/resources/extensions/gsd/tests/dynamic-routing-default.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/empty-content-abort-loop.test.ts +74 -0
- package/src/resources/extensions/gsd/tests/event-replay-idempotency.test.ts +140 -0
- package/src/resources/extensions/gsd/tests/forensics-context-persist.test.ts +129 -0
- package/src/resources/extensions/gsd/tests/forensics-db-completion.test.ts +96 -0
- package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +125 -12
- package/src/resources/extensions/gsd/tests/gsdroot-worktree-detection.test.ts +164 -0
- package/src/resources/extensions/gsd/tests/guided-flow-dynamic-routing.test.ts +135 -0
- package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +97 -0
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +67 -0
- package/src/resources/extensions/gsd/tests/hook-key-parsing.test.ts +107 -0
- package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +111 -1
- package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +101 -0
- package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +59 -0
- package/src/resources/extensions/gsd/tests/integration/doctor-false-positives.test.ts +243 -0
- package/src/resources/extensions/gsd/tests/integration/gitignore-staging-2570.test.ts +150 -0
- package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +110 -0
- package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +959 -0
- package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +85 -2
- package/src/resources/extensions/gsd/tests/migrate-external-worktree.test.ts +105 -0
- package/src/resources/extensions/gsd/tests/milestone-status-authoritative.test.ts +116 -0
- package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/model-router.test.ts +68 -3
- package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +28 -0
- package/src/resources/extensions/gsd/tests/notifications.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/parallel-commit-scope.test.ts +159 -0
- package/src/resources/extensions/gsd/tests/parallel-eligibility-ghost.test.ts +150 -0
- package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +9 -8
- package/src/resources/extensions/gsd/tests/plan-milestone-title.test.ts +70 -0
- package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +33 -1
- package/src/resources/extensions/gsd/tests/preferences.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/project-relocation-recovery.test.ts +297 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/prompt-loader-replacement.test.ts +178 -0
- package/src/resources/extensions/gsd/tests/prompt-tool-names.test.ts +69 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/queue-execution-guard.test.ts +157 -0
- package/src/resources/extensions/gsd/tests/quick-turn-end-cleanup.test.ts +90 -0
- package/src/resources/extensions/gsd/tests/reassess-handler.test.ts +117 -0
- package/src/resources/extensions/gsd/tests/reconciliation-edge-cases.test.ts +162 -0
- package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +97 -0
- package/src/resources/extensions/gsd/tests/secure-env-collect.test.ts +134 -0
- package/src/resources/extensions/gsd/tests/slice-disk-reconcile.test.ts +233 -0
- package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +305 -0
- package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +405 -0
- package/src/resources/extensions/gsd/tests/state-derivation-parity.test.ts +257 -0
- package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +1628 -0
- package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +106 -0
- package/src/resources/extensions/gsd/tests/stuck-detection-coverage.test.ts +174 -0
- package/src/resources/extensions/gsd/tests/summary-render-parity.test.ts +221 -0
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/triage-resolution.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/uat-stuck-loop-orphaned-worktree.test.ts +289 -0
- package/src/resources/extensions/gsd/tests/unit-ownership.test.ts +100 -17
- package/src/resources/extensions/gsd/tests/vacuum-recovery.test.ts +154 -0
- package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +27 -2
- package/src/resources/extensions/gsd/tests/validation-gate-patterns.test.ts +44 -2
- package/src/resources/extensions/gsd/tests/verdict-parser.test.ts +156 -0
- package/src/resources/extensions/gsd/tests/verification-operational-gate.test.ts +82 -0
- package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +92 -0
- package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/worktree-db-respawn-truncation.test.ts +140 -0
- package/src/resources/extensions/gsd/tests/worktree-db-same-file.test.ts +175 -0
- package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +101 -0
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +48 -1
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +29 -5
- package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +95 -0
- package/src/resources/extensions/gsd/tools/complete-task.ts +36 -74
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +13 -1
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +36 -0
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +25 -2
- package/src/resources/extensions/gsd/triage-resolution.ts +23 -6
- package/src/resources/extensions/gsd/types.ts +4 -2
- package/src/resources/extensions/gsd/undo.ts +2 -2
- package/src/resources/extensions/gsd/unit-ownership.ts +206 -35
- package/src/resources/extensions/gsd/verdict-parser.ts +21 -6
- package/src/resources/extensions/gsd/workflow-logger.ts +3 -1
- package/src/resources/extensions/gsd/workflow-manifest.ts +22 -5
- package/src/resources/extensions/gsd/workflow-projections.ts +97 -64
- package/src/resources/extensions/gsd/workflow-reconcile.ts +39 -10
- package/src/resources/extensions/gsd/workspace-index.ts +30 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +120 -1
- package/src/resources/extensions/gsd/worktree-resolver.ts +22 -3
- package/src/resources/extensions/mcp-client/index.ts +13 -7
- package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +55 -0
- package/src/resources/extensions/ollama/index.ts +130 -0
- package/src/resources/extensions/ollama/model-capabilities.ts +145 -0
- package/src/resources/extensions/ollama/ollama-client.ts +196 -0
- package/src/resources/extensions/ollama/ollama-commands.ts +248 -0
- package/src/resources/extensions/ollama/ollama-discovery.ts +106 -0
- package/src/resources/extensions/ollama/ollama-tool.ts +218 -0
- package/src/resources/extensions/ollama/tests/model-capabilities.test.ts +162 -0
- package/src/resources/extensions/ollama/tests/ollama-client.test.ts +38 -0
- package/src/resources/extensions/ollama/tests/ollama-discovery.test.ts +28 -0
- package/src/resources/extensions/ollama/types.ts +130 -0
- package/src/resources/extensions/search-the-web/extension-manifest.json +1 -1
- package/src/resources/extensions/shared/interview-ui.ts +12 -1
- package/src/resources/extensions/shared/tests/ask-user-freetext.test.ts +156 -0
- package/src/resources/skills/create-gsd-extension/SKILL.md +5 -3
- package/src/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +5 -4
- package/src/resources/skills/create-gsd-extension/workflows/add-capability.md +2 -2
- package/src/resources/skills/create-gsd-extension/workflows/create-extension.md +4 -4
- package/src/resources/skills/create-gsd-extension/workflows/debug-extension.md +5 -3
- package/dist/web/standalone/.next/static/chunks/6502.2305d0afd2385711.js +0 -9
- package/dist/web/standalone/.next/static/chunks/app/page-62be3b5fa91e4c8f.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/css/a58ef8a151aa0493.css +0 -1
- package/src/resources/extensions/gsd/tests/empty-db-reconciliation.test.ts +0 -79
- /package/dist/web/standalone/.next/static/{yowc5qPtuKxjOr22KmOAy → R0D4xaIPl5kg93edN7Oo0}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{yowc5qPtuKxjOr22KmOAy → R0D4xaIPl5kg93edN7Oo0}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Guided-flow dynamic routing — regression test for #2958.
|
|
3
|
+
*
|
|
4
|
+
* Verifies that dispatchWorkflow() routes through the dynamic routing pipeline
|
|
5
|
+
* (selectAndApplyModel from auto-model-selection.ts) instead of bypassing it
|
|
6
|
+
* with a direct call to resolveModelWithFallbacksForUnit.
|
|
7
|
+
*
|
|
8
|
+
* Copyright (c) 2026 Jeremy McSpadden <jeremy@fluxlabs.net>
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import test from "node:test";
|
|
12
|
+
import assert from "node:assert/strict";
|
|
13
|
+
import { readFileSync } from "node:fs";
|
|
14
|
+
import { join, dirname } from "node:path";
|
|
15
|
+
import { fileURLToPath } from "node:url";
|
|
16
|
+
|
|
17
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
18
|
+
const gsdDir = join(__dirname, "..");
|
|
19
|
+
|
|
20
|
+
function readSrc(file: string): string {
|
|
21
|
+
return readFileSync(join(gsdDir, file), "utf-8");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const guidedFlowSrc = readSrc("guided-flow.ts");
|
|
25
|
+
|
|
26
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
27
|
+
// #2958: dispatchWorkflow must route through dynamic routing pipeline
|
|
28
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
29
|
+
|
|
30
|
+
test("#2958: guided-flow imports selectAndApplyModel from auto-model-selection", () => {
|
|
31
|
+
assert.ok(
|
|
32
|
+
guidedFlowSrc.includes("selectAndApplyModel"),
|
|
33
|
+
"guided-flow.ts must import and use selectAndApplyModel from auto-model-selection.ts",
|
|
34
|
+
);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("#2958: dispatchWorkflow does not call resolveModelWithFallbacksForUnit directly", () => {
|
|
38
|
+
// Extract the dispatchWorkflow function body
|
|
39
|
+
const fnStart = guidedFlowSrc.indexOf("async function dispatchWorkflow(");
|
|
40
|
+
assert.ok(fnStart !== -1, "dispatchWorkflow function not found");
|
|
41
|
+
|
|
42
|
+
// Find the function body by tracking brace depth
|
|
43
|
+
const openBrace = guidedFlowSrc.indexOf("{", fnStart);
|
|
44
|
+
let depth = 1;
|
|
45
|
+
let pos = openBrace + 1;
|
|
46
|
+
while (depth > 0 && pos < guidedFlowSrc.length) {
|
|
47
|
+
if (guidedFlowSrc[pos] === "{") depth++;
|
|
48
|
+
else if (guidedFlowSrc[pos] === "}") depth--;
|
|
49
|
+
pos++;
|
|
50
|
+
}
|
|
51
|
+
const fnBody = guidedFlowSrc.slice(openBrace, pos);
|
|
52
|
+
|
|
53
|
+
assert.ok(
|
|
54
|
+
!fnBody.includes("resolveModelWithFallbacksForUnit"),
|
|
55
|
+
"dispatchWorkflow must NOT call resolveModelWithFallbacksForUnit directly — " +
|
|
56
|
+
"it must route through selectAndApplyModel for dynamic routing support (#2958)",
|
|
57
|
+
);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test("#2958: dispatchWorkflow calls selectAndApplyModel for model selection", () => {
|
|
61
|
+
// Extract the dispatchWorkflow function body
|
|
62
|
+
const fnStart = guidedFlowSrc.indexOf("async function dispatchWorkflow(");
|
|
63
|
+
assert.ok(fnStart !== -1, "dispatchWorkflow function not found");
|
|
64
|
+
|
|
65
|
+
const openBrace = guidedFlowSrc.indexOf("{", fnStart);
|
|
66
|
+
let depth = 1;
|
|
67
|
+
let pos = openBrace + 1;
|
|
68
|
+
while (depth > 0 && pos < guidedFlowSrc.length) {
|
|
69
|
+
if (guidedFlowSrc[pos] === "{") depth++;
|
|
70
|
+
else if (guidedFlowSrc[pos] === "}") depth--;
|
|
71
|
+
pos++;
|
|
72
|
+
}
|
|
73
|
+
const fnBody = guidedFlowSrc.slice(openBrace, pos);
|
|
74
|
+
|
|
75
|
+
assert.ok(
|
|
76
|
+
fnBody.includes("selectAndApplyModel"),
|
|
77
|
+
"dispatchWorkflow must call selectAndApplyModel to route through the dynamic routing pipeline (#2958)",
|
|
78
|
+
);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("#2958: dispatchWorkflow does not use resolveAvailableModel inline", () => {
|
|
82
|
+
const fnStart = guidedFlowSrc.indexOf("async function dispatchWorkflow(");
|
|
83
|
+
assert.ok(fnStart !== -1, "dispatchWorkflow function not found");
|
|
84
|
+
|
|
85
|
+
const openBrace = guidedFlowSrc.indexOf("{", fnStart);
|
|
86
|
+
let depth = 1;
|
|
87
|
+
let pos = openBrace + 1;
|
|
88
|
+
while (depth > 0 && pos < guidedFlowSrc.length) {
|
|
89
|
+
if (guidedFlowSrc[pos] === "{") depth++;
|
|
90
|
+
else if (guidedFlowSrc[pos] === "}") depth--;
|
|
91
|
+
pos++;
|
|
92
|
+
}
|
|
93
|
+
const fnBody = guidedFlowSrc.slice(openBrace, pos);
|
|
94
|
+
|
|
95
|
+
assert.ok(
|
|
96
|
+
!fnBody.includes("resolveAvailableModel"),
|
|
97
|
+
"dispatchWorkflow must NOT use resolveAvailableModel inline — " +
|
|
98
|
+
"model resolution is handled by selectAndApplyModel (#2958)",
|
|
99
|
+
);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test("#2958: guided-flow does not import resolveModelWithFallbacksForUnit", () => {
|
|
103
|
+
// The import should be removed since dispatchWorkflow was the only consumer
|
|
104
|
+
// Check if resolveModelWithFallbacksForUnit is still used elsewhere in the file
|
|
105
|
+
const fnStart = guidedFlowSrc.indexOf("async function dispatchWorkflow(");
|
|
106
|
+
const beforeDispatch = guidedFlowSrc.slice(0, fnStart);
|
|
107
|
+
const afterFnEnd = (() => {
|
|
108
|
+
const openBrace = guidedFlowSrc.indexOf("{", fnStart);
|
|
109
|
+
let depth = 1;
|
|
110
|
+
let p = openBrace + 1;
|
|
111
|
+
while (depth > 0 && p < guidedFlowSrc.length) {
|
|
112
|
+
if (guidedFlowSrc[p] === "{") depth++;
|
|
113
|
+
else if (guidedFlowSrc[p] === "}") depth--;
|
|
114
|
+
p++;
|
|
115
|
+
}
|
|
116
|
+
return guidedFlowSrc.slice(p);
|
|
117
|
+
})();
|
|
118
|
+
|
|
119
|
+
// If resolveModelWithFallbacksForUnit is not used outside dispatchWorkflow,
|
|
120
|
+
// the import should be removed
|
|
121
|
+
const usedOutside = beforeDispatch.includes("resolveModelWithFallbacksForUnit(")
|
|
122
|
+
|| afterFnEnd.includes("resolveModelWithFallbacksForUnit(");
|
|
123
|
+
|
|
124
|
+
if (!usedOutside) {
|
|
125
|
+
// Verify the import line was cleaned up
|
|
126
|
+
const importLines = guidedFlowSrc.split("\n").filter(l =>
|
|
127
|
+
l.includes("import") && l.includes("resolveModelWithFallbacksForUnit"),
|
|
128
|
+
);
|
|
129
|
+
assert.equal(
|
|
130
|
+
importLines.length,
|
|
131
|
+
0,
|
|
132
|
+
"resolveModelWithFallbacksForUnit import should be removed when no longer used outside dispatchWorkflow",
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regression test for #2985 Bugs 3 & 4:
|
|
3
|
+
* Bug 3 — module-level pendingAutoStart singleton clobbers concurrent sessions.
|
|
4
|
+
* Bug 4 — getDiscussionMilestoneId() returns wrong project's milestone under concurrency.
|
|
5
|
+
*
|
|
6
|
+
* pendingAutoStart must be keyed by basePath so concurrent discuss sessions
|
|
7
|
+
* in different projects are independent. getDiscussionMilestoneId() must accept
|
|
8
|
+
* a basePath parameter to perform a keyed lookup.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { describe, test, beforeEach } from "node:test";
|
|
12
|
+
import assert from "node:assert/strict";
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
getDiscussionMilestoneId,
|
|
16
|
+
setPendingAutoStart,
|
|
17
|
+
clearPendingAutoStart,
|
|
18
|
+
} from "../guided-flow.ts";
|
|
19
|
+
|
|
20
|
+
// ─── Tests ─────────────────────────────────────────────────────────────────
|
|
21
|
+
|
|
22
|
+
describe("#2985 Bug 3 — concurrent discuss sessions must be independent", () => {
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
clearPendingAutoStart();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test("second session does not clobber first session's pending auto-start", () => {
|
|
28
|
+
// Simulate two concurrent discuss sessions for different projects
|
|
29
|
+
const projectA = "/projects/alpha";
|
|
30
|
+
const projectB = "/projects/beta";
|
|
31
|
+
|
|
32
|
+
setPendingAutoStart(projectA, {
|
|
33
|
+
basePath: projectA,
|
|
34
|
+
milestoneId: "M001-aaa111",
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
setPendingAutoStart(projectB, {
|
|
38
|
+
basePath: projectB,
|
|
39
|
+
milestoneId: "M002-bbb222",
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Both sessions should be retrievable
|
|
43
|
+
const milestoneA = getDiscussionMilestoneId(projectA);
|
|
44
|
+
const milestoneB = getDiscussionMilestoneId(projectB);
|
|
45
|
+
|
|
46
|
+
assert.equal(milestoneA, "M001-aaa111", "projectA's milestone should be preserved");
|
|
47
|
+
assert.equal(milestoneB, "M002-bbb222", "projectB's milestone should be preserved");
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test("clearing one session does not affect the other", () => {
|
|
51
|
+
const projectA = "/projects/alpha";
|
|
52
|
+
const projectB = "/projects/beta";
|
|
53
|
+
|
|
54
|
+
setPendingAutoStart(projectA, { basePath: projectA, milestoneId: "M001-aaa111" });
|
|
55
|
+
setPendingAutoStart(projectB, { basePath: projectB, milestoneId: "M002-bbb222" });
|
|
56
|
+
|
|
57
|
+
// Clear only projectA
|
|
58
|
+
clearPendingAutoStart(projectA);
|
|
59
|
+
|
|
60
|
+
assert.equal(getDiscussionMilestoneId(projectA), null, "projectA should be cleared");
|
|
61
|
+
assert.equal(getDiscussionMilestoneId(projectB), "M002-bbb222", "projectB should survive");
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe("#2985 Bug 4 — getDiscussionMilestoneId must be keyed by basePath", () => {
|
|
66
|
+
beforeEach(() => {
|
|
67
|
+
clearPendingAutoStart();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test("getDiscussionMilestoneId(basePath) returns correct milestone for each project", () => {
|
|
71
|
+
setPendingAutoStart("/proj/a", { basePath: "/proj/a", milestoneId: "M001" });
|
|
72
|
+
setPendingAutoStart("/proj/b", { basePath: "/proj/b", milestoneId: "M002" });
|
|
73
|
+
|
|
74
|
+
assert.equal(getDiscussionMilestoneId("/proj/a"), "M001");
|
|
75
|
+
assert.equal(getDiscussionMilestoneId("/proj/b"), "M002");
|
|
76
|
+
assert.equal(getDiscussionMilestoneId("/proj/unknown"), null);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("getDiscussionMilestoneId() without basePath returns null when multiple sessions exist", () => {
|
|
80
|
+
setPendingAutoStart("/proj/a", { basePath: "/proj/a", milestoneId: "M001" });
|
|
81
|
+
setPendingAutoStart("/proj/b", { basePath: "/proj/b", milestoneId: "M002" });
|
|
82
|
+
|
|
83
|
+
// Without a key, the function should not blindly return the first entry
|
|
84
|
+
const result = getDiscussionMilestoneId();
|
|
85
|
+
// When there's ambiguity (multiple sessions), it should return null
|
|
86
|
+
// to force callers to be explicit
|
|
87
|
+
assert.equal(result, null, "should not return arbitrary milestone when multiple sessions exist");
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test("getDiscussionMilestoneId() without basePath returns the milestone when only one session", () => {
|
|
91
|
+
setPendingAutoStart("/proj/a", { basePath: "/proj/a", milestoneId: "M001" });
|
|
92
|
+
|
|
93
|
+
// With only one session, backward compat — return it
|
|
94
|
+
const result = getDiscussionMilestoneId();
|
|
95
|
+
assert.equal(result, "M001", "should return the only active milestone for backward compat");
|
|
96
|
+
});
|
|
97
|
+
});
|
|
@@ -6,6 +6,7 @@ import { tmpdir } from "node:os";
|
|
|
6
6
|
import {
|
|
7
7
|
buildHealthLines,
|
|
8
8
|
detectHealthWidgetProjectState,
|
|
9
|
+
formatRelativeTime,
|
|
9
10
|
type HealthWidgetData,
|
|
10
11
|
} from "../health-widget-core.ts";
|
|
11
12
|
|
|
@@ -34,6 +35,8 @@ function activeData(overrides: Partial<HealthWidgetData> = {}): HealthWidgetData
|
|
|
34
35
|
providerIssue: null,
|
|
35
36
|
environmentErrorCount: 0,
|
|
36
37
|
environmentWarningCount: 0,
|
|
38
|
+
lastCommitEpoch: null,
|
|
39
|
+
lastCommitMessage: null,
|
|
37
40
|
lastRefreshed: Date.now(),
|
|
38
41
|
...overrides,
|
|
39
42
|
};
|
|
@@ -98,6 +101,70 @@ test("buildHealthLines: active state with issues reports issue summary", (t) =>
|
|
|
98
101
|
assert.match(lines[0]!, /Env: 1 error/);
|
|
99
102
|
});
|
|
100
103
|
|
|
104
|
+
// ── Last commit display ──────────────────────────────────────────────────
|
|
105
|
+
|
|
106
|
+
test("buildHealthLines: shows last commit with relative time and message", (t) => {
|
|
107
|
+
const epoch = Math.floor(Date.now() / 1000) - 300; // 5 minutes ago
|
|
108
|
+
const lines = buildHealthLines(activeData({
|
|
109
|
+
lastCommitEpoch: epoch,
|
|
110
|
+
lastCommitMessage: "feat(widget): add health display",
|
|
111
|
+
}));
|
|
112
|
+
assert.equal(lines.length, 1);
|
|
113
|
+
assert.match(lines[0]!, /Last commit: 5m ago/);
|
|
114
|
+
assert.match(lines[0]!, /feat\(widget\): add health display/);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test("buildHealthLines: truncates long commit messages", (t) => {
|
|
118
|
+
const epoch = Math.floor(Date.now() / 1000) - 60;
|
|
119
|
+
const longMsg = "a".repeat(80);
|
|
120
|
+
const lines = buildHealthLines(activeData({
|
|
121
|
+
lastCommitEpoch: epoch,
|
|
122
|
+
lastCommitMessage: longMsg,
|
|
123
|
+
}));
|
|
124
|
+
assert.equal(lines.length, 1);
|
|
125
|
+
assert.match(lines[0]!, /a{49}…/);
|
|
126
|
+
assert.ok(!lines[0]!.includes("a".repeat(51)), "message is truncated");
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test("buildHealthLines: no last commit section when epoch is null", (t) => {
|
|
130
|
+
const lines = buildHealthLines(activeData({ lastCommitEpoch: null }));
|
|
131
|
+
assert.equal(lines.length, 1);
|
|
132
|
+
assert.ok(!lines[0]!.includes("Last commit"), "no last commit when null");
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test("buildHealthLines: last commit without message shows only time", (t) => {
|
|
136
|
+
const epoch = Math.floor(Date.now() / 1000) - 3600; // 1 hour ago
|
|
137
|
+
const lines = buildHealthLines(activeData({
|
|
138
|
+
lastCommitEpoch: epoch,
|
|
139
|
+
lastCommitMessage: null,
|
|
140
|
+
}));
|
|
141
|
+
assert.equal(lines.length, 1);
|
|
142
|
+
assert.match(lines[0]!, /Last commit: 1h ago/);
|
|
143
|
+
assert.ok(!lines[0]!.includes(" — "), "no dash separator when no message");
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// ── formatRelativeTime ───────────────────────────────────────────────────
|
|
147
|
+
|
|
148
|
+
test("formatRelativeTime: just now for <60s", () => {
|
|
149
|
+
const epoch = Math.floor(Date.now() / 1000) - 30;
|
|
150
|
+
assert.equal(formatRelativeTime(epoch), "just now");
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
test("formatRelativeTime: minutes", () => {
|
|
154
|
+
const epoch = Math.floor(Date.now() / 1000) - 300;
|
|
155
|
+
assert.equal(formatRelativeTime(epoch), "5m ago");
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
test("formatRelativeTime: hours", () => {
|
|
159
|
+
const epoch = Math.floor(Date.now() / 1000) - 7200;
|
|
160
|
+
assert.equal(formatRelativeTime(epoch), "2h ago");
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
test("formatRelativeTime: days", () => {
|
|
164
|
+
const epoch = Math.floor(Date.now() / 1000) - 172800;
|
|
165
|
+
assert.equal(formatRelativeTime(epoch), "2d ago");
|
|
166
|
+
});
|
|
167
|
+
|
|
101
168
|
test("detectHealthWidgetProjectState: metrics file alone does not imply project", (t) => {
|
|
102
169
|
const dir = makeTempDir("metrics-only");
|
|
103
170
|
t.after(() => { cleanup(dir); });
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { describe, it } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
import { join, dirname } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
|
|
7
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const gsdDir = join(__dirname, "..");
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Regression tests for #2826: hook/* completed-unit keys were parsed
|
|
12
|
+
* incorrectly by forensics + doctor, causing false-positive missing-artifact
|
|
13
|
+
* errors for all hook units.
|
|
14
|
+
*
|
|
15
|
+
* The root cause: `key.indexOf("/")` splits "hook/telegram-progress/M007/S01"
|
|
16
|
+
* into unitType="hook" + unitId="telegram-progress/M007/S01" instead of
|
|
17
|
+
* unitType="hook/telegram-progress" + unitId="M007/S01".
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
describe("splitCompletedKey (#2826)", () => {
|
|
21
|
+
it("is exported from forensics.ts", () => {
|
|
22
|
+
const source = readFileSync(join(gsdDir, "forensics.ts"), "utf-8");
|
|
23
|
+
assert.ok(
|
|
24
|
+
source.includes("export function splitCompletedKey"),
|
|
25
|
+
"forensics.ts must export splitCompletedKey helper",
|
|
26
|
+
);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("splits simple unit types correctly", async () => {
|
|
30
|
+
const { splitCompletedKey } = await import("../forensics.ts");
|
|
31
|
+
const result = splitCompletedKey("execute-task/M007/S01/T01");
|
|
32
|
+
assert.deepStrictEqual(result, {
|
|
33
|
+
unitType: "execute-task",
|
|
34
|
+
unitId: "M007/S01/T01",
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("splits hook unit types preserving the compound hook/<hookName> prefix", async () => {
|
|
39
|
+
const { splitCompletedKey } = await import("../forensics.ts");
|
|
40
|
+
const result = splitCompletedKey("hook/telegram-progress/M007/S01");
|
|
41
|
+
assert.deepStrictEqual(result, {
|
|
42
|
+
unitType: "hook/telegram-progress",
|
|
43
|
+
unitId: "M007/S01",
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("splits hook unit types with task-level unitId", async () => {
|
|
48
|
+
const { splitCompletedKey } = await import("../forensics.ts");
|
|
49
|
+
const result = splitCompletedKey("hook/telegram-progress/M007/S02/T01");
|
|
50
|
+
assert.deepStrictEqual(result, {
|
|
51
|
+
unitType: "hook/telegram-progress",
|
|
52
|
+
unitId: "M007/S02/T01",
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("returns null for malformed keys without a slash", async () => {
|
|
57
|
+
const { splitCompletedKey } = await import("../forensics.ts");
|
|
58
|
+
assert.strictEqual(splitCompletedKey("noslash"), null);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("returns null for malformed hook keys with only 'hook/' and no more segments", async () => {
|
|
62
|
+
const { splitCompletedKey } = await import("../forensics.ts");
|
|
63
|
+
// "hook/someName" has no unitId segment after the hook name
|
|
64
|
+
assert.strictEqual(splitCompletedKey("hook/someName"), null);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe("forensics detectMissingArtifacts uses splitCompletedKey (#2826)", () => {
|
|
69
|
+
it("does not use indexOf for key splitting", () => {
|
|
70
|
+
const source = readFileSync(join(gsdDir, "forensics.ts"), "utf-8");
|
|
71
|
+
// Extract only the detectMissingArtifacts function body
|
|
72
|
+
const fnStart = source.indexOf("function detectMissingArtifacts");
|
|
73
|
+
assert.ok(fnStart !== -1, "detectMissingArtifacts must exist");
|
|
74
|
+
const fnBody = source.slice(fnStart, source.indexOf("\n}\n", fnStart) + 3);
|
|
75
|
+
|
|
76
|
+
assert.ok(
|
|
77
|
+
!fnBody.includes('key.indexOf("/")'),
|
|
78
|
+
"detectMissingArtifacts must not use key.indexOf('/') — use splitCompletedKey instead",
|
|
79
|
+
);
|
|
80
|
+
assert.ok(
|
|
81
|
+
fnBody.includes("splitCompletedKey"),
|
|
82
|
+
"detectMissingArtifacts must use splitCompletedKey helper",
|
|
83
|
+
);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
describe("doctor-runtime-checks uses splitCompletedKey (#2826)", () => {
|
|
88
|
+
it("does not use indexOf for key splitting in orphaned-key check", () => {
|
|
89
|
+
const source = readFileSync(
|
|
90
|
+
join(gsdDir, "doctor-runtime-checks.ts"),
|
|
91
|
+
"utf-8",
|
|
92
|
+
);
|
|
93
|
+
// Find the orphaned completed-units section
|
|
94
|
+
const sectionStart = source.indexOf("Orphaned completed-units");
|
|
95
|
+
assert.ok(sectionStart !== -1, "orphaned completed-units section must exist");
|
|
96
|
+
const sectionBody = source.slice(sectionStart, source.indexOf("} catch", sectionStart));
|
|
97
|
+
|
|
98
|
+
assert.ok(
|
|
99
|
+
!sectionBody.includes('key.indexOf("/")'),
|
|
100
|
+
"doctor orphaned-key check must not use key.indexOf('/') — use splitCompletedKey instead",
|
|
101
|
+
);
|
|
102
|
+
assert.ok(
|
|
103
|
+
sectionBody.includes("splitCompletedKey"),
|
|
104
|
+
"doctor orphaned-key check must use splitCompletedKey helper",
|
|
105
|
+
);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
@@ -111,7 +111,51 @@ test("resolveExpectedArtifactPath returns correct path for all slice-level types
|
|
|
111
111
|
|
|
112
112
|
const uatResult = resolveExpectedArtifactPath("run-uat", "M001/S01", base);
|
|
113
113
|
assert.ok(uatResult);
|
|
114
|
-
assert.ok(uatResult!.includes("
|
|
114
|
+
assert.ok(uatResult!.includes("ASSESSMENT"));
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// ─── run-uat artifact path contract (#2873) ──────────────────────────────
|
|
118
|
+
|
|
119
|
+
test("resolveExpectedArtifactPath for run-uat returns ASSESSMENT path, not UAT (#2873)", (t) => {
|
|
120
|
+
// The run-uat prompt instructs the agent to call gsd_summary_save with
|
|
121
|
+
// artifact_type: "ASSESSMENT", which writes S##-ASSESSMENT.md. The artifact
|
|
122
|
+
// verification path must match — otherwise verification fails and auto-mode
|
|
123
|
+
// retries the unit in an infinite loop.
|
|
124
|
+
const base = makeTmpBase();
|
|
125
|
+
t.after(() => cleanup(base));
|
|
126
|
+
|
|
127
|
+
const result = resolveExpectedArtifactPath("run-uat", "M001/S01", base);
|
|
128
|
+
assert.ok(result, "run-uat should resolve to a non-null artifact path");
|
|
129
|
+
assert.ok(
|
|
130
|
+
result!.endsWith("S01-ASSESSMENT.md"),
|
|
131
|
+
`run-uat artifact path should end with S01-ASSESSMENT.md, got: ${result}`,
|
|
132
|
+
);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test("diagnoseExpectedArtifact for run-uat references ASSESSMENT (#2873)", (t) => {
|
|
136
|
+
const base = makeTmpBase();
|
|
137
|
+
t.after(() => cleanup(base));
|
|
138
|
+
|
|
139
|
+
const diag = diagnoseExpectedArtifact("run-uat", "M001/S01", base);
|
|
140
|
+
assert.ok(diag, "run-uat should have a diagnostic message");
|
|
141
|
+
assert.ok(
|
|
142
|
+
diag!.includes("ASSESSMENT"),
|
|
143
|
+
`run-uat diagnostic should reference ASSESSMENT, got: ${diag}`,
|
|
144
|
+
);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
test("verifyExpectedArtifact passes for run-uat when ASSESSMENT file exists (#2873)", (t) => {
|
|
148
|
+
// Regression test: run-uat writes S##-ASSESSMENT.md via gsd_summary_save,
|
|
149
|
+
// but verification looked for S##-UAT.md, causing false stuck retries.
|
|
150
|
+
const base = makeTmpBase();
|
|
151
|
+
t.after(() => cleanup(base));
|
|
152
|
+
|
|
153
|
+
// Write the ASSESSMENT file (what gsd_summary_save actually produces)
|
|
154
|
+
const assessPath = join(base, ".gsd", "milestones", "M001", "slices", "S01", "S01-ASSESSMENT.md");
|
|
155
|
+
writeFileSync(assessPath, "---\nverdict: PASS\n---\n# UAT Assessment\n");
|
|
156
|
+
|
|
157
|
+
const verified = verifyExpectedArtifact("run-uat", "M001/S01", base);
|
|
158
|
+
assert.ok(verified, "verifyExpectedArtifact should pass when ASSESSMENT file exists");
|
|
115
159
|
});
|
|
116
160
|
|
|
117
161
|
// ─── diagnoseExpectedArtifact ─────────────────────────────────────────────
|
|
@@ -697,6 +741,72 @@ test("verifyExpectedArtifact complete-milestone fails with only .gsd/ files (#17
|
|
|
697
741
|
assert.equal(result, false, "complete-milestone should fail verification when only .gsd/ files present");
|
|
698
742
|
});
|
|
699
743
|
|
|
744
|
+
// ─── reconcileMergeState: silent nativeCommit failure (#2542) ─────────────
|
|
745
|
+
|
|
746
|
+
import { reconcileMergeState } from "../../auto-recovery.ts";
|
|
747
|
+
import { chmodSync } from "node:fs";
|
|
748
|
+
|
|
749
|
+
function makeMockCtx(): { ctx: any; notifications: Array<{ msg: string; level: string }> } {
|
|
750
|
+
const notifications: Array<{ msg: string; level: string }> = [];
|
|
751
|
+
const ctx = {
|
|
752
|
+
ui: {
|
|
753
|
+
notify(msg: string, level: string) {
|
|
754
|
+
notifications.push({ msg, level });
|
|
755
|
+
},
|
|
756
|
+
},
|
|
757
|
+
};
|
|
758
|
+
return { ctx, notifications };
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
test("reconcileMergeState returns false and notifies error when nativeCommit fails (#2542)", (t) => {
|
|
762
|
+
const base = makeGitBase();
|
|
763
|
+
t.after(() => cleanup(base));
|
|
764
|
+
|
|
765
|
+
// Create a second branch with a commit, then start a merge on main
|
|
766
|
+
execFileSync("git", ["checkout", "-b", "feature"], { cwd: base, stdio: "ignore" });
|
|
767
|
+
writeFileSync(join(base, "feature.txt"), "feature content");
|
|
768
|
+
execFileSync("git", ["add", "."], { cwd: base, stdio: "ignore" });
|
|
769
|
+
execFileSync("git", ["commit", "-m", "add feature"], { cwd: base, stdio: "ignore" });
|
|
770
|
+
execFileSync("git", ["checkout", "main"], { cwd: base, stdio: "ignore" });
|
|
771
|
+
|
|
772
|
+
// Start merge (no conflicts — fast path with MERGE_HEAD)
|
|
773
|
+
execFileSync("git", ["merge", "--no-ff", "--no-commit", "feature"], { cwd: base, stdio: "ignore" });
|
|
774
|
+
|
|
775
|
+
// Verify MERGE_HEAD exists
|
|
776
|
+
assert.ok(existsSync(join(base, ".git", "MERGE_HEAD")), "MERGE_HEAD should exist");
|
|
777
|
+
|
|
778
|
+
// Make .git/objects read-only so git cannot write the commit object,
|
|
779
|
+
// causing nativeCommit to throw a non-"nothing to commit" error.
|
|
780
|
+
const objectsDir = join(base, ".git", "objects");
|
|
781
|
+
chmodSync(objectsDir, 0o444);
|
|
782
|
+
t.after(() => { try { chmodSync(objectsDir, 0o755); } catch { /* cleanup */ } });
|
|
783
|
+
|
|
784
|
+
const { ctx, notifications } = makeMockCtx();
|
|
785
|
+
const result = reconcileMergeState(base, ctx);
|
|
786
|
+
|
|
787
|
+
// The function should return false to signal reconciliation failure
|
|
788
|
+
// (Currently it silently swallows the error and returns true — this test should FAIL before the fix)
|
|
789
|
+
assert.equal(result, false, "reconcileMergeState should return false when nativeCommit fails");
|
|
790
|
+
const errorNotifications = notifications.filter(n => n.level === "error");
|
|
791
|
+
assert.ok(errorNotifications.length > 0, "should notify an error when nativeCommit fails");
|
|
792
|
+
assert.ok(
|
|
793
|
+
errorNotifications[0].msg.includes("Failed to finalize"),
|
|
794
|
+
"error notification should describe the commit failure",
|
|
795
|
+
);
|
|
796
|
+
});
|
|
797
|
+
|
|
798
|
+
test("reconcileMergeState returns true when no merge state present", (t) => {
|
|
799
|
+
// When there's no MERGE_HEAD or SQUASH_MSG, reconcileMergeState returns false (no dirty state)
|
|
800
|
+
const base = makeGitBase();
|
|
801
|
+
t.after(() => cleanup(base));
|
|
802
|
+
|
|
803
|
+
const { ctx, notifications } = makeMockCtx();
|
|
804
|
+
const result = reconcileMergeState(base, ctx);
|
|
805
|
+
|
|
806
|
+
assert.equal(result, false, "should return false when no merge state exists");
|
|
807
|
+
assert.equal(notifications.length, 0, "should not notify when no merge state present");
|
|
808
|
+
});
|
|
809
|
+
|
|
700
810
|
test("verifyExpectedArtifact complete-milestone passes with impl files (#1703)", (t) => {
|
|
701
811
|
const base = makeGitBase();
|
|
702
812
|
t.after(() => cleanup(base));
|
package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts
CHANGED
|
@@ -638,6 +638,107 @@ describe("auto-worktree-milestone-merge", { timeout: 300_000 }, () => {
|
|
|
638
638
|
"#1906: codeFilesChanged must be false when only .gsd/ files were merged");
|
|
639
639
|
});
|
|
640
640
|
|
|
641
|
+
test("#2912: MERGE_HEAD cleaned up after squash-merge conflict", () => {
|
|
642
|
+
const repo = freshRepo();
|
|
643
|
+
const wtPath = createAutoWorktree(repo, "M291");
|
|
644
|
+
|
|
645
|
+
// Create a file on main that will conflict with the milestone branch
|
|
646
|
+
run("git checkout main", repo);
|
|
647
|
+
writeFileSync(join(repo, "conflict.ts"), "// main version\nexport const x = 1;\n");
|
|
648
|
+
run("git add .", repo);
|
|
649
|
+
run("git commit -m 'add conflict.ts on main'", repo);
|
|
650
|
+
|
|
651
|
+
// Switch back to milestone branch and create conflicting content
|
|
652
|
+
run("git checkout milestone/M291", wtPath);
|
|
653
|
+
writeFileSync(join(wtPath, "conflict.ts"), "// milestone version\nexport const x = 2;\n");
|
|
654
|
+
run("git add .", wtPath);
|
|
655
|
+
run("git commit -m 'add conflict.ts on milestone'", wtPath);
|
|
656
|
+
|
|
657
|
+
const roadmap = makeRoadmap("M291", "Conflict milestone", [
|
|
658
|
+
{ id: "S01", title: "Conflict test" },
|
|
659
|
+
]);
|
|
660
|
+
|
|
661
|
+
// The merge should throw MergeConflictError due to conflict.ts
|
|
662
|
+
let threw = false;
|
|
663
|
+
try {
|
|
664
|
+
mergeMilestoneToMain(repo, "M291", roadmap);
|
|
665
|
+
} catch (err: unknown) {
|
|
666
|
+
threw = true;
|
|
667
|
+
// Verify it's a merge conflict error
|
|
668
|
+
assert.ok(
|
|
669
|
+
err instanceof Error && err.message.includes("conflict"),
|
|
670
|
+
"should throw a conflict-related error",
|
|
671
|
+
);
|
|
672
|
+
}
|
|
673
|
+
assert.ok(threw, "mergeMilestoneToMain must throw on code conflict");
|
|
674
|
+
|
|
675
|
+
// BUG #2912: MERGE_HEAD must NOT be left on disk after the error
|
|
676
|
+
const mergeHeadPath = join(repo, ".git", "MERGE_HEAD");
|
|
677
|
+
assert.ok(
|
|
678
|
+
!existsSync(mergeHeadPath),
|
|
679
|
+
"#2912: MERGE_HEAD must be cleaned up after merge conflict error",
|
|
680
|
+
);
|
|
681
|
+
});
|
|
682
|
+
|
|
683
|
+
test("#2912: stale MERGE_HEAD from native merge is cleaned after successful commit", () => {
|
|
684
|
+
const repo = freshRepo();
|
|
685
|
+
const wtPath = createAutoWorktree(repo, "M292");
|
|
686
|
+
|
|
687
|
+
addSliceToMilestone(repo, wtPath, "M292", "S01", "Feature A", [
|
|
688
|
+
{ file: "feature-a.ts", content: "export const a = true;\n", message: "add feature a" },
|
|
689
|
+
]);
|
|
690
|
+
|
|
691
|
+
const roadmap = makeRoadmap("M292", "Clean merge", [
|
|
692
|
+
{ id: "S01", title: "Feature A" },
|
|
693
|
+
]);
|
|
694
|
+
|
|
695
|
+
// Simulate what libgit2's merge implementation does: it creates MERGE_HEAD
|
|
696
|
+
// even for squash merges (unlike CLI git). We plant MERGE_HEAD before calling
|
|
697
|
+
// mergeMilestoneToMain to verify the success path cleans it up.
|
|
698
|
+
// We cannot plant it before the call because the function manages checkout
|
|
699
|
+
// internally, so instead we verify after the call.
|
|
700
|
+
mergeMilestoneToMain(repo, "M292", roadmap);
|
|
701
|
+
|
|
702
|
+
// After successful merge+commit, MERGE_HEAD must not linger
|
|
703
|
+
const mergeHeadPath = join(repo, ".git", "MERGE_HEAD");
|
|
704
|
+
assert.ok(
|
|
705
|
+
!existsSync(mergeHeadPath),
|
|
706
|
+
"#2912: MERGE_HEAD must be cleaned up after successful merge",
|
|
707
|
+
);
|
|
708
|
+
});
|
|
709
|
+
|
|
710
|
+
test("#2912: planted MERGE_HEAD is cleaned up in success path", () => {
|
|
711
|
+
// This test directly verifies the cleanup code handles a MERGE_HEAD file
|
|
712
|
+
// left by the native (libgit2) merge path. We hook into the merge by
|
|
713
|
+
// planting MERGE_HEAD right after nativeMergeSquash would create it.
|
|
714
|
+
const repo = freshRepo();
|
|
715
|
+
const wtPath = createAutoWorktree(repo, "M293");
|
|
716
|
+
|
|
717
|
+
addSliceToMilestone(repo, wtPath, "M293", "S01", "Feature B", [
|
|
718
|
+
{ file: "feature-b.ts", content: "export const b = true;\n", message: "add feature b" },
|
|
719
|
+
]);
|
|
720
|
+
|
|
721
|
+
const roadmap = makeRoadmap("M293", "Planted MERGE_HEAD", [
|
|
722
|
+
{ id: "S01", title: "Feature B" },
|
|
723
|
+
]);
|
|
724
|
+
|
|
725
|
+
// Plant a fake MERGE_HEAD in the git dir to simulate libgit2 behavior.
|
|
726
|
+
// We need to do this after the function checks out main but before it
|
|
727
|
+
// commits. Since we can't intercept mid-function, we plant it before
|
|
728
|
+
// the call. If the function cleans it up, the test passes.
|
|
729
|
+
const gitDir = join(repo, ".git");
|
|
730
|
+
const fakeHead = run("git rev-parse HEAD", repo);
|
|
731
|
+
writeFileSync(join(gitDir, "MERGE_HEAD"), fakeHead + "\n");
|
|
732
|
+
|
|
733
|
+
mergeMilestoneToMain(repo, "M293", roadmap);
|
|
734
|
+
|
|
735
|
+
// The planted MERGE_HEAD must be cleaned up
|
|
736
|
+
assert.ok(
|
|
737
|
+
!existsSync(join(gitDir, "MERGE_HEAD")),
|
|
738
|
+
"#2912: planted MERGE_HEAD must be removed by success-path cleanup",
|
|
739
|
+
);
|
|
740
|
+
});
|
|
741
|
+
|
|
641
742
|
test("#1906: codeFilesChanged=true when real code is merged", () => {
|
|
642
743
|
const repo = freshRepo();
|
|
643
744
|
const wtPath = createAutoWorktree(repo, "M190");
|