@opengsd/gsd-pi 1.3.0-dev.eed73bea → 1.4.0-dev.5fc22c6f
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/cli.js +17 -4
- package/dist/headless-answers.js +1 -1
- package/dist/headless-ui.d.ts +1 -1
- package/dist/headless-ui.js +1 -1
- package/dist/headless.js +1 -1
- 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/models.js +9 -0
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +61 -50
- 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 +431 -0
- package/dist/resources/extensions/gsd/auto/session.js +11 -0
- package/dist/resources/extensions/gsd/auto/verification-retry-policy.js +1 -1
- package/dist/resources/extensions/gsd/auto-artifact-paths.js +28 -1
- package/dist/resources/extensions/gsd/auto-budget.js +5 -1
- package/dist/resources/extensions/gsd/auto-dispatch.js +32 -11
- package/dist/resources/extensions/gsd/auto-model-selection.js +36 -18
- package/dist/resources/extensions/gsd/auto-post-unit.js +1 -1
- package/dist/resources/extensions/gsd/auto-prompts.js +83 -25
- package/dist/resources/extensions/gsd/auto-recovery.js +9 -517
- package/dist/resources/extensions/gsd/auto-runtime-state.js +4 -5
- package/dist/resources/extensions/gsd/auto-start.js +4 -3
- package/dist/resources/extensions/gsd/auto-timeout-recovery.js +7 -3
- package/dist/resources/extensions/gsd/auto-verification.js +5 -2
- package/dist/resources/extensions/gsd/auto-worktree.js +38 -11
- package/dist/resources/extensions/gsd/auto.js +32 -10
- package/dist/resources/extensions/gsd/bootstrap/core-session-tools.js +39 -0
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +8 -4
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +2 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +147 -23
- package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +56 -36
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +29 -5
- package/dist/resources/extensions/gsd/closeout-consistency-gate.js +3 -1
- package/dist/resources/extensions/gsd/codebase-generator.js +157 -19
- package/dist/resources/extensions/gsd/commands/handlers/auto.js +1 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +40 -4
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +154 -2
- package/dist/resources/extensions/gsd/commands-usage.js +1 -1
- package/dist/resources/extensions/gsd/commands-worktree.js +11 -2
- package/dist/resources/extensions/gsd/db/engine.js +4 -1
- package/dist/resources/extensions/gsd/db/queries.js +39 -0
- package/dist/resources/extensions/gsd/db-memory-fts-schema.js +34 -0
- package/dist/resources/extensions/gsd/db-workspace.js +55 -3
- package/dist/resources/extensions/gsd/delegation-policy.js +1 -1
- package/dist/resources/extensions/gsd/discussion-handoff.js +8 -3
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +10 -4
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +227 -5
- package/dist/resources/extensions/gsd/doctor-providers.js +38 -10
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +3 -0
- package/dist/resources/extensions/gsd/doctor.js +93 -3
- package/dist/resources/extensions/gsd/exec-sandbox.js +14 -4
- package/dist/resources/extensions/gsd/flat-phase-migration.js +119 -23
- package/dist/resources/extensions/gsd/git-service.js +61 -8
- package/dist/resources/extensions/gsd/gitignore.js +4 -1
- package/dist/resources/extensions/gsd/guidance.js +1 -0
- package/dist/resources/extensions/gsd/guided-flow-queue.js +20 -13
- package/dist/resources/extensions/gsd/guided-flow.js +40 -2
- package/dist/resources/extensions/gsd/json-persistence.js +20 -0
- package/dist/resources/extensions/gsd/key-manager.js +1 -0
- package/dist/resources/extensions/gsd/knowledge-backfill.js +18 -11
- package/dist/resources/extensions/gsd/layout-policy.js +3 -1
- package/dist/resources/extensions/gsd/markdown-renderer.js +27 -15
- package/dist/resources/extensions/gsd/memory-backfill.js +28 -21
- package/dist/resources/extensions/gsd/metrics.js +4 -4
- package/dist/resources/extensions/gsd/migrate-external.js +22 -5
- package/dist/resources/extensions/gsd/migration-auto-check.js +22 -0
- package/dist/resources/extensions/gsd/milestone-ids.js +32 -2
- package/dist/resources/extensions/gsd/orphan-stash-audit.js +92 -16
- 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-validation.js +25 -2
- package/dist/resources/extensions/gsd/preferences.js +29 -2
- package/dist/resources/extensions/gsd/prompts/code-review.md +6 -4
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +2 -2
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +5 -3
- package/dist/resources/extensions/gsd/redact-secrets.js +37 -0
- package/dist/resources/extensions/gsd/repository-registry.js +6 -1
- package/dist/resources/extensions/gsd/root-write-leak-guard.js +7 -1
- package/dist/resources/extensions/gsd/safe-fs.js +23 -2
- package/dist/resources/extensions/gsd/safety/destructive-guard.js +8 -1
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +16 -1
- package/dist/resources/extensions/gsd/safety/file-change-validator.js +5 -2
- package/dist/resources/extensions/gsd/skills/gsd-headless/SKILL.md +7 -9
- package/dist/resources/extensions/gsd/skills/gsd-headless/references/commands.md +2 -1
- package/dist/resources/extensions/gsd/state/derive/cache.js +28 -0
- package/dist/resources/extensions/gsd/state/derive/db-open.js +39 -0
- package/dist/resources/extensions/gsd/state/derive/from-db.js +452 -0
- package/dist/resources/extensions/gsd/state/derive/index.js +75 -0
- package/dist/resources/extensions/gsd/state/derive/interrupted-work.js +21 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-render.js +27 -33
- package/dist/resources/extensions/gsd/state-reconciliation/index.js +48 -23
- package/dist/resources/extensions/gsd/state-reconciliation/registry.js +32 -28
- package/dist/resources/extensions/gsd/state.js +12 -611
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +4 -2
- package/dist/resources/extensions/gsd/tools/complete-slice.js +3 -34
- package/dist/resources/extensions/gsd/tools/complete-task.js +8 -41
- package/dist/resources/extensions/gsd/tools/plan-slice.js +59 -44
- package/dist/resources/extensions/gsd/tools/plan-task.js +103 -12
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +40 -0
- package/dist/resources/extensions/gsd/undo.js +43 -6
- package/dist/resources/extensions/gsd/unit-context-manifest.js +5 -4
- package/dist/resources/extensions/gsd/unit-registry.js +11 -3
- package/dist/resources/extensions/gsd/unit-runtime.js +21 -0
- package/dist/resources/extensions/gsd/verification-gate.js +7 -0
- package/dist/resources/extensions/gsd/workflow-manifest.js +126 -13
- package/dist/resources/extensions/gsd/workflow-projections.js +19 -14
- package/dist/resources/extensions/gsd/workspace.js +26 -8
- package/dist/resources/extensions/gsd/worktree-manager.js +140 -5
- 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 +12 -12
- 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/react-loadable-manifest.json +9 -9
- 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_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 +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- 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 +1 -1
- 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/update/route.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +2 -2
- 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 +2 -2
- 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 +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +12 -12
- package/dist/web/standalone/.next/server/chunks/8357.js +2 -2
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/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/{2659.b7b129ee6a769448.js → 2659.58e950899a9bb82f.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/2772.a7c1fcc69a4685ef.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{3616.3c60753b8ffcbd2e.js → 3616.61a2af74bb8833c8.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/{4283.8e446784528ed9dc.js → 4283.d0d9e0a955e441cb.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/{5826.a46ecdd1cfe8dabc.js → 5826.5421d66c72b9f34e.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/{8785.481aa5869991b760.js → 8785.e29b3134cab1d153.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/8937.640dc9c2aaa1dfad.js +10 -0
- package/dist/web/standalone/.next/static/chunks/app/{page-6644fc6ee8ca1247.js → page-72a856634ad14c10.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/webpack-9c401904f87ded16.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/pty.target.mk +14 -14
- package/dist/wizard.d.ts +8 -0
- package/dist/wizard.js +8 -1
- package/integrations/hermes/__init__.py +31 -0
- package/integrations/hermes/tests/test_directory_loader.py +37 -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/package.json +5 -5
- package/packages/gsd-agent-core/dist/agent-session.d.ts +1 -0
- package/packages/gsd-agent-core/dist/agent-session.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/agent-session.js +3 -0
- package/packages/gsd-agent-core/dist/agent-session.js.map +1 -1
- 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/extension-ui-snapshot.d.ts +41 -0
- package/packages/gsd-agent-core/dist/extension-ui-snapshot.d.ts.map +1 -0
- package/packages/gsd-agent-core/dist/extension-ui-snapshot.js +62 -0
- package/packages/gsd-agent-core/dist/extension-ui-snapshot.js.map +1 -0
- package/packages/gsd-agent-core/dist/index.d.ts +2 -0
- package/packages/gsd-agent-core/dist/index.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/index.js +2 -0
- package/packages/gsd-agent-core/dist/index.js.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-events.js +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-events.js.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts +1 -0
- package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-host.js.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.d.ts +5 -0
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.js +60 -3
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.js.map +1 -1
- package/packages/gsd-agent-core/dist/transcript-store.d.ts +58 -0
- package/packages/gsd-agent-core/dist/transcript-store.d.ts.map +1 -0
- package/packages/gsd-agent-core/dist/transcript-store.js +132 -0
- package/packages/gsd-agent-core/dist/transcript-store.js.map +1 -0
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +2 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +25 -11
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.d.ts +4 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.js +7 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts +3 -24
- 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 +26 -841
- 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-handoff-filter.d.ts +58 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.js +312 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.d.ts +31 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.js +130 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.d.ts +15 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.js +259 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.d.ts +13 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.js +118 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.d.ts +9 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.js +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.d.ts +54 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.js +20 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts +4 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js +9 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.d.ts +56 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.js +44 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.d.ts +5 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.js +77 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.d.ts +2 -0
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.js +24 -6
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js +18 -0
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/dist/workflow-tools.js +1 -1
- package/packages/mcp-server/dist/workflow-tools.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.js +3 -2
- 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/models.generated.d.ts +46 -0
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +38 -0
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/types.d.ts +2 -2
- 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/README.md +3 -2
- 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-context.d.ts +9 -0
- package/packages/pi-coding-agent/dist/core/session-manager-context.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-context.js +94 -0
- package/packages/pi-coding-agent/dist/core/session-manager-context.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-list.d.ts +8 -0
- package/packages/pi-coding-agent/dist/core/session-manager-list.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-list.js +244 -0
- package/packages/pi-coding-agent/dist/core/session-manager-list.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-migration.d.ts +12 -0
- package/packages/pi-coding-agent/dist/core/session-manager-migration.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-migration.js +84 -0
- package/packages/pi-coding-agent/dist/core/session-manager-migration.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-types.d.ts +135 -0
- package/packages/pi-coding-agent/dist/core/session-manager-types.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-types.js +2 -0
- package/packages/pi-coding-agent/dist/core/session-manager-types.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager.d.ts +6 -154
- package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.js +22 -459
- package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/theme/theme-schema.d.ts +75 -75
- package/packages/pi-coding-agent/dist/theme/theme-schema.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/theme/theme-schema.js +1 -1
- package/packages/pi-coding-agent/dist/theme/theme-schema.js.map +1 -1
- package/packages/pi-coding-agent/dist/theme/theme.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/theme/theme.js +11 -7
- package/packages/pi-coding-agent/dist/theme/theme.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/theme/theme-schema.d.ts +75 -75
- package/pkg/dist/theme/theme-schema.d.ts.map +1 -1
- package/pkg/dist/theme/theme-schema.js +1 -1
- package/pkg/dist/theme/theme-schema.js.map +1 -1
- package/pkg/dist/theme/theme.d.ts.map +1 -1
- package/pkg/dist/theme/theme.js +11 -7
- package/pkg/dist/theme/theme.js.map +1 -1
- 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/models.ts +9 -0
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +67 -49
- package/src/resources/extensions/claude-code-cli/tests/index.test.ts +14 -0
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +159 -0
- 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 +468 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
- package/src/resources/extensions/gsd/auto/session.ts +14 -0
- package/src/resources/extensions/gsd/auto/verification-retry-policy.ts +3 -1
- package/src/resources/extensions/gsd/auto-artifact-paths.ts +47 -1
- package/src/resources/extensions/gsd/auto-budget.ts +12 -1
- package/src/resources/extensions/gsd/auto-dispatch.ts +34 -12
- package/src/resources/extensions/gsd/auto-model-selection.ts +49 -18
- package/src/resources/extensions/gsd/auto-post-unit.ts +1 -1
- package/src/resources/extensions/gsd/auto-prompts.ts +80 -25
- package/src/resources/extensions/gsd/auto-recovery.ts +13 -518
- package/src/resources/extensions/gsd/auto-runtime-state.ts +4 -5
- package/src/resources/extensions/gsd/auto-start.ts +4 -3
- package/src/resources/extensions/gsd/auto-timeout-recovery.ts +7 -2
- package/src/resources/extensions/gsd/auto-verification.ts +5 -1
- package/src/resources/extensions/gsd/auto-worktree.ts +50 -11
- package/src/resources/extensions/gsd/auto.ts +36 -8
- package/src/resources/extensions/gsd/bootstrap/core-session-tools.ts +44 -0
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +8 -4
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +2 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +171 -23
- package/src/resources/extensions/gsd/bootstrap/tests/write-gate-basepath.test.ts +49 -1
- package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +60 -37
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +39 -5
- package/src/resources/extensions/gsd/closeout-consistency-gate.ts +2 -1
- package/src/resources/extensions/gsd/codebase-generator.ts +179 -18
- package/src/resources/extensions/gsd/commands/handlers/auto.ts +1 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +39 -3
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +136 -2
- package/src/resources/extensions/gsd/commands-usage.ts +1 -1
- package/src/resources/extensions/gsd/commands-worktree.ts +13 -2
- package/src/resources/extensions/gsd/db/engine.ts +8 -1
- package/src/resources/extensions/gsd/db/queries.ts +40 -0
- package/src/resources/extensions/gsd/db-memory-fts-schema.ts +45 -0
- package/src/resources/extensions/gsd/db-workspace.ts +61 -3
- package/src/resources/extensions/gsd/delegation-policy.ts +1 -1
- package/src/resources/extensions/gsd/discussion-handoff.ts +10 -2
- package/src/resources/extensions/gsd/docs/preferences-reference.md +10 -4
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +275 -5
- package/src/resources/extensions/gsd/doctor-providers.ts +39 -10
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +3 -0
- package/src/resources/extensions/gsd/doctor-types.ts +8 -1
- package/src/resources/extensions/gsd/doctor.ts +95 -3
- package/src/resources/extensions/gsd/exec-sandbox.ts +13 -4
- package/src/resources/extensions/gsd/flat-phase-migration.ts +142 -22
- package/src/resources/extensions/gsd/git-service.ts +70 -9
- package/src/resources/extensions/gsd/gitignore.ts +4 -1
- package/src/resources/extensions/gsd/guidance.ts +2 -0
- package/src/resources/extensions/gsd/guided-flow-queue.ts +20 -13
- package/src/resources/extensions/gsd/guided-flow.ts +45 -2
- package/src/resources/extensions/gsd/json-persistence.ts +20 -0
- package/src/resources/extensions/gsd/key-manager.ts +1 -0
- package/src/resources/extensions/gsd/knowledge-backfill.ts +16 -10
- package/src/resources/extensions/gsd/layout-policy.ts +2 -1
- package/src/resources/extensions/gsd/markdown-renderer.ts +27 -17
- package/src/resources/extensions/gsd/memory-backfill.ts +26 -20
- package/src/resources/extensions/gsd/metrics.ts +4 -4
- package/src/resources/extensions/gsd/migrate-external.ts +17 -4
- package/src/resources/extensions/gsd/migration-auto-check.ts +23 -0
- package/src/resources/extensions/gsd/milestone-ids.ts +31 -2
- package/src/resources/extensions/gsd/model-router.ts +4 -5
- package/src/resources/extensions/gsd/orphan-stash-audit.ts +108 -20
- 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-validation.ts +28 -2
- package/src/resources/extensions/gsd/preferences.ts +38 -4
- package/src/resources/extensions/gsd/prompts/code-review.md +6 -4
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +2 -2
- package/src/resources/extensions/gsd/prompts/plan-slice.md +5 -3
- package/src/resources/extensions/gsd/redact-secrets.ts +40 -0
- package/src/resources/extensions/gsd/repository-registry.ts +7 -1
- package/src/resources/extensions/gsd/root-write-leak-guard.ts +13 -1
- package/src/resources/extensions/gsd/safe-fs.ts +22 -2
- package/src/resources/extensions/gsd/safety/destructive-guard.ts +9 -1
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +16 -1
- package/src/resources/extensions/gsd/safety/file-change-validator.ts +8 -2
- package/src/resources/extensions/gsd/skills/gsd-headless/SKILL.md +7 -9
- package/src/resources/extensions/gsd/skills/gsd-headless/references/commands.md +2 -1
- package/src/resources/extensions/gsd/state/derive/cache.ts +46 -0
- package/src/resources/extensions/gsd/state/derive/db-open.ts +45 -0
- package/src/resources/extensions/gsd/state/derive/from-db.ts +561 -0
- package/src/resources/extensions/gsd/state/derive/index.ts +104 -0
- package/src/resources/extensions/gsd/state/derive/interrupted-work.ts +31 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +36 -30
- package/src/resources/extensions/gsd/state-reconciliation/index.ts +50 -24
- package/src/resources/extensions/gsd/state-reconciliation/registry.ts +43 -28
- package/src/resources/extensions/gsd/state.ts +32 -732
- package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/auto-artifact-paths.test.ts +98 -1
- package/src/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +14 -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-pause-double-entry-guard.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +182 -4
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/auto-remote-session-lock-cleanup.test.ts +41 -0
- package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +30 -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-timeout-recovery-harness-abort.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +8 -0
- 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/commands-gsd-core.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +62 -1
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +28 -0
- package/src/resources/extensions/gsd/tests/complete-slice-reopen-handoff.test.ts +69 -0
- package/src/resources/extensions/gsd/tests/db-memory-fts-schema.test.ts +58 -3
- package/src/resources/extensions/gsd/tests/decisions-projection-from-memories.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/destructive-guard.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +143 -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 +296 -2
- package/src/resources/extensions/gsd/tests/doctor-workspace.test.ts +207 -0
- package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +74 -2
- 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/gitignore-bg-shell-runtime.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +11 -2
- package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/json-persistence-atomic.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/knowledge-backfill-projection.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +122 -0
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/merge-closeout-consistency-gate.test.ts +31 -1
- package/src/resources/extensions/gsd/tests/metrics-prune-cache-invalidation.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/metrics.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/migrate-external-worktree.test.ts +57 -0
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +70 -0
- package/src/resources/extensions/gsd/tests/orphan-stash-audit.test.ts +91 -7
- package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +4 -1
- package/src/resources/extensions/gsd/tests/pending-autostart-scope.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +103 -4
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +307 -1
- package/src/resources/extensions/gsd/tests/post-mutation-hook.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/preferences.test.ts +150 -0
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +142 -0
- package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +50 -14
- package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +58 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +8 -6
- 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 +378 -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 +20 -1
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +15 -3
- package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +105 -0
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +115 -0
- package/src/resources/extensions/gsd/tests/status-per-repo.test.ts +94 -0
- 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 +203 -0
- package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/undo.test.ts +74 -0
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +66 -18
- package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/uok-gitops-turn-action.test.ts +90 -0
- package/src/resources/extensions/gsd/tests/validator-scope-parity.test.ts +53 -1
- package/src/resources/extensions/gsd/tests/verification-retry-policy.test.ts +69 -4
- package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +96 -15
- package/src/resources/extensions/gsd/tests/workflow-mcp-preflight.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +8 -4
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +214 -6
- package/src/resources/extensions/gsd/tests/workspace.test.ts +18 -4
- package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +31 -1
- package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +32 -0
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +3 -2
- package/src/resources/extensions/gsd/tools/complete-slice.ts +3 -30
- package/src/resources/extensions/gsd/tools/complete-task.ts +7 -39
- package/src/resources/extensions/gsd/tools/plan-slice.ts +60 -47
- package/src/resources/extensions/gsd/tools/plan-task.ts +135 -12
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +58 -0
- package/src/resources/extensions/gsd/undo.ts +47 -6
- package/src/resources/extensions/gsd/unit-context-manifest.ts +11 -5
- package/src/resources/extensions/gsd/unit-registry.ts +11 -3
- package/src/resources/extensions/gsd/unit-runtime.ts +42 -0
- package/src/resources/extensions/gsd/verification-gate.ts +8 -0
- package/src/resources/extensions/gsd/workflow-manifest.ts +141 -7
- package/src/resources/extensions/gsd/workflow-projections.ts +20 -14
- package/src/resources/extensions/gsd/workspace.ts +42 -8
- package/src/resources/extensions/gsd/worktree-manager.ts +183 -5
- package/dist/web/standalone/.next/static/chunks/2772.bfa657f49f955239.js +0 -1
- package/dist/web/standalone/.next/static/chunks/796.3976108148518f7d.js +0 -10
- package/dist/web/standalone/.next/static/chunks/webpack-7c1d97e39be2da11.js +0 -1
- /package/dist/web/standalone/.next/static/{SzEuqWX37DR9MEpEuQjP1 → kIEFsCryyGy6RzifULbJl}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{SzEuqWX37DR9MEpEuQjP1 → kIEFsCryyGy6RzifULbJl}/_ssgManifest.js +0 -0
|
@@ -1,24 +1,31 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tool-call loop guard.
|
|
3
3
|
*
|
|
4
|
-
* Detects when a model calls
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* Detects when a model repeats tool calls within a single Agent Turn.
|
|
5
|
+
* Works in both auto-mode and interactive sessions by hooking into the
|
|
6
|
+
* native engine's `tool_call` event, which fires before execution and can
|
|
7
|
+
* block the call.
|
|
8
8
|
*
|
|
9
|
-
* The guard
|
|
10
|
-
* and
|
|
11
|
-
*
|
|
12
|
-
* and
|
|
9
|
+
* The guard has two independent checks: a sliding window for identical
|
|
10
|
+
* tool signatures, and a per-tool-name cap for repeated calls with varied
|
|
11
|
+
* arguments. State resets at Agent Turn boundaries (session_start,
|
|
12
|
+
* agent_end) and the identical-signature streak also resets when a
|
|
13
|
+
* different tool call breaks the streak. Block messages instruct the model
|
|
14
|
+
* to stop tooling for the rest of that turn and answer in text.
|
|
13
15
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
+
* The per-tool-name check (#783 Brief C) tracks call counts within a
|
|
17
|
+
* turn regardless of args, decaying after successful state-mutating tools.
|
|
18
|
+
* This catches improvisation
|
|
16
19
|
* loops where the model attempts the same missing workflow tool through
|
|
17
20
|
* varied surfaces (bash → `node -e` → CLI), each with a different
|
|
18
|
-
* signature, so the identical-args streak never trips
|
|
21
|
+
* signature, so the identical-args streak never trips, while allowing
|
|
22
|
+
* tool-heavy turns that are making file-mutation progress. Whichever guard
|
|
19
23
|
* trips first blocks.
|
|
20
24
|
*/
|
|
21
25
|
import { createHash } from "node:crypto";
|
|
26
|
+
import { INHERENTLY_REPEATABLE_TOOL_SET } from "./core-session-tools.js";
|
|
27
|
+
import { hasBrowserContractPrefix } from "../../shared/browser-contract.js";
|
|
28
|
+
import { canonicalToolName } from "../engine-hook-contract.js";
|
|
22
29
|
const MAX_CONSECUTIVE_IDENTICAL_CALLS = 4;
|
|
23
30
|
/** Interactive/user-facing tools where even 1 duplicate is confusing. */
|
|
24
31
|
const STRICT_LOOP_TOOLS = new Set(["ask_user_questions"]);
|
|
@@ -35,32 +42,16 @@ const MAX_CONSECUTIVE_STRICT = 1;
|
|
|
35
42
|
*/
|
|
36
43
|
const PER_TOOL_DEFAULT_CAP = 6;
|
|
37
44
|
const PER_TOOL_REPEATABLE_CAP = 15;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
* (reading/writing several files, running several commands, searching). These
|
|
41
|
-
* get PER_TOOL_REPEATABLE_CAP rather than the default. Keep this list
|
|
42
|
-
* conservative — a tool here can be invoked up to PER_TOOL_REPEATABLE_CAP times
|
|
43
|
-
* per turn before the guard blocks.
|
|
44
|
-
*/
|
|
45
|
-
const REPEATABLE_TOOLS = new Set([
|
|
46
|
-
"read",
|
|
47
|
-
"write",
|
|
48
|
-
"edit",
|
|
49
|
-
"multi_edit",
|
|
50
|
-
"bash",
|
|
51
|
-
"grep",
|
|
52
|
-
"glob",
|
|
53
|
-
"search-the-web",
|
|
54
|
-
"fetch_page",
|
|
55
|
-
"todo_write",
|
|
56
|
-
"notebook_edit",
|
|
57
|
-
]);
|
|
45
|
+
const PER_TOOL_CAP_EXEMPT_TOOLS = new Set(["find", "glob", "grep", "ls", "read", "search_and_read"]);
|
|
46
|
+
const STATE_MUTATING_TOOL_SET = new Set(["edit", "write", "multi_edit", "notebook_edit"]);
|
|
58
47
|
let consecutiveCount = 0;
|
|
59
48
|
let lastSignature = "";
|
|
60
49
|
let lastToolName = "";
|
|
61
50
|
let enabled = true;
|
|
62
51
|
/** Per-tool-name call counts within the current turn (#783 Brief C). */
|
|
63
52
|
const perToolCounts = new Map();
|
|
53
|
+
let mutationEpoch = 0;
|
|
54
|
+
const perToolLastMutationEpoch = new Map();
|
|
64
55
|
/** Hash tool name + args into a compact signature for comparison. */
|
|
65
56
|
function hashToolCall(toolName, args) {
|
|
66
57
|
const h = createHash("sha256");
|
|
@@ -84,7 +75,8 @@ function hashToolCall(toolName, args) {
|
|
|
84
75
|
* 1. Identical-signature streak (MAX_CONSECUTIVE_IDENTICAL_CALLS, strict for
|
|
85
76
|
* ask_user_questions).
|
|
86
77
|
* 2. Per-tool-name cap (PER_TOOL_DEFAULT_CAP / PER_TOOL_REPEATABLE_CAP),
|
|
87
|
-
* independent of args
|
|
78
|
+
* independent of args, reset after file-mutation progress — catches
|
|
79
|
+
* improvisation loops (#783).
|
|
88
80
|
*/
|
|
89
81
|
export function checkToolCallLoop(toolName, args) {
|
|
90
82
|
if (!enabled)
|
|
@@ -107,16 +99,31 @@ export function checkToolCallLoop(toolName, args) {
|
|
|
107
99
|
block: true,
|
|
108
100
|
reason: `Tool loop detected (identical args): ${toolName} called ${consecutiveCount} times ` +
|
|
109
101
|
`with identical arguments. Blocking to prevent infinite loop. ` +
|
|
110
|
-
`
|
|
102
|
+
`Do not retry this tool or call other tools this turn — stop and respond to the user in text.`,
|
|
111
103
|
count: consecutiveCount,
|
|
112
104
|
};
|
|
113
105
|
}
|
|
114
106
|
// ── Guard 2: per-tool-name cap, independent of args (#783 Brief C) ──
|
|
115
107
|
// Catches improvisation loops where the same tool is invoked many times with
|
|
116
108
|
// varied args (e.g. retrying a missing workflow tool via bash/node -e/CLI).
|
|
117
|
-
const
|
|
109
|
+
const priorPerToolCount = (perToolLastMutationEpoch.get(toolName) ?? mutationEpoch) < mutationEpoch
|
|
110
|
+
? 0
|
|
111
|
+
: (perToolCounts.get(toolName) ?? 0);
|
|
112
|
+
const perToolCount = priorPerToolCount + 1;
|
|
118
113
|
perToolCounts.set(toolName, perToolCount);
|
|
119
|
-
|
|
114
|
+
perToolLastMutationEpoch.set(toolName, mutationEpoch);
|
|
115
|
+
// Read-only navigation tools are normal context gathering; Guard 1 still
|
|
116
|
+
// catches true reread loops with identical arguments. Browser Automation
|
|
117
|
+
// Contract tools (browser_*) are the same shape: a browser-backed UAT makes
|
|
118
|
+
// many distinct-arg calls (read a message, count edits, inspect a card, …),
|
|
119
|
+
// so the arg-independent per-tool cap misfires on legitimate verification;
|
|
120
|
+
// Guard 1's identical-signature streak still catches a genuinely stuck
|
|
121
|
+
// browser loop.
|
|
122
|
+
if (PER_TOOL_CAP_EXEMPT_TOOLS.has(toolName) ||
|
|
123
|
+
hasBrowserContractPrefix(canonicalToolName(toolName))) {
|
|
124
|
+
return { block: false, count: consecutiveCount };
|
|
125
|
+
}
|
|
126
|
+
const perToolCap = INHERENTLY_REPEATABLE_TOOL_SET.has(toolName)
|
|
120
127
|
? PER_TOOL_REPEATABLE_CAP
|
|
121
128
|
: PER_TOOL_DEFAULT_CAP;
|
|
122
129
|
if (perToolCount > perToolCap) {
|
|
@@ -124,12 +131,21 @@ export function checkToolCallLoop(toolName, args) {
|
|
|
124
131
|
block: true,
|
|
125
132
|
reason: `Tool loop detected (repeated tool): ${toolName} called ${perToolCount} times ` +
|
|
126
133
|
`this turn (cap ${perToolCap}). Blocking to prevent infinite loop. ` +
|
|
127
|
-
`The tool may be unavailable or failing repeatedly
|
|
134
|
+
`The tool may be unavailable or failing repeatedly. ` +
|
|
135
|
+
`Do not retry this tool or pivot to other tools this turn — stop and respond to the user in text.`,
|
|
128
136
|
count: perToolCount,
|
|
129
137
|
};
|
|
130
138
|
}
|
|
131
139
|
return { block: false, count: consecutiveCount };
|
|
132
140
|
}
|
|
141
|
+
/** Record successful mutation progress so Guard 2 can decay on the next count. */
|
|
142
|
+
export function recordToolCallLoopMutation(toolName) {
|
|
143
|
+
if (!enabled)
|
|
144
|
+
return;
|
|
145
|
+
if (!STATE_MUTATING_TOOL_SET.has(toolName))
|
|
146
|
+
return;
|
|
147
|
+
mutationEpoch++;
|
|
148
|
+
}
|
|
133
149
|
/** Reset the guard state. Call at agent turn boundaries. */
|
|
134
150
|
export function resetToolCallLoopGuard() {
|
|
135
151
|
consecutiveCount = 0;
|
|
@@ -137,6 +153,8 @@ export function resetToolCallLoopGuard() {
|
|
|
137
153
|
lastToolName = "";
|
|
138
154
|
enabled = true;
|
|
139
155
|
perToolCounts.clear();
|
|
156
|
+
mutationEpoch = 0;
|
|
157
|
+
perToolLastMutationEpoch.clear();
|
|
140
158
|
}
|
|
141
159
|
/** Disable the guard (e.g. during shutdown). */
|
|
142
160
|
export function disableToolCallLoopGuard() {
|
|
@@ -145,6 +163,8 @@ export function disableToolCallLoopGuard() {
|
|
|
145
163
|
lastSignature = "";
|
|
146
164
|
lastToolName = "";
|
|
147
165
|
perToolCounts.clear();
|
|
166
|
+
mutationEpoch = 0;
|
|
167
|
+
perToolLastMutationEpoch.clear();
|
|
148
168
|
}
|
|
149
169
|
/** Get current consecutive count for diagnostics. */
|
|
150
170
|
export function getToolCallLoopCount() {
|
|
@@ -81,8 +81,18 @@ function createEmptyWriteGateState() {
|
|
|
81
81
|
};
|
|
82
82
|
}
|
|
83
83
|
const writeGateStatesByBasePath = new Map();
|
|
84
|
+
/**
|
|
85
|
+
* Write-gate snapshots are project-scoped, not worktree-scoped. When auto-mode
|
|
86
|
+
* routes MCP tool writes to `.gsd-worktrees/<MID>/`, depth verification still
|
|
87
|
+
* lands in the authoritative project `.gsd/runtime/` tree (or external-state
|
|
88
|
+
* symlink target). Without this canonicalization, `loadWriteGateSnapshot(worktree)`
|
|
89
|
+
* sees an empty snapshot and CONTEXT saves loop forever (#M020 gate loop).
|
|
90
|
+
*/
|
|
91
|
+
function resolveWriteGateSnapshotRoot(basePath) {
|
|
92
|
+
return resolve(resolveWorktreeProjectRoot(basePath));
|
|
93
|
+
}
|
|
84
94
|
function writeGateStateKey(basePath) {
|
|
85
|
-
return
|
|
95
|
+
return resolveWriteGateSnapshotRoot(basePath);
|
|
86
96
|
}
|
|
87
97
|
function getWriteGateState(basePath = process.cwd()) {
|
|
88
98
|
const key = writeGateStateKey(basePath);
|
|
@@ -123,16 +133,17 @@ function shouldPersistWriteGateSnapshot(env = process.env) {
|
|
|
123
133
|
return v !== "0" && v !== "false";
|
|
124
134
|
}
|
|
125
135
|
function writeGateSnapshotPath(basePath) {
|
|
126
|
-
return join(basePath, ".gsd", "runtime", "write-gate-state.json");
|
|
136
|
+
return join(resolveWriteGateSnapshotRoot(basePath), ".gsd", "runtime", "write-gate-state.json");
|
|
127
137
|
}
|
|
128
138
|
function ensureWriteGateSnapshotDirectory(basePath) {
|
|
129
|
-
const
|
|
139
|
+
const snapshotRoot = resolveWriteGateSnapshotRoot(basePath);
|
|
140
|
+
const gsdPath = join(snapshotRoot, ".gsd");
|
|
130
141
|
if (!existsSync(gsdPath)) {
|
|
131
142
|
try {
|
|
132
143
|
const stat = lstatSync(gsdPath);
|
|
133
144
|
if (stat.isSymbolicLink()) {
|
|
134
145
|
const target = readlinkSync(gsdPath);
|
|
135
|
-
mkdirSync(isAbsolute(target) ? target : resolve(
|
|
146
|
+
mkdirSync(isAbsolute(target) ? target : resolve(snapshotRoot, target), { recursive: true });
|
|
136
147
|
}
|
|
137
148
|
}
|
|
138
149
|
catch {
|
|
@@ -936,7 +947,7 @@ function allowedPlanningDispatchAgentsList() {
|
|
|
936
947
|
return [...ALLOWED_PLANNING_DISPATCH_AGENTS].join(", ");
|
|
937
948
|
}
|
|
938
949
|
function allowsControlledSubagentDispatch(policy) {
|
|
939
|
-
return ((policy.mode === "planning-dispatch" || policy.mode === "verification") &&
|
|
950
|
+
return ((policy.mode === "planning-dispatch" || policy.mode === "verification" || policy.mode === "workflow-only") &&
|
|
940
951
|
Array.isArray(policy.allowedSubagents));
|
|
941
952
|
}
|
|
942
953
|
function warnMissingControlledDispatchAgentClasses(unitType, mode, toolName) {
|
|
@@ -964,6 +975,7 @@ function warnMissingControlledDispatchAgentClasses(unitType, mode, toolName) {
|
|
|
964
975
|
const PLANNING_SAFE_TOOLS = new Set([
|
|
965
976
|
"read", "grep", "find", "ls", "glob",
|
|
966
977
|
"ask_user_questions",
|
|
978
|
+
"memory_query",
|
|
967
979
|
"search-the-web", "resolve_library", "get_library_docs", "fetch_page",
|
|
968
980
|
"search_and_read",
|
|
969
981
|
]);
|
|
@@ -1020,6 +1032,9 @@ function planningBlock(unitType, mode, what) {
|
|
|
1020
1032
|
* → allows Bash for project verification commands, keeps
|
|
1021
1033
|
* writes restricted to .gsd/, and permits subagent dispatch
|
|
1022
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.
|
|
1023
1038
|
*
|
|
1024
1039
|
* `pathOrCommand` is the file path for write/edit-shaped tools and the
|
|
1025
1040
|
* shell command for bash. Other tools ignore this argument.
|
|
@@ -1090,6 +1105,15 @@ export function shouldBlockPlanningUnit(toolName, pathOrCommand, basePath, unitT
|
|
|
1090
1105
|
}
|
|
1091
1106
|
return planningBlock(unitType, policy.mode, "subagent dispatch is not permitted in planning units");
|
|
1092
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
|
+
}
|
|
1093
1117
|
if (tool === "bash") {
|
|
1094
1118
|
if (policy.mode === "verification") {
|
|
1095
1119
|
if (BASH_VERIFICATION_RE.test(pathOrCommand) || BASH_READ_ONLY_RE.test(pathOrCommand))
|
|
@@ -4,7 +4,7 @@ import { existsSync, mkdirSync, unlinkSync, writeFileSync } from "node:fs";
|
|
|
4
4
|
import { dirname, join } from "node:path";
|
|
5
5
|
import { getLatestAssessmentByScope, getMilestone, getMilestoneSlices, getPendingGates, getSliceTasks, insertAssessment, isDbAvailable, transaction, } from "./gsd-db.js";
|
|
6
6
|
import { getWorkflowDatabasePath, refreshWorkflowDatabaseFromDisk, } from "./db-workspace.js";
|
|
7
|
-
import { isClosedStatus } from "./status-guards.js";
|
|
7
|
+
import { isClosedStatus, isDeferredStatus } from "./status-guards.js";
|
|
8
8
|
import { closeQualityGatesFromEvidence } from "./quality-gate-closure.js";
|
|
9
9
|
import { insertMilestoneValidationGates } from "./milestone-validation-gates.js";
|
|
10
10
|
import { relMilestoneFile, resolveSliceFile } from "./paths.js";
|
|
@@ -144,6 +144,8 @@ export function checkCloseoutConsistencyGate(milestoneId, options = {}) {
|
|
|
144
144
|
});
|
|
145
145
|
}
|
|
146
146
|
for (const slice of slices) {
|
|
147
|
+
if (isDeferredStatus(slice.status))
|
|
148
|
+
continue;
|
|
147
149
|
if (!isClosedStatus(slice.status)) {
|
|
148
150
|
return blocked("slice-open", `Closeout consistency blocked for ${milestoneId}: slice ${slice.id} status is "${slice.status}".`);
|
|
149
151
|
}
|
|
@@ -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;
|
|
@@ -190,7 +190,7 @@ export async function handleAutoCommand(trimmed, ctx, pi) {
|
|
|
190
190
|
}
|
|
191
191
|
return true;
|
|
192
192
|
}
|
|
193
|
-
await pauseAuto(ctx, pi);
|
|
193
|
+
await pauseAuto(ctx, pi, undefined, { abortActiveTurn: true });
|
|
194
194
|
return true;
|
|
195
195
|
}
|
|
196
196
|
if (trimmed === "rate" || trimmed.startsWith("rate ")) {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import { computeProgressScore, formatProgressLine } from "../../progress-score.js";
|
|
3
|
-
import {
|
|
3
|
+
import { isRepositoryDirty } from "../../git-service.js";
|
|
4
|
+
import { loadEffectiveGSDPreferences, getGlobalGSDPreferencesPath, getProjectGSDPreferencesPath, modelIdsForProfileResolution, resolveProfileAnchorProvider, resolveDisabledModelProvidersFromPreferences } from "../../preferences.js";
|
|
5
|
+
import { createRepositoryRegistryFromPreferences } from "../../repository-registry.js";
|
|
4
6
|
import { ensurePreferencesFile, handlePrefs, handlePrefsMode, handlePrefsWizard, handleLanguage } from "../../commands-prefs-wizard.js";
|
|
5
7
|
import { runEnvironmentChecks } from "../../doctor-environment.js";
|
|
6
8
|
import { deriveState } from "../../state.js";
|
|
@@ -206,7 +208,7 @@ export async function handleStatus(ctx) {
|
|
|
206
208
|
},
|
|
207
209
|
});
|
|
208
210
|
if (result === undefined) {
|
|
209
|
-
ctx.ui.notify(formatTextStatus(state), "info");
|
|
211
|
+
ctx.ui.notify(formatTextStatus(state, basePath), "info");
|
|
210
212
|
}
|
|
211
213
|
}
|
|
212
214
|
export async function fireStatusViaCommand(ctx) {
|
|
@@ -539,7 +541,8 @@ export async function handleCoreCommand(trimmed, ctx, pi) {
|
|
|
539
541
|
}
|
|
540
542
|
return false;
|
|
541
543
|
}
|
|
542
|
-
export function formatTextStatus(state) {
|
|
544
|
+
export function formatTextStatus(state, basePath) {
|
|
545
|
+
const root = basePath ?? projectRoot();
|
|
543
546
|
const lines = ["GSD Status\n"];
|
|
544
547
|
lines.push(formatProgressLine(computeProgressScore()));
|
|
545
548
|
lines.push("");
|
|
@@ -582,7 +585,7 @@ export function formatTextStatus(state) {
|
|
|
582
585
|
lines.push(` ${icon} ${milestone.id}: ${milestone.title} (${milestone.status})`);
|
|
583
586
|
}
|
|
584
587
|
}
|
|
585
|
-
const envResults = runEnvironmentChecks(
|
|
588
|
+
const envResults = runEnvironmentChecks(root);
|
|
586
589
|
const envIssues = envResults.filter((result) => result.status !== "ok");
|
|
587
590
|
if (envIssues.length > 0) {
|
|
588
591
|
lines.push("");
|
|
@@ -591,5 +594,38 @@ export function formatTextStatus(state) {
|
|
|
591
594
|
lines.push(` ${issue.status === "error" ? "✗" : "⚠"} ${issue.message}`);
|
|
592
595
|
}
|
|
593
596
|
}
|
|
597
|
+
// Parent-workspace per-repository git health (#818). No-op for single-repo
|
|
598
|
+
// projects; surfaces which declared child repos have uncommitted changes.
|
|
599
|
+
const repoBlock = buildWorkspaceRepoStatusBlock(root);
|
|
600
|
+
if (repoBlock) {
|
|
601
|
+
lines.push("");
|
|
602
|
+
lines.push("Repositories:");
|
|
603
|
+
lines.push(repoBlock);
|
|
604
|
+
}
|
|
594
605
|
return lines.join("\n");
|
|
595
606
|
}
|
|
607
|
+
/**
|
|
608
|
+
* Build a per-repository dirty/clean summary for parent-workspace status.
|
|
609
|
+
* Returns "" for single-repo (project-mode) projects so the status output is
|
|
610
|
+
* unchanged; otherwise one line per declared child repository.
|
|
611
|
+
*/
|
|
612
|
+
function buildWorkspaceRepoStatusBlock(basePath) {
|
|
613
|
+
let registry;
|
|
614
|
+
try {
|
|
615
|
+
registry = createRepositoryRegistryFromPreferences(basePath, loadEffectiveGSDPreferences(basePath)?.preferences);
|
|
616
|
+
}
|
|
617
|
+
catch {
|
|
618
|
+
return "";
|
|
619
|
+
}
|
|
620
|
+
if (registry.mode !== "parent")
|
|
621
|
+
return "";
|
|
622
|
+
const childRepos = registry.repositories.filter((repo) => repo.id !== "project");
|
|
623
|
+
if (childRepos.length === 0)
|
|
624
|
+
return "";
|
|
625
|
+
return childRepos
|
|
626
|
+
.map((repo) => {
|
|
627
|
+
const dirty = isRepositoryDirty(repo.root);
|
|
628
|
+
return ` ${dirty ? "✗" : "✓"} ${repo.id}${repo.role ? ` — ${repo.role}` : ""}${dirty ? " (uncommitted changes)" : " (clean)"}`;
|
|
629
|
+
})
|
|
630
|
+
.join("\n");
|
|
631
|
+
}
|