@opengsd/gsd-pi 1.4.0 → 1.5.0-dev.553dc518
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 +11 -11
- package/dist/onboarding.js +11 -0
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +20 -25
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +118 -53
- package/dist/resources/extensions/cursor-cli/index.js +16 -0
- package/dist/resources/extensions/cursor-cli/models.js +63 -0
- package/dist/resources/extensions/cursor-cli/package.json +11 -0
- package/dist/resources/extensions/cursor-cli/readiness.js +128 -0
- package/dist/resources/extensions/cursor-cli/stream-adapter.js +353 -0
- package/dist/resources/extensions/gsd/activity-log.js +4 -1
- package/dist/resources/extensions/gsd/artifact-verification.js +25 -9
- package/dist/resources/extensions/gsd/auto/closeout.js +137 -42
- package/dist/resources/extensions/gsd/auto/finalize.js +9 -0
- package/dist/resources/extensions/gsd/auto/orchestrator.js +4 -3
- package/dist/resources/extensions/gsd/auto/pre-dispatch.js +6 -3
- package/dist/resources/extensions/gsd/auto/run-unit.js +5 -2
- package/dist/resources/extensions/gsd/auto/schedule-wakeup.js +3 -0
- package/dist/resources/extensions/gsd/auto/unit-phase.js +5 -9
- package/dist/resources/extensions/gsd/auto-direct-dispatch.js +4 -5
- package/dist/resources/extensions/gsd/auto-dispatch.js +15 -5
- package/dist/resources/extensions/gsd/auto-model-selection.js +36 -18
- package/dist/resources/extensions/gsd/auto-prompts.js +76 -2
- package/dist/resources/extensions/gsd/auto-start.js +7 -5
- package/dist/resources/extensions/gsd/auto-timeout-recovery.js +4 -0
- package/dist/resources/extensions/gsd/auto-worktree-branch-lifecycle.js +189 -0
- package/dist/resources/extensions/gsd/auto-worktree-cleanup.js +133 -0
- package/dist/resources/extensions/gsd/auto-worktree-conflict-auto-resolve.js +35 -0
- package/dist/resources/extensions/gsd/auto-worktree-creation.js +130 -0
- package/dist/resources/extensions/gsd/auto-worktree-entry.js +118 -0
- package/dist/resources/extensions/gsd/auto-worktree-merge-already-merged.js +98 -0
- package/dist/resources/extensions/gsd/auto-worktree-merge-branch-head.js +52 -0
- package/dist/resources/extensions/gsd/auto-worktree-merge-cleanup.js +87 -0
- package/dist/resources/extensions/gsd/auto-worktree-merge-code-changes.js +46 -0
- package/dist/resources/extensions/gsd/auto-worktree-merge-db-ready.js +68 -0
- package/dist/resources/extensions/gsd/auto-worktree-merge-integration-branch.js +51 -0
- package/dist/resources/extensions/gsd/auto-worktree-merge-message.js +106 -0
- package/dist/resources/extensions/gsd/auto-worktree-merge-pre-teardown.js +64 -0
- package/dist/resources/extensions/gsd/auto-worktree-merge-stash.js +168 -0
- package/dist/resources/extensions/gsd/auto-worktree-merge.js +302 -0
- package/dist/resources/extensions/gsd/auto-worktree-milestone-shelter.js +119 -0
- package/dist/resources/extensions/gsd/auto-worktree-path-resolution.js +5 -0
- package/dist/resources/extensions/gsd/auto-worktree-path-utils.js +5 -0
- package/dist/resources/extensions/gsd/auto-worktree-resource-version.js +41 -0
- package/dist/resources/extensions/gsd/auto-worktree-runtime-cleanup.js +99 -0
- package/dist/resources/extensions/gsd/auto-worktree-session-registry.js +57 -0
- package/dist/resources/extensions/gsd/auto-worktree-sync.js +249 -0
- package/dist/resources/extensions/gsd/auto-worktree-teardown.js +120 -0
- package/dist/resources/extensions/gsd/auto-worktree.js +20 -2046
- package/dist/resources/extensions/gsd/auto.js +31 -5
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +3 -0
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +1 -1
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +133 -6
- package/dist/resources/extensions/gsd/bootstrap/schedule-wakeup-tool.js +58 -9
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +1 -1
- package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +127 -22
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +14 -1
- package/dist/resources/extensions/gsd/codebase-generator.js +157 -19
- package/dist/resources/extensions/gsd/commands/handlers/core.js +40 -4
- package/dist/resources/extensions/gsd/commands-handlers.js +1 -1
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +153 -1
- package/dist/resources/extensions/gsd/commands-workflow-templates.js +3 -3
- package/dist/resources/extensions/gsd/commands-worktree.js +11 -2
- package/dist/resources/extensions/gsd/db/queries.js +48 -9
- package/dist/resources/extensions/gsd/discussion-handoff.js +8 -3
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +8 -2
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +292 -18
- package/dist/resources/extensions/gsd/doctor-providers.js +38 -10
- package/dist/resources/extensions/gsd/doctor.js +93 -3
- package/dist/resources/extensions/gsd/exec-sandbox.js +6 -2
- package/dist/resources/extensions/gsd/flat-phase-migration.js +88 -26
- package/dist/resources/extensions/gsd/forensics.js +1 -1
- package/dist/resources/extensions/gsd/git-conflict-resolve.js +2 -2
- package/dist/resources/extensions/gsd/git-service.js +59 -18
- package/dist/resources/extensions/gsd/gsd-db.js +63 -0
- package/dist/resources/extensions/gsd/guidance.js +1 -0
- package/dist/resources/extensions/gsd/guided-flow.js +46 -12
- package/dist/resources/extensions/gsd/key-manager.js +1 -0
- package/dist/resources/extensions/gsd/markdown-renderer.js +40 -11
- package/dist/resources/extensions/gsd/migrate-external.js +24 -7
- package/dist/resources/extensions/gsd/milestone-merge-transaction.js +14 -3
- package/dist/resources/extensions/gsd/milestone-settlement.js +1 -1
- package/dist/resources/extensions/gsd/parallel-merge.js +1 -1
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +3 -1
- package/dist/resources/extensions/gsd/preferences-diagnostics.js +24 -1
- package/dist/resources/extensions/gsd/preferences-models.js +6 -4
- package/dist/resources/extensions/gsd/preferences-types.js +1 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +107 -2
- package/dist/resources/extensions/gsd/preferences.js +29 -2
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -2
- package/dist/resources/extensions/gsd/prompts/system.md +6 -6
- package/dist/resources/extensions/gsd/quick.js +12 -3
- package/dist/resources/extensions/gsd/redact-secrets.js +37 -0
- package/dist/resources/extensions/gsd/repo-identity.js +16 -0
- package/dist/resources/extensions/gsd/repository-registry.js +6 -1
- package/dist/resources/extensions/gsd/root-write-leak-guard.js +4 -2
- package/dist/resources/extensions/gsd/safe-fs.js +23 -2
- package/dist/resources/extensions/gsd/skills/gsd-headless/SKILL.md +7 -9
- package/dist/resources/extensions/gsd/skills/gsd-headless/references/commands.md +1 -0
- package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +2 -1
- package/dist/resources/extensions/gsd/state/derive/from-db.js +88 -153
- package/dist/resources/extensions/gsd/tool-contract.js +14 -0
- package/dist/resources/extensions/gsd/tools/plan-task.js +76 -8
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +40 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +5 -4
- package/dist/resources/extensions/gsd/unit-registry.js +37 -2
- package/dist/resources/extensions/gsd/unit-runtime.js +21 -0
- package/dist/resources/extensions/gsd/unmerged-milestone-guard.js +1 -1
- package/dist/resources/extensions/gsd/validation-block-guard.js +2 -1
- package/dist/resources/extensions/gsd/workspace-git-preflight.js +2 -2
- package/dist/resources/extensions/gsd/workspace.js +26 -8
- package/dist/resources/extensions/gsd/worktree-command.js +1 -1
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +81 -14
- package/dist/resources/extensions/gsd/worktree-manager.js +97 -4
- package/dist/resources/extensions/gsd/worktree-reentry.js +2 -1
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +10 -10
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/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/mcp-connections/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/mcp-connections/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 +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 +1 -1
- 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 +1 -1
- 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 +10 -10
- package/dist/web/standalone/.next/server/chunks/2842.js +4 -4
- package/dist/web/standalone/.next/server/chunks/8357.js +2 -2
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware.js +3 -3
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/app/_not-found/page-a6fb1847f67f167c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/{layout-b35cbfff38aaf4cf.js → layout-4ae2d68984392bbf.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/page-72a856634ad14c10.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{main-app-590a74400e35f685.js → main-app-90d1d8d5e5d2dc6b.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-1115d46ac61b9823.js +1 -0
- package/dist/web/standalone/node_modules/@gsd/native/package.json +1 -1
- 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/server.js +1 -1
- package/dist/wizard.d.ts +8 -0
- package/dist/wizard.js +8 -1
- package/integrations/hermes/CONTEXT.md +47 -0
- package/integrations/hermes/README.md +21 -0
- package/integrations/hermes/__init__.py +31 -0
- package/integrations/hermes/docs/issue-1162-grilling.md +197 -0
- package/integrations/hermes/docs/setup.md +4 -0
- package/integrations/hermes/open_gsd_hermes/commands.py +141 -0
- package/integrations/hermes/open_gsd_hermes/config.py +2 -0
- package/integrations/hermes/open_gsd_hermes/gsd_client.py +591 -39
- package/integrations/hermes/open_gsd_hermes/notifications.py +10 -1
- package/integrations/hermes/plugin.yaml +4 -0
- package/integrations/hermes/tests/test_config.py +6 -0
- package/integrations/hermes/tests/test_directory_loader.py +37 -0
- package/integrations/hermes/tests/test_gsd_client_cache.py +3 -0
- package/integrations/hermes/tests/test_gsd_client_execute.py +35 -0
- package/integrations/hermes/tests/test_gsd_client_process_cwd.py +22 -0
- package/integrations/hermes/tests/test_gsd_client_timeout.py +98 -0
- package/integrations/hermes/tests/test_milestone_client.py +447 -0
- package/integrations/hermes/tests/test_new_milestone_command.py +313 -0
- package/integrations/hermes/tests/test_supervisor_fsm.py +40 -0
- package/package.json +8 -8
- package/packages/cloud-mcp-gateway/dist/auth-store.d.ts +1 -0
- package/packages/cloud-mcp-gateway/dist/auth-store.d.ts.map +1 -1
- package/packages/cloud-mcp-gateway/dist/auth-store.js +21 -1
- package/packages/cloud-mcp-gateway/dist/auth-store.js.map +1 -1
- package/packages/cloud-mcp-gateway/dist/auth-store.test.js +34 -0
- package/packages/cloud-mcp-gateway/dist/auth-store.test.js.map +1 -1
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/dist/cloud-runtime.d.ts +2 -0
- package/packages/daemon/dist/cloud-runtime.d.ts.map +1 -1
- package/packages/daemon/dist/cloud-runtime.js +25 -1
- package/packages/daemon/dist/cloud-runtime.js.map +1 -1
- package/packages/daemon/dist/cloud-runtime.test.js +51 -0
- package/packages/daemon/dist/cloud-runtime.test.js.map +1 -1
- package/packages/daemon/dist/message-batcher.d.ts +7 -0
- package/packages/daemon/dist/message-batcher.d.ts.map +1 -1
- package/packages/daemon/dist/message-batcher.js +13 -0
- package/packages/daemon/dist/message-batcher.js.map +1 -1
- package/packages/daemon/dist/message-batcher.test.js +48 -0
- package/packages/daemon/dist/message-batcher.test.js.map +1 -1
- package/packages/daemon/dist/session-manager.js +1 -1
- package/packages/daemon/dist/session-manager.js.map +1 -1
- package/packages/daemon/package.json +5 -5
- package/packages/gsd-agent-core/dist/compaction/compaction.d.ts +13 -1
- package/packages/gsd-agent-core/dist/compaction/compaction.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/compaction/compaction.js +15 -1
- package/packages/gsd-agent-core/dist/compaction/compaction.js.map +1 -1
- package/packages/gsd-agent-core/dist/export-html/template.js +53 -4
- package/packages/gsd-agent-core/dist/session/agent-session-navigation.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-navigation.js +4 -1
- package/packages/gsd-agent-core/dist/session/agent-session-navigation.js.map +1 -1
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +3 -2
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.js +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.js +1 -1
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/dist/server.d.ts +18 -5
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +46 -5
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/session-manager.js +1 -1
- package/packages/mcp-server/dist/session-manager.js.map +1 -1
- package/packages/mcp-server/package.json +4 -4
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent-loop.js +14 -9
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/env-api-keys.d.ts.map +1 -1
- package/packages/pi-ai/dist/env-api-keys.js +3 -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/transform-messages.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/transform-messages.js +7 -3
- package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
- package/packages/pi-ai/dist/tool-result-content.d.ts +3 -0
- package/packages/pi-ai/dist/tool-result-content.d.ts.map +1 -0
- package/packages/pi-ai/dist/tool-result-content.js +62 -0
- package/packages/pi-ai/dist/tool-result-content.js.map +1 -0
- package/packages/pi-ai/dist/types.d.ts +10 -22
- 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/package.json +1 -1
- 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/session-manager-types.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager-types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.js +3 -0
- package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/package.json +2 -2
- package/packages/rpc-client/dist/rpc-client.js +1 -1
- package/packages/rpc-client/dist/rpc-client.js.map +1 -1
- package/packages/rpc-client/package.json +2 -2
- package/pkg/dist/core/export-html/template.js +53 -4
- package/pkg/package.json +1 -1
- package/scripts/link-workspace-packages.cjs +14 -4
- package/src/resources/GSD-WORKFLOW.md +20 -25
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +130 -51
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +371 -39
- package/src/resources/extensions/cursor-cli/index.ts +18 -0
- package/src/resources/extensions/cursor-cli/models.ts +65 -0
- package/src/resources/extensions/cursor-cli/package.json +11 -0
- package/src/resources/extensions/cursor-cli/readiness.ts +143 -0
- package/src/resources/extensions/cursor-cli/stream-adapter.ts +440 -0
- package/src/resources/extensions/cursor-cli/tests/index.test.ts +54 -0
- package/src/resources/extensions/cursor-cli/tests/readiness.test.ts +29 -0
- package/src/resources/extensions/cursor-cli/tests/stream-adapter.test.ts +166 -0
- package/src/resources/extensions/gsd/activity-log.ts +4 -1
- package/src/resources/extensions/gsd/artifact-verification.ts +25 -9
- package/src/resources/extensions/gsd/auto/closeout.ts +163 -58
- package/src/resources/extensions/gsd/auto/finalize.ts +8 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
- package/src/resources/extensions/gsd/auto/orchestrator.ts +4 -3
- package/src/resources/extensions/gsd/auto/pre-dispatch.ts +6 -3
- package/src/resources/extensions/gsd/auto/run-unit.ts +5 -2
- package/src/resources/extensions/gsd/auto/schedule-wakeup.ts +8 -0
- package/src/resources/extensions/gsd/auto/unit-phase.ts +5 -9
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +4 -5
- package/src/resources/extensions/gsd/auto-dispatch.ts +17 -5
- package/src/resources/extensions/gsd/auto-model-selection.ts +49 -18
- package/src/resources/extensions/gsd/auto-prompts.ts +73 -2
- package/src/resources/extensions/gsd/auto-start.ts +8 -5
- package/src/resources/extensions/gsd/auto-timeout-recovery.ts +4 -0
- package/src/resources/extensions/gsd/auto-worktree-branch-lifecycle.ts +237 -0
- package/src/resources/extensions/gsd/auto-worktree-cleanup.ts +166 -0
- package/src/resources/extensions/gsd/auto-worktree-conflict-auto-resolve.ts +37 -0
- package/src/resources/extensions/gsd/auto-worktree-creation.ts +171 -0
- package/src/resources/extensions/gsd/auto-worktree-entry.ts +154 -0
- package/src/resources/extensions/gsd/auto-worktree-merge-already-merged.ts +161 -0
- package/src/resources/extensions/gsd/auto-worktree-merge-branch-head.ts +83 -0
- package/src/resources/extensions/gsd/auto-worktree-merge-cleanup.ts +132 -0
- package/src/resources/extensions/gsd/auto-worktree-merge-code-changes.ts +71 -0
- package/src/resources/extensions/gsd/auto-worktree-merge-db-ready.ts +112 -0
- package/src/resources/extensions/gsd/auto-worktree-merge-integration-branch.ts +99 -0
- package/src/resources/extensions/gsd/auto-worktree-merge-message.ts +166 -0
- package/src/resources/extensions/gsd/auto-worktree-merge-pre-teardown.ts +93 -0
- package/src/resources/extensions/gsd/auto-worktree-merge-stash.ts +213 -0
- package/src/resources/extensions/gsd/auto-worktree-merge.ts +391 -0
- package/src/resources/extensions/gsd/auto-worktree-milestone-shelter.ts +159 -0
- package/src/resources/extensions/gsd/auto-worktree-path-resolution.ts +6 -0
- package/src/resources/extensions/gsd/auto-worktree-path-utils.ts +10 -0
- package/src/resources/extensions/gsd/auto-worktree-resource-version.ts +44 -0
- package/src/resources/extensions/gsd/auto-worktree-runtime-cleanup.ts +119 -0
- package/src/resources/extensions/gsd/auto-worktree-session-registry.ts +71 -0
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +370 -0
- package/src/resources/extensions/gsd/auto-worktree-teardown.ts +161 -0
- package/src/resources/extensions/gsd/auto-worktree.ts +69 -2390
- package/src/resources/extensions/gsd/auto.ts +32 -19
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +3 -0
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +1 -1
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +147 -6
- package/src/resources/extensions/gsd/bootstrap/schedule-wakeup-tool.ts +80 -12
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +1 -1
- package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +163 -22
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +23 -1
- package/src/resources/extensions/gsd/codebase-generator.ts +179 -18
- package/src/resources/extensions/gsd/commands/handlers/core.ts +39 -3
- package/src/resources/extensions/gsd/commands-handlers.ts +1 -1
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +135 -1
- package/src/resources/extensions/gsd/commands-workflow-templates.ts +3 -3
- package/src/resources/extensions/gsd/commands-worktree.ts +13 -2
- package/src/resources/extensions/gsd/db/queries.ts +49 -9
- package/src/resources/extensions/gsd/discussion-handoff.ts +10 -2
- package/src/resources/extensions/gsd/docs/preferences-reference.md +8 -2
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +372 -22
- package/src/resources/extensions/gsd/doctor-providers.ts +39 -10
- package/src/resources/extensions/gsd/doctor-types.ts +5 -1
- package/src/resources/extensions/gsd/doctor.ts +95 -3
- package/src/resources/extensions/gsd/exec-sandbox.ts +6 -2
- package/src/resources/extensions/gsd/flat-phase-migration.ts +112 -25
- package/src/resources/extensions/gsd/forensics.ts +1 -1
- package/src/resources/extensions/gsd/git-conflict-resolve.ts +2 -2
- package/src/resources/extensions/gsd/git-service.ts +67 -17
- package/src/resources/extensions/gsd/gsd-db.ts +85 -0
- package/src/resources/extensions/gsd/guidance.ts +2 -0
- package/src/resources/extensions/gsd/guided-flow.ts +52 -13
- package/src/resources/extensions/gsd/key-manager.ts +1 -0
- package/src/resources/extensions/gsd/markdown-renderer.ts +40 -10
- package/src/resources/extensions/gsd/migrate-external.ts +23 -6
- package/src/resources/extensions/gsd/milestone-merge-transaction.ts +19 -4
- package/src/resources/extensions/gsd/milestone-settlement.ts +1 -1
- package/src/resources/extensions/gsd/model-router.ts +4 -5
- package/src/resources/extensions/gsd/parallel-merge.ts +1 -1
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +3 -1
- package/src/resources/extensions/gsd/preferences-diagnostics.ts +24 -0
- package/src/resources/extensions/gsd/preferences-models.ts +6 -3
- package/src/resources/extensions/gsd/preferences-types.ts +30 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +97 -2
- package/src/resources/extensions/gsd/preferences.ts +38 -4
- package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -2
- package/src/resources/extensions/gsd/prompts/system.md +6 -6
- package/src/resources/extensions/gsd/quick.ts +11 -3
- package/src/resources/extensions/gsd/redact-secrets.ts +40 -0
- package/src/resources/extensions/gsd/repo-identity.ts +17 -0
- package/src/resources/extensions/gsd/repository-registry.ts +7 -1
- package/src/resources/extensions/gsd/root-write-leak-guard.ts +3 -2
- package/src/resources/extensions/gsd/safe-fs.ts +22 -2
- package/src/resources/extensions/gsd/skills/gsd-headless/SKILL.md +7 -9
- package/src/resources/extensions/gsd/skills/gsd-headless/references/commands.md +1 -0
- package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +3 -1
- package/src/resources/extensions/gsd/state/derive/from-db.ts +201 -157
- package/src/resources/extensions/gsd/tests/auto-loop-no-copy-artifacts.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +131 -5
- package/src/resources/extensions/gsd/tests/auto-migrating-recovery.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +178 -0
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +43 -1
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/auto-remote-session-lock-cleanup.test.ts +41 -0
- package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +41 -0
- package/src/resources/extensions/gsd/tests/auto-session-scope.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-timeout-recovery-harness-abort.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +10 -1
- package/src/resources/extensions/gsd/tests/auto-worktree-auto-resolve.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-worktree-merge-already-merged.test.ts +177 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-merge-branch-head.test.ts +118 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-merge-cleanup.test.ts +115 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-merge-code-changes.test.ts +76 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-merge-db-ready.test.ts +140 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-merge-integration-branch.test.ts +123 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-merge-message.test.ts +114 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-merge-pre-teardown.test.ts +84 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-merge-stash.test.ts +70 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-shelter.test.ts +52 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +6 -6
- package/src/resources/extensions/gsd/tests/auto-worktree-resource-version.test.ts +59 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-untracked-content.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/batch-task-query.test.ts +85 -0
- package/src/resources/extensions/gsd/tests/check-auto-start-ready-guard.test.ts +29 -0
- package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +365 -0
- package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +62 -1
- package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +138 -1
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +571 -5
- package/src/resources/extensions/gsd/tests/doctor-workspace.test.ts +207 -0
- package/src/resources/extensions/gsd/tests/fast-forward-reused-milestone-branch.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +82 -2
- package/src/resources/extensions/gsd/tests/flat-phase-renderer.test.ts +25 -1
- package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +87 -19
- package/src/resources/extensions/gsd/tests/gate-1b-orphan-discrimination.test.ts +89 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +4 -6
- package/src/resources/extensions/gsd/tests/integration/auto-stash-merge.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +7 -8
- package/src/resources/extensions/gsd/tests/integration/feature-branch-lifecycle-integration.test.ts +2 -5
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +76 -0
- package/src/resources/extensions/gsd/tests/integration/merge-cwd-restore.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/integration/merge-preserve-worktree-on-preteardown-error.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/integration/merge-strategy-regular.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/integration/milestone-transition-worktree.test.ts +5 -7
- package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/integration/workspace-collapse-integration.test.ts +2 -4
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +122 -0
- package/src/resources/extensions/gsd/tests/merge-closeout-consistency-gate.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/merge-self-branch-guard.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/migrate-external-worktree.test.ts +116 -0
- package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +592 -23
- package/src/resources/extensions/gsd/tests/milestone-merge-transaction.test.ts +25 -1
- package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/parallel-worker-lock-contention.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/pending-autostart-scope.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +50 -6
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +17 -0
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +264 -1
- package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +1 -4
- package/src/resources/extensions/gsd/tests/preferences.test.ts +150 -0
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +147 -0
- package/src/resources/extensions/gsd/tests/recovery-verify-logs.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/redact-secrets.test.ts +56 -0
- package/src/resources/extensions/gsd/tests/register-hooks-flat-phase-migration.test.ts +73 -0
- package/src/resources/extensions/gsd/tests/register-hooks-loop-guard-auto.test.ts +275 -0
- package/src/resources/extensions/gsd/tests/repository-registry.test.ts +41 -2
- package/src/resources/extensions/gsd/tests/require-slice-discussion-dispatch.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/root-write-leak-guard.test.ts +31 -9
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/schedule-wakeup-tool.test.ts +167 -0
- package/src/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +3 -5
- package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +49 -0
- package/src/resources/extensions/gsd/tests/stash-pop-gsd-conflict.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/status-per-repo.test.ts +94 -0
- package/src/resources/extensions/gsd/tests/steer-worktree-path.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/system-flat-phase-layout.test.ts +33 -0
- package/src/resources/extensions/gsd/tests/teardown-chdir-failure-clears-registry.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/teardown-cleanup-parity.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/teardown-failure-clears-registry.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +166 -0
- package/src/resources/extensions/gsd/tests/uat-stuck-loop-orphaned-worktree.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +66 -18
- package/src/resources/extensions/gsd/tests/unit-registry.test.ts +81 -0
- package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/uok-gitops-turn-action.test.ts +52 -0
- package/src/resources/extensions/gsd/tests/validator-scope-parity.test.ts +53 -1
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +208 -1
- package/src/resources/extensions/gsd/tests/workspace.test.ts +18 -4
- package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-db-respawn-truncation.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-db-same-file.test.ts +1 -3
- package/src/resources/extensions/gsd/tests/worktree-expected-warnings.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-git-pathspec.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/worktree-main-branch.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-preferences-sync.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-reentry.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +36 -3
- package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-sync-tasks.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +32 -0
- package/src/resources/extensions/gsd/tool-contract.ts +29 -0
- package/src/resources/extensions/gsd/tools/plan-task.ts +107 -9
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +58 -0
- package/src/resources/extensions/gsd/unit-context-manifest.ts +11 -5
- package/src/resources/extensions/gsd/unit-registry.ts +48 -2
- package/src/resources/extensions/gsd/unit-runtime.ts +42 -0
- package/src/resources/extensions/gsd/unmerged-milestone-guard.ts +1 -1
- package/src/resources/extensions/gsd/validation-block-guard.ts +2 -1
- package/src/resources/extensions/gsd/workspace-git-preflight.ts +2 -2
- package/src/resources/extensions/gsd/workspace.ts +42 -8
- package/src/resources/extensions/gsd/worktree-command.ts +1 -1
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +154 -26
- package/src/resources/extensions/gsd/worktree-manager.ts +143 -5
- package/src/resources/extensions/gsd/worktree-reentry.ts +2 -1
- package/dist/web/standalone/.next/static/chunks/app/_not-found/page-49f565245e1e4afe.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/page-bc4c723c6a19c6f0.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ec3eaffc9785ba48.js +0 -1
- /package/dist/web/standalone/.next/static/{zQLcXm0Za8lexoXtgDpMG → ZpFDazP-38PXBPiI_LdZf}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{zQLcXm0Za8lexoXtgDpMG → ZpFDazP-38PXBPiI_LdZf}/_ssgManifest.js +0 -0
|
@@ -21,31 +21,155 @@
|
|
|
21
21
|
* signature, so the identical-args streak never trips, while allowing
|
|
22
22
|
* tool-heavy turns that are making file-mutation progress. Whichever guard
|
|
23
23
|
* trips first blocks.
|
|
24
|
+
*
|
|
25
|
+
* Thresholds, exempt tools, and enable flags are user-tunable (#1198) via the
|
|
26
|
+
* `tool_call_loop_guard` key in `.gsd/PREFERENCES.md` and `GSD_TOOL_LOOP_*`
|
|
27
|
+
* environment variables, applied through {@link configureToolCallLoopGuard}.
|
|
28
|
+
* Defaults preserve the original hardcoded behavior.
|
|
24
29
|
*/
|
|
25
30
|
|
|
26
31
|
import { createHash } from "node:crypto";
|
|
27
32
|
import { INHERENTLY_REPEATABLE_TOOL_SET } from "./core-session-tools.js";
|
|
33
|
+
import { hasBrowserContractPrefix } from "../../shared/browser-contract.js";
|
|
34
|
+
import { canonicalToolName } from "../engine-hook-contract.js";
|
|
28
35
|
|
|
29
|
-
|
|
36
|
+
/** Built-in defaults. Preserved when preferences/env do not override them. */
|
|
37
|
+
const DEFAULT_MAX_CONSECUTIVE_IDENTICAL_CALLS = 4;
|
|
38
|
+
const DEFAULT_PER_TOOL_DEFAULT_CAP = 6;
|
|
39
|
+
const DEFAULT_PER_TOOL_REPEATABLE_CAP = 15;
|
|
40
|
+
const DEFAULT_PER_TOOL_CAP_EXEMPT_TOOLS = ["find", "glob", "grep", "ls", "read", "search_and_read"] as const;
|
|
30
41
|
|
|
31
42
|
/** Interactive/user-facing tools where even 1 duplicate is confusing. */
|
|
32
43
|
const STRICT_LOOP_TOOLS = new Set(["ask_user_questions"]);
|
|
33
44
|
const MAX_CONSECUTIVE_STRICT = 1;
|
|
34
45
|
|
|
46
|
+
const STATE_MUTATING_TOOL_SET = new Set(["edit", "write", "multi_edit", "notebook_edit"]);
|
|
47
|
+
|
|
35
48
|
/**
|
|
36
|
-
*
|
|
49
|
+
* User-tunable configuration shape for the loop guard (#1198).
|
|
37
50
|
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* and any non-allowlisted tool — gets the default cap. The default is generous
|
|
42
|
-
* enough to absorb legitimate retries but catches the reported improvisation
|
|
43
|
-
* loop (~51 calls) well before a cost spike.
|
|
51
|
+
* Mirrors the `tool_call_loop_guard` key in `.gsd/PREFERENCES.md`. All fields
|
|
52
|
+
* are optional; anything omitted falls back to the built-in defaults so that
|
|
53
|
+
* existing installs keep their current behavior.
|
|
44
54
|
*/
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
55
|
+
export interface ToolCallLoopGuardConfig {
|
|
56
|
+
enabled?: boolean;
|
|
57
|
+
identical_args?: {
|
|
58
|
+
enabled?: boolean;
|
|
59
|
+
max_consecutive_calls?: number;
|
|
60
|
+
};
|
|
61
|
+
repeated_tool?: {
|
|
62
|
+
enabled?: boolean;
|
|
63
|
+
default_cap?: number;
|
|
64
|
+
repeatable_cap?: number;
|
|
65
|
+
exempt_tools?: string[];
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Active, resolved configuration. Set by {@link configureToolCallLoopGuard}
|
|
71
|
+
* from preferences + environment overrides, and deliberately NOT touched by
|
|
72
|
+
* {@link resetToolCallLoopGuard} so a session's tuning survives turn
|
|
73
|
+
* boundaries.
|
|
74
|
+
*/
|
|
75
|
+
interface ResolvedGuardConfig {
|
|
76
|
+
/** Master switch for both guards. */
|
|
77
|
+
guardEnabled: boolean;
|
|
78
|
+
identicalEnabled: boolean;
|
|
79
|
+
maxConsecutiveIdentical: number;
|
|
80
|
+
repeatedEnabled: boolean;
|
|
81
|
+
perToolDefaultCap: number;
|
|
82
|
+
perToolRepeatableCap: number;
|
|
83
|
+
/** Tool names exempt from Guard 2 (per-tool-name cap). */
|
|
84
|
+
perToolExempt: Set<string>;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function defaultGuardConfig(): ResolvedGuardConfig {
|
|
88
|
+
return {
|
|
89
|
+
guardEnabled: true,
|
|
90
|
+
identicalEnabled: true,
|
|
91
|
+
maxConsecutiveIdentical: DEFAULT_MAX_CONSECUTIVE_IDENTICAL_CALLS,
|
|
92
|
+
repeatedEnabled: true,
|
|
93
|
+
perToolDefaultCap: DEFAULT_PER_TOOL_DEFAULT_CAP,
|
|
94
|
+
perToolRepeatableCap: DEFAULT_PER_TOOL_REPEATABLE_CAP,
|
|
95
|
+
perToolExempt: new Set<string>(DEFAULT_PER_TOOL_CAP_EXEMPT_TOOLS),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
let config: ResolvedGuardConfig = defaultGuardConfig();
|
|
100
|
+
|
|
101
|
+
/** Parse a positive-integer env var, returning undefined when unset/invalid. */
|
|
102
|
+
function envPositiveInt(name: string): number | undefined {
|
|
103
|
+
const raw = process.env[name];
|
|
104
|
+
if (raw === undefined || raw.trim() === "") return undefined;
|
|
105
|
+
const n = Number(raw);
|
|
106
|
+
return Number.isFinite(n) && n >= 1 ? Math.floor(n) : undefined;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Parse a boolean env var (`true`/`1` vs `false`/`0`), undefined when unset. */
|
|
110
|
+
function envBool(name: string): boolean | undefined {
|
|
111
|
+
const raw = process.env[name];
|
|
112
|
+
if (raw === undefined || raw.trim() === "") return undefined;
|
|
113
|
+
const v = raw.trim().toLowerCase();
|
|
114
|
+
if (v === "true" || v === "1" || v === "yes" || v === "on") return true;
|
|
115
|
+
if (v === "false" || v === "0" || v === "no" || v === "off") return false;
|
|
116
|
+
return undefined;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** Parse a comma-separated tool-name list env var. */
|
|
120
|
+
function envToolList(name: string): string[] {
|
|
121
|
+
const raw = process.env[name];
|
|
122
|
+
if (!raw) return [];
|
|
123
|
+
return raw.split(",").map((s) => s.trim()).filter(Boolean);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Resolve preferences + environment overrides into the active configuration.
|
|
128
|
+
* Environment variables win over preferences; preferences win over built-in
|
|
129
|
+
* defaults. User-supplied exempt tools are additive to the built-in exempt
|
|
130
|
+
* set so defaults are always preserved.
|
|
131
|
+
*
|
|
132
|
+
* Applied to both interactive sessions and `/gsd auto` (called from the
|
|
133
|
+
* session_start / session_switch hooks).
|
|
134
|
+
*/
|
|
135
|
+
export function configureToolCallLoopGuard(prefs?: ToolCallLoopGuardConfig | null): void {
|
|
136
|
+
const next = defaultGuardConfig();
|
|
137
|
+
|
|
138
|
+
if (prefs) {
|
|
139
|
+
if (typeof prefs.enabled === "boolean") next.guardEnabled = prefs.enabled;
|
|
140
|
+
if (prefs.identical_args) {
|
|
141
|
+
if (typeof prefs.identical_args.enabled === "boolean") next.identicalEnabled = prefs.identical_args.enabled;
|
|
142
|
+
if (typeof prefs.identical_args.max_consecutive_calls === "number" && prefs.identical_args.max_consecutive_calls >= 1) {
|
|
143
|
+
next.maxConsecutiveIdentical = Math.floor(prefs.identical_args.max_consecutive_calls);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (prefs.repeated_tool) {
|
|
147
|
+
if (typeof prefs.repeated_tool.enabled === "boolean") next.repeatedEnabled = prefs.repeated_tool.enabled;
|
|
148
|
+
if (typeof prefs.repeated_tool.default_cap === "number" && prefs.repeated_tool.default_cap >= 1) {
|
|
149
|
+
next.perToolDefaultCap = Math.floor(prefs.repeated_tool.default_cap);
|
|
150
|
+
}
|
|
151
|
+
if (typeof prefs.repeated_tool.repeatable_cap === "number" && prefs.repeated_tool.repeatable_cap >= 1) {
|
|
152
|
+
next.perToolRepeatableCap = Math.floor(prefs.repeated_tool.repeatable_cap);
|
|
153
|
+
}
|
|
154
|
+
for (const tool of prefs.repeated_tool.exempt_tools ?? []) {
|
|
155
|
+
if (typeof tool === "string" && tool.trim()) next.perToolExempt.add(tool.trim());
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Environment overrides (win over preferences).
|
|
161
|
+
const envEnabled = envBool("GSD_TOOL_LOOP_GUARD_ENABLED");
|
|
162
|
+
if (envEnabled !== undefined) next.guardEnabled = envEnabled;
|
|
163
|
+
const envIdenticalMax = envPositiveInt("GSD_TOOL_LOOP_IDENTICAL_MAX");
|
|
164
|
+
if (envIdenticalMax !== undefined) next.maxConsecutiveIdentical = envIdenticalMax;
|
|
165
|
+
const envDefaultCap = envPositiveInt("GSD_TOOL_LOOP_REPEATED_DEFAULT_CAP");
|
|
166
|
+
if (envDefaultCap !== undefined) next.perToolDefaultCap = envDefaultCap;
|
|
167
|
+
const envRepeatableCap = envPositiveInt("GSD_TOOL_LOOP_REPEATED_REPEATABLE_CAP");
|
|
168
|
+
if (envRepeatableCap !== undefined) next.perToolRepeatableCap = envRepeatableCap;
|
|
169
|
+
for (const tool of envToolList("GSD_TOOL_LOOP_EXEMPT_TOOLS")) next.perToolExempt.add(tool);
|
|
170
|
+
|
|
171
|
+
config = next;
|
|
172
|
+
}
|
|
49
173
|
|
|
50
174
|
let consecutiveCount = 0;
|
|
51
175
|
let lastSignature = "";
|
|
@@ -80,17 +204,20 @@ function hashToolCall(toolName: string, args: Record<string, unknown>): string {
|
|
|
80
204
|
* Returns `{ block: true, reason }` when the loop threshold is exceeded.
|
|
81
205
|
*
|
|
82
206
|
* Two independent guards run; whichever trips first blocks:
|
|
83
|
-
* 1. Identical-signature streak (
|
|
207
|
+
* 1. Identical-signature streak (config.maxConsecutiveIdentical, strict for
|
|
84
208
|
* ask_user_questions).
|
|
85
|
-
* 2. Per-tool-name cap (
|
|
209
|
+
* 2. Per-tool-name cap (config.perToolDefaultCap / config.perToolRepeatableCap),
|
|
86
210
|
* independent of args, reset after file-mutation progress — catches
|
|
87
211
|
* improvisation loops (#783).
|
|
212
|
+
*
|
|
213
|
+
* Both guards, their thresholds, and the per-tool exempt set are user-tunable
|
|
214
|
+
* via {@link configureToolCallLoopGuard} (#1198).
|
|
88
215
|
*/
|
|
89
216
|
export function checkToolCallLoop(
|
|
90
217
|
toolName: string,
|
|
91
218
|
args: Record<string, unknown>,
|
|
92
219
|
): { block: boolean; reason?: string; count?: number } {
|
|
93
|
-
if (!enabled) return { block: false, count: 0 };
|
|
220
|
+
if (!enabled || !config.guardEnabled) return { block: false, count: 0 };
|
|
94
221
|
|
|
95
222
|
const sig = hashToolCall(toolName, args);
|
|
96
223
|
|
|
@@ -105,14 +232,16 @@ export function checkToolCallLoop(
|
|
|
105
232
|
// ── Guard 1: identical-signature streak ──
|
|
106
233
|
const threshold = STRICT_LOOP_TOOLS.has(toolName)
|
|
107
234
|
? MAX_CONSECUTIVE_STRICT
|
|
108
|
-
:
|
|
235
|
+
: config.maxConsecutiveIdentical;
|
|
109
236
|
|
|
110
|
-
if (consecutiveCount > threshold) {
|
|
237
|
+
if (config.identicalEnabled && consecutiveCount > threshold) {
|
|
111
238
|
return {
|
|
112
239
|
block: true,
|
|
113
240
|
reason:
|
|
114
241
|
`Tool loop detected (identical args): ${toolName} called ${consecutiveCount} times ` +
|
|
115
|
-
`with identical arguments. Blocking to prevent infinite loop. ` +
|
|
242
|
+
`with identical arguments (max ${threshold}). Blocking to prevent infinite loop. ` +
|
|
243
|
+
`Raise tool_call_loop_guard.identical_args.max_consecutive_calls in .gsd/PREFERENCES.md ` +
|
|
244
|
+
`(or GSD_TOOL_LOOP_IDENTICAL_MAX) if this is expected. ` +
|
|
116
245
|
`Do not retry this tool or call other tools this turn — stop and respond to the user in text.`,
|
|
117
246
|
count: consecutiveCount,
|
|
118
247
|
};
|
|
@@ -130,14 +259,23 @@ export function checkToolCallLoop(
|
|
|
130
259
|
perToolLastMutationEpoch.set(toolName, mutationEpoch);
|
|
131
260
|
|
|
132
261
|
// Read-only navigation tools are normal context gathering; Guard 1 still
|
|
133
|
-
// catches true reread loops with identical arguments.
|
|
134
|
-
|
|
262
|
+
// catches true reread loops with identical arguments. Browser Automation
|
|
263
|
+
// Contract tools (browser_*) are the same shape: a browser-backed UAT makes
|
|
264
|
+
// many distinct-arg calls (read a message, count edits, inspect a card, …),
|
|
265
|
+
// so the arg-independent per-tool cap misfires on legitimate verification;
|
|
266
|
+
// Guard 1's identical-signature streak still catches a genuinely stuck
|
|
267
|
+
// browser loop.
|
|
268
|
+
if (
|
|
269
|
+
!config.repeatedEnabled ||
|
|
270
|
+
config.perToolExempt.has(toolName) ||
|
|
271
|
+
hasBrowserContractPrefix(canonicalToolName(toolName))
|
|
272
|
+
) {
|
|
135
273
|
return { block: false, count: consecutiveCount };
|
|
136
274
|
}
|
|
137
275
|
|
|
138
276
|
const perToolCap = INHERENTLY_REPEATABLE_TOOL_SET.has(toolName)
|
|
139
|
-
?
|
|
140
|
-
:
|
|
277
|
+
? config.perToolRepeatableCap
|
|
278
|
+
: config.perToolDefaultCap;
|
|
141
279
|
|
|
142
280
|
if (perToolCount > perToolCap) {
|
|
143
281
|
return {
|
|
@@ -146,6 +284,9 @@ export function checkToolCallLoop(
|
|
|
146
284
|
`Tool loop detected (repeated tool): ${toolName} called ${perToolCount} times ` +
|
|
147
285
|
`this turn (cap ${perToolCap}). Blocking to prevent infinite loop. ` +
|
|
148
286
|
`The tool may be unavailable or failing repeatedly. ` +
|
|
287
|
+
`Raise tool_call_loop_guard.repeated_tool.default_cap/repeatable_cap or add "${toolName}" ` +
|
|
288
|
+
`to tool_call_loop_guard.repeated_tool.exempt_tools in .gsd/PREFERENCES.md ` +
|
|
289
|
+
`(or GSD_TOOL_LOOP_REPEATED_* / GSD_TOOL_LOOP_EXEMPT_TOOLS) if this is expected. ` +
|
|
149
290
|
`Do not retry this tool or pivot to other tools this turn — stop and respond to the user in text.`,
|
|
150
291
|
count: perToolCount,
|
|
151
292
|
};
|
|
@@ -1169,7 +1169,7 @@ function allowsControlledSubagentDispatch(
|
|
|
1169
1169
|
policy: ToolsPolicy,
|
|
1170
1170
|
): policy is ToolsPolicy & { readonly allowedSubagents: readonly string[] } {
|
|
1171
1171
|
return (
|
|
1172
|
-
(policy.mode === "planning-dispatch" || policy.mode === "verification") &&
|
|
1172
|
+
(policy.mode === "planning-dispatch" || policy.mode === "verification" || policy.mode === "workflow-only") &&
|
|
1173
1173
|
Array.isArray((policy as { readonly allowedSubagents?: unknown }).allowedSubagents)
|
|
1174
1174
|
);
|
|
1175
1175
|
}
|
|
@@ -1199,6 +1199,7 @@ function warnMissingControlledDispatchAgentClasses(unitType: string, mode: strin
|
|
|
1199
1199
|
const PLANNING_SAFE_TOOLS = new Set([
|
|
1200
1200
|
"read", "grep", "find", "ls", "glob",
|
|
1201
1201
|
"ask_user_questions",
|
|
1202
|
+
"memory_query",
|
|
1202
1203
|
"search-the-web", "resolve_library", "get_library_docs", "fetch_page",
|
|
1203
1204
|
"search_and_read",
|
|
1204
1205
|
]);
|
|
@@ -1265,6 +1266,9 @@ type PlanningUnitBlockResult = {
|
|
|
1265
1266
|
* → allows Bash for project verification commands, keeps
|
|
1266
1267
|
* writes restricted to .gsd/, and permits subagent dispatch
|
|
1267
1268
|
* only when the manifest declares allowedSubagents.
|
|
1269
|
+
* - "workflow-only"
|
|
1270
|
+
* → allows reads, GSD workflow tools, and declared read-only
|
|
1271
|
+
* subagents; blocks generic Bash and direct file writes.
|
|
1268
1272
|
*
|
|
1269
1273
|
* `pathOrCommand` is the file path for write/edit-shaped tools and the
|
|
1270
1274
|
* shell command for bash. Other tools ignore this argument.
|
|
@@ -1354,6 +1358,24 @@ export function shouldBlockPlanningUnit(
|
|
|
1354
1358
|
return planningBlock(unitType, policy.mode, "subagent dispatch is not permitted in planning units");
|
|
1355
1359
|
}
|
|
1356
1360
|
|
|
1361
|
+
if (policy.mode === "workflow-only") {
|
|
1362
|
+
if (tool === "bash") {
|
|
1363
|
+
return planningBlock(
|
|
1364
|
+
unitType,
|
|
1365
|
+
policy.mode,
|
|
1366
|
+
`bash is not permitted; use the unit's dedicated GSD workflow tools for durable validation output`,
|
|
1367
|
+
);
|
|
1368
|
+
}
|
|
1369
|
+
if (PLANNING_WRITE_TOOLS.has(tool)) {
|
|
1370
|
+
return planningBlock(
|
|
1371
|
+
unitType,
|
|
1372
|
+
policy.mode,
|
|
1373
|
+
`cannot ${tool} "${pathOrCommand}" — direct artifact writes are disabled; call the required GSD workflow tool instead`,
|
|
1374
|
+
);
|
|
1375
|
+
}
|
|
1376
|
+
return planningBlock(unitType, policy.mode, `tool "${tool}" is not on the workflow-only allowlist`);
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1357
1379
|
if (tool === "bash") {
|
|
1358
1380
|
if (policy.mode === "verification") {
|
|
1359
1381
|
if (BASH_VERIFICATION_RE.test(pathOrCommand) || BASH_READ_ONLY_RE.test(pathOrCommand)) return { block: false };
|
|
@@ -10,10 +10,15 @@
|
|
|
10
10
|
|
|
11
11
|
import { createHash } from "node:crypto";
|
|
12
12
|
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
13
|
-
import { join, dirname, extname } from "node:path";
|
|
13
|
+
import { join, dirname, extname, relative, sep } from "node:path";
|
|
14
14
|
|
|
15
15
|
import { execSync } from "node:child_process";
|
|
16
16
|
import { gsdRoot } from "./paths.js";
|
|
17
|
+
import {
|
|
18
|
+
createRepositoryRegistryFromPreferences,
|
|
19
|
+
type RepositoryRegistry,
|
|
20
|
+
} from "./repository-registry.js";
|
|
21
|
+
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
17
22
|
|
|
18
23
|
// ─── Types ───────────────────────────────────────────────────────────────────
|
|
19
24
|
|
|
@@ -28,6 +33,8 @@ export interface CodebaseMapMetadata {
|
|
|
28
33
|
fingerprint: string;
|
|
29
34
|
fileCount: number;
|
|
30
35
|
truncated: boolean;
|
|
36
|
+
/** Repo ids whose files appear in a workspace-aware map (parent mode only). */
|
|
37
|
+
repositories?: string[];
|
|
31
38
|
}
|
|
32
39
|
|
|
33
40
|
export interface EnsureCodebaseMapOptions {
|
|
@@ -48,12 +55,16 @@ export interface EnsureCodebaseMapResult {
|
|
|
48
55
|
interface FileEntry {
|
|
49
56
|
path: string;
|
|
50
57
|
description: string;
|
|
58
|
+
/** Declaring repo id for workspace-aware maps (parent mode); undefined otherwise. */
|
|
59
|
+
repo?: string;
|
|
51
60
|
}
|
|
52
61
|
|
|
53
62
|
interface DirectoryGroup {
|
|
54
63
|
path: string;
|
|
55
64
|
files: FileEntry[];
|
|
56
65
|
collapsed: boolean;
|
|
66
|
+
/** Repo id this group belongs to for workspace-aware maps; undefined otherwise. */
|
|
67
|
+
repo?: string;
|
|
57
68
|
}
|
|
58
69
|
|
|
59
70
|
interface ResolvedCodebaseMapOptions {
|
|
@@ -66,6 +77,8 @@ interface ResolvedCodebaseMapOptions {
|
|
|
66
77
|
interface EnumeratedFiles {
|
|
67
78
|
files: string[];
|
|
68
79
|
truncated: boolean;
|
|
80
|
+
/** Per-file repo labels aligned with `files` (workspace-aware maps only). */
|
|
81
|
+
repos?: string[];
|
|
69
82
|
}
|
|
70
83
|
|
|
71
84
|
// ─── Defaults ────────────────────────────────────────────────────────────────
|
|
@@ -209,13 +222,99 @@ function lsFiles(basePath: string): string[] {
|
|
|
209
222
|
* Enumerate tracked files, applying exclusions and the maxFiles cap.
|
|
210
223
|
* Returns both the file list and whether truncation occurred.
|
|
211
224
|
*/
|
|
212
|
-
function enumerateFiles(basePath: string, excludes: string[], maxFiles: number):
|
|
225
|
+
function enumerateFiles(basePath: string, excludes: string[], maxFiles: number): EnumeratedFiles {
|
|
213
226
|
const allFiles = lsFiles(basePath);
|
|
214
227
|
const filtered = allFiles.filter((f) => !shouldExclude(f, excludes));
|
|
215
228
|
const truncated = filtered.length > maxFiles;
|
|
216
229
|
return { files: truncated ? filtered.slice(0, maxFiles) : filtered, truncated };
|
|
217
230
|
}
|
|
218
231
|
|
|
232
|
+
/**
|
|
233
|
+
* Build a workspace-aware registry for parent mode, or null when the project is
|
|
234
|
+
* single-repo (no declared child repositories). Returns null so the caller falls
|
|
235
|
+
* back to the legacy single-root enumeration and produces byte-identical output.
|
|
236
|
+
*/
|
|
237
|
+
function loadWorkspaceRegistry(basePath: string): RepositoryRegistry | null {
|
|
238
|
+
const preferences = loadEffectiveGSDPreferences(basePath)?.preferences;
|
|
239
|
+
const workspace = preferences?.workspace;
|
|
240
|
+
const mode = workspace?.mode ?? "project";
|
|
241
|
+
// Parent mode is only meaningful with at least one declared child repo; the
|
|
242
|
+
// implicit "project" repo is always present, so require a declared non-project id.
|
|
243
|
+
const hasDeclaredChildRepo = workspace?.repositories
|
|
244
|
+
? Object.keys(workspace.repositories).some((id) => id !== "project")
|
|
245
|
+
: false;
|
|
246
|
+
if (mode !== "parent" || !hasDeclaredChildRepo) {
|
|
247
|
+
return null;
|
|
248
|
+
}
|
|
249
|
+
return createRepositoryRegistryFromPreferences(basePath, preferences);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/** Stable key fragment for workspace-aware enumeration inputs (mode + declared repos). */
|
|
253
|
+
function workspaceEnumerationSignature(basePath: string): string {
|
|
254
|
+
const registry = loadWorkspaceRegistry(basePath);
|
|
255
|
+
if (!registry) return "single-root";
|
|
256
|
+
return JSON.stringify({
|
|
257
|
+
mode: registry.mode,
|
|
258
|
+
repositories: registry.repositories
|
|
259
|
+
.map((repo) => ({ id: repo.id, root: repo.root }))
|
|
260
|
+
.sort((a, b) => a.id.localeCompare(b.id)),
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Enumerate tracked files across every declared repository in a parent workspace.
|
|
266
|
+
* Child-repo paths are rewritten to be workspace-relative (e.g. `frontend/src/x`)
|
|
267
|
+
* and tagged with their declaring repo id so the map can render repo-labelled
|
|
268
|
+
* sections. The maxFiles cap is applied across the union of all repositories.
|
|
269
|
+
*/
|
|
270
|
+
function enumerateWorkspaceFiles(
|
|
271
|
+
registry: RepositoryRegistry,
|
|
272
|
+
excludes: string[],
|
|
273
|
+
maxFiles: number,
|
|
274
|
+
): EnumeratedFiles {
|
|
275
|
+
type WorkspaceEntry = { workspacePath: string; repoId: string };
|
|
276
|
+
const perRepo: WorkspaceEntry[][] = [];
|
|
277
|
+
const seen = new Set<string>();
|
|
278
|
+
let totalEligible = 0;
|
|
279
|
+
|
|
280
|
+
for (const repo of registry.repositories) {
|
|
281
|
+
const rawFiles = lsFiles(repo.root);
|
|
282
|
+
const repoPrefix = relative(registry.projectRoot, repo.root).split(sep).join("/");
|
|
283
|
+
const repoEntries: WorkspaceEntry[] = [];
|
|
284
|
+
|
|
285
|
+
for (const file of rawFiles) {
|
|
286
|
+
// Rewrite before exclusion so workspace-relative patterns (e.g. frontend/…) apply.
|
|
287
|
+
const workspacePath = repoPrefix ? `${repoPrefix}/${file}` : file;
|
|
288
|
+
if (shouldExclude(workspacePath, excludes)) continue;
|
|
289
|
+
if (seen.has(workspacePath)) continue;
|
|
290
|
+
seen.add(workspacePath);
|
|
291
|
+
totalEligible++;
|
|
292
|
+
repoEntries.push({ workspacePath, repoId: repo.id });
|
|
293
|
+
}
|
|
294
|
+
perRepo.push(repoEntries);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const files: string[] = [];
|
|
298
|
+
const repos: string[] = [];
|
|
299
|
+
const indices = new Array(perRepo.length).fill(0);
|
|
300
|
+
|
|
301
|
+
while (files.length < maxFiles) {
|
|
302
|
+
let progressed = false;
|
|
303
|
+
for (let i = 0; i < perRepo.length; i++) {
|
|
304
|
+
if (indices[i] < perRepo[i].length) {
|
|
305
|
+
const entry = perRepo[i][indices[i]++];
|
|
306
|
+
files.push(entry.workspacePath);
|
|
307
|
+
repos.push(entry.repoId);
|
|
308
|
+
progressed = true;
|
|
309
|
+
if (files.length >= maxFiles) break;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
if (!progressed) break;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return { files, repos, truncated: totalEligible > files.length };
|
|
316
|
+
}
|
|
317
|
+
|
|
219
318
|
function resolveGeneratorOptions(options?: CodebaseMapOptions): ResolvedCodebaseMapOptions {
|
|
220
319
|
const excludes = [...DEFAULT_EXCLUDES, ...(options?.excludePatterns ?? [])];
|
|
221
320
|
const maxFiles = options?.maxFiles ?? DEFAULT_MAX_FILES;
|
|
@@ -236,10 +335,12 @@ function computeCodebaseFingerprint(
|
|
|
236
335
|
files: string[],
|
|
237
336
|
resolved: ResolvedCodebaseMapOptions,
|
|
238
337
|
truncated: boolean,
|
|
338
|
+
repos?: string[],
|
|
239
339
|
): string {
|
|
240
340
|
return createHash("sha1")
|
|
241
341
|
.update(JSON.stringify({
|
|
242
342
|
files,
|
|
343
|
+
...(repos ? { repos } : {}),
|
|
243
344
|
truncated,
|
|
244
345
|
optionSignature: resolved.optionSignature,
|
|
245
346
|
}))
|
|
@@ -252,32 +353,61 @@ function groupByDirectory(
|
|
|
252
353
|
files: string[],
|
|
253
354
|
descriptions: Map<string, string>,
|
|
254
355
|
collapseThreshold: number,
|
|
356
|
+
repos?: string[],
|
|
255
357
|
): DirectoryGroup[] {
|
|
256
358
|
const dirMap = new Map<string, FileEntry[]>();
|
|
257
359
|
|
|
258
|
-
for (
|
|
360
|
+
for (let i = 0; i < files.length; i++) {
|
|
361
|
+
const file = files[i];
|
|
259
362
|
const dir = dirname(file);
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
363
|
+
const dirPath = dir === "." ? "" : dir;
|
|
364
|
+
const repoId = repos?.[i];
|
|
365
|
+
const groupKey = repoId !== undefined ? `${repoId}\0${dirPath}` : dirPath;
|
|
366
|
+
if (!dirMap.has(groupKey)) {
|
|
367
|
+
dirMap.set(groupKey, []);
|
|
263
368
|
}
|
|
264
|
-
dirMap.get(
|
|
369
|
+
dirMap.get(groupKey)!.push({
|
|
265
370
|
path: file,
|
|
266
371
|
description: descriptions.get(file) ?? "",
|
|
372
|
+
repo: repoId,
|
|
267
373
|
});
|
|
268
374
|
}
|
|
269
375
|
|
|
270
376
|
const groups: DirectoryGroup[] = [];
|
|
271
|
-
const
|
|
377
|
+
const repoOrder = new Map<string, number>();
|
|
378
|
+
if (repos) {
|
|
379
|
+
for (let i = 0; i < repos.length; i++) {
|
|
380
|
+
if (!repoOrder.has(repos[i])) {
|
|
381
|
+
repoOrder.set(repos[i], repoOrder.size);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
const sortedDirs = [...dirMap.keys()].sort((a, b) => {
|
|
386
|
+
// Single-repo (project) mode must stay byte-identical to the pre-workspace
|
|
387
|
+
// output, which ordered directories with a bare `.sort()` (UTF-16 code-unit
|
|
388
|
+
// order, so uppercase sorts before lowercase). localeCompare would diverge
|
|
389
|
+
// for mixed-case names (e.g. "Zoo" before "apple" flips), so preserve
|
|
390
|
+
// code-unit ordering here; only the repo-partitioning key is added on top.
|
|
391
|
+
if (!repos) return a < b ? -1 : a > b ? 1 : 0;
|
|
392
|
+
const repoA = dirMap.get(a)![0]?.repo ?? "";
|
|
393
|
+
const repoB = dirMap.get(b)![0]?.repo ?? "";
|
|
394
|
+
const orderA = repoOrder.get(repoA) ?? 0;
|
|
395
|
+
const orderB = repoOrder.get(repoB) ?? 0;
|
|
396
|
+
if (orderA !== orderB) return orderA - orderB;
|
|
397
|
+
return a.localeCompare(b);
|
|
398
|
+
});
|
|
272
399
|
|
|
273
|
-
for (const
|
|
274
|
-
const dirFiles = dirMap.get(
|
|
400
|
+
for (const groupKey of sortedDirs) {
|
|
401
|
+
const dirFiles = dirMap.get(groupKey)!;
|
|
275
402
|
dirFiles.sort((a, b) => a.path.localeCompare(b.path));
|
|
403
|
+
const dirPath = repos ? groupKey.slice(groupKey.indexOf("\0") + 1) : groupKey;
|
|
276
404
|
|
|
277
405
|
groups.push({
|
|
278
|
-
path:
|
|
406
|
+
path: dirPath,
|
|
279
407
|
files: dirFiles,
|
|
280
408
|
collapsed: dirFiles.length > collapseThreshold,
|
|
409
|
+
// Each group is scoped to one repo in workspace-aware mode.
|
|
410
|
+
repo: dirFiles[0]?.repo,
|
|
281
411
|
});
|
|
282
412
|
}
|
|
283
413
|
|
|
@@ -304,7 +434,19 @@ function renderCodebaseMap(
|
|
|
304
434
|
}
|
|
305
435
|
lines.push("");
|
|
306
436
|
|
|
437
|
+
let emittedRepo: string | undefined;
|
|
307
438
|
for (const group of groups) {
|
|
439
|
+
// In a workspace-aware map, partition directories under their declaring
|
|
440
|
+
// repository. `## [repo-id]` headings are used (not `###`) so they never
|
|
441
|
+
// collide with the per-directory `### <dir>/` headings or the
|
|
442
|
+
// `parseCodebaseMap` list-item regexes. Groups are sorted by declaring
|
|
443
|
+
// repo (enumeration order) then directory path so each repo is contiguous.
|
|
444
|
+
if (group.repo && group.repo !== emittedRepo) {
|
|
445
|
+
emittedRepo = group.repo;
|
|
446
|
+
lines.push(`## [${group.repo}]`);
|
|
447
|
+
lines.push("");
|
|
448
|
+
}
|
|
449
|
+
|
|
308
450
|
const heading = group.path || "(root)";
|
|
309
451
|
lines.push(`### ${heading}/`);
|
|
310
452
|
|
|
@@ -361,13 +503,15 @@ function buildCodebaseMap(
|
|
|
361
503
|
} {
|
|
362
504
|
const listed = enumerated ?? enumerateFiles(basePath, resolved.excludes, resolved.maxFiles);
|
|
363
505
|
const descriptions = existingDescriptions ?? new Map<string, string>();
|
|
364
|
-
const groups = groupByDirectory(listed.files, descriptions, resolved.collapseThreshold);
|
|
506
|
+
const groups = groupByDirectory(listed.files, descriptions, resolved.collapseThreshold, listed.repos);
|
|
365
507
|
const generatedAt = new Date().toISOString().split(".")[0] + "Z";
|
|
508
|
+
const repoIds = listed.repos ? Array.from(new Set(listed.repos)) : undefined;
|
|
366
509
|
const metadata: CodebaseMapMetadata = {
|
|
367
510
|
generatedAt,
|
|
368
|
-
fingerprint: computeCodebaseFingerprint(listed.files, resolved, listed.truncated),
|
|
511
|
+
fingerprint: computeCodebaseFingerprint(listed.files, resolved, listed.truncated, listed.repos),
|
|
369
512
|
fileCount: listed.files.length,
|
|
370
513
|
truncated: listed.truncated,
|
|
514
|
+
...(repoIds ? { repositories: repoIds } : {}),
|
|
371
515
|
};
|
|
372
516
|
const content = renderCodebaseMap(groups, listed.files.length, listed.truncated, metadata);
|
|
373
517
|
|
|
@@ -387,13 +531,28 @@ function buildCodebaseMap(
|
|
|
387
531
|
* Generate a fresh CODEBASE.md from scratch.
|
|
388
532
|
* Preserves existing descriptions if `existingDescriptions` is provided.
|
|
389
533
|
*/
|
|
534
|
+
/**
|
|
535
|
+
* Resolve workspace-aware enumeration for parent mode, or undefined to fall
|
|
536
|
+
* back to the legacy single-root enumeration. Centralized so all three public
|
|
537
|
+
* entry points (generate/update/ensure) share one discovery path.
|
|
538
|
+
*/
|
|
539
|
+
function resolveWorkspaceEnumeration(
|
|
540
|
+
basePath: string,
|
|
541
|
+
resolved: ResolvedCodebaseMapOptions,
|
|
542
|
+
): EnumeratedFiles | undefined {
|
|
543
|
+
const registry = loadWorkspaceRegistry(basePath);
|
|
544
|
+
if (!registry) return undefined;
|
|
545
|
+
return enumerateWorkspaceFiles(registry, resolved.excludes, resolved.maxFiles);
|
|
546
|
+
}
|
|
547
|
+
|
|
390
548
|
export function generateCodebaseMap(
|
|
391
549
|
basePath: string,
|
|
392
550
|
options?: CodebaseMapOptions,
|
|
393
551
|
existingDescriptions?: Map<string, string>,
|
|
394
552
|
): { content: string; fileCount: number; truncated: boolean; files: string[]; fingerprint: string; generatedAt: string } {
|
|
395
553
|
const resolved = resolveGeneratorOptions(options);
|
|
396
|
-
|
|
554
|
+
const enumerated = resolveWorkspaceEnumeration(basePath, resolved);
|
|
555
|
+
return buildCodebaseMap(basePath, resolved, existingDescriptions, enumerated);
|
|
397
556
|
}
|
|
398
557
|
|
|
399
558
|
/**
|
|
@@ -427,7 +586,8 @@ export function updateCodebaseMap(
|
|
|
427
586
|
|
|
428
587
|
// Generate new map preserving descriptions — reuse the returned file list
|
|
429
588
|
// to avoid a second enumeration (prevents race between content and stats).
|
|
430
|
-
const
|
|
589
|
+
const enumerated = resolveWorkspaceEnumeration(basePath, resolved);
|
|
590
|
+
const result = buildCodebaseMap(basePath, resolved, existingDescriptions, enumerated);
|
|
431
591
|
const currentSet = new Set(result.files);
|
|
432
592
|
|
|
433
593
|
// Count changes
|
|
@@ -467,7 +627,7 @@ export function ensureCodebaseMapFresh(
|
|
|
467
627
|
ensureOptions?: EnsureCodebaseMapOptions,
|
|
468
628
|
): EnsureCodebaseMapResult {
|
|
469
629
|
const resolved = resolveGeneratorOptions(options);
|
|
470
|
-
const cacheKey = `${basePath}::${resolved.optionSignature}`;
|
|
630
|
+
const cacheKey = `${basePath}::${resolved.optionSignature}::${workspaceEnumerationSignature(basePath)}`;
|
|
471
631
|
const ttlMs = ensureOptions?.ttlMs ?? DEFAULT_REFRESH_TTL_MS;
|
|
472
632
|
const force = ensureOptions?.force === true;
|
|
473
633
|
const now = Date.now();
|
|
@@ -481,8 +641,9 @@ export function ensureCodebaseMapFresh(
|
|
|
481
641
|
}
|
|
482
642
|
|
|
483
643
|
const existing = readCodebaseMap(basePath);
|
|
484
|
-
const listed =
|
|
485
|
-
|
|
644
|
+
const listed = resolveWorkspaceEnumeration(basePath, resolved)
|
|
645
|
+
?? enumerateFiles(basePath, resolved.excludes, resolved.maxFiles);
|
|
646
|
+
const fingerprint = computeCodebaseFingerprint(listed.files, resolved, listed.truncated, listed.repos);
|
|
486
647
|
|
|
487
648
|
const cacheAndReturn = (result: EnsureCodebaseMapResult): EnsureCodebaseMapResult => {
|
|
488
649
|
freshnessCache.set(cacheKey, { checkedAt: now, result });
|