@opengsd/gsd-pi 1.3.0-dev.65546769 → 1.3.0-dev.72e3af2a
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/dist/resources/.managed-resources-content-hash +1 -1
- 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 +3 -0
- package/dist/resources/extensions/gsd/auto-artifact-paths.js +28 -1
- package/dist/resources/extensions/gsd/auto-dispatch.js +20 -19
- package/dist/resources/extensions/gsd/auto-prompts.js +26 -11
- package/dist/resources/extensions/gsd/auto-recovery.js +6 -507
- 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/bootstrap/agent-end-recovery.js +103 -13
- package/dist/resources/extensions/gsd/bootstrap/core-session-tools.js +38 -0
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +6 -1
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +2 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +10 -19
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +46 -19
- package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +68 -10
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +1 -1
- package/dist/resources/extensions/gsd/commands-context.js +19 -1
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +16 -10
- 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/queries.js +60 -0
- package/dist/resources/extensions/gsd/db-workspace.js +55 -3
- package/dist/resources/extensions/gsd/doctor-providers.js +92 -8
- package/dist/resources/extensions/gsd/exec-sandbox.js +45 -9
- package/dist/resources/extensions/gsd/forensics.js +2 -32
- package/dist/resources/extensions/gsd/git-service.js +4 -4
- 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/layout-policy.js +3 -1
- package/dist/resources/extensions/gsd/markdown-renderer.js +8 -9
- package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +44 -21
- 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/prompts/code-review.md +6 -4
- package/dist/resources/extensions/gsd/quick.js +45 -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-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/unit-context-composer.js +23 -7
- package/dist/resources/extensions/gsd/unit-registry.js +32 -4
- 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/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/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-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 +34 -20
- 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/package.json +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/stream-adapter.ts +20 -2
- 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/orchestrator.ts +25 -11
- package/src/resources/extensions/gsd/auto/session.ts +5 -0
- package/src/resources/extensions/gsd/auto-artifact-paths.ts +47 -1
- package/src/resources/extensions/gsd/auto-dispatch.ts +21 -23
- package/src/resources/extensions/gsd/auto-prompts.ts +38 -12
- package/src/resources/extensions/gsd/auto-recovery.ts +10 -508
- 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/bootstrap/agent-end-recovery.ts +125 -12
- package/src/resources/extensions/gsd/bootstrap/core-session-tools.ts +43 -0
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +6 -1
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +2 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +11 -19
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +52 -18
- package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +74 -10
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +1 -1
- package/src/resources/extensions/gsd/commands-context.ts +18 -1
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +14 -9
- 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/queries.ts +79 -0
- package/src/resources/extensions/gsd/db-workspace.ts +61 -3
- package/src/resources/extensions/gsd/doctor-providers.ts +103 -9
- package/src/resources/extensions/gsd/exec-sandbox.ts +49 -9
- package/src/resources/extensions/gsd/forensics.ts +2 -33
- package/src/resources/extensions/gsd/git-service.ts +5 -5
- 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/layout-policy.ts +2 -1
- package/src/resources/extensions/gsd/markdown-renderer.ts +8 -11
- package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +51 -19
- 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/prompts/code-review.md +6 -4
- package/src/resources/extensions/gsd/quick.ts +43 -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/auto-artifact-paths.test.ts +98 -1
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +111 -1
- 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-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/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/exec-graceful-kill.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/exec-tool.test.ts +45 -1
- package/src/resources/extensions/gsd/tests/forensics-error-filter.test.ts +88 -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 +119 -1
- 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/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/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/parallel-research-dispatch.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +1 -1
- 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/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/runtime-invariant-modules.test.ts +7 -0
- 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 +151 -0
- package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +26 -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/validation-block-guard.test.ts +79 -0
- package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +66 -0
- 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-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/unit-context-composer.ts +33 -7
- package/src/resources/extensions/gsd/unit-registry.ts +32 -4
- 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/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 → O7xDYXO0r4zFhIzY1hrWV}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{BTKtGFF1Y-hvVJEGhBRo9 → O7xDYXO0r4zFhIzY1hrWV}/_ssgManifest.js +0 -0
|
@@ -42,6 +42,8 @@ import {
|
|
|
42
42
|
type ReconciliationDeps,
|
|
43
43
|
} from "../state-reconciliation.ts";
|
|
44
44
|
import { classifyFailure } from "../recovery-classification.ts";
|
|
45
|
+
import { handlerPhaseIndex, RECONCILIATION_REPAIR_PHASES } from "../state-reconciliation/registry.ts";
|
|
46
|
+
import { staleRenderHandler } from "../state-reconciliation/drift/stale-render.ts";
|
|
45
47
|
import type { GSDState } from "../types.ts";
|
|
46
48
|
|
|
47
49
|
function makeState(overrides: Partial<GSDState> = {}): GSDState {
|
|
@@ -159,6 +161,29 @@ test("ADR-017 (#5700): repair failure throws ReconciliationFailedError with shap
|
|
|
159
161
|
);
|
|
160
162
|
});
|
|
161
163
|
|
|
164
|
+
test("ADR-017 (#5700): custom registry handlers outside built-in phases are repaired", async () => {
|
|
165
|
+
const drift = { kind: "custom-drift", id: "D001" } as unknown as DriftRecord;
|
|
166
|
+
let repaired = false;
|
|
167
|
+
const handler = {
|
|
168
|
+
kind: "custom-drift",
|
|
169
|
+
detect: () => (repaired ? [] : [drift]),
|
|
170
|
+
repair: () => {
|
|
171
|
+
repaired = true;
|
|
172
|
+
},
|
|
173
|
+
} as unknown as DriftHandler;
|
|
174
|
+
|
|
175
|
+
const result = await reconcileBeforeDispatch("/project", {
|
|
176
|
+
invalidateStateCache: () => {},
|
|
177
|
+
deriveState: async () => makeState(),
|
|
178
|
+
registry: [handler],
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
assert.equal(result.ok, true);
|
|
182
|
+
assert.equal(repaired, true);
|
|
183
|
+
assert.equal(result.repaired.length, 1);
|
|
184
|
+
assert.equal(result.repaired[0]?.kind, "custom-drift");
|
|
185
|
+
});
|
|
186
|
+
|
|
162
187
|
test("ADR-017 (#5700): a detector failure degrades to a blocker without aborting other handlers", async () => {
|
|
163
188
|
// A single detector throwing (e.g. a transient file read error) must NOT
|
|
164
189
|
// abort the whole cycle and hide every later handler's drift. It is collected
|
|
@@ -696,6 +721,126 @@ test("ADR-017 (#5702): stale-render drift detected and repaired end-to-end", asy
|
|
|
696
721
|
assert.match(repairedContent, /\[x\][^\n]*\*\*T02\*\*/, "T02 checkbox should be checked after repair");
|
|
697
722
|
});
|
|
698
723
|
|
|
724
|
+
test("#1003: stale-render plan repair reopens DB before rendering", async (t) => {
|
|
725
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-stale-render-reopen-"));
|
|
726
|
+
const sliceDir = join(base, ".gsd", "phases", "01-test");
|
|
727
|
+
mkdirSync(sliceDir, { recursive: true });
|
|
728
|
+
t.after(() => {
|
|
729
|
+
try { closeDatabase(); } catch { /* noop */ }
|
|
730
|
+
rmTreeQuiet(base);
|
|
731
|
+
});
|
|
732
|
+
|
|
733
|
+
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
734
|
+
clearRendererCaches();
|
|
735
|
+
insertMilestone({ id: "M001", title: "Test", status: "active" });
|
|
736
|
+
insertSlice({ id: "S01", milestoneId: "M001", title: "Slice", status: "pending" });
|
|
737
|
+
insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", title: "First task", status: "done" });
|
|
738
|
+
|
|
739
|
+
const planPath = join(sliceDir, "01-01-PLAN.md");
|
|
740
|
+
writeFileSync(planPath, makeStalePlanContent("S01", [
|
|
741
|
+
{ id: "T01", title: "First task", done: false },
|
|
742
|
+
]));
|
|
743
|
+
closeDatabase();
|
|
744
|
+
|
|
745
|
+
await staleRenderHandler.repair(
|
|
746
|
+
{
|
|
747
|
+
kind: "stale-render",
|
|
748
|
+
renderPath: planPath,
|
|
749
|
+
reason: "T01 is done in DB but unchecked in plan",
|
|
750
|
+
},
|
|
751
|
+
{ basePath: base, state: makeState() },
|
|
752
|
+
);
|
|
753
|
+
|
|
754
|
+
const repairedContent = readFileSync(planPath, "utf-8");
|
|
755
|
+
assert.match(repairedContent, /\[x\][^\n]*\*\*T01\*\*/, "T01 checkbox should be checked after DB reopen repair");
|
|
756
|
+
assert.equal(getSliceTasks("M001", "S01").length, 1, "DB should be reopened on the original project database");
|
|
757
|
+
});
|
|
758
|
+
|
|
759
|
+
test("#1003: stale-render plan repair switches back from an open wrong DB", async (t) => {
|
|
760
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-stale-render-wrong-db-"));
|
|
761
|
+
const wrongBase = mkdtempSync(join(tmpdir(), "gsd-stale-render-other-db-"));
|
|
762
|
+
const sliceDir = join(base, ".gsd", "phases", "01-test");
|
|
763
|
+
mkdirSync(sliceDir, { recursive: true });
|
|
764
|
+
mkdirSync(join(wrongBase, ".gsd"), { recursive: true });
|
|
765
|
+
t.after(() => {
|
|
766
|
+
try { closeDatabase(); } catch { /* noop */ }
|
|
767
|
+
rmTreeQuiet(base);
|
|
768
|
+
rmTreeQuiet(wrongBase);
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
772
|
+
clearRendererCaches();
|
|
773
|
+
insertMilestone({ id: "M001", title: "Test", status: "active" });
|
|
774
|
+
insertSlice({ id: "S01", milestoneId: "M001", title: "Slice", status: "pending" });
|
|
775
|
+
insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", title: "First task", status: "done" });
|
|
776
|
+
|
|
777
|
+
const planPath = join(sliceDir, "01-01-PLAN.md");
|
|
778
|
+
writeFileSync(planPath, makeStalePlanContent("S01", [
|
|
779
|
+
{ id: "T01", title: "First task", done: false },
|
|
780
|
+
]));
|
|
781
|
+
closeDatabase();
|
|
782
|
+
|
|
783
|
+
openDatabase(join(wrongBase, ".gsd", "gsd.db"));
|
|
784
|
+
|
|
785
|
+
await staleRenderHandler.repair(
|
|
786
|
+
{
|
|
787
|
+
kind: "stale-render",
|
|
788
|
+
renderPath: planPath,
|
|
789
|
+
reason: "T01 is done in DB but unchecked in plan",
|
|
790
|
+
},
|
|
791
|
+
{ basePath: base, state: makeState() },
|
|
792
|
+
);
|
|
793
|
+
|
|
794
|
+
const repairedContent = readFileSync(planPath, "utf-8");
|
|
795
|
+
assert.match(repairedContent, /\[x\][^\n]*\*\*T01\*\*/, "T01 checkbox should be checked after switching back to the project DB");
|
|
796
|
+
assert.equal(getSliceTasks("M001", "S01").length, 1, "repair should leave the project DB active");
|
|
797
|
+
});
|
|
798
|
+
|
|
799
|
+
test("#1034: validation-blocked milestone summary drift returns blocker instead of exhausting repair passes", async () => {
|
|
800
|
+
const drift: Extract<DriftRecord, { kind: "stale-render" }> = {
|
|
801
|
+
kind: "stale-render",
|
|
802
|
+
renderPath: "/repo/.gsd/milestones/M001/M001-SUMMARY.md",
|
|
803
|
+
reason: "M001 is complete with summary in DB but SUMMARY.md missing on disk",
|
|
804
|
+
};
|
|
805
|
+
let repairCalled = false;
|
|
806
|
+
const handler: DriftHandler<Extract<DriftRecord, { kind: "stale-render" }>> = {
|
|
807
|
+
kind: "stale-render",
|
|
808
|
+
detect: () => [drift],
|
|
809
|
+
blocker: staleRenderHandler.blocker!,
|
|
810
|
+
repair: () => {
|
|
811
|
+
repairCalled = true;
|
|
812
|
+
},
|
|
813
|
+
};
|
|
814
|
+
|
|
815
|
+
const validationBlocker = [
|
|
816
|
+
"Milestone M001 is blocked because milestone validation returned needs-attention.",
|
|
817
|
+
"Fix options:",
|
|
818
|
+
"1. Review the validation details: `/gsd status`",
|
|
819
|
+
].join("\n");
|
|
820
|
+
|
|
821
|
+
const result = await reconcileBeforeDispatch("/repo", {
|
|
822
|
+
invalidateStateCache: () => {},
|
|
823
|
+
deriveState: async () =>
|
|
824
|
+
makeState({
|
|
825
|
+
phase: "blocked",
|
|
826
|
+
blockers: [validationBlocker],
|
|
827
|
+
nextAction: "Resolve M001 validation attention before proceeding.",
|
|
828
|
+
}),
|
|
829
|
+
registry: [handler],
|
|
830
|
+
});
|
|
831
|
+
|
|
832
|
+
assert.equal(result.ok, true);
|
|
833
|
+
assert.equal(repairCalled, false, "validation-blocked milestone summary drift should not attempt repair");
|
|
834
|
+
assert.ok(
|
|
835
|
+
result.blockers.some((blocker) => blocker.includes("milestone validation returned needs-attention")),
|
|
836
|
+
"validation blocker should be returned to the caller",
|
|
837
|
+
);
|
|
838
|
+
assert.ok(
|
|
839
|
+
result.blockers.some((blocker) => blocker.includes("Stale milestone summary render")),
|
|
840
|
+
"stale-render blocker should explain why repair did not run",
|
|
841
|
+
);
|
|
842
|
+
});
|
|
843
|
+
|
|
699
844
|
test("ADR-017 (#5702): stale-render detector reason strings match repair contract", (t) => {
|
|
700
845
|
t.skip("TODO(flat-phase): stale-render detection temporarily disabled during layout transition"); return;
|
|
701
846
|
const base = mkdtempSync(join(tmpdir(), "gsd-adr017-render-reasons-"));
|
|
@@ -1811,3 +1956,49 @@ test("ADR-017 (#5700): cascading drift triggers second pass within cap", async (
|
|
|
1811
1956
|
assert.equal(result.repaired.length, 2, "both passes' repairs collected");
|
|
1812
1957
|
assert.equal(repaired.length, 2);
|
|
1813
1958
|
});
|
|
1959
|
+
|
|
1960
|
+
test("deriveState is pure: stale sketch healed only via reconcileBeforeDispatch", async (t) => {
|
|
1961
|
+
const base = makeFixtureBase();
|
|
1962
|
+
t.after(() => cleanup(base));
|
|
1963
|
+
|
|
1964
|
+
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
1965
|
+
insertMilestone({ id: "M001", title: "Test", status: "active" });
|
|
1966
|
+
insertSlice({
|
|
1967
|
+
id: "S02",
|
|
1968
|
+
milestoneId: "M001",
|
|
1969
|
+
title: "Feature",
|
|
1970
|
+
status: "pending",
|
|
1971
|
+
risk: "medium",
|
|
1972
|
+
depends: [],
|
|
1973
|
+
demo: "S02 demo.",
|
|
1974
|
+
sequence: 1,
|
|
1975
|
+
isSketch: true,
|
|
1976
|
+
sketchScope: "limited",
|
|
1977
|
+
});
|
|
1978
|
+
writeFileSync(
|
|
1979
|
+
join(base, ".gsd", "phases", "01-test", "01-02-PLAN.md"),
|
|
1980
|
+
"# S02 Plan\n",
|
|
1981
|
+
);
|
|
1982
|
+
|
|
1983
|
+
const { deriveState } = await import("../state.ts");
|
|
1984
|
+
invalidateStateCache();
|
|
1985
|
+
|
|
1986
|
+
const beforeReconcile = await deriveState(base);
|
|
1987
|
+
assert.equal(beforeReconcile.phase, "refining", "derive alone must not heal stale sketch flag");
|
|
1988
|
+
assert.equal(getSlice("M001", "S02")?.is_sketch, 1, "DB flag unchanged before reconcile");
|
|
1989
|
+
|
|
1990
|
+
const result = await reconcileBeforeDispatch(base);
|
|
1991
|
+
assert.equal(result.ok, true);
|
|
1992
|
+
assert.equal(getSlice("M001", "S02")?.is_sketch, 0, "reconcile clears sketch flag");
|
|
1993
|
+
|
|
1994
|
+
invalidateStateCache();
|
|
1995
|
+
const afterReconcile = await deriveState(base);
|
|
1996
|
+
assert.notEqual(afterReconcile.phase, "refining", "derive after reconcile advances past sketch gate");
|
|
1997
|
+
});
|
|
1998
|
+
|
|
1999
|
+
test("reconciliation repair phases: external edits precede re-project handlers", () => {
|
|
2000
|
+
assert.equal(RECONCILIATION_REPAIR_PHASES.length, 3);
|
|
2001
|
+
assert.ok(handlerPhaseIndex("external-markdown-edit") < handlerPhaseIndex("stale-render"));
|
|
2002
|
+
assert.ok(handlerPhaseIndex("external-planning-edit") < handlerPhaseIndex("roadmap-divergence"));
|
|
2003
|
+
assert.ok(handlerPhaseIndex("stale-sketch-flag") < handlerPhaseIndex("stale-render"));
|
|
2004
|
+
});
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
resetToolCallLoopGuard,
|
|
11
11
|
disableToolCallLoopGuard,
|
|
12
12
|
getToolCallLoopCount,
|
|
13
|
+
getToolCallCountForTool,
|
|
13
14
|
} from '../bootstrap/tool-call-loop-guard.ts';
|
|
14
15
|
|
|
15
16
|
|
|
@@ -177,3 +178,153 @@ console.log('\n── Loop guard: nested key order is normalized ──');
|
|
|
177
178
|
}
|
|
178
179
|
|
|
179
180
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
181
|
+
// Per-tool-name cap (#783 Brief C) — catches improvisation loops with varied args
|
|
182
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
183
|
+
|
|
184
|
+
console.log('\n── Loop guard: per-tool cap blocks varied-args improvisation (#783) ──');
|
|
185
|
+
|
|
186
|
+
{
|
|
187
|
+
resetToolCallLoopGuard();
|
|
188
|
+
|
|
189
|
+
// A one-shot workflow tool called with DIFFERENT args each time (the reported
|
|
190
|
+
// improvisation pattern). The identical-signature streak alone would reset
|
|
191
|
+
// every call; the per-tool cap must catch it.
|
|
192
|
+
for (let i = 1; i <= 6; i++) {
|
|
193
|
+
const result = checkToolCallLoop('gsd_complete_milestone', { milestone: `M${i}` });
|
|
194
|
+
assert.ok(result.block === false, `one-shot call ${i} (varied args) should be allowed`);
|
|
195
|
+
assert.deepStrictEqual(getToolCallCountForTool('gsd_complete_milestone'), i, `per-tool count should be ${i}`);
|
|
196
|
+
}
|
|
197
|
+
// 7th call (cap 6 + 1) must be blocked by the per-tool guard.
|
|
198
|
+
const blocked = checkToolCallLoop('gsd_complete_milestone', { milestone: 'M7' });
|
|
199
|
+
assert.ok(blocked.block === true, '7th one-shot call (varied args) should be blocked by per-tool cap');
|
|
200
|
+
assert.ok(blocked.reason!.includes('repeated tool'), 'reason should identify the per-tool guard');
|
|
201
|
+
assert.ok(blocked.reason!.includes('gsd_complete_milestone'), 'reason should name the tool');
|
|
202
|
+
assert.ok(blocked.reason!.includes('7'), 'reason should mention the count');
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
206
|
+
// Repeatable tools get the higher cap
|
|
207
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
208
|
+
|
|
209
|
+
console.log('\n── Loop guard: repeatable tools get the higher cap (#783) ──');
|
|
210
|
+
|
|
211
|
+
{
|
|
212
|
+
resetToolCallLoopGuard();
|
|
213
|
+
|
|
214
|
+
// bash is repeatable: varied commands are legitimate up to the higher cap.
|
|
215
|
+
for (let i = 1; i <= 15; i++) {
|
|
216
|
+
const result = checkToolCallLoop('bash', { command: `echo ${i}` });
|
|
217
|
+
assert.ok(result.block === false, `bash call ${i} (varied args) should be allowed`);
|
|
218
|
+
}
|
|
219
|
+
// 16th call (cap 15 + 1) is blocked by the per-tool guard — this is the
|
|
220
|
+
// improvisation-through-bash case from the forensics (~51 calls).
|
|
221
|
+
const blocked = checkToolCallLoop('bash', { command: 'echo 16' });
|
|
222
|
+
assert.ok(blocked.block === true, '16th bash call (varied args) should be blocked by per-tool cap');
|
|
223
|
+
assert.ok(blocked.reason!.includes('cap 15'), 'reason should mention the repeatable cap');
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
227
|
+
// Per-tool counts are independent per tool and reset together
|
|
228
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
229
|
+
|
|
230
|
+
console.log('\n── Loop guard: per-tool counts are independent and reset together (#783) ──');
|
|
231
|
+
|
|
232
|
+
{
|
|
233
|
+
resetToolCallLoopGuard();
|
|
234
|
+
|
|
235
|
+
// Two different tools tracked separately.
|
|
236
|
+
for (let i = 0; i < 3; i++) checkToolCallLoop('read', { path: `f${i}` });
|
|
237
|
+
for (let i = 0; i < 3; i++) checkToolCallLoop('write', { path: `g${i}` });
|
|
238
|
+
assert.deepStrictEqual(getToolCallCountForTool('read'), 3, 'read tracked separately');
|
|
239
|
+
assert.deepStrictEqual(getToolCallCountForTool('write'), 3, 'write tracked separately');
|
|
240
|
+
assert.deepStrictEqual(getToolCallCountForTool('edit'), 0, 'uncalled tool reports 0');
|
|
241
|
+
|
|
242
|
+
resetToolCallLoopGuard();
|
|
243
|
+
assert.deepStrictEqual(getToolCallCountForTool('read'), 0, 'per-tool counts cleared on reset');
|
|
244
|
+
assert.deepStrictEqual(getToolCallCountForTool('write'), 0, 'per-tool counts cleared on reset');
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
248
|
+
// Newly-repeatable tools from core-session-tools.ts get the higher cap.
|
|
249
|
+
// bg_shell, find, ls, search_and_read were added to INHERENTLY_REPEATABLE_TOOL_SET
|
|
250
|
+
// in the code-quality consolidation PR (previously only bash/read/write/etc).
|
|
251
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
252
|
+
|
|
253
|
+
console.log('\n── Loop guard: new repeatable tools (bg_shell, find, ls, search_and_read) get high cap ──');
|
|
254
|
+
|
|
255
|
+
{
|
|
256
|
+
for (const toolName of ['bg_shell', 'find', 'ls', 'search_and_read']) {
|
|
257
|
+
resetToolCallLoopGuard();
|
|
258
|
+
|
|
259
|
+
// Should allow up to 15 varied calls without blocking.
|
|
260
|
+
for (let i = 1; i <= 15; i++) {
|
|
261
|
+
const result = checkToolCallLoop(toolName, { arg: `v${i}` });
|
|
262
|
+
assert.ok(result.block === false, `${toolName} call ${i} (varied args) should be allowed`);
|
|
263
|
+
}
|
|
264
|
+
// 16th call with varied args must be blocked by the per-tool repeatable cap.
|
|
265
|
+
const blocked = checkToolCallLoop(toolName, { arg: 'v16' });
|
|
266
|
+
assert.ok(blocked.block === true, `${toolName}: 16th call must be blocked by repeatable cap`);
|
|
267
|
+
assert.ok(blocked.reason?.includes('cap 15'), `${toolName}: reason must mention cap 15`);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
272
|
+
// Non-repeatable tools excluded from INHERENTLY_REPEATABLE_TOOL_SET use the
|
|
273
|
+
// default cap (6), not the repeatable cap (15).
|
|
274
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
275
|
+
|
|
276
|
+
console.log('\n── Loop guard: ToolSearch (excluded from repeatable set) hits default cap ──');
|
|
277
|
+
|
|
278
|
+
{
|
|
279
|
+
// ToolSearch is in MINIMAL_AUTO_BASE but explicitly excluded from repeatable.
|
|
280
|
+
// It should hit the default cap of 6, not 15.
|
|
281
|
+
resetToolCallLoopGuard();
|
|
282
|
+
for (let i = 1; i <= 6; i++) {
|
|
283
|
+
const result = checkToolCallLoop('ToolSearch', { query: `q${i}` });
|
|
284
|
+
assert.ok(result.block === false, `ToolSearch call ${i} should be allowed`);
|
|
285
|
+
}
|
|
286
|
+
const blocked = checkToolCallLoop('ToolSearch', { query: 'q7' });
|
|
287
|
+
assert.ok(blocked.block === true, 'ToolSearch: 7th varied call must be blocked by default cap');
|
|
288
|
+
assert.ok(!blocked.reason?.includes('cap 15'), 'ToolSearch must NOT use the repeatable cap');
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
292
|
+
// Block reasons instruct the model to stop tooling this turn
|
|
293
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
294
|
+
|
|
295
|
+
console.log('\n── Loop guard: block reasons tell model to respond in text ──');
|
|
296
|
+
|
|
297
|
+
{
|
|
298
|
+
resetToolCallLoopGuard();
|
|
299
|
+
|
|
300
|
+
for (let i = 0; i < 4; i++) {
|
|
301
|
+
checkToolCallLoop('web_search', { query: 'same query' });
|
|
302
|
+
}
|
|
303
|
+
const identicalBlocked = checkToolCallLoop('web_search', { query: 'same query' });
|
|
304
|
+
assert.ok(identicalBlocked.block === true, 'identical-args guard should block');
|
|
305
|
+
assert.ok(
|
|
306
|
+
identicalBlocked.reason!.includes('respond to the user in text'),
|
|
307
|
+
'identical-args reason should tell the model to stop tooling',
|
|
308
|
+
);
|
|
309
|
+
assert.ok(
|
|
310
|
+
!identicalBlocked.reason!.includes('Try a different approach'),
|
|
311
|
+
'identical-args reason should not suggest retrying another tool',
|
|
312
|
+
);
|
|
313
|
+
|
|
314
|
+
resetToolCallLoopGuard();
|
|
315
|
+
for (let i = 0; i < 6; i++) {
|
|
316
|
+
checkToolCallLoop('gsd_complete_milestone', { milestone: `M${i}` });
|
|
317
|
+
}
|
|
318
|
+
const perToolBlocked = checkToolCallLoop('gsd_complete_milestone', { milestone: 'M7' });
|
|
319
|
+
assert.ok(perToolBlocked.block === true, 'per-tool guard should block');
|
|
320
|
+
assert.ok(
|
|
321
|
+
perToolBlocked.reason!.includes('respond to the user in text'),
|
|
322
|
+
'per-tool reason should tell the model to stop tooling',
|
|
323
|
+
);
|
|
324
|
+
assert.ok(
|
|
325
|
+
perToolBlocked.reason!.includes('Do not retry this tool'),
|
|
326
|
+
'per-tool reason should forbid retrying the blocked tool',
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -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", () => {
|