@opengsd/gsd-pi 1.3.0-dev.65546769 → 1.3.0-dev.738160b9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cli.js +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/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/claude-code-cli/models.js +9 -0
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +11 -2
- package/dist/resources/extensions/google-cli/stream-adapter.js +82 -15
- package/dist/resources/extensions/gsd/artifact-verification.js +427 -0
- package/dist/resources/extensions/gsd/auto/orchestrator.js +12 -3
- 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 +34 -20
- package/dist/resources/extensions/gsd/auto-post-unit.js +1 -1
- package/dist/resources/extensions/gsd/auto-prompts.js +29 -14
- package/dist/resources/extensions/gsd/auto-recovery.js +9 -510
- package/dist/resources/extensions/gsd/auto-runtime-state.js +4 -5
- package/dist/resources/extensions/gsd/auto-timeout-recovery.js +3 -3
- package/dist/resources/extensions/gsd/auto-verification.js +5 -2
- package/dist/resources/extensions/gsd/auto.js +19 -10
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +103 -13
- package/dist/resources/extensions/gsd/bootstrap/core-session-tools.js +39 -0
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +11 -5
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +2 -0
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +2 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +41 -21
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +46 -19
- package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +96 -10
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +1 -1
- package/dist/resources/extensions/gsd/closeout-consistency-gate.js +3 -1
- package/dist/resources/extensions/gsd/commands/handlers/auto.js +1 -1
- package/dist/resources/extensions/gsd/commands-context.js +19 -1
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +17 -11
- package/dist/resources/extensions/gsd/commands-usage.js +1 -1
- package/dist/resources/extensions/gsd/commands-worktree.js +12 -10
- package/dist/resources/extensions/gsd/dashboard-overlay.js +32 -3
- package/dist/resources/extensions/gsd/db/engine.js +4 -1
- package/dist/resources/extensions/gsd/db/queries.js +60 -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/docs/preferences-reference.md +2 -2
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +192 -4
- package/dist/resources/extensions/gsd/doctor-providers.js +92 -8
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +3 -0
- package/dist/resources/extensions/gsd/exec-sandbox.js +53 -11
- package/dist/resources/extensions/gsd/flat-phase-migration.js +45 -0
- package/dist/resources/extensions/gsd/forensics.js +2 -32
- package/dist/resources/extensions/gsd/git-service.js +61 -4
- package/dist/resources/extensions/gsd/gitignore.js +4 -1
- package/dist/resources/extensions/gsd/guided-flow-queue.js +66 -5
- package/dist/resources/extensions/gsd/health-widget.js +55 -29
- package/dist/resources/extensions/gsd/json-persistence.js +20 -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 +8 -9
- package/dist/resources/extensions/gsd/memory-backfill.js +28 -21
- package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +44 -21
- package/dist/resources/extensions/gsd/metrics.js +4 -4
- package/dist/resources/extensions/gsd/migrate-external.js +11 -2
- 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/milestone-implementation-evidence.js +26 -20
- package/dist/resources/extensions/gsd/orphan-stash-audit.js +92 -16
- 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 +3 -3
- package/dist/resources/extensions/gsd/quick.js +45 -2
- package/dist/resources/extensions/gsd/root-write-leak-guard.js +7 -1
- 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/session-forensics.js +11 -1
- package/dist/resources/extensions/gsd/skills/gsd-headless/references/commands.md +1 -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 +45 -2
- 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 +2 -2
- package/dist/resources/extensions/gsd/tools/complete-task.js +43 -14
- package/dist/resources/extensions/gsd/tools/exec-tool.js +7 -2
- package/dist/resources/extensions/gsd/tools/plan-slice.js +59 -44
- package/dist/resources/extensions/gsd/tools/plan-task.js +28 -5
- package/dist/resources/extensions/gsd/undo.js +43 -6
- package/dist/resources/extensions/gsd/unit-context-composer.js +23 -7
- package/dist/resources/extensions/gsd/unit-registry.js +36 -6
- package/dist/resources/extensions/gsd/unmerged-milestone-guard.js +33 -3
- package/dist/resources/extensions/gsd/validation-block-guard.js +9 -4
- 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-git-preflight.js +30 -1
- package/dist/resources/extensions/gsd/worktree-manager.js +44 -2
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +10 -10
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/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/visualizer/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 +10 -10
- package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
- 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/node-pty/build/Makefile +1 -1
- package/package.json +1 -1
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/dist/workflow.d.ts +1 -0
- package/packages/contracts/dist/workflow.d.ts.map +1 -1
- package/packages/contracts/dist/workflow.js +2 -0
- package/packages/contracts/dist/workflow.js.map +1 -1
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- 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/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 -829
- 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 +258 -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 +23 -5
- 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/README.md +1 -1
- package/packages/mcp-server/dist/server.d.ts +1 -1
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +3 -3
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts +13 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +35 -21
- 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/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/package.json +1 -1
- package/packages/pi-coding-agent/README.md +3 -2
- 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/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/src/resources/extensions/claude-code-cli/models.ts +9 -0
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +20 -2
- 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 +80 -0
- package/src/resources/extensions/google-cli/stream-adapter.ts +106 -19
- package/src/resources/extensions/gsd/artifact-verification.ts +464 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
- package/src/resources/extensions/gsd/auto/orchestrator.ts +25 -11
- 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 +35 -24
- package/src/resources/extensions/gsd/auto-post-unit.ts +1 -1
- package/src/resources/extensions/gsd/auto-prompts.ts +41 -15
- package/src/resources/extensions/gsd/auto-recovery.ts +13 -511
- package/src/resources/extensions/gsd/auto-runtime-state.ts +4 -5
- package/src/resources/extensions/gsd/auto-timeout-recovery.ts +3 -2
- package/src/resources/extensions/gsd/auto-verification.ts +5 -1
- package/src/resources/extensions/gsd/auto.ts +23 -8
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +125 -12
- package/src/resources/extensions/gsd/bootstrap/core-session-tools.ts +44 -0
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +11 -5
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +2 -0
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +2 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +52 -21
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +52 -18
- package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +104 -10
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +1 -1
- package/src/resources/extensions/gsd/closeout-consistency-gate.ts +2 -1
- package/src/resources/extensions/gsd/commands/handlers/auto.ts +1 -1
- package/src/resources/extensions/gsd/commands-context.ts +18 -1
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +15 -10
- package/src/resources/extensions/gsd/commands-usage.ts +1 -1
- package/src/resources/extensions/gsd/commands-worktree.ts +12 -10
- package/src/resources/extensions/gsd/dashboard-overlay.ts +32 -3
- package/src/resources/extensions/gsd/db/engine.ts +8 -1
- package/src/resources/extensions/gsd/db/queries.ts +79 -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/docs/preferences-reference.md +2 -2
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +233 -5
- package/src/resources/extensions/gsd/doctor-providers.ts +103 -9
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +3 -0
- package/src/resources/extensions/gsd/doctor-types.ts +3 -0
- package/src/resources/extensions/gsd/exec-sandbox.ts +56 -11
- package/src/resources/extensions/gsd/flat-phase-migration.ts +44 -0
- package/src/resources/extensions/gsd/forensics.ts +2 -33
- package/src/resources/extensions/gsd/git-service.ts +69 -5
- package/src/resources/extensions/gsd/gitignore.ts +4 -1
- package/src/resources/extensions/gsd/guided-flow-queue.ts +89 -4
- package/src/resources/extensions/gsd/health-widget.ts +69 -32
- package/src/resources/extensions/gsd/json-persistence.ts +20 -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 +8 -11
- package/src/resources/extensions/gsd/memory-backfill.ts +26 -20
- package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +51 -19
- package/src/resources/extensions/gsd/metrics.ts +4 -4
- package/src/resources/extensions/gsd/migrate-external.ts +8 -2
- 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/milestone-implementation-evidence.ts +35 -21
- package/src/resources/extensions/gsd/orphan-stash-audit.ts +108 -20
- 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 +3 -3
- package/src/resources/extensions/gsd/quick.ts +43 -2
- package/src/resources/extensions/gsd/root-write-leak-guard.ts +13 -1
- 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/session-forensics.ts +11 -1
- package/src/resources/extensions/gsd/skills/gsd-headless/references/commands.md +1 -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 +81 -7
- 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-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 +146 -1
- package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/commands-context.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/commands-gsd-core.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/commands-worktree-clean.test.ts +80 -0
- 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/complete-slice.test.ts +11 -0
- package/src/resources/extensions/gsd/tests/complete-task-rollback-evidence.test.ts +48 -8
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/dashboard-overlay.test.ts +55 -2
- 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/dispatch-rule-coverage.test.ts +26 -1
- package/src/resources/extensions/gsd/tests/doctor-forensics-db-open-regression.test.ts +70 -2
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +107 -0
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +239 -2
- package/src/resources/extensions/gsd/tests/exec-graceful-kill.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/exec-tool.test.ts +45 -1
- package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +37 -2
- package/src/resources/extensions/gsd/tests/forensics-error-filter.test.ts +88 -0
- package/src/resources/extensions/gsd/tests/gitignore-bg-shell-runtime.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +268 -3
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +130 -3
- package/src/resources/extensions/gsd/tests/integration/queue-active-milestone-context-budget.test.ts +93 -0
- package/src/resources/extensions/gsd/tests/integration/quick-branch-lifecycle.test.ts +56 -9
- 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/knowledge-cold-start.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/memory-consolidation-scanner.test.ts +78 -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/orchestrator-logs.test.ts +43 -1
- package/src/resources/extensions/gsd/tests/orphan-stash-audit.test.ts +91 -7
- package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +4 -1
- package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +103 -4
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +44 -1
- package/src/resources/extensions/gsd/tests/post-mutation-hook.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +54 -1
- 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/provider-errors.test.ts +195 -1
- package/src/resources/extensions/gsd/tests/read-uat-gate-verdict.test.ts +185 -0
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +87 -0
- package/src/resources/extensions/gsd/tests/register-hooks-loop-guard-auto.test.ts +103 -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 +56 -0
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +191 -0
- package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +208 -0
- package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +32 -3
- package/src/resources/extensions/gsd/tests/undo.test.ts +74 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +193 -14
- package/src/resources/extensions/gsd/tests/unmerged-milestone-guard.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/uok-gitops-turn-action.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/validation-block-guard.test.ts +79 -0
- package/src/resources/extensions/gsd/tests/verification-retry-policy.test.ts +69 -4
- package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +66 -0
- 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 +6 -5
- package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +151 -2
- package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +39 -0
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +3 -2
- package/src/resources/extensions/gsd/tools/complete-slice.ts +2 -2
- package/src/resources/extensions/gsd/tools/complete-task.ts +53 -15
- package/src/resources/extensions/gsd/tools/exec-tool.ts +7 -3
- package/src/resources/extensions/gsd/tools/plan-slice.ts +60 -47
- package/src/resources/extensions/gsd/tools/plan-task.ts +30 -5
- package/src/resources/extensions/gsd/undo.ts +47 -6
- package/src/resources/extensions/gsd/unit-context-composer.ts +33 -7
- package/src/resources/extensions/gsd/unit-registry.ts +36 -6
- package/src/resources/extensions/gsd/unmerged-milestone-guard.ts +41 -5
- package/src/resources/extensions/gsd/validation-block-guard.ts +13 -7
- 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-git-preflight.ts +31 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +41 -1
- package/dist/web/standalone/.next/static/chunks/2772.bfa657f49f955239.js +0 -1
- package/dist/web/standalone/.next/static/chunks/796.e0bdc932325d7e03.js +0 -10
- package/dist/web/standalone/.next/static/chunks/webpack-f46ea08200a0227e.js +0 -1
- /package/dist/web/standalone/.next/static/{BTKtGFF1Y-hvVJEGhBRo9 → 2A_WqqCS-EoYZxN9_v3d2}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{BTKtGFF1Y-hvVJEGhBRo9 → 2A_WqqCS-EoYZxN9_v3d2}/_ssgManifest.js +0 -0
|
@@ -7,9 +7,11 @@ import { test } from 'node:test';
|
|
|
7
7
|
import assert from 'node:assert/strict';
|
|
8
8
|
import {
|
|
9
9
|
checkToolCallLoop,
|
|
10
|
+
recordToolCallLoopMutation,
|
|
10
11
|
resetToolCallLoopGuard,
|
|
11
12
|
disableToolCallLoopGuard,
|
|
12
13
|
getToolCallLoopCount,
|
|
14
|
+
getToolCallCountForTool,
|
|
13
15
|
} from '../bootstrap/tool-call-loop-guard.ts';
|
|
14
16
|
|
|
15
17
|
|
|
@@ -177,3 +179,209 @@ console.log('\n── Loop guard: nested key order is normalized ──');
|
|
|
177
179
|
}
|
|
178
180
|
|
|
179
181
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
182
|
+
// Per-tool-name cap (#783 Brief C) — catches improvisation loops with varied args
|
|
183
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
184
|
+
|
|
185
|
+
console.log('\n── Loop guard: per-tool cap blocks varied-args improvisation (#783) ──');
|
|
186
|
+
|
|
187
|
+
{
|
|
188
|
+
resetToolCallLoopGuard();
|
|
189
|
+
|
|
190
|
+
// A one-shot workflow tool called with DIFFERENT args each time (the reported
|
|
191
|
+
// improvisation pattern). The identical-signature streak alone would reset
|
|
192
|
+
// every call; the per-tool cap must catch it.
|
|
193
|
+
for (let i = 1; i <= 6; i++) {
|
|
194
|
+
const result = checkToolCallLoop('gsd_complete_milestone', { milestone: `M${i}` });
|
|
195
|
+
assert.ok(result.block === false, `one-shot call ${i} (varied args) should be allowed`);
|
|
196
|
+
assert.deepStrictEqual(getToolCallCountForTool('gsd_complete_milestone'), i, `per-tool count should be ${i}`);
|
|
197
|
+
}
|
|
198
|
+
// 7th call (cap 6 + 1) must be blocked by the per-tool guard.
|
|
199
|
+
const blocked = checkToolCallLoop('gsd_complete_milestone', { milestone: 'M7' });
|
|
200
|
+
assert.ok(blocked.block === true, '7th one-shot call (varied args) should be blocked by per-tool cap');
|
|
201
|
+
assert.ok(blocked.reason!.includes('repeated tool'), 'reason should identify the per-tool guard');
|
|
202
|
+
assert.ok(blocked.reason!.includes('gsd_complete_milestone'), 'reason should name the tool');
|
|
203
|
+
assert.ok(blocked.reason!.includes('7'), 'reason should mention the count');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
207
|
+
// Repeatable tools get the higher cap
|
|
208
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
209
|
+
|
|
210
|
+
console.log('\n── Loop guard: repeatable tools get the higher cap (#783) ──');
|
|
211
|
+
|
|
212
|
+
{
|
|
213
|
+
resetToolCallLoopGuard();
|
|
214
|
+
|
|
215
|
+
// bash is repeatable: varied commands are legitimate up to the higher cap.
|
|
216
|
+
for (let i = 1; i <= 15; i++) {
|
|
217
|
+
const result = checkToolCallLoop('bash', { command: `echo ${i}` });
|
|
218
|
+
assert.ok(result.block === false, `bash call ${i} (varied args) should be allowed`);
|
|
219
|
+
}
|
|
220
|
+
// 16th call (cap 15 + 1) is blocked by the per-tool guard — this is the
|
|
221
|
+
// improvisation-through-bash case from the forensics (~51 calls).
|
|
222
|
+
const blocked = checkToolCallLoop('bash', { command: 'echo 16' });
|
|
223
|
+
assert.ok(blocked.block === true, '16th bash call (varied args) should be blocked by per-tool cap');
|
|
224
|
+
assert.ok(blocked.reason!.includes('cap 15'), 'reason should mention the repeatable cap');
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
228
|
+
// Mutation progress decays per-tool counts (#1092)
|
|
229
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
230
|
+
|
|
231
|
+
console.log('\n── Loop guard: mutation progress decays per-tool counts (#1092) ──');
|
|
232
|
+
|
|
233
|
+
{
|
|
234
|
+
resetToolCallLoopGuard();
|
|
235
|
+
|
|
236
|
+
// bash is called more than the repeatable cap, but each count is separated
|
|
237
|
+
// by a successful file mutation. Guard 2 should treat that as progress and
|
|
238
|
+
// avoid blocking the progressing unit.
|
|
239
|
+
for (let i = 1; i <= 20; i++) {
|
|
240
|
+
const result = checkToolCallLoop('bash', { command: `echo ${i}` });
|
|
241
|
+
assert.ok(result.block === false, `bash call ${i} after mutation progress should be allowed`);
|
|
242
|
+
assert.deepStrictEqual(getToolCallCountForTool('bash'), 1, `bash count should decay before call ${i}`);
|
|
243
|
+
|
|
244
|
+
const mutationTool = i % 2 === 0 ? 'write' : 'edit';
|
|
245
|
+
const mutation = checkToolCallLoop(mutationTool, {
|
|
246
|
+
path: `file-${i}.ts`,
|
|
247
|
+
content: `content ${i}`,
|
|
248
|
+
});
|
|
249
|
+
assert.ok(mutation.block === false, `${mutationTool} mutation ${i} should be allowed`);
|
|
250
|
+
recordToolCallLoopMutation(mutationTool);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
255
|
+
// Distinct read-only navigation calls are context gathering, not repeated-tool loops.
|
|
256
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
257
|
+
|
|
258
|
+
console.log('\n── Loop guard: distinct read-only navigation calls are not capped by per-tool count ──');
|
|
259
|
+
|
|
260
|
+
{
|
|
261
|
+
const exemptTools = ['find', 'glob', 'grep', 'ls', 'read', 'search_and_read'];
|
|
262
|
+
|
|
263
|
+
for (const toolName of exemptTools) {
|
|
264
|
+
resetToolCallLoopGuard();
|
|
265
|
+
|
|
266
|
+
for (let i = 1; i <= 20; i++) {
|
|
267
|
+
const result = checkToolCallLoop(toolName, { path: `file-${i}.ts` });
|
|
268
|
+
assert.ok(result.block === false, `distinct ${toolName} call ${i} should be allowed`);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
resetToolCallLoopGuard();
|
|
272
|
+
for (let i = 1; i <= 4; i++) {
|
|
273
|
+
const result = checkToolCallLoop(toolName, { path: 'same-file.ts' });
|
|
274
|
+
assert.ok(result.block === false, `identical ${toolName} call ${i} should be allowed`);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const blocked = checkToolCallLoop(toolName, { path: 'same-file.ts' });
|
|
278
|
+
assert.ok(blocked.block === true, `5th identical ${toolName} call should still be blocked`);
|
|
279
|
+
assert.ok(blocked.reason?.includes('identical args'), `${toolName} loops should be caught by Guard 1`);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
284
|
+
// Per-tool counts are independent per tool and reset together
|
|
285
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
286
|
+
|
|
287
|
+
console.log('\n── Loop guard: per-tool counts are independent and reset together (#783) ──');
|
|
288
|
+
|
|
289
|
+
{
|
|
290
|
+
resetToolCallLoopGuard();
|
|
291
|
+
|
|
292
|
+
// Two different tools tracked separately.
|
|
293
|
+
for (let i = 0; i < 3; i++) checkToolCallLoop('read', { path: `f${i}` });
|
|
294
|
+
for (let i = 0; i < 3; i++) checkToolCallLoop('write', { path: `g${i}` });
|
|
295
|
+
assert.deepStrictEqual(getToolCallCountForTool('read'), 3, 'read tracked separately');
|
|
296
|
+
assert.deepStrictEqual(getToolCallCountForTool('write'), 3, 'write tracked separately');
|
|
297
|
+
assert.deepStrictEqual(getToolCallCountForTool('edit'), 0, 'uncalled tool reports 0');
|
|
298
|
+
|
|
299
|
+
resetToolCallLoopGuard();
|
|
300
|
+
assert.deepStrictEqual(getToolCallCountForTool('read'), 0, 'per-tool counts cleared on reset');
|
|
301
|
+
assert.deepStrictEqual(getToolCallCountForTool('write'), 0, 'per-tool counts cleared on reset');
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
305
|
+
// Non-exempt repeatable tools from core-session-tools.ts get the higher cap.
|
|
306
|
+
// Read-only navigation tools are exempted earlier; mutating/execution repeatable
|
|
307
|
+
// tools (e.g. gsd_exec) must still trip the per-tool cap.
|
|
308
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
309
|
+
|
|
310
|
+
console.log('\n── Loop guard: non-exempt repeatable tools get high cap ──');
|
|
311
|
+
|
|
312
|
+
{
|
|
313
|
+
for (const toolName of ['bg_shell', 'gsd_exec', 'write']) {
|
|
314
|
+
resetToolCallLoopGuard();
|
|
315
|
+
|
|
316
|
+
// Should allow up to 15 varied calls without blocking.
|
|
317
|
+
for (let i = 1; i <= 15; i++) {
|
|
318
|
+
const result = checkToolCallLoop(toolName, { arg: `v${i}` });
|
|
319
|
+
assert.ok(result.block === false, `${toolName} call ${i} (varied args) should be allowed`);
|
|
320
|
+
}
|
|
321
|
+
// 16th call with varied args must be blocked by the per-tool repeatable cap.
|
|
322
|
+
const blocked = checkToolCallLoop(toolName, { arg: 'v16' });
|
|
323
|
+
assert.ok(blocked.block === true, `${toolName}: 16th call must be blocked by repeatable cap`);
|
|
324
|
+
assert.ok(blocked.reason?.includes('cap 15'), `${toolName}: reason must mention cap 15`);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
329
|
+
// Non-repeatable tools excluded from INHERENTLY_REPEATABLE_TOOL_SET use the
|
|
330
|
+
// default cap (6), not the repeatable cap (15).
|
|
331
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
332
|
+
|
|
333
|
+
console.log('\n── Loop guard: ToolSearch (excluded from repeatable set) hits default cap ──');
|
|
334
|
+
|
|
335
|
+
{
|
|
336
|
+
// ToolSearch is in MINIMAL_AUTO_BASE but explicitly excluded from repeatable.
|
|
337
|
+
// It should hit the default cap of 6, not 15.
|
|
338
|
+
resetToolCallLoopGuard();
|
|
339
|
+
for (let i = 1; i <= 6; i++) {
|
|
340
|
+
const result = checkToolCallLoop('ToolSearch', { query: `q${i}` });
|
|
341
|
+
assert.ok(result.block === false, `ToolSearch call ${i} should be allowed`);
|
|
342
|
+
}
|
|
343
|
+
const blocked = checkToolCallLoop('ToolSearch', { query: 'q7' });
|
|
344
|
+
assert.ok(blocked.block === true, 'ToolSearch: 7th varied call must be blocked by default cap');
|
|
345
|
+
assert.ok(!blocked.reason?.includes('cap 15'), 'ToolSearch must NOT use the repeatable cap');
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
349
|
+
// Block reasons instruct the model to stop tooling this turn
|
|
350
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
351
|
+
|
|
352
|
+
console.log('\n── Loop guard: block reasons tell model to respond in text ──');
|
|
353
|
+
|
|
354
|
+
{
|
|
355
|
+
resetToolCallLoopGuard();
|
|
356
|
+
|
|
357
|
+
for (let i = 0; i < 4; i++) {
|
|
358
|
+
checkToolCallLoop('web_search', { query: 'same query' });
|
|
359
|
+
}
|
|
360
|
+
const identicalBlocked = checkToolCallLoop('web_search', { query: 'same query' });
|
|
361
|
+
assert.ok(identicalBlocked.block === true, 'identical-args guard should block');
|
|
362
|
+
assert.ok(
|
|
363
|
+
identicalBlocked.reason!.includes('respond to the user in text'),
|
|
364
|
+
'identical-args reason should tell the model to stop tooling',
|
|
365
|
+
);
|
|
366
|
+
assert.ok(
|
|
367
|
+
!identicalBlocked.reason!.includes('Try a different approach'),
|
|
368
|
+
'identical-args reason should not suggest retrying another tool',
|
|
369
|
+
);
|
|
370
|
+
|
|
371
|
+
resetToolCallLoopGuard();
|
|
372
|
+
for (let i = 0; i < 6; i++) {
|
|
373
|
+
checkToolCallLoop('gsd_complete_milestone', { milestone: `M${i}` });
|
|
374
|
+
}
|
|
375
|
+
const perToolBlocked = checkToolCallLoop('gsd_complete_milestone', { milestone: 'M7' });
|
|
376
|
+
assert.ok(perToolBlocked.block === true, 'per-tool guard should block');
|
|
377
|
+
assert.ok(
|
|
378
|
+
perToolBlocked.reason!.includes('respond to the user in text'),
|
|
379
|
+
'per-tool reason should tell the model to stop tooling',
|
|
380
|
+
);
|
|
381
|
+
assert.ok(
|
|
382
|
+
perToolBlocked.reason!.includes('Do not retry this tool'),
|
|
383
|
+
'per-tool reason should forbid retrying the blocked tool',
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
import { test } from "node:test";
|
|
15
15
|
import assert from "node:assert/strict";
|
|
16
|
+
import { SUMMARY_SAVE_CONTENT_MAX_LENGTH } from "@opengsd/contracts";
|
|
16
17
|
import { registerDbTools } from "../bootstrap/db-tools.ts";
|
|
17
18
|
import AjvModule from "ajv";
|
|
18
19
|
|
|
@@ -86,6 +87,31 @@ test("gsd_summary_save — validates UAT assessment params", () => {
|
|
|
86
87
|
assert.strictEqual(valid, true, `UAT assessment params should validate but got errors: ${JSON.stringify(validate.errors)}`);
|
|
87
88
|
});
|
|
88
89
|
|
|
90
|
+
test("gsd_summary_save — content has a provider-safe maxLength", () => {
|
|
91
|
+
const tool = getTool("gsd_summary_save");
|
|
92
|
+
assert.ok(tool, "gsd_summary_save must be registered");
|
|
93
|
+
|
|
94
|
+
const contentSchema = tool.parameters.properties.content;
|
|
95
|
+
assert.strictEqual(contentSchema.maxLength, SUMMARY_SAVE_CONTENT_MAX_LENGTH);
|
|
96
|
+
|
|
97
|
+
const validAtLimit = validateSchema(tool, {
|
|
98
|
+
milestone_id: "M001",
|
|
99
|
+
artifact_type: "CONTEXT-DRAFT",
|
|
100
|
+
content: "x".repeat(SUMMARY_SAVE_CONTENT_MAX_LENGTH),
|
|
101
|
+
});
|
|
102
|
+
assert.deepEqual(validAtLimit, []);
|
|
103
|
+
|
|
104
|
+
const overLimit = validateSchema(tool, {
|
|
105
|
+
milestone_id: "M001",
|
|
106
|
+
artifact_type: "CONTEXT-DRAFT",
|
|
107
|
+
content: "x".repeat(SUMMARY_SAVE_CONTENT_MAX_LENGTH + 1),
|
|
108
|
+
});
|
|
109
|
+
assert.ok(
|
|
110
|
+
overLimit.some((error) => error.includes(`must NOT have more than ${SUMMARY_SAVE_CONTENT_MAX_LENGTH} characters`)),
|
|
111
|
+
`expected maxLength validation error, got: ${overLimit.join("; ")}`,
|
|
112
|
+
);
|
|
113
|
+
});
|
|
114
|
+
|
|
89
115
|
// ─── gsd_slice_complete: enrichment arrays must be optional ──────────────────
|
|
90
116
|
|
|
91
117
|
test("gsd_slice_complete — enrichment arrays are optional", () => {
|
|
@@ -359,14 +385,17 @@ test("gsd_plan_slice — enrichment fields are optional", () => {
|
|
|
359
385
|
|
|
360
386
|
const required = new Set(getRequiredProps(tool));
|
|
361
387
|
|
|
362
|
-
// Core fields
|
|
363
|
-
|
|
388
|
+
// Core fields. `tasks` is intentionally NOT here: incremental planning
|
|
389
|
+
// (#1027) lets gsd_plan_slice persist slice metadata only, then add tasks
|
|
390
|
+
// one at a time via gsd_plan_task, so tasks must be optional.
|
|
391
|
+
const coreRequired = ["milestoneId", "sliceId", "goal"];
|
|
364
392
|
for (const field of coreRequired) {
|
|
365
393
|
assert.ok(required.has(field), `core field "${field}" must be required`);
|
|
366
394
|
}
|
|
367
395
|
|
|
368
|
-
// Enrichment fields
|
|
396
|
+
// Enrichment fields (plus tasks, optional for incremental planning).
|
|
369
397
|
const enrichmentFields = [
|
|
398
|
+
"tasks",
|
|
370
399
|
"successCriteria",
|
|
371
400
|
"proofLevel",
|
|
372
401
|
"integrationClosure",
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
handleUndo,
|
|
11
11
|
handleUndoTask,
|
|
12
12
|
handleResetSlice,
|
|
13
|
+
parseActivityLogFilename,
|
|
13
14
|
uncheckTaskInPlan,
|
|
14
15
|
} from "../undo.ts";
|
|
15
16
|
import {
|
|
@@ -67,6 +68,37 @@ test("handleUndo without --force only warns and leaves completed units intact",
|
|
|
67
68
|
}
|
|
68
69
|
});
|
|
69
70
|
|
|
71
|
+
test("handleUndo execute-task with --force reopens the task row and re-renders plan", async () => {
|
|
72
|
+
const base = makeTempDir("gsd-undo-execute-task");
|
|
73
|
+
try {
|
|
74
|
+
setupTaskFixture(base);
|
|
75
|
+
mkdirSync(join(base, ".gsd", "activity"), { recursive: true });
|
|
76
|
+
writeFileSync(
|
|
77
|
+
join(base, ".gsd", "activity", "001-execute-task-M001-S01-T01.jsonl"),
|
|
78
|
+
"",
|
|
79
|
+
"utf-8",
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
const { notifications, ctx } = makeCtx();
|
|
83
|
+
await handleUndo("--force", ctx, {} as any, base);
|
|
84
|
+
|
|
85
|
+
const task = getTask("M001", "S01", "T01");
|
|
86
|
+
assert.equal(task?.status, "pending");
|
|
87
|
+
|
|
88
|
+
const planContent = readFileSync(
|
|
89
|
+
join(base, ".gsd", "phases", "01-test", "01-01-PLAN.md"),
|
|
90
|
+
"utf-8",
|
|
91
|
+
);
|
|
92
|
+
assert.match(planContent, /\[ \] \*\*T01\*\*:/);
|
|
93
|
+
|
|
94
|
+
assert.equal(notifications[0]?.level, "success");
|
|
95
|
+
assert.match(notifications[0]?.message ?? "", /Unchecked task in PLAN/);
|
|
96
|
+
} finally {
|
|
97
|
+
closeDatabase();
|
|
98
|
+
rmSync(base, { recursive: true, force: true });
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
70
102
|
test("uncheckTaskInPlan flips a checked task back to unchecked", () => {
|
|
71
103
|
const base = makeTempDir("gsd-undo-plan");
|
|
72
104
|
try {
|
|
@@ -154,6 +186,48 @@ test("extractCommitShas ignores malformed commit tokens", () => {
|
|
|
154
186
|
assert.deepEqual(extractCommitShas(content), ["1234567"]);
|
|
155
187
|
});
|
|
156
188
|
|
|
189
|
+
test("parseActivityLogFilename splits hyphenated unit types from their IDs", () => {
|
|
190
|
+
// Task-level: unit type and ID both contain hyphens.
|
|
191
|
+
assert.deepEqual(parseActivityLogFilename("001-execute-task-M001-S01-T01.jsonl"), {
|
|
192
|
+
unitType: "execute-task",
|
|
193
|
+
unitId: "M001-S01-T01",
|
|
194
|
+
});
|
|
195
|
+
// Variant must win over its shorter prefix ("execute-task").
|
|
196
|
+
assert.deepEqual(parseActivityLogFilename("002-execute-task-simple-M001-S02-T03.jsonl"), {
|
|
197
|
+
unitType: "execute-task-simple",
|
|
198
|
+
unitId: "M001-S02-T03",
|
|
199
|
+
});
|
|
200
|
+
// Milestone- and slice-shaped IDs.
|
|
201
|
+
assert.deepEqual(parseActivityLogFilename("003-research-milestone-M001.jsonl"), {
|
|
202
|
+
unitType: "research-milestone",
|
|
203
|
+
unitId: "M001",
|
|
204
|
+
});
|
|
205
|
+
assert.deepEqual(parseActivityLogFilename("004-plan-slice-M001-S01.jsonl"), {
|
|
206
|
+
unitType: "plan-slice",
|
|
207
|
+
unitId: "M001-S01",
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
test("parseActivityLogFilename accepts non-milestone-shaped unit IDs", () => {
|
|
212
|
+
// Regression (#1057): project-level units use IDs that do not start with
|
|
213
|
+
// "M<digit>". A milestone-shaped regex made /gsd undo bail out with
|
|
214
|
+
// "could not parse latest activity log" when one of these was most recent.
|
|
215
|
+
assert.deepEqual(parseActivityLogFilename("005-discuss-project-PROJECT.jsonl"), {
|
|
216
|
+
unitType: "discuss-project",
|
|
217
|
+
unitId: "PROJECT",
|
|
218
|
+
});
|
|
219
|
+
assert.deepEqual(parseActivityLogFilename("006-workflow-preferences-WORKFLOW-PREFS.jsonl"), {
|
|
220
|
+
unitType: "workflow-preferences",
|
|
221
|
+
unitId: "WORKFLOW-PREFS",
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
test("parseActivityLogFilename returns null for unrecognized names", () => {
|
|
226
|
+
assert.equal(parseActivityLogFilename("007-not-a-real-unit-M001.jsonl"), null);
|
|
227
|
+
assert.equal(parseActivityLogFilename("no-sequence-prefix.jsonl"), null);
|
|
228
|
+
assert.equal(parseActivityLogFilename("001-execute-task-M001-S01-T01.txt"), null);
|
|
229
|
+
});
|
|
230
|
+
|
|
157
231
|
// ─── handleUndoTask tests ────────────────────────────────────────────────────
|
|
158
232
|
|
|
159
233
|
function makeCtx(): { notifications: Array<{ message: string; level: string }>; ctx: any } {
|
|
@@ -8,6 +8,7 @@ import { join } from "node:path";
|
|
|
8
8
|
import { tmpdir } from "node:os";
|
|
9
9
|
|
|
10
10
|
import {
|
|
11
|
+
CONTEXT_MODE_GUIDANCE_BY_UNIT,
|
|
11
12
|
composeContractedUnitContext,
|
|
12
13
|
composeContextModeInstructions,
|
|
13
14
|
composeInlinedContext,
|
|
@@ -141,9 +142,13 @@ test("Context Mode composer: nested output is compact single sentence", () => {
|
|
|
141
142
|
assert.ok(!out.startsWith("## Context Mode"));
|
|
142
143
|
assert.match(out, /^Context Mode \(verification lane\): /);
|
|
143
144
|
assert.strictEqual(out.split(/\n/).length, 1);
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
assert.
|
|
145
|
+
// Nested guidance is embedded into tester subagent prompts — it must instruct the tester
|
|
146
|
+
// to run verification and call gsd_save_gate_result, NOT to dispatch further subagents.
|
|
147
|
+
assert.doesNotMatch(out, /`subagent`/, "tester prompts must not be told to dispatch subagents");
|
|
148
|
+
assert.match(out, /`gsd_save_gate_result`/);
|
|
149
|
+
assert.doesNotMatch(out, /`gsd_exec`/);
|
|
150
|
+
assert.doesNotMatch(out, /`gsd_exec_search`/);
|
|
151
|
+
assert.doesNotMatch(out, /`gsd_resume`/);
|
|
147
152
|
assert.ok(out.length < 240, `nested guidance should stay compact, got ${out.length} chars`);
|
|
148
153
|
});
|
|
149
154
|
|
|
@@ -158,6 +163,53 @@ const laneLabelByMode: Record<string, string> = {
|
|
|
158
163
|
triage: "triage",
|
|
159
164
|
};
|
|
160
165
|
|
|
166
|
+
const contextModeGuidanceOverrideExpectedTools: Record<string, readonly string[]> = {
|
|
167
|
+
"discuss-milestone": [
|
|
168
|
+
"ask_user_questions",
|
|
169
|
+
"gsd_summary_save",
|
|
170
|
+
"gsd_decision_save",
|
|
171
|
+
"gsd_requirement_save",
|
|
172
|
+
"gsd_requirement_update",
|
|
173
|
+
"gsd_plan_milestone",
|
|
174
|
+
"gsd_milestone_generate_id",
|
|
175
|
+
],
|
|
176
|
+
"discuss-project": [
|
|
177
|
+
"ask_user_questions",
|
|
178
|
+
"gsd_summary_save",
|
|
179
|
+
"gsd_decision_save",
|
|
180
|
+
"gsd_requirement_save",
|
|
181
|
+
],
|
|
182
|
+
"discuss-requirements": [
|
|
183
|
+
"ask_user_questions",
|
|
184
|
+
"gsd_requirement_save",
|
|
185
|
+
"gsd_summary_save",
|
|
186
|
+
],
|
|
187
|
+
"discuss-slice": [
|
|
188
|
+
"ask_user_questions",
|
|
189
|
+
"gsd_summary_save",
|
|
190
|
+
"gsd_decision_save",
|
|
191
|
+
],
|
|
192
|
+
"replan-slice": [
|
|
193
|
+
"gsd_replan_slice",
|
|
194
|
+
"gsd_decision_save",
|
|
195
|
+
],
|
|
196
|
+
"reassess-roadmap": [
|
|
197
|
+
"gsd_milestone_status",
|
|
198
|
+
"gsd_reassess_roadmap",
|
|
199
|
+
],
|
|
200
|
+
"run-uat": [
|
|
201
|
+
"gsd_uat_exec",
|
|
202
|
+
"gsd_resume",
|
|
203
|
+
],
|
|
204
|
+
// research-project uses scout subagents that write .gsd/research/ files directly;
|
|
205
|
+
// the parent dispatches Task calls and verifies file outputs — no GSD save tools.
|
|
206
|
+
"research-project": [],
|
|
207
|
+
"gate-evaluate": [
|
|
208
|
+
"subagent",
|
|
209
|
+
"gsd_save_gate_result",
|
|
210
|
+
],
|
|
211
|
+
};
|
|
212
|
+
|
|
161
213
|
test("Context Mode composer: every known eligible unit renders its configured lane and required tools", () => {
|
|
162
214
|
for (const unitType of KNOWN_UNIT_TYPES) {
|
|
163
215
|
const manifest = UNIT_MANIFESTS[unitType];
|
|
@@ -170,18 +222,65 @@ test("Context Mode composer: every known eligible unit renders its configured la
|
|
|
170
222
|
assert.ok(out.startsWith("## Context Mode"), `${unitType} should render standalone Context Mode heading`);
|
|
171
223
|
assert.match(out, new RegExp(`Lane: \\*\\*${laneLabelByMode[manifest.contextMode]} lane\\*\\*\\.`, "i"));
|
|
172
224
|
const forbidden = getUnitToolSurfaceContract(unitType)?.forbiddenGsdTools ?? {};
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
//
|
|
176
|
-
//
|
|
177
|
-
assert.doesNotMatch(out, /`gsd_exec`/, `${unitType}
|
|
225
|
+
const overrideExpectedTools = contextModeGuidanceOverrideExpectedTools[unitType];
|
|
226
|
+
if ("gsd_exec" in forbidden || overrideExpectedTools) {
|
|
227
|
+
// Unit overrides are the contract-specific exception to lane defaults.
|
|
228
|
+
// Steering to the lane default here can produce unavailable-tool loops.
|
|
229
|
+
assert.doesNotMatch(out, /`gsd_exec`/, `${unitType} guidance must not steer to gsd_exec`);
|
|
178
230
|
assert.doesNotMatch(out, /`gsd_exec_search`/, `${unitType} guidance must not steer to gsd_exec_search`);
|
|
179
|
-
|
|
231
|
+
for (const toolName of overrideExpectedTools ?? []) {
|
|
232
|
+
assert.match(out, new RegExp(`\`${toolName}\``), `${unitType} guidance should mention ${toolName}`);
|
|
233
|
+
}
|
|
180
234
|
} else {
|
|
181
235
|
assert.match(out, /`gsd_exec`/, `${unitType} should mention gsd_exec`);
|
|
182
236
|
assert.match(out, /`gsd_exec_search`/, `${unitType} should mention gsd_exec_search`);
|
|
183
237
|
}
|
|
184
|
-
|
|
238
|
+
if (!overrideExpectedTools || overrideExpectedTools.includes("gsd_resume")) {
|
|
239
|
+
assert.match(out, /`gsd_resume`/, `${unitType} should mention gsd_resume`);
|
|
240
|
+
} else {
|
|
241
|
+
assert.doesNotMatch(out, /`gsd_resume`/, `${unitType} guidance must not steer to gsd_resume`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
test("Context Mode composer: discuss interview overrides stay within unit contracts", () => {
|
|
247
|
+
const discussUnits = [
|
|
248
|
+
"discuss-milestone",
|
|
249
|
+
"discuss-project",
|
|
250
|
+
"discuss-requirements",
|
|
251
|
+
"discuss-slice",
|
|
252
|
+
];
|
|
253
|
+
|
|
254
|
+
for (const unitType of discussUnits) {
|
|
255
|
+
const guidance = CONTEXT_MODE_GUIDANCE_BY_UNIT[unitType];
|
|
256
|
+
assert.ok(guidance, `${unitType} should have a Context Mode override`);
|
|
257
|
+
assert.doesNotMatch(guidance, /`gsd_exec`/, `${unitType} guidance must not mention gsd_exec`);
|
|
258
|
+
assert.doesNotMatch(guidance, /`gsd_exec_search`/, `${unitType} guidance must not mention gsd_exec_search`);
|
|
259
|
+
assert.doesNotMatch(guidance, /`gsd_resume`/, `${unitType} guidance must not mention gsd_resume`);
|
|
260
|
+
|
|
261
|
+
const expectedTools = contextModeGuidanceOverrideExpectedTools[unitType] ?? [];
|
|
262
|
+
assert.ok(expectedTools.length > 0, `${unitType} should declare expected override tools`);
|
|
263
|
+
const contract = getUnitToolSurfaceContract(unitType);
|
|
264
|
+
assert.ok(contract, `${unitType} should have a tool contract`);
|
|
265
|
+
const contractTools = new Set([
|
|
266
|
+
...contract.allowedGsdTools,
|
|
267
|
+
...contract.requiredWorkflowTools,
|
|
268
|
+
]);
|
|
269
|
+
|
|
270
|
+
for (const toolName of expectedTools) {
|
|
271
|
+
assert.match(guidance, new RegExp(`\`${toolName}\``), `${unitType} guidance should mention ${toolName}`);
|
|
272
|
+
assert.ok(contractTools.has(toolName as UnitGsdToolName), `${unitType} contract should allow ${toolName}`);
|
|
273
|
+
const scope = shouldBlockAutoUnitToolCall(unitType, toolName);
|
|
274
|
+
assert.equal(scope.block, false, `${unitType} should not hard-block ${toolName}: ${scope.reason ?? ""}`);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const out = composeContextModeInstructions(unitType, { enabled: true, renderMode: "standalone" });
|
|
278
|
+
if (out) {
|
|
279
|
+
assert.match(out, /interview lane/i);
|
|
280
|
+
assert.doesNotMatch(out, /`gsd_exec`/);
|
|
281
|
+
assert.doesNotMatch(out, /`gsd_exec_search`/);
|
|
282
|
+
assert.doesNotMatch(out, /`gsd_resume`/);
|
|
283
|
+
}
|
|
185
284
|
}
|
|
186
285
|
});
|
|
187
286
|
|
|
@@ -195,8 +294,67 @@ test("Context Mode composer: run-uat guidance steers to gsd_uat_exec in both ren
|
|
|
195
294
|
assert.doesNotMatch(standalone, /`gsd_exec`/);
|
|
196
295
|
});
|
|
197
296
|
|
|
198
|
-
test("Context Mode composer:
|
|
199
|
-
const
|
|
297
|
+
test("Context Mode composer: research-project guidance steers to scout orchestration", () => {
|
|
298
|
+
for (const renderMode of ["nested", "standalone"] as const) {
|
|
299
|
+
const out = composeContextModeInstructions("research-project", { enabled: true, renderMode });
|
|
300
|
+
assert.match(out, /research lane/i);
|
|
301
|
+
assert.match(out, /scout subagents/i);
|
|
302
|
+
assert.match(out, /\.gsd\/research\//);
|
|
303
|
+
assert.match(out, /STACK\.md/);
|
|
304
|
+
assert.match(out, /PITFALLS\.md/);
|
|
305
|
+
assert.doesNotMatch(out, /`gsd_summary_save`/);
|
|
306
|
+
assert.doesNotMatch(out, /`gsd_decision_save`/);
|
|
307
|
+
assert.doesNotMatch(out, /`gsd_exec`/);
|
|
308
|
+
assert.doesNotMatch(out, /`gsd_exec_search`/);
|
|
309
|
+
assert.doesNotMatch(out, /`gsd_resume`/);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
const contract = getUnitToolSurfaceContract("research-project");
|
|
313
|
+
assert.deepEqual(contract?.allowedGsdTools, []);
|
|
314
|
+
assert.deepEqual(contract?.requiredWorkflowTools, []);
|
|
315
|
+
for (const toolName of ["gsd_summary_save", "gsd_decision_save"]) {
|
|
316
|
+
const scope = shouldBlockAutoUnitToolCall("research-project", toolName);
|
|
317
|
+
assert.equal(scope.block, true, `research-project should not allow ${toolName}`);
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
test("Context Mode composer: narrow planning guidance steers only to contracted tools", () => {
|
|
322
|
+
const cases = [
|
|
323
|
+
{
|
|
324
|
+
unitType: "replan-slice",
|
|
325
|
+
expectedTools: ["gsd_replan_slice", "gsd_decision_save"],
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
unitType: "reassess-roadmap",
|
|
329
|
+
expectedTools: ["gsd_milestone_status", "gsd_reassess_roadmap"],
|
|
330
|
+
},
|
|
331
|
+
];
|
|
332
|
+
const disallowedTools = ["gsd_exec", "gsd_exec_search", "gsd_resume"];
|
|
333
|
+
|
|
334
|
+
for (const { unitType, expectedTools } of cases) {
|
|
335
|
+
for (const renderMode of ["nested", "standalone"] as const) {
|
|
336
|
+
const out = composeContextModeInstructions(unitType, { enabled: true, renderMode });
|
|
337
|
+
assert.match(out, /planning lane/i, `${unitType} should still render planning lane guidance`);
|
|
338
|
+
for (const toolName of expectedTools) {
|
|
339
|
+
assert.ok(out.includes(`\`${toolName}\``), `${unitType} guidance should mention ${toolName}`);
|
|
340
|
+
}
|
|
341
|
+
for (const toolName of disallowedTools) {
|
|
342
|
+
assert.ok(!out.includes(`\`${toolName}\``), `${unitType} guidance must not mention ${toolName}`);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
test("Context Mode composer: lane guidance tools pass unit contracts", () => {
|
|
349
|
+
const affectedUnits = [
|
|
350
|
+
"research-milestone",
|
|
351
|
+
"research-slice",
|
|
352
|
+
"plan-slice",
|
|
353
|
+
"refine-slice",
|
|
354
|
+
"complete-slice",
|
|
355
|
+
"validate-milestone",
|
|
356
|
+
"complete-milestone",
|
|
357
|
+
];
|
|
200
358
|
const contextModeTools: UnitGsdToolName[] = ["gsd_exec", "gsd_exec_search", "gsd_resume"];
|
|
201
359
|
const readOnlyOrientationTools: UnitGsdToolName[] = ["gsd_milestone_status", ...contextModeTools];
|
|
202
360
|
|
|
@@ -207,7 +365,10 @@ test("Context Mode composer: slice planning and research guidance tools pass uni
|
|
|
207
365
|
for (const toolName of contextModeTools) {
|
|
208
366
|
assert.ok(out.includes(`\`${toolName}\``), `${unitType} guidance should mention ${toolName}`);
|
|
209
367
|
}
|
|
210
|
-
|
|
368
|
+
const expectedContractTools = unitType === "research-milestone"
|
|
369
|
+
? contextModeTools
|
|
370
|
+
: readOnlyOrientationTools;
|
|
371
|
+
for (const toolName of expectedContractTools) {
|
|
211
372
|
assert.ok(allowed.has(toolName), `${unitType} contract should allow ${toolName}`);
|
|
212
373
|
const scope = shouldBlockAutoUnitToolCall(unitType, toolName);
|
|
213
374
|
assert.equal(scope.block, false, `${unitType} should not hard-block ${toolName}: ${scope.reason ?? ""}`);
|
|
@@ -357,13 +518,31 @@ test("#4782 phase 2: buildReassessRoadmapPrompt emits composer-shaped context wi
|
|
|
357
518
|
assert.ok(!prompt.includes("Slice Context (from discussion)"));
|
|
358
519
|
});
|
|
359
520
|
|
|
360
|
-
test("execute-task prompt
|
|
521
|
+
test("execute-task prompt omits on-demand slice research when the artifact is absent", async (t) => {
|
|
522
|
+
const base = makeFixtureBase();
|
|
523
|
+
t.after(() => cleanup(base));
|
|
524
|
+
invalidateAllCaches();
|
|
525
|
+
|
|
526
|
+
seed(base, "M001");
|
|
527
|
+
writeArtifacts(base);
|
|
528
|
+
|
|
529
|
+
const prompt = await buildExecuteTaskPrompt("M001", "S01", "First", "T01", "Task", base);
|
|
530
|
+
|
|
531
|
+
assert.doesNotMatch(prompt, /## On-demand Context/);
|
|
532
|
+
assert.doesNotMatch(prompt, /\.gsd\/milestones\/M001\/slices\/S01\/S01-RESEARCH\.md/);
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
test("execute-task prompt surfaces on-demand slice research when the artifact exists", async (t) => {
|
|
361
536
|
const base = makeFixtureBase();
|
|
362
537
|
t.after(() => cleanup(base));
|
|
363
538
|
invalidateAllCaches();
|
|
364
539
|
|
|
365
540
|
seed(base, "M001");
|
|
366
541
|
writeArtifacts(base);
|
|
542
|
+
writeFileSync(
|
|
543
|
+
join(base, ".gsd", "milestones", "M001", "slices", "S01", "S01-RESEARCH.md"),
|
|
544
|
+
"# S01 Research\n",
|
|
545
|
+
);
|
|
367
546
|
|
|
368
547
|
const prompt = await buildExecuteTaskPrompt("M001", "S01", "First", "T01", "Task", base);
|
|
369
548
|
|