@opengsd/gsd-pi 1.4.0 → 1.5.0-dev.4fb2d460
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/ask-user-questions.js +1 -1
- 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-artifact-paths.js +12 -3
- package/dist/resources/extensions/gsd/auto-direct-dispatch.js +11 -7
- package/dist/resources/extensions/gsd/auto-dispatch.js +31 -7
- 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-recovery.js +50 -6
- package/dist/resources/extensions/gsd/auto-start.js +8 -6
- 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 +134 -7
- 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 +194 -28
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +14 -1
- package/dist/resources/extensions/gsd/codebase-generator.js +164 -20
- 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/db/writers/cascades.js +20 -2
- 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 +106 -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 +75 -11
- package/dist/resources/extensions/gsd/guidance.js +1 -0
- package/dist/resources/extensions/gsd/guided-flow.js +62 -19
- 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/md-importer.js +89 -23
- package/dist/resources/extensions/gsd/migrate-external.js +24 -7
- package/dist/resources/extensions/gsd/migration-auto-check.js +30 -3
- 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/paths.js +17 -3
- 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-skills.js +10 -16
- 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 +49 -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/skill-discovery.js +36 -23
- 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/reopen-slice.js +5 -0
- package/dist/resources/extensions/gsd/tools/reopen-task.js +13 -5
- 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/resources/extensions/shared/interview-ui.js +62 -9
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
- package/dist/web/standalone/.next/build-manifest.json +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 +9 -9
- 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/package-manager.d.ts +9 -0
- package/packages/pi-coding-agent/dist/core/package-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/package-manager.js +74 -53
- package/packages/pi-coding-agent/dist/core/package-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.d.ts +6 -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 +30 -2
- package/packages/pi-coding-agent/dist/core/resource-loader.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/dist/core/skill-directories.d.ts +66 -0
- package/packages/pi-coding-agent/dist/core/skill-directories.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/skill-directories.js +138 -0
- package/packages/pi-coding-agent/dist/core/skill-directories.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/skills.d.ts +4 -1
- package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.js +4 -1
- package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts +1 -0
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +1 -0
- package/packages/pi-coding-agent/dist/index.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/ask-user-questions.ts +1 -1
- 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-artifact-paths.ts +12 -3
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +13 -7
- package/src/resources/extensions/gsd/auto-dispatch.ts +35 -7
- 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-recovery.ts +50 -6
- package/src/resources/extensions/gsd/auto-start.ts +9 -6
- 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 +148 -7
- 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 +229 -28
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +23 -1
- package/src/resources/extensions/gsd/codebase-generator.ts +186 -19
- 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/db/writers/cascades.ts +23 -1
- 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 +132 -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 +105 -11
- package/src/resources/extensions/gsd/guidance.ts +2 -0
- package/src/resources/extensions/gsd/guided-flow.ts +71 -20
- 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/md-importer.ts +93 -22
- package/src/resources/extensions/gsd/migrate-external.ts +23 -6
- package/src/resources/extensions/gsd/migration-auto-check.ts +32 -3
- 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/paths.ts +21 -3
- 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-skills.ts +10 -16
- 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 +58 -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/skill-discovery.ts +47 -23
- 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-artifact-paths.test.ts +169 -1
- 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 +111 -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 +387 -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 +109 -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/import-completion-lost-update.test.ts +196 -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/journal-integration.test.ts +16 -15
- 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/migration-auto-check.test.ts +91 -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 +169 -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/reopen-slice.test.ts +52 -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/skill-discovery.test.ts +46 -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 +259 -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/reopen-slice.ts +5 -0
- package/src/resources/extensions/gsd/tools/reopen-task.ts +13 -5
- 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/src/resources/extensions/shared/interview-ui.ts +58 -11
- package/src/resources/extensions/shared/tests/interview-ui-border.test.ts +32 -0
- 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 → gXoWec4UNqcR0tkuHwYCr}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{zQLcXm0Za8lexoXtgDpMG → gXoWec4UNqcR0tkuHwYCr}/_ssgManifest.js +0 -0
|
@@ -14,34 +14,173 @@
|
|
|
14
14
|
* to stop tooling for the rest of that turn and answer in text.
|
|
15
15
|
*
|
|
16
16
|
* The per-tool-name check (#783 Brief C) tracks call counts within a
|
|
17
|
-
* turn regardless of args, decaying after successful state-
|
|
17
|
+
* turn regardless of args, decaying after successful state-progressing tools.
|
|
18
18
|
* This catches improvisation
|
|
19
19
|
* loops where the model attempts the same missing workflow tool through
|
|
20
20
|
* varied surfaces (bash → `node -e` → CLI), each with a different
|
|
21
21
|
* signature, so the identical-args streak never trips, while allowing
|
|
22
|
-
* tool-heavy turns that are making
|
|
23
|
-
*
|
|
22
|
+
* tool-heavy turns that are making progress. Progress means a successful file
|
|
23
|
+
* mutation (edit/write) or a successful shell/exec call (bg_shell,
|
|
24
|
+
* gsd_uat_exec, …) — so a local model running a legitimate iterative
|
|
25
|
+
* debugging loop (restart server, npm install, curl an endpoint) is not
|
|
26
|
+
* blocked as a false loop (#1206). Whichever guard trips first blocks.
|
|
27
|
+
*
|
|
28
|
+
* Thresholds, exempt tools, and enable flags are user-tunable (#1198) via the
|
|
29
|
+
* `tool_call_loop_guard` key in `.gsd/PREFERENCES.md` and `GSD_TOOL_LOOP_*`
|
|
30
|
+
* environment variables, applied through {@link configureToolCallLoopGuard}.
|
|
31
|
+
* Defaults preserve the original hardcoded behavior.
|
|
24
32
|
*/
|
|
25
33
|
import { createHash } from "node:crypto";
|
|
26
34
|
import { INHERENTLY_REPEATABLE_TOOL_SET } from "./core-session-tools.js";
|
|
27
|
-
|
|
35
|
+
import { hasBrowserContractPrefix } from "../../shared/browser-contract.js";
|
|
36
|
+
import { canonicalToolName } from "../engine-hook-contract.js";
|
|
37
|
+
/** Built-in defaults. Preserved when preferences/env do not override them. */
|
|
38
|
+
const DEFAULT_MAX_CONSECUTIVE_IDENTICAL_CALLS = 4;
|
|
39
|
+
const DEFAULT_PER_TOOL_DEFAULT_CAP = 6;
|
|
40
|
+
const DEFAULT_PER_TOOL_REPEATABLE_CAP = 15;
|
|
41
|
+
const DEFAULT_PER_TOOL_CAP_EXEMPT_TOOLS = ["find", "glob", "grep", "ls", "read", "search_and_read"];
|
|
28
42
|
/** Interactive/user-facing tools where even 1 duplicate is confusing. */
|
|
29
43
|
const STRICT_LOOP_TOOLS = new Set(["ask_user_questions"]);
|
|
30
44
|
const MAX_CONSECUTIVE_STRICT = 1;
|
|
45
|
+
const STATE_MUTATING_TOOL_SET = new Set(["edit", "write", "multi_edit", "notebook_edit"]);
|
|
31
46
|
/**
|
|
32
|
-
*
|
|
47
|
+
* Successful shell/exec calls are state progression too (#1206), not just file
|
|
48
|
+
* mutations. A local model debugging a UAT scenario legitimately restarts
|
|
49
|
+
* servers, runs `npm install`, and curls endpoints via bg_shell / gsd_uat_exec
|
|
50
|
+
* with varied args — productive work that never touches a file, so Guard 2's
|
|
51
|
+
* per-tool cap would otherwise misfire as a false loop. Decaying on these
|
|
52
|
+
* successful calls keeps the guard from aborting a progressing turn.
|
|
33
53
|
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
54
|
+
* Only successful calls reach {@link recordToolCallLoopMutation}: the
|
|
55
|
+
* tool_result hook skips `isError` results, and the bash tool throws on
|
|
56
|
+
* non-zero exit, so a genuinely stuck improvisation loop of failing commands
|
|
57
|
+
* (#783) never decays and still trips the cap. `async_bash` is excluded
|
|
58
|
+
* because it only registers a background job; command success is reported
|
|
59
|
+
* later via `await_job`. `bg_shell` may return `isError: false` for failed
|
|
60
|
+
* `run`/`start` outcomes, so the hook passes `details` for validation.
|
|
40
61
|
*/
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
62
|
+
const STATE_PROGRESSING_EXEC_TOOL_SET = new Set([
|
|
63
|
+
"bash",
|
|
64
|
+
"bg_shell",
|
|
65
|
+
"shell",
|
|
66
|
+
"powershell",
|
|
67
|
+
"gsd_exec",
|
|
68
|
+
"gsd_uat_exec",
|
|
69
|
+
]);
|
|
70
|
+
function isSuccessfulBgShellLoopProgress(details) {
|
|
71
|
+
if (!details || typeof details !== "object")
|
|
72
|
+
return false;
|
|
73
|
+
const record = details;
|
|
74
|
+
switch (record.action) {
|
|
75
|
+
case "run":
|
|
76
|
+
return record.exitCode === 0 && record.timedOut !== true;
|
|
77
|
+
case "start":
|
|
78
|
+
case "restart": {
|
|
79
|
+
const process = record.process;
|
|
80
|
+
if (!process || typeof process !== "object")
|
|
81
|
+
return false;
|
|
82
|
+
return process.alive === true;
|
|
83
|
+
}
|
|
84
|
+
case "wait_for_ready":
|
|
85
|
+
return record.ready === true;
|
|
86
|
+
case "send_and_wait":
|
|
87
|
+
return record.matched === true;
|
|
88
|
+
default:
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function defaultGuardConfig() {
|
|
93
|
+
return {
|
|
94
|
+
guardEnabled: true,
|
|
95
|
+
identicalEnabled: true,
|
|
96
|
+
maxConsecutiveIdentical: DEFAULT_MAX_CONSECUTIVE_IDENTICAL_CALLS,
|
|
97
|
+
repeatedEnabled: true,
|
|
98
|
+
perToolDefaultCap: DEFAULT_PER_TOOL_DEFAULT_CAP,
|
|
99
|
+
perToolRepeatableCap: DEFAULT_PER_TOOL_REPEATABLE_CAP,
|
|
100
|
+
perToolExempt: new Set(DEFAULT_PER_TOOL_CAP_EXEMPT_TOOLS),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
let config = defaultGuardConfig();
|
|
104
|
+
/** Parse a positive-integer env var, returning undefined when unset/invalid. */
|
|
105
|
+
function envPositiveInt(name) {
|
|
106
|
+
const raw = process.env[name];
|
|
107
|
+
if (raw === undefined || raw.trim() === "")
|
|
108
|
+
return undefined;
|
|
109
|
+
const n = Number(raw);
|
|
110
|
+
return Number.isFinite(n) && n >= 1 ? Math.floor(n) : undefined;
|
|
111
|
+
}
|
|
112
|
+
/** Parse a boolean env var (`true`/`1` vs `false`/`0`), undefined when unset. */
|
|
113
|
+
function envBool(name) {
|
|
114
|
+
const raw = process.env[name];
|
|
115
|
+
if (raw === undefined || raw.trim() === "")
|
|
116
|
+
return undefined;
|
|
117
|
+
const v = raw.trim().toLowerCase();
|
|
118
|
+
if (v === "true" || v === "1" || v === "yes" || v === "on")
|
|
119
|
+
return true;
|
|
120
|
+
if (v === "false" || v === "0" || v === "no" || v === "off")
|
|
121
|
+
return false;
|
|
122
|
+
return undefined;
|
|
123
|
+
}
|
|
124
|
+
/** Parse a comma-separated tool-name list env var. */
|
|
125
|
+
function envToolList(name) {
|
|
126
|
+
const raw = process.env[name];
|
|
127
|
+
if (!raw)
|
|
128
|
+
return [];
|
|
129
|
+
return raw.split(",").map((s) => s.trim()).filter(Boolean);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Resolve preferences + environment overrides into the active configuration.
|
|
133
|
+
* Environment variables win over preferences; preferences win over built-in
|
|
134
|
+
* defaults. User-supplied exempt tools are additive to the built-in exempt
|
|
135
|
+
* set so defaults are always preserved.
|
|
136
|
+
*
|
|
137
|
+
* Applied to both interactive sessions and `/gsd auto` (called from the
|
|
138
|
+
* session_start / session_switch hooks).
|
|
139
|
+
*/
|
|
140
|
+
export function configureToolCallLoopGuard(prefs) {
|
|
141
|
+
const next = defaultGuardConfig();
|
|
142
|
+
if (prefs) {
|
|
143
|
+
if (typeof prefs.enabled === "boolean")
|
|
144
|
+
next.guardEnabled = prefs.enabled;
|
|
145
|
+
if (prefs.identical_args) {
|
|
146
|
+
if (typeof prefs.identical_args.enabled === "boolean")
|
|
147
|
+
next.identicalEnabled = prefs.identical_args.enabled;
|
|
148
|
+
if (typeof prefs.identical_args.max_consecutive_calls === "number" && prefs.identical_args.max_consecutive_calls >= 1) {
|
|
149
|
+
next.maxConsecutiveIdentical = Math.floor(prefs.identical_args.max_consecutive_calls);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (prefs.repeated_tool) {
|
|
153
|
+
if (typeof prefs.repeated_tool.enabled === "boolean")
|
|
154
|
+
next.repeatedEnabled = prefs.repeated_tool.enabled;
|
|
155
|
+
if (typeof prefs.repeated_tool.default_cap === "number" && prefs.repeated_tool.default_cap >= 1) {
|
|
156
|
+
next.perToolDefaultCap = Math.floor(prefs.repeated_tool.default_cap);
|
|
157
|
+
}
|
|
158
|
+
if (typeof prefs.repeated_tool.repeatable_cap === "number" && prefs.repeated_tool.repeatable_cap >= 1) {
|
|
159
|
+
next.perToolRepeatableCap = Math.floor(prefs.repeated_tool.repeatable_cap);
|
|
160
|
+
}
|
|
161
|
+
for (const tool of prefs.repeated_tool.exempt_tools ?? []) {
|
|
162
|
+
if (typeof tool === "string" && tool.trim())
|
|
163
|
+
next.perToolExempt.add(tool.trim());
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// Environment overrides (win over preferences).
|
|
168
|
+
const envEnabled = envBool("GSD_TOOL_LOOP_GUARD_ENABLED");
|
|
169
|
+
if (envEnabled !== undefined)
|
|
170
|
+
next.guardEnabled = envEnabled;
|
|
171
|
+
const envIdenticalMax = envPositiveInt("GSD_TOOL_LOOP_IDENTICAL_MAX");
|
|
172
|
+
if (envIdenticalMax !== undefined)
|
|
173
|
+
next.maxConsecutiveIdentical = envIdenticalMax;
|
|
174
|
+
const envDefaultCap = envPositiveInt("GSD_TOOL_LOOP_REPEATED_DEFAULT_CAP");
|
|
175
|
+
if (envDefaultCap !== undefined)
|
|
176
|
+
next.perToolDefaultCap = envDefaultCap;
|
|
177
|
+
const envRepeatableCap = envPositiveInt("GSD_TOOL_LOOP_REPEATED_REPEATABLE_CAP");
|
|
178
|
+
if (envRepeatableCap !== undefined)
|
|
179
|
+
next.perToolRepeatableCap = envRepeatableCap;
|
|
180
|
+
for (const tool of envToolList("GSD_TOOL_LOOP_EXEMPT_TOOLS"))
|
|
181
|
+
next.perToolExempt.add(tool);
|
|
182
|
+
config = next;
|
|
183
|
+
}
|
|
45
184
|
let consecutiveCount = 0;
|
|
46
185
|
let lastSignature = "";
|
|
47
186
|
let lastToolName = "";
|
|
@@ -70,14 +209,17 @@ function hashToolCall(toolName, args) {
|
|
|
70
209
|
* Returns `{ block: true, reason }` when the loop threshold is exceeded.
|
|
71
210
|
*
|
|
72
211
|
* Two independent guards run; whichever trips first blocks:
|
|
73
|
-
* 1. Identical-signature streak (
|
|
212
|
+
* 1. Identical-signature streak (config.maxConsecutiveIdentical, strict for
|
|
74
213
|
* ask_user_questions).
|
|
75
|
-
* 2. Per-tool-name cap (
|
|
214
|
+
* 2. Per-tool-name cap (config.perToolDefaultCap / config.perToolRepeatableCap),
|
|
76
215
|
* independent of args, reset after file-mutation progress — catches
|
|
77
216
|
* improvisation loops (#783).
|
|
217
|
+
*
|
|
218
|
+
* Both guards, their thresholds, and the per-tool exempt set are user-tunable
|
|
219
|
+
* via {@link configureToolCallLoopGuard} (#1198).
|
|
78
220
|
*/
|
|
79
221
|
export function checkToolCallLoop(toolName, args) {
|
|
80
|
-
if (!enabled)
|
|
222
|
+
if (!enabled || !config.guardEnabled)
|
|
81
223
|
return { block: false, count: 0 };
|
|
82
224
|
const sig = hashToolCall(toolName, args);
|
|
83
225
|
if (sig === lastSignature) {
|
|
@@ -91,12 +233,14 @@ export function checkToolCallLoop(toolName, args) {
|
|
|
91
233
|
// ── Guard 1: identical-signature streak ──
|
|
92
234
|
const threshold = STRICT_LOOP_TOOLS.has(toolName)
|
|
93
235
|
? MAX_CONSECUTIVE_STRICT
|
|
94
|
-
:
|
|
95
|
-
if (consecutiveCount > threshold) {
|
|
236
|
+
: config.maxConsecutiveIdentical;
|
|
237
|
+
if (config.identicalEnabled && consecutiveCount > threshold) {
|
|
96
238
|
return {
|
|
97
239
|
block: true,
|
|
98
240
|
reason: `Tool loop detected (identical args): ${toolName} called ${consecutiveCount} times ` +
|
|
99
|
-
`with identical arguments. Blocking to prevent infinite loop. ` +
|
|
241
|
+
`with identical arguments (max ${threshold}). Blocking to prevent infinite loop. ` +
|
|
242
|
+
`Raise tool_call_loop_guard.identical_args.max_consecutive_calls in .gsd/PREFERENCES.md ` +
|
|
243
|
+
`(or GSD_TOOL_LOOP_IDENTICAL_MAX) if this is expected. ` +
|
|
100
244
|
`Do not retry this tool or call other tools this turn — stop and respond to the user in text.`,
|
|
101
245
|
count: consecutiveCount,
|
|
102
246
|
};
|
|
@@ -111,30 +255,52 @@ export function checkToolCallLoop(toolName, args) {
|
|
|
111
255
|
perToolCounts.set(toolName, perToolCount);
|
|
112
256
|
perToolLastMutationEpoch.set(toolName, mutationEpoch);
|
|
113
257
|
// Read-only navigation tools are normal context gathering; Guard 1 still
|
|
114
|
-
// catches true reread loops with identical arguments.
|
|
115
|
-
|
|
258
|
+
// catches true reread loops with identical arguments. Browser Automation
|
|
259
|
+
// Contract tools (browser_*) are the same shape: a browser-backed UAT makes
|
|
260
|
+
// many distinct-arg calls (read a message, count edits, inspect a card, …),
|
|
261
|
+
// so the arg-independent per-tool cap misfires on legitimate verification;
|
|
262
|
+
// Guard 1's identical-signature streak still catches a genuinely stuck
|
|
263
|
+
// browser loop.
|
|
264
|
+
if (!config.repeatedEnabled ||
|
|
265
|
+
config.perToolExempt.has(toolName) ||
|
|
266
|
+
hasBrowserContractPrefix(canonicalToolName(toolName))) {
|
|
116
267
|
return { block: false, count: consecutiveCount };
|
|
117
268
|
}
|
|
118
269
|
const perToolCap = INHERENTLY_REPEATABLE_TOOL_SET.has(toolName)
|
|
119
|
-
?
|
|
120
|
-
:
|
|
270
|
+
? config.perToolRepeatableCap
|
|
271
|
+
: config.perToolDefaultCap;
|
|
121
272
|
if (perToolCount > perToolCap) {
|
|
122
273
|
return {
|
|
123
274
|
block: true,
|
|
124
275
|
reason: `Tool loop detected (repeated tool): ${toolName} called ${perToolCount} times ` +
|
|
125
276
|
`this turn (cap ${perToolCap}). Blocking to prevent infinite loop. ` +
|
|
126
277
|
`The tool may be unavailable or failing repeatedly. ` +
|
|
278
|
+
`Raise tool_call_loop_guard.repeated_tool.default_cap/repeatable_cap or add "${toolName}" ` +
|
|
279
|
+
`to tool_call_loop_guard.repeated_tool.exempt_tools in .gsd/PREFERENCES.md ` +
|
|
280
|
+
`(or GSD_TOOL_LOOP_REPEATED_* / GSD_TOOL_LOOP_EXEMPT_TOOLS) if this is expected. ` +
|
|
127
281
|
`Do not retry this tool or pivot to other tools this turn — stop and respond to the user in text.`,
|
|
128
282
|
count: perToolCount,
|
|
129
283
|
};
|
|
130
284
|
}
|
|
131
285
|
return { block: false, count: consecutiveCount };
|
|
132
286
|
}
|
|
133
|
-
/**
|
|
134
|
-
|
|
287
|
+
/**
|
|
288
|
+
* Record successful state progress so Guard 2 can decay on the next count.
|
|
289
|
+
* File mutations (edit/write/…) and successful shell/exec calls (bash,
|
|
290
|
+
* bg_shell, gsd_uat_exec, …) both count as progress (#1092, #1206). The caller
|
|
291
|
+
* only invokes this for non-error results, so failing improvisation loops
|
|
292
|
+
* (#783) never decay and still trip the per-tool cap.
|
|
293
|
+
*/
|
|
294
|
+
export function recordToolCallLoopMutation(toolName, details) {
|
|
135
295
|
if (!enabled)
|
|
136
296
|
return;
|
|
137
|
-
if (
|
|
297
|
+
if (STATE_MUTATING_TOOL_SET.has(toolName)) {
|
|
298
|
+
mutationEpoch++;
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
if (!STATE_PROGRESSING_EXEC_TOOL_SET.has(toolName))
|
|
302
|
+
return;
|
|
303
|
+
if (toolName === "bg_shell" && details !== undefined && !isSuccessfulBgShellLoopProgress(details))
|
|
138
304
|
return;
|
|
139
305
|
mutationEpoch++;
|
|
140
306
|
}
|
|
@@ -947,7 +947,7 @@ function allowedPlanningDispatchAgentsList() {
|
|
|
947
947
|
return [...ALLOWED_PLANNING_DISPATCH_AGENTS].join(", ");
|
|
948
948
|
}
|
|
949
949
|
function allowsControlledSubagentDispatch(policy) {
|
|
950
|
-
return ((policy.mode === "planning-dispatch" || policy.mode === "verification") &&
|
|
950
|
+
return ((policy.mode === "planning-dispatch" || policy.mode === "verification" || policy.mode === "workflow-only") &&
|
|
951
951
|
Array.isArray(policy.allowedSubagents));
|
|
952
952
|
}
|
|
953
953
|
function warnMissingControlledDispatchAgentClasses(unitType, mode, toolName) {
|
|
@@ -975,6 +975,7 @@ function warnMissingControlledDispatchAgentClasses(unitType, mode, toolName) {
|
|
|
975
975
|
const PLANNING_SAFE_TOOLS = new Set([
|
|
976
976
|
"read", "grep", "find", "ls", "glob",
|
|
977
977
|
"ask_user_questions",
|
|
978
|
+
"memory_query",
|
|
978
979
|
"search-the-web", "resolve_library", "get_library_docs", "fetch_page",
|
|
979
980
|
"search_and_read",
|
|
980
981
|
]);
|
|
@@ -1031,6 +1032,9 @@ function planningBlock(unitType, mode, what) {
|
|
|
1031
1032
|
* → allows Bash for project verification commands, keeps
|
|
1032
1033
|
* writes restricted to .gsd/, and permits subagent dispatch
|
|
1033
1034
|
* only when the manifest declares allowedSubagents.
|
|
1035
|
+
* - "workflow-only"
|
|
1036
|
+
* → allows reads, GSD workflow tools, and declared read-only
|
|
1037
|
+
* subagents; blocks generic Bash and direct file writes.
|
|
1034
1038
|
*
|
|
1035
1039
|
* `pathOrCommand` is the file path for write/edit-shaped tools and the
|
|
1036
1040
|
* shell command for bash. Other tools ignore this argument.
|
|
@@ -1101,6 +1105,15 @@ export function shouldBlockPlanningUnit(toolName, pathOrCommand, basePath, unitT
|
|
|
1101
1105
|
}
|
|
1102
1106
|
return planningBlock(unitType, policy.mode, "subagent dispatch is not permitted in planning units");
|
|
1103
1107
|
}
|
|
1108
|
+
if (policy.mode === "workflow-only") {
|
|
1109
|
+
if (tool === "bash") {
|
|
1110
|
+
return planningBlock(unitType, policy.mode, `bash is not permitted; use the unit's dedicated GSD workflow tools for durable validation output`);
|
|
1111
|
+
}
|
|
1112
|
+
if (PLANNING_WRITE_TOOLS.has(tool)) {
|
|
1113
|
+
return planningBlock(unitType, policy.mode, `cannot ${tool} "${pathOrCommand}" — direct artifact writes are disabled; call the required GSD workflow tool instead`);
|
|
1114
|
+
}
|
|
1115
|
+
return planningBlock(unitType, policy.mode, `tool "${tool}" is not on the workflow-only allowlist`);
|
|
1116
|
+
}
|
|
1104
1117
|
if (tool === "bash") {
|
|
1105
1118
|
if (policy.mode === "verification") {
|
|
1106
1119
|
if (BASH_VERIFICATION_RE.test(pathOrCommand) || BASH_READ_ONLY_RE.test(pathOrCommand))
|
|
@@ -9,9 +9,11 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { createHash } from "node:crypto";
|
|
11
11
|
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
12
|
-
import { join, dirname, extname } from "node:path";
|
|
12
|
+
import { join, dirname, extname, relative, sep } from "node:path";
|
|
13
13
|
import { execSync } from "node:child_process";
|
|
14
14
|
import { gsdRoot } from "./paths.js";
|
|
15
|
+
import { createRepositoryRegistryFromPreferences, } from "./repository-registry.js";
|
|
16
|
+
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
15
17
|
// ─── Defaults ────────────────────────────────────────────────────────────────
|
|
16
18
|
const DEFAULT_EXCLUDES = [
|
|
17
19
|
// ── AI / tooling meta ──
|
|
@@ -144,6 +146,84 @@ function enumerateFiles(basePath, excludes, maxFiles) {
|
|
|
144
146
|
const truncated = filtered.length > maxFiles;
|
|
145
147
|
return { files: truncated ? filtered.slice(0, maxFiles) : filtered, truncated };
|
|
146
148
|
}
|
|
149
|
+
/**
|
|
150
|
+
* Build a workspace-aware registry for parent mode, or null when the project is
|
|
151
|
+
* single-repo (no declared child repositories). Returns null so the caller falls
|
|
152
|
+
* back to the legacy single-root enumeration and produces byte-identical output.
|
|
153
|
+
*/
|
|
154
|
+
function loadWorkspaceRegistry(basePath) {
|
|
155
|
+
const preferences = loadEffectiveGSDPreferences(basePath)?.preferences;
|
|
156
|
+
const workspace = preferences?.workspace;
|
|
157
|
+
const mode = workspace?.mode ?? "project";
|
|
158
|
+
// Parent mode is only meaningful with at least one declared child repo; the
|
|
159
|
+
// implicit "project" repo is always present, so require a declared non-project id.
|
|
160
|
+
const hasDeclaredChildRepo = workspace?.repositories
|
|
161
|
+
? Object.keys(workspace.repositories).some((id) => id !== "project")
|
|
162
|
+
: false;
|
|
163
|
+
if (mode !== "parent" || !hasDeclaredChildRepo) {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
return createRepositoryRegistryFromPreferences(basePath, preferences);
|
|
167
|
+
}
|
|
168
|
+
/** Stable key fragment for workspace-aware enumeration inputs (mode + declared repos). */
|
|
169
|
+
function workspaceEnumerationSignature(basePath) {
|
|
170
|
+
const registry = loadWorkspaceRegistry(basePath);
|
|
171
|
+
if (!registry)
|
|
172
|
+
return "single-root";
|
|
173
|
+
return JSON.stringify({
|
|
174
|
+
mode: registry.mode,
|
|
175
|
+
repositories: registry.repositories
|
|
176
|
+
.map((repo) => ({ id: repo.id, root: repo.root }))
|
|
177
|
+
.sort((a, b) => a.id.localeCompare(b.id)),
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Enumerate tracked files across every declared repository in a parent workspace.
|
|
182
|
+
* Child-repo paths are rewritten to be workspace-relative (e.g. `frontend/src/x`)
|
|
183
|
+
* and tagged with their declaring repo id so the map can render repo-labelled
|
|
184
|
+
* sections. The maxFiles cap is applied across the union of all repositories.
|
|
185
|
+
*/
|
|
186
|
+
function enumerateWorkspaceFiles(registry, excludes, maxFiles) {
|
|
187
|
+
const perRepo = [];
|
|
188
|
+
const seen = new Set();
|
|
189
|
+
let totalEligible = 0;
|
|
190
|
+
for (const repo of registry.repositories) {
|
|
191
|
+
const rawFiles = lsFiles(repo.root);
|
|
192
|
+
const repoPrefix = relative(registry.projectRoot, repo.root).split(sep).join("/");
|
|
193
|
+
const repoEntries = [];
|
|
194
|
+
for (const file of rawFiles) {
|
|
195
|
+
// Rewrite before exclusion so workspace-relative patterns (e.g. frontend/…) apply.
|
|
196
|
+
const workspacePath = repoPrefix ? `${repoPrefix}/${file}` : file;
|
|
197
|
+
if (shouldExclude(workspacePath, excludes))
|
|
198
|
+
continue;
|
|
199
|
+
if (seen.has(workspacePath))
|
|
200
|
+
continue;
|
|
201
|
+
seen.add(workspacePath);
|
|
202
|
+
totalEligible++;
|
|
203
|
+
repoEntries.push({ workspacePath, repoId: repo.id });
|
|
204
|
+
}
|
|
205
|
+
perRepo.push(repoEntries);
|
|
206
|
+
}
|
|
207
|
+
const files = [];
|
|
208
|
+
const repos = [];
|
|
209
|
+
const indices = new Array(perRepo.length).fill(0);
|
|
210
|
+
while (files.length < maxFiles) {
|
|
211
|
+
let progressed = false;
|
|
212
|
+
for (let i = 0; i < perRepo.length; i++) {
|
|
213
|
+
if (indices[i] < perRepo[i].length) {
|
|
214
|
+
const entry = perRepo[i][indices[i]++];
|
|
215
|
+
files.push(entry.workspacePath);
|
|
216
|
+
repos.push(entry.repoId);
|
|
217
|
+
progressed = true;
|
|
218
|
+
if (files.length >= maxFiles)
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
if (!progressed)
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
return { files, repos, truncated: totalEligible > files.length };
|
|
226
|
+
}
|
|
147
227
|
function resolveGeneratorOptions(options) {
|
|
148
228
|
const excludes = [...DEFAULT_EXCLUDES, ...(options?.excludePatterns ?? [])];
|
|
149
229
|
const maxFiles = options?.maxFiles ?? DEFAULT_MAX_FILES;
|
|
@@ -159,38 +239,69 @@ function resolveGeneratorOptions(options) {
|
|
|
159
239
|
}),
|
|
160
240
|
};
|
|
161
241
|
}
|
|
162
|
-
function computeCodebaseFingerprint(files, resolved, truncated) {
|
|
242
|
+
function computeCodebaseFingerprint(files, resolved, truncated, repos) {
|
|
163
243
|
return createHash("sha1")
|
|
164
244
|
.update(JSON.stringify({
|
|
165
245
|
files,
|
|
246
|
+
...(repos ? { repos } : {}),
|
|
166
247
|
truncated,
|
|
167
248
|
optionSignature: resolved.optionSignature,
|
|
168
249
|
}))
|
|
169
250
|
.digest("hex");
|
|
170
251
|
}
|
|
171
252
|
// ─── Grouping ────────────────────────────────────────────────────────────────
|
|
172
|
-
function groupByDirectory(files, descriptions, collapseThreshold) {
|
|
253
|
+
function groupByDirectory(files, descriptions, collapseThreshold, repos) {
|
|
173
254
|
const dirMap = new Map();
|
|
174
|
-
for (
|
|
255
|
+
for (let i = 0; i < files.length; i++) {
|
|
256
|
+
const file = files[i];
|
|
175
257
|
const dir = dirname(file);
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
|
|
258
|
+
const dirPath = dir === "." ? "" : dir;
|
|
259
|
+
const repoId = repos?.[i];
|
|
260
|
+
const groupKey = repoId !== undefined ? `${repoId}\0${dirPath}` : dirPath;
|
|
261
|
+
if (!dirMap.has(groupKey)) {
|
|
262
|
+
dirMap.set(groupKey, []);
|
|
179
263
|
}
|
|
180
|
-
dirMap.get(
|
|
264
|
+
dirMap.get(groupKey).push({
|
|
181
265
|
path: file,
|
|
182
266
|
description: descriptions.get(file) ?? "",
|
|
267
|
+
repo: repoId,
|
|
183
268
|
});
|
|
184
269
|
}
|
|
185
270
|
const groups = [];
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
|
|
271
|
+
const repoOrder = new Map();
|
|
272
|
+
if (repos) {
|
|
273
|
+
for (let i = 0; i < repos.length; i++) {
|
|
274
|
+
if (!repoOrder.has(repos[i])) {
|
|
275
|
+
repoOrder.set(repos[i], repoOrder.size);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
const sortedDirs = [...dirMap.keys()].sort((a, b) => {
|
|
280
|
+
// Single-repo (project) mode must stay byte-identical to the pre-workspace
|
|
281
|
+
// output, which ordered directories with a bare `.sort()` (UTF-16 code-unit
|
|
282
|
+
// order, so uppercase sorts before lowercase). localeCompare would diverge
|
|
283
|
+
// for mixed-case names (e.g. "Zoo" before "apple" flips), so preserve
|
|
284
|
+
// code-unit ordering here; only the repo-partitioning key is added on top.
|
|
285
|
+
if (!repos)
|
|
286
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
287
|
+
const repoA = dirMap.get(a)[0]?.repo ?? "";
|
|
288
|
+
const repoB = dirMap.get(b)[0]?.repo ?? "";
|
|
289
|
+
const orderA = repoOrder.get(repoA) ?? 0;
|
|
290
|
+
const orderB = repoOrder.get(repoB) ?? 0;
|
|
291
|
+
if (orderA !== orderB)
|
|
292
|
+
return orderA - orderB;
|
|
293
|
+
return a.localeCompare(b);
|
|
294
|
+
});
|
|
295
|
+
for (const groupKey of sortedDirs) {
|
|
296
|
+
const dirFiles = dirMap.get(groupKey);
|
|
189
297
|
dirFiles.sort((a, b) => a.path.localeCompare(b.path));
|
|
298
|
+
const dirPath = repos ? groupKey.slice(groupKey.indexOf("\0") + 1) : groupKey;
|
|
190
299
|
groups.push({
|
|
191
|
-
path:
|
|
300
|
+
path: dirPath,
|
|
192
301
|
files: dirFiles,
|
|
193
302
|
collapsed: dirFiles.length > collapseThreshold,
|
|
303
|
+
// Each group is scoped to one repo in workspace-aware mode.
|
|
304
|
+
repo: dirFiles[0]?.repo,
|
|
194
305
|
});
|
|
195
306
|
}
|
|
196
307
|
return groups;
|
|
@@ -207,7 +318,18 @@ function renderCodebaseMap(groups, totalFiles, truncated, metadata) {
|
|
|
207
318
|
lines.push(`Note: Truncated to first ${totalFiles} files. Run with higher --max-files to include all.`);
|
|
208
319
|
}
|
|
209
320
|
lines.push("");
|
|
321
|
+
let emittedRepo;
|
|
210
322
|
for (const group of groups) {
|
|
323
|
+
// In a workspace-aware map, partition directories under their declaring
|
|
324
|
+
// repository. `## [repo-id]` headings are used (not `###`) so they never
|
|
325
|
+
// collide with the per-directory `### <dir>/` headings or the
|
|
326
|
+
// `parseCodebaseMap` list-item regexes. Groups are sorted by declaring
|
|
327
|
+
// repo (enumeration order) then directory path so each repo is contiguous.
|
|
328
|
+
if (group.repo && group.repo !== emittedRepo) {
|
|
329
|
+
emittedRepo = group.repo;
|
|
330
|
+
lines.push(`## [${group.repo}]`);
|
|
331
|
+
lines.push("");
|
|
332
|
+
}
|
|
211
333
|
const heading = group.path || "(root)";
|
|
212
334
|
lines.push(`### ${heading}/`);
|
|
213
335
|
if (group.collapsed) {
|
|
@@ -250,13 +372,15 @@ function renderCodebaseMap(groups, totalFiles, truncated, metadata) {
|
|
|
250
372
|
function buildCodebaseMap(basePath, resolved, existingDescriptions, enumerated) {
|
|
251
373
|
const listed = enumerated ?? enumerateFiles(basePath, resolved.excludes, resolved.maxFiles);
|
|
252
374
|
const descriptions = existingDescriptions ?? new Map();
|
|
253
|
-
const groups = groupByDirectory(listed.files, descriptions, resolved.collapseThreshold);
|
|
375
|
+
const groups = groupByDirectory(listed.files, descriptions, resolved.collapseThreshold, listed.repos);
|
|
254
376
|
const generatedAt = new Date().toISOString().split(".")[0] + "Z";
|
|
377
|
+
const repoIds = listed.repos ? Array.from(new Set(listed.repos)) : undefined;
|
|
255
378
|
const metadata = {
|
|
256
379
|
generatedAt,
|
|
257
|
-
fingerprint: computeCodebaseFingerprint(listed.files, resolved, listed.truncated),
|
|
380
|
+
fingerprint: computeCodebaseFingerprint(listed.files, resolved, listed.truncated, listed.repos),
|
|
258
381
|
fileCount: listed.files.length,
|
|
259
382
|
truncated: listed.truncated,
|
|
383
|
+
...(repoIds ? { repositories: repoIds } : {}),
|
|
260
384
|
};
|
|
261
385
|
const content = renderCodebaseMap(groups, listed.files.length, listed.truncated, metadata);
|
|
262
386
|
return {
|
|
@@ -273,9 +397,21 @@ function buildCodebaseMap(basePath, resolved, existingDescriptions, enumerated)
|
|
|
273
397
|
* Generate a fresh CODEBASE.md from scratch.
|
|
274
398
|
* Preserves existing descriptions if `existingDescriptions` is provided.
|
|
275
399
|
*/
|
|
400
|
+
/**
|
|
401
|
+
* Resolve workspace-aware enumeration for parent mode, or undefined to fall
|
|
402
|
+
* back to the legacy single-root enumeration. Centralized so all three public
|
|
403
|
+
* entry points (generate/update/ensure) share one discovery path.
|
|
404
|
+
*/
|
|
405
|
+
function resolveWorkspaceEnumeration(basePath, resolved) {
|
|
406
|
+
const registry = loadWorkspaceRegistry(basePath);
|
|
407
|
+
if (!registry)
|
|
408
|
+
return undefined;
|
|
409
|
+
return enumerateWorkspaceFiles(registry, resolved.excludes, resolved.maxFiles);
|
|
410
|
+
}
|
|
276
411
|
export function generateCodebaseMap(basePath, options, existingDescriptions) {
|
|
277
412
|
const resolved = resolveGeneratorOptions(options);
|
|
278
|
-
|
|
413
|
+
const enumerated = resolveWorkspaceEnumeration(basePath, resolved);
|
|
414
|
+
return buildCodebaseMap(basePath, resolved, existingDescriptions, enumerated);
|
|
279
415
|
}
|
|
280
416
|
/**
|
|
281
417
|
* Incremental update: re-scan files, preserve existing descriptions,
|
|
@@ -293,7 +429,8 @@ export function updateCodebaseMap(basePath, options) {
|
|
|
293
429
|
const existingFiles = new Set(existingDescriptions.keys());
|
|
294
430
|
// Generate new map preserving descriptions — reuse the returned file list
|
|
295
431
|
// to avoid a second enumeration (prevents race between content and stats).
|
|
296
|
-
const
|
|
432
|
+
const enumerated = resolveWorkspaceEnumeration(basePath, resolved);
|
|
433
|
+
const result = buildCodebaseMap(basePath, resolved, existingDescriptions, enumerated);
|
|
297
434
|
const currentSet = new Set(result.files);
|
|
298
435
|
// Count changes
|
|
299
436
|
let added = 0;
|
|
@@ -326,7 +463,7 @@ function clearFreshnessCache(basePath) {
|
|
|
326
463
|
}
|
|
327
464
|
export function ensureCodebaseMapFresh(basePath, options, ensureOptions) {
|
|
328
465
|
const resolved = resolveGeneratorOptions(options);
|
|
329
|
-
const cacheKey = `${basePath}::${resolved.optionSignature}`;
|
|
466
|
+
const cacheKey = `${basePath}::${resolved.optionSignature}::${workspaceEnumerationSignature(basePath)}`;
|
|
330
467
|
const ttlMs = ensureOptions?.ttlMs ?? DEFAULT_REFRESH_TTL_MS;
|
|
331
468
|
const force = ensureOptions?.force === true;
|
|
332
469
|
const now = Date.now();
|
|
@@ -338,8 +475,9 @@ export function ensureCodebaseMapFresh(basePath, options, ensureOptions) {
|
|
|
338
475
|
}
|
|
339
476
|
}
|
|
340
477
|
const existing = readCodebaseMap(basePath);
|
|
341
|
-
const listed =
|
|
342
|
-
|
|
478
|
+
const listed = resolveWorkspaceEnumeration(basePath, resolved)
|
|
479
|
+
?? enumerateFiles(basePath, resolved.excludes, resolved.maxFiles);
|
|
480
|
+
const fingerprint = computeCodebaseFingerprint(listed.files, resolved, listed.truncated, listed.repos);
|
|
343
481
|
const cacheAndReturn = (result) => {
|
|
344
482
|
freshnessCache.set(cacheKey, { checkedAt: now, result });
|
|
345
483
|
return result;
|
|
@@ -368,9 +506,15 @@ export function ensureCodebaseMapFresh(basePath, options, ensureOptions) {
|
|
|
368
506
|
}
|
|
369
507
|
const metadata = parseCodebaseMapMetadata(existing);
|
|
370
508
|
const existingDescriptions = parseCodebaseMap(existing);
|
|
509
|
+
// Compare against the truncated count: when the repository has more tracked
|
|
510
|
+
// files than maxFiles, the map only lists the first maxFiles entries, so a
|
|
511
|
+
// stored fileCount above the cap (e.g. from an older map that recorded the
|
|
512
|
+
// full count) still matches the current truncated listing. Comparing raw
|
|
513
|
+
// values would flag "file-count-changed" on every turn, rewriting the
|
|
514
|
+
// timestamp and invalidating the provider KV cache prefix.
|
|
371
515
|
const staleReason = !metadata ? "missing-metadata"
|
|
372
516
|
: metadata.fingerprint !== fingerprint ? "files-changed"
|
|
373
|
-
: metadata.fileCount !== listed.files.length ? "file-count-changed"
|
|
517
|
+
: Math.min(metadata.fileCount, resolved.maxFiles) !== listed.files.length ? "file-count-changed"
|
|
374
518
|
: metadata.truncated !== listed.truncated ? "truncation-changed"
|
|
375
519
|
: undefined;
|
|
376
520
|
if (!staleReason) {
|