gsd-pi 2.77.0 → 2.78.0
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 +18 -36
- package/dist/claude-cli-check.js +5 -1
- package/dist/cli-web-branch.d.ts +1 -0
- package/dist/cli-web-branch.js +3 -0
- package/dist/cli.js +38 -2
- package/dist/extension-discovery.d.ts +6 -0
- package/dist/extension-discovery.js +37 -0
- package/dist/extension-registry.d.ts +3 -0
- package/dist/extension-sort.d.ts +18 -0
- package/dist/extension-sort.js +114 -0
- package/dist/extension-validator.d.ts +47 -0
- package/dist/extension-validator.js +127 -0
- package/dist/headless.js +49 -4
- package/dist/loader.js +35 -7
- package/dist/provider-migrations.d.ts +18 -0
- package/dist/provider-migrations.js +14 -0
- package/dist/resource-loader.d.ts +40 -0
- package/dist/resource-loader.js +32 -13
- package/dist/resources/extensions/browser-tools/capture.js +9 -0
- package/dist/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
- package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
- package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
- package/dist/resources/extensions/browser-tools/tools/forms.js +5 -1
- package/dist/resources/extensions/browser-tools/tools/intent.js +5 -1
- package/dist/resources/extensions/claude-code-cli/readiness.js +5 -1
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +552 -67
- package/dist/resources/extensions/cmux/index.js +20 -0
- package/dist/resources/extensions/github-sync/templates.js +103 -0
- package/dist/resources/extensions/google-search/extension-manifest.json +5 -4
- package/dist/resources/extensions/google-search/index.js +3 -375
- package/dist/resources/extensions/gsd/abandon-detect.js +44 -0
- package/dist/resources/extensions/gsd/auto/loop.js +124 -2
- package/dist/resources/extensions/gsd/auto/phases.js +57 -39
- package/dist/resources/extensions/gsd/auto/resolve.js +24 -0
- package/dist/resources/extensions/gsd/auto/run-unit.js +10 -2
- package/dist/resources/extensions/gsd/auto/session.js +6 -2
- package/dist/resources/extensions/gsd/auto/turn-epoch.js +95 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +201 -38
- package/dist/resources/extensions/gsd/auto-loop.js +1 -1
- package/dist/resources/extensions/gsd/auto-model-selection.js +124 -4
- package/dist/resources/extensions/gsd/auto-post-unit.js +215 -64
- package/dist/resources/extensions/gsd/auto-prompts.js +372 -104
- package/dist/resources/extensions/gsd/auto-recovery.js +210 -24
- package/dist/resources/extensions/gsd/auto-start.js +122 -30
- package/dist/resources/extensions/gsd/auto-timeout-recovery.js +11 -5
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +47 -7
- package/dist/resources/extensions/gsd/auto-unit-closeout.js +11 -2
- package/dist/resources/extensions/gsd/auto-worktree.js +180 -34
- package/dist/resources/extensions/gsd/auto.js +107 -35
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +19 -1
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +209 -0
- package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +5 -6
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +11 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +7 -3
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +11 -6
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +127 -9
- package/dist/resources/extensions/gsd/commands/handlers/workflow.js +31 -4
- package/dist/resources/extensions/gsd/commands-cmux.js +9 -6
- package/dist/resources/extensions/gsd/commands-extensions.js +634 -43
- package/dist/resources/extensions/gsd/component-loader.js +447 -0
- package/dist/resources/extensions/gsd/component-types.js +69 -0
- package/dist/resources/extensions/gsd/context-store.js +23 -7
- package/dist/resources/extensions/gsd/detection.js +49 -1
- package/dist/resources/extensions/gsd/dispatch-guard.js +29 -3
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/dist/resources/extensions/gsd/file-lock.js +49 -9
- package/dist/resources/extensions/gsd/forensics.js +106 -0
- package/dist/resources/extensions/gsd/gate-registry.js +2 -2
- package/dist/resources/extensions/gsd/git-constants.js +28 -1
- package/dist/resources/extensions/gsd/git-self-heal.js +27 -0
- package/dist/resources/extensions/gsd/git-service.js +127 -2
- package/dist/resources/extensions/gsd/gitignore.js +1 -0
- package/dist/resources/extensions/gsd/gsd-db.js +6 -3
- package/dist/resources/extensions/gsd/guided-flow-queue.js +4 -1
- package/dist/resources/extensions/gsd/guided-flow.js +39 -13
- package/dist/resources/extensions/gsd/journal.js +17 -2
- package/dist/resources/extensions/gsd/memory-extractor.js +7 -1
- package/dist/resources/extensions/gsd/milestone-actions.js +15 -0
- package/dist/resources/extensions/gsd/milestone-scope-classifier.js +299 -0
- package/dist/resources/extensions/gsd/milestone-summary-classifier.js +37 -0
- package/dist/resources/extensions/gsd/model-cost-table.js +3 -0
- package/dist/resources/extensions/gsd/model-router.js +6 -0
- package/dist/resources/extensions/gsd/native-git-bridge.js +34 -4
- package/dist/resources/extensions/gsd/notifications.js +30 -16
- package/dist/resources/extensions/gsd/preferences-validation.js +23 -0
- package/dist/resources/extensions/gsd/prompt-cache-optimizer.js +4 -0
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +23 -4
- package/dist/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +15 -2
- package/dist/resources/extensions/gsd/prompts/system.md +1 -0
- package/dist/resources/extensions/gsd/reports.js +5 -4
- package/dist/resources/extensions/gsd/safety/git-checkpoint.js +11 -0
- package/dist/resources/extensions/gsd/service-tier.js +5 -2
- package/dist/resources/extensions/gsd/session-lock.js +19 -10
- package/dist/resources/extensions/gsd/skill-manifest.js +168 -0
- package/dist/resources/extensions/gsd/slice-cadence.js +238 -0
- package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +278 -8
- package/dist/resources/extensions/gsd/state-transition-matrix.js +118 -0
- package/dist/resources/extensions/gsd/state.js +69 -58
- package/dist/resources/extensions/gsd/sync-lock.js +98 -42
- package/dist/resources/extensions/gsd/tools/complete-slice.js +21 -0
- package/dist/resources/extensions/gsd/tools/complete-task.js +31 -0
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +7 -2
- package/dist/resources/extensions/gsd/unit-context-composer.js +147 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +370 -0
- package/dist/resources/extensions/gsd/uok/audit.js +18 -2
- package/dist/resources/extensions/gsd/uok/dispatch-envelope.js +33 -0
- package/dist/resources/extensions/gsd/uok/execution-graph.js +10 -0
- package/dist/resources/extensions/gsd/uok/gate-runner.js +53 -5
- package/dist/resources/extensions/gsd/uok/gitops.js +2 -1
- package/dist/resources/extensions/gsd/uok/loop-adapter.js +37 -10
- package/dist/resources/extensions/gsd/uok/parity-report.js +58 -0
- package/dist/resources/extensions/gsd/uok/plan-v2.js +10 -4
- package/dist/resources/extensions/gsd/uok/writer.js +82 -0
- package/dist/resources/extensions/gsd/workflow-logger.js +10 -2
- package/dist/resources/extensions/gsd/workflow-mcp.js +6 -0
- package/dist/resources/extensions/gsd/worktree-manager.js +86 -8
- package/dist/resources/extensions/gsd/worktree-resolver.js +86 -7
- package/dist/resources/extensions/gsd/worktree-telemetry.js +198 -0
- package/dist/resources/extensions/mcp-client/auth.js +10 -1
- package/dist/resources/extensions/mcp-client/index.js +121 -10
- package/dist/resources/extensions/ollama/index.js +5 -1
- package/dist/resources/extensions/remote-questions/manager.js +11 -5
- package/dist/resources/extensions/shared/cmux-events.js +12 -0
- package/dist/resources/extensions/shared/rtk-session-stats.js +1 -2
- package/dist/resources/skills/create-skill/SKILL.md +2 -2
- package/dist/resources/skills/create-skill/references/gsd-skill-ecosystem.md +4 -4
- package/dist/resources/skills/create-skill/workflows/audit-skill.md +4 -4
- package/dist/resources/skills/create-skill/workflows/create-new-skill.md +5 -5
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +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.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/boot/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/notifications/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- 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-paths-manifest.json +12 -12
- package/dist/web/standalone/.next/server/chunks/1926.js +1 -0
- package/dist/web/standalone/.next/server/chunks/6897.js +2 -2
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-manifest.json +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/static/chunks/2826.e9f5195e91f9cad2.js +11 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-5fc74f13a25fa1bb.js → webpack-2e68521d7c82f7c2.js} +1 -1
- package/package.json +17 -16
- package/packages/daemon/package.json +2 -2
- package/packages/daemon/src/logger.ts +4 -3
- package/packages/mcp-server/README.md +3 -3
- package/packages/mcp-server/dist/env-writer.d.ts +1 -0
- package/packages/mcp-server/dist/env-writer.d.ts.map +1 -1
- package/packages/mcp-server/dist/env-writer.js +74 -6
- package/packages/mcp-server/dist/env-writer.js.map +1 -1
- package/packages/mcp-server/dist/server.d.ts +24 -0
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +111 -87
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +15 -6
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +7 -2
- package/packages/mcp-server/src/env-writer.test.ts +79 -1
- package/packages/mcp-server/src/env-writer.ts +76 -6
- package/packages/mcp-server/src/mcp-server.test.ts +25 -3
- package/packages/mcp-server/src/readers/graph.test.ts +87 -15
- package/packages/mcp-server/src/readers/readers.test.ts +5 -1
- package/packages/mcp-server/src/secure-env-collect.test.ts +232 -237
- package/packages/mcp-server/src/server.ts +158 -105
- package/packages/mcp-server/src/workflow-tools.test.ts +85 -0
- package/packages/mcp-server/src/workflow-tools.ts +19 -6
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/package.json +7 -2
- package/packages/native/src/__tests__/_test-coverage-guard.test.mjs +98 -0
- package/packages/native/src/__tests__/clipboard.test.mjs +69 -23
- package/packages/native/src/__tests__/module-compat.test.mjs +59 -27
- package/packages/native/src/__tests__/ps.test.mjs +14 -8
- package/packages/native/src/__tests__/stream-process.test.mjs +23 -2
- package/packages/native/src/__tests__/truncate.test.mjs +17 -2
- package/packages/native/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-agent-core/package.json +6 -1
- package/packages/pi-agent-core/src/agent-loop.test.ts +226 -31
- package/packages/pi-agent-core/src/agent.test.ts +96 -102
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/models/capability-patches.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/capability-patches.js +9 -2
- package/packages/pi-ai/dist/models/capability-patches.js.map +1 -1
- package/packages/pi-ai/dist/models/generated/index.d.ts +34 -0
- package/packages/pi-ai/dist/models/generated/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +17 -0
- package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/generated/openai-codex.js +17 -0
- package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -1
- package/packages/pi-ai/dist/models/generated/openai.d.ts +17 -0
- package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/generated/openai.js +17 -0
- package/packages/pi-ai/dist/models/generated/openai.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.test.js +43 -70
- package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
- package/packages/pi-ai/dist/models.test.js +36 -11
- package/packages/pi-ai/dist/models.test.js.map +1 -1
- package/packages/pi-ai/package.json +6 -1
- package/packages/pi-ai/scripts/generate-models.ts +44 -0
- package/packages/pi-ai/src/models/capability-patches.ts +10 -2
- package/packages/pi-ai/src/models/generated/openai-codex.ts +17 -0
- package/packages/pi-ai/src/models/generated/openai.ts +17 -0
- package/packages/pi-ai/src/models.generated.test.ts +46 -73
- package/packages/pi-ai/src/models.test.ts +48 -11
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +96 -32
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js +75 -12
- package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +99 -31
- package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +25 -0
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js +105 -6
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.test.js +230 -28
- package/packages/pi-coding-agent/dist/core/compaction/compaction.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/utils.d.ts +30 -2
- package/packages/pi-coding-agent/dist/core/compaction/utils.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/utils.js +113 -12
- package/packages/pi-coding-agent/dist/core/compaction/utils.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js +29 -18
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.js +130 -0
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/compaction-utils.test.js +56 -1
- package/packages/pi-coding-agent/dist/core/compaction-utils.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/discovery-cache.test.js +8 -15
- package/packages/pi-coding-agent/dist/core/discovery-cache.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-discovery.d.ts +25 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-discovery.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-discovery.js +109 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-discovery.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-registry.d.ts +67 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-registry.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-registry.js +167 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-registry.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +8 -2
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +85 -8
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +7 -0
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js +41 -4
- package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +19 -2
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js +76 -18
- package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.js +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js +2 -6
- package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js +5 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts +18 -0
- package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/retryable-error-regex.js +18 -0
- package/packages/pi-coding-agent/dist/core/retryable-error-regex.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/sdk.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +4 -1
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.test.js +19 -1
- package/packages/pi-coding-agent/dist/core/sdk.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +20 -0
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +19 -5
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/path-utils.test.js +2 -1
- package/packages/pi-coding-agent/dist/core/tools/path-utils.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts +1 -0
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +1 -0
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.js +15 -6
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +36 -5
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js +20 -13
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +14 -5
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts +7 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js +31 -9
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +30 -12
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +18 -3
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +139 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +4 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +105 -13
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js +130 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js.map +1 -0
- package/packages/pi-coding-agent/package.json +6 -1
- package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +113 -37
- package/packages/pi-coding-agent/src/core/agent-session-model-switch.test.ts +89 -17
- package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +112 -43
- package/packages/pi-coding-agent/src/core/compaction/compaction.test.ts +368 -28
- package/packages/pi-coding-agent/src/core/compaction/compaction.ts +122 -6
- package/packages/pi-coding-agent/src/core/compaction/utils.ts +111 -13
- package/packages/pi-coding-agent/src/core/compaction-orchestrator.test.ts +154 -0
- package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +32 -18
- package/packages/pi-coding-agent/src/core/compaction-utils.test.ts +68 -1
- package/packages/pi-coding-agent/src/core/discovery-cache.test.ts +9 -18
- package/packages/pi-coding-agent/src/core/extensions/extension-discovery.ts +119 -0
- package/packages/pi-coding-agent/src/core/extensions/extension-registry.ts +222 -0
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +82 -11
- package/packages/pi-coding-agent/src/core/extensions/types.ts +8 -0
- package/packages/pi-coding-agent/src/core/lsp/lsp-integration.test.ts +48 -4
- package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +22 -2
- package/packages/pi-coding-agent/src/core/resource-loader-cache-reset.test.ts +93 -28
- package/packages/pi-coding-agent/src/core/resource-loader.ts +1 -1
- package/packages/pi-coding-agent/src/core/retry-handler.test.ts +5 -1
- package/packages/pi-coding-agent/src/core/retry-handler.ts +2 -8
- package/packages/pi-coding-agent/src/core/retryable-error-regex.ts +18 -0
- package/packages/pi-coding-agent/src/core/sdk.test.ts +25 -1
- package/packages/pi-coding-agent/src/core/sdk.ts +10 -3
- package/packages/pi-coding-agent/src/core/system-prompt.ts +38 -4
- package/packages/pi-coding-agent/src/core/tools/path-utils.test.ts +2 -1
- package/packages/pi-coding-agent/src/index.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/provider-display-name.test.ts +17 -7
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +49 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +26 -20
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +14 -5
- package/packages/pi-coding-agent/src/modes/interactive/components/model-selector.ts +45 -11
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +48 -9
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +160 -1
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +20 -3
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +2 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +119 -13
- package/packages/pi-coding-agent/src/tests/system-prompt-skill-filter.test.ts +157 -0
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/__tests__/autocomplete.test.js +31 -14
- package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
- package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +128 -17
- package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
- package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +51 -6
- package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -1
- package/packages/pi-tui/dist/__tests__/tui.test.js +18 -30
- package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
- package/packages/pi-tui/dist/components/__tests__/input.test.js +10 -3
- package/packages/pi-tui/dist/components/__tests__/input.test.js.map +1 -1
- package/packages/pi-tui/dist/components/__tests__/loader.test.js +53 -9
- package/packages/pi-tui/dist/components/__tests__/loader.test.js.map +1 -1
- package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js +6 -2
- package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js.map +1 -1
- package/packages/pi-tui/dist/components/editor.d.ts +14 -0
- package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/editor.js +19 -0
- package/packages/pi-tui/dist/components/editor.js.map +1 -1
- package/packages/pi-tui/dist/components/image.test.js +6 -5
- package/packages/pi-tui/dist/components/image.test.js.map +1 -1
- package/packages/pi-tui/dist/editor-component.d.ts +2 -0
- package/packages/pi-tui/dist/editor-component.d.ts.map +1 -1
- package/packages/pi-tui/dist/editor-component.js.map +1 -1
- package/packages/pi-tui/dist/stdin-buffer.d.ts +7 -0
- package/packages/pi-tui/dist/stdin-buffer.d.ts.map +1 -1
- package/packages/pi-tui/dist/stdin-buffer.js +20 -0
- package/packages/pi-tui/dist/stdin-buffer.js.map +1 -1
- package/packages/pi-tui/package.json +6 -1
- package/packages/pi-tui/src/__tests__/autocomplete.test.ts +46 -15
- package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +140 -17
- package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +62 -6
- package/packages/pi-tui/src/__tests__/tui.test.ts +18 -37
- package/packages/pi-tui/src/components/__tests__/input.test.ts +19 -3
- package/packages/pi-tui/src/components/__tests__/loader.test.ts +112 -35
- package/packages/pi-tui/src/components/__tests__/markdown-maxlines.test.ts +9 -2
- package/packages/pi-tui/src/components/editor.ts +22 -0
- package/packages/pi-tui/src/components/image.test.ts +10 -5
- package/packages/pi-tui/src/editor-component.ts +3 -0
- package/packages/pi-tui/src/stdin-buffer.ts +26 -0
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/packages/rpc-client/dist/rpc-client.test.js +101 -51
- package/packages/rpc-client/dist/rpc-client.test.js.map +1 -1
- package/packages/rpc-client/package.json +6 -1
- package/packages/rpc-client/src/rpc-client.test.ts +109 -52
- package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
- package/pkg/package.json +1 -1
- package/scripts/install.js +526 -0
- package/scripts/lib/workspace-manifest.cjs +86 -0
- package/scripts/link-workspace-packages.cjs +5 -17
- package/scripts/postinstall.js +9 -178
- package/src/resources/extensions/browser-tools/capture.ts +12 -0
- package/src/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
- package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
- package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
- package/src/resources/extensions/browser-tools/tools/forms.ts +5 -1
- package/src/resources/extensions/browser-tools/tools/intent.ts +5 -1
- package/src/resources/extensions/claude-code-cli/readiness.ts +5 -1
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +602 -73
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +1028 -91
- package/src/resources/extensions/cmux/index.ts +35 -10
- package/src/resources/extensions/github-sync/templates.ts +151 -0
- package/src/resources/extensions/github-sync/tests/cli.test.ts +76 -7
- package/src/resources/extensions/github-sync/tests/templates.test.ts +92 -1
- package/src/resources/extensions/google-search/extension-manifest.json +5 -4
- package/src/resources/extensions/google-search/index.ts +9 -470
- package/src/resources/extensions/gsd/abandon-detect.ts +62 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -1
- package/src/resources/extensions/gsd/auto/loop.ts +142 -2
- package/src/resources/extensions/gsd/auto/phases.ts +62 -38
- package/src/resources/extensions/gsd/auto/resolve.ts +29 -0
- package/src/resources/extensions/gsd/auto/run-unit.ts +16 -2
- package/src/resources/extensions/gsd/auto/session.ts +7 -2
- package/src/resources/extensions/gsd/auto/turn-epoch.ts +108 -0
- package/src/resources/extensions/gsd/auto/types.ts +1 -1
- package/src/resources/extensions/gsd/auto-dispatch.ts +214 -37
- package/src/resources/extensions/gsd/auto-loop.ts +1 -1
- package/src/resources/extensions/gsd/auto-model-selection.ts +131 -4
- package/src/resources/extensions/gsd/auto-post-unit.ts +226 -73
- package/src/resources/extensions/gsd/auto-prompts.ts +385 -93
- package/src/resources/extensions/gsd/auto-recovery.ts +240 -25
- package/src/resources/extensions/gsd/auto-start.ts +146 -14
- package/src/resources/extensions/gsd/auto-timeout-recovery.ts +12 -5
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +51 -7
- package/src/resources/extensions/gsd/auto-unit-closeout.ts +14 -3
- package/src/resources/extensions/gsd/auto-worktree.ts +190 -31
- package/src/resources/extensions/gsd/auto.ts +127 -41
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +20 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +221 -0
- package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +6 -6
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +11 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +7 -3
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +13 -9
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +158 -9
- package/src/resources/extensions/gsd/commands/handlers/workflow.ts +27 -8
- package/src/resources/extensions/gsd/commands-cmux.ts +10 -6
- package/src/resources/extensions/gsd/commands-extensions.ts +747 -41
- package/src/resources/extensions/gsd/component-loader.ts +598 -0
- package/src/resources/extensions/gsd/component-types.ts +362 -0
- package/src/resources/extensions/gsd/context-store.ts +25 -8
- package/src/resources/extensions/gsd/detection.ts +58 -1
- package/src/resources/extensions/gsd/dispatch-guard.ts +26 -2
- package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/src/resources/extensions/gsd/file-lock.ts +84 -11
- package/src/resources/extensions/gsd/forensics.ts +118 -1
- package/src/resources/extensions/gsd/gate-registry.ts +2 -2
- package/src/resources/extensions/gsd/git-constants.ts +30 -1
- package/src/resources/extensions/gsd/git-self-heal.ts +31 -0
- package/src/resources/extensions/gsd/git-service.ts +150 -2
- package/src/resources/extensions/gsd/gitignore.ts +1 -0
- package/src/resources/extensions/gsd/gsd-db.ts +6 -3
- package/src/resources/extensions/gsd/guided-flow-queue.ts +4 -1
- package/src/resources/extensions/gsd/guided-flow.ts +57 -14
- package/src/resources/extensions/gsd/journal.ts +38 -3
- package/src/resources/extensions/gsd/memory-extractor.ts +11 -3
- package/src/resources/extensions/gsd/milestone-actions.ts +18 -0
- package/src/resources/extensions/gsd/milestone-scope-classifier.ts +366 -0
- package/src/resources/extensions/gsd/milestone-summary-classifier.ts +42 -0
- package/src/resources/extensions/gsd/model-cost-table.ts +3 -0
- package/src/resources/extensions/gsd/model-router.ts +6 -0
- package/src/resources/extensions/gsd/native-git-bridge.ts +34 -4
- package/src/resources/extensions/gsd/notifications.ts +27 -15
- package/src/resources/extensions/gsd/preferences-validation.ts +21 -0
- package/src/resources/extensions/gsd/prompt-cache-optimizer.ts +4 -0
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +23 -4
- package/src/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
- package/src/resources/extensions/gsd/prompts/plan-slice.md +15 -2
- package/src/resources/extensions/gsd/prompts/system.md +1 -0
- package/src/resources/extensions/gsd/reports.ts +5 -4
- package/src/resources/extensions/gsd/safety/git-checkpoint.ts +15 -0
- package/src/resources/extensions/gsd/service-tier.ts +5 -2
- package/src/resources/extensions/gsd/session-lock.ts +20 -10
- package/src/resources/extensions/gsd/skill-manifest.ts +175 -0
- package/src/resources/extensions/gsd/slice-cadence.ts +299 -0
- package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +309 -8
- package/src/resources/extensions/gsd/state-transition-matrix.ts +152 -0
- package/src/resources/extensions/gsd/state.ts +76 -66
- package/src/resources/extensions/gsd/sync-lock.ts +97 -39
- package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +270 -0
- package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +341 -0
- package/src/resources/extensions/gsd/tests/auto-discuss-milestone-deadlock-4973.test.ts +264 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +135 -285
- package/src/resources/extensions/gsd/tests/auto-mode-guards.test.ts +79 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +742 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +78 -0
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +61 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +166 -0
- package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +4 -1
- package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +8 -194
- package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +64 -0
- package/src/resources/extensions/gsd/tests/auto-start-cold-db-bootstrap.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +15 -58
- package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +17 -21
- package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +108 -0
- package/src/resources/extensions/gsd/tests/cmux.test.ts +5 -9
- package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +263 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +192 -0
- package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +16 -8
- package/src/resources/extensions/gsd/tests/component-loader.test.ts +589 -0
- package/src/resources/extensions/gsd/tests/component-types.test.ts +127 -0
- package/src/resources/extensions/gsd/tests/context-store.test.ts +79 -0
- package/src/resources/extensions/gsd/tests/copy-planning-artifacts-samepath.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +50 -1
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +159 -0
- package/src/resources/extensions/gsd/tests/db-access-guardrails.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +91 -3
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/discuss-tool-scope-leak.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +14 -9
- package/src/resources/extensions/gsd/tests/dispatch-guard-summary-db-mismatch.test.ts +77 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/empty-content-abort-loop.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/execution-entry-missing-context-4671.test.ts +173 -0
- package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +139 -129
- package/src/resources/extensions/gsd/tests/file-lock.test.ts +86 -12
- package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +8 -104
- package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +102 -0
- package/src/resources/extensions/gsd/tests/gate-storage.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/google-search-stub.test.ts +131 -0
- package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +117 -0
- package/src/resources/extensions/gsd/tests/hook-key-parsing.test.ts +4 -55
- package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +7 -56
- package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/integration/doctor-proactive.test.ts +18 -2
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/integration/queue-completed-milestone-perf.test.ts +10 -4
- package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +144 -7
- package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +2 -16
- package/src/resources/extensions/gsd/tests/integration/worktree-e2e.test.ts +11 -0
- package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +9 -3
- package/src/resources/extensions/gsd/tests/interrupted-session-ui.test.ts +6 -9
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +64 -0
- package/src/resources/extensions/gsd/tests/knowledge.test.ts +93 -1
- package/src/resources/extensions/gsd/tests/mcp-client-security.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +5 -15
- package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +227 -55
- package/src/resources/extensions/gsd/tests/milestone-scope-classifier.test.ts +187 -0
- package/src/resources/extensions/gsd/tests/milestone-status-authoritative.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/milestone-summary-classifier.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +9 -1
- package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +6 -48
- package/src/resources/extensions/gsd/tests/notification-widget.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +59 -2
- package/src/resources/extensions/gsd/tests/parallel-commit-scope.test.ts +5 -0
- package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +273 -130
- package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +150 -0
- package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +301 -0
- package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +32 -1
- package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/prompt-cache-optimizer.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +15 -4
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +54 -41
- package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +213 -0
- package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +4 -5
- package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +13 -7
- package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +75 -2
- package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +132 -0
- package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +8 -40
- package/src/resources/extensions/gsd/tests/regex-hardening.test.ts +136 -256
- package/src/resources/extensions/gsd/tests/require-slice-discussion-dispatch.test.ts +170 -0
- package/src/resources/extensions/gsd/tests/research-milestone-composer.test.ts +114 -0
- package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/rewrite-docs-abandon-detect.test.ts +195 -0
- package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +148 -0
- package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +29 -0
- package/src/resources/extensions/gsd/tests/sidecar-queue.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/silent-catch-diagnostics.test.ts +55 -95
- package/src/resources/extensions/gsd/tests/single-writer-v3-tool-surface.test.ts +158 -0
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +120 -1
- package/src/resources/extensions/gsd/tests/skill-manifest.test.ts +112 -0
- package/src/resources/extensions/gsd/tests/slice-cadence.test.ts +242 -0
- package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +164 -1
- package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/stale-dirlistcache-4648.test.ts +112 -0
- package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +29 -5
- package/src/resources/extensions/gsd/tests/state-transition-matrix.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +11 -92
- package/src/resources/extensions/gsd/tests/stuck-detection-coverage.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +7 -6
- package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +102 -101
- package/src/resources/extensions/gsd/tests/sync-lock.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/test-helpers.test.ts +98 -0
- package/src/resources/extensions/gsd/tests/test-helpers.ts +153 -0
- package/src/resources/extensions/gsd/tests/token-profile.test.ts +8 -1
- package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +61 -1
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +8 -1
- package/src/resources/extensions/gsd/tests/triage-resolution.test.ts +50 -2
- package/src/resources/extensions/gsd/tests/turn-epoch.test.ts +162 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +355 -0
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +258 -0
- package/src/resources/extensions/gsd/tests/uok-contracts.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/uok-execution-graph.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +49 -26
- package/src/resources/extensions/gsd/tests/uok-loop-adapter-writer.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/uok-parity-report.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +19 -2
- package/src/resources/extensions/gsd/tests/uok-writer.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/validate-extension-package.test.ts +168 -0
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +139 -5
- package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +144 -80
- package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -54
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +342 -277
- package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +37 -29
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +25 -2
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +226 -266
- package/src/resources/extensions/gsd/tests/worktree-health-monorepo.test.ts +103 -67
- package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +92 -90
- package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +238 -59
- package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +113 -161
- package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +210 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +262 -0
- package/src/resources/extensions/gsd/tests/write-gate-predicates.test.ts +186 -0
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +7 -5
- package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +80 -96
- package/src/resources/extensions/gsd/tools/complete-slice.ts +38 -0
- package/src/resources/extensions/gsd/tools/complete-task.ts +49 -0
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +8 -2
- package/src/resources/extensions/gsd/types.ts +3 -3
- package/src/resources/extensions/gsd/unit-context-composer.ts +218 -0
- package/src/resources/extensions/gsd/unit-context-manifest.ts +574 -0
- package/src/resources/extensions/gsd/uok/audit.ts +20 -2
- package/src/resources/extensions/gsd/uok/contracts.ts +65 -0
- package/src/resources/extensions/gsd/uok/dispatch-envelope.ts +56 -0
- package/src/resources/extensions/gsd/uok/execution-graph.ts +22 -0
- package/src/resources/extensions/gsd/uok/gate-runner.ts +65 -5
- package/src/resources/extensions/gsd/uok/gitops.ts +6 -1
- package/src/resources/extensions/gsd/uok/loop-adapter.ts +45 -10
- package/src/resources/extensions/gsd/uok/parity-report.ts +84 -0
- package/src/resources/extensions/gsd/uok/plan-v2.ts +13 -5
- package/src/resources/extensions/gsd/uok/writer.ts +113 -0
- package/src/resources/extensions/gsd/workflow-logger.ts +22 -3
- package/src/resources/extensions/gsd/workflow-mcp.ts +6 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +109 -7
- package/src/resources/extensions/gsd/worktree-resolver.ts +96 -9
- package/src/resources/extensions/gsd/worktree-telemetry.ts +322 -0
- package/src/resources/extensions/mcp-client/auth.ts +12 -1
- package/src/resources/extensions/mcp-client/index.ts +132 -11
- package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +70 -36
- package/src/resources/extensions/ollama/index.ts +5 -1
- package/src/resources/extensions/ollama/ollama-auth-mode.test.ts +123 -15
- package/src/resources/extensions/ollama/ollama-status-indicator.test.ts +206 -19
- package/src/resources/extensions/remote-questions/manager.ts +36 -4
- package/src/resources/extensions/remote-questions/tests/command-polling.test.ts +200 -190
- package/src/resources/extensions/shared/cmux-events.ts +59 -0
- package/src/resources/extensions/shared/rtk-session-stats.ts +1 -2
- package/src/resources/extensions/shared/tests/interview-preview.test.ts +11 -3
- package/src/resources/extensions/voice/tests/linux-ready.test.ts +129 -113
- package/src/resources/skills/create-skill/SKILL.md +2 -2
- package/src/resources/skills/create-skill/references/gsd-skill-ecosystem.md +4 -4
- package/src/resources/skills/create-skill/workflows/audit-skill.md +4 -4
- package/src/resources/skills/create-skill/workflows/create-new-skill.md +5 -5
- package/dist/web/standalone/.next/server/chunks/7461.js +0 -1
- package/dist/web/standalone/.next/static/chunks/2826.e59e8578e2e28639.js +0 -9
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts +0 -2
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts.map +0 -1
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js +0 -289
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js.map +0 -1
- package/packages/pi-ai/src/utils/oauth/oauth-providers.test.ts +0 -363
- package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +0 -143
- package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +0 -142
- package/src/resources/extensions/gsd/tests/dashboard-model-label-ordering.test.ts +0 -107
- package/src/resources/extensions/gsd/tests/find-missing-summaries-closed.test.ts +0 -48
- package/src/resources/extensions/gsd/tests/forensics-context-persist.test.ts +0 -159
- package/src/resources/extensions/gsd/tests/forensics-db-completion.test.ts +0 -96
- package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +0 -79
- package/src/resources/extensions/gsd/tests/forensics-hook-key-parse.test.ts +0 -74
- package/src/resources/extensions/gsd/tests/forensics-journal.test.ts +0 -162
- package/src/resources/extensions/gsd/tests/gitignore-bg-shell.test.ts +0 -38
- package/src/resources/extensions/gsd/tests/gsd-no-project-error.test.ts +0 -73
- package/src/resources/extensions/gsd/tests/idle-watchdog-stall-override.test.ts +0 -125
- package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +0 -42
- /package/dist/web/standalone/.next/static/{pV-mPo7rYGb5JBC09C8GG → C1zT2kEfoLhDdbWPWKrXd}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{pV-mPo7rYGb5JBC09C8GG → C1zT2kEfoLhDdbWPWKrXd}/_ssgManifest.js +0 -0
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
computeFileLists,
|
|
17
17
|
createFileOps,
|
|
18
18
|
createSummarizationMessage,
|
|
19
|
+
estimateSerializedTokens,
|
|
19
20
|
extractFileOpsFromMessage,
|
|
20
21
|
extractTextContent,
|
|
21
22
|
type FileOperations,
|
|
@@ -500,7 +501,13 @@ export function chunkMessages(messages: AgentMessage[], maxTokensPerChunk: numbe
|
|
|
500
501
|
let currentTokens = 0;
|
|
501
502
|
|
|
502
503
|
for (const msg of messages) {
|
|
503
|
-
|
|
504
|
+
// Use POST-truncation token estimate: serializeConversation caps every
|
|
505
|
+
// large content block to TOOL_RESULT_MAX_CHARS before sending to the LLM,
|
|
506
|
+
// so chunk sizing must reflect what the LLM will actually see. Using the
|
|
507
|
+
// pre-truncation `estimateTokens` here was the root cause of issue #4665:
|
|
508
|
+
// a single 400K-char tool result looked like 100K tokens but serialized
|
|
509
|
+
// to ~600 tokens, producing tens of tiny information-starved chunks.
|
|
510
|
+
const msgTokens = estimateSerializedTokens(msg);
|
|
504
511
|
|
|
505
512
|
if (currentChunk.length > 0 && currentTokens + msgTokens > maxTokensPerChunk) {
|
|
506
513
|
// Current chunk is full — start a new one
|
|
@@ -520,6 +527,39 @@ export function chunkMessages(messages: AgentMessage[], maxTokensPerChunk: numbe
|
|
|
520
527
|
return chunks;
|
|
521
528
|
}
|
|
522
529
|
|
|
530
|
+
// ============================================================================
|
|
531
|
+
// Degenerate summary detection (issue #4665)
|
|
532
|
+
// ============================================================================
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Heuristic: does this summary look like the "empty conversation" degenerate
|
|
536
|
+
* output that poisons the iterative UPDATE_SUMMARIZATION_PROMPT chain?
|
|
537
|
+
*
|
|
538
|
+
* The LLM occasionally returns short empty-sounding summaries when a chunk
|
|
539
|
+
* contains only truncated tool-call preambles without results. If the chain
|
|
540
|
+
* propagates this forward, every subsequent chunk is told to "PRESERVE all
|
|
541
|
+
* existing information" — which preserves the emptiness.
|
|
542
|
+
*
|
|
543
|
+
* Conservative match: an explicit substring hit OR length < 100 chars. We keep
|
|
544
|
+
* this deterministic (no fuzzy scoring) because fuzzy matching is where
|
|
545
|
+
* quality gates become flaky and hard to test.
|
|
546
|
+
*
|
|
547
|
+
* Exported for test access only.
|
|
548
|
+
*/
|
|
549
|
+
export function isDegenerateSummary(summary: string | undefined): boolean {
|
|
550
|
+
// undefined means "no summary was produced yet" (first chunk before any call)
|
|
551
|
+
// — not degenerate. Empty string IS degenerate: the LLM returned nothing.
|
|
552
|
+
if (summary === undefined) return false;
|
|
553
|
+
const lower = summary.toLowerCase();
|
|
554
|
+
if (lower.includes("empty conversation")) return true;
|
|
555
|
+
if (lower.includes("no conversation to summarize")) return true;
|
|
556
|
+
if (lower.includes("no messages to summarize")) return true;
|
|
557
|
+
// Length guard: any summary shorter than 100 chars is almost certainly
|
|
558
|
+
// degenerate for a multi-chunk pipeline.
|
|
559
|
+
if (summary.trim().length < 100) return true;
|
|
560
|
+
return false;
|
|
561
|
+
}
|
|
562
|
+
|
|
523
563
|
/** Type for the completion function, allowing injection for tests. */
|
|
524
564
|
type CompleteFn = typeof completeSimple;
|
|
525
565
|
|
|
@@ -545,10 +585,12 @@ export async function generateSummary(
|
|
|
545
585
|
): Promise<string> {
|
|
546
586
|
const complete = _completeFn ?? completeSimple;
|
|
547
587
|
|
|
548
|
-
// Estimate total tokens
|
|
588
|
+
// Estimate total tokens using the POST-truncation serializer view (issue #4665).
|
|
589
|
+
// serializeConversation caps large content blocks to TOOL_RESULT_MAX_CHARS
|
|
590
|
+
// before sending, so asking "does this fit in one pass?" must reflect that.
|
|
549
591
|
let totalTokens = 0;
|
|
550
592
|
for (const msg of currentMessages) {
|
|
551
|
-
totalTokens +=
|
|
593
|
+
totalTokens += estimateSerializedTokens(msg);
|
|
552
594
|
}
|
|
553
595
|
|
|
554
596
|
// Overhead for the prompt framing, system prompt, and response budget
|
|
@@ -561,12 +603,12 @@ export async function generateSummary(
|
|
|
561
603
|
return singlePassSummary(currentMessages, model, reserveTokens, apiKey, signal, customInstructions, previousSummary, complete);
|
|
562
604
|
}
|
|
563
605
|
|
|
564
|
-
// Chunked fallback: split messages and iteratively summarize
|
|
606
|
+
// Chunked fallback: split messages and iteratively summarize.
|
|
565
607
|
const chunks = chunkMessages(currentMessages, maxInputTokens);
|
|
566
608
|
let runningSummary = previousSummary;
|
|
567
609
|
|
|
568
610
|
for (let i = 0; i < chunks.length; i++) {
|
|
569
|
-
|
|
611
|
+
const chunkSummary = await singlePassSummary(
|
|
570
612
|
chunks[i],
|
|
571
613
|
model,
|
|
572
614
|
reserveTokens,
|
|
@@ -576,9 +618,83 @@ export async function generateSummary(
|
|
|
576
618
|
runningSummary,
|
|
577
619
|
complete,
|
|
578
620
|
);
|
|
621
|
+
|
|
622
|
+
// Degenerate-summary guard (issue #4665). UPDATE_SUMMARIZATION_PROMPT says
|
|
623
|
+
// "PRESERVE all existing information" — so if a chunk summary is empty or
|
|
624
|
+
// near-empty, propagating it forward actively reinforces the emptiness
|
|
625
|
+
// for every subsequent chunk.
|
|
626
|
+
//
|
|
627
|
+
// Strategy per chunk:
|
|
628
|
+
// 1. If degenerate, retry once. For the FIRST chunk with no prior
|
|
629
|
+
// context, retry with the initial prompt (undefined previousSummary)
|
|
630
|
+
// to break the poison chain at its source. For later chunks, retry
|
|
631
|
+
// with the same prompt state (runningSummary preserved) since the
|
|
632
|
+
// first failure may have been transient.
|
|
633
|
+
// 2. If the retry is also degenerate, warn and continue WITHOUT
|
|
634
|
+
// updating runningSummary — losing that chunk's content is still
|
|
635
|
+
// preferable to propagating emptiness forward, but the drop is now
|
|
636
|
+
// observable in logs.
|
|
637
|
+
if (isDegenerateSummary(chunkSummary)) {
|
|
638
|
+
const retryPreviousSummary = i === 0 && runningSummary === undefined
|
|
639
|
+
? undefined
|
|
640
|
+
: runningSummary;
|
|
641
|
+
const retry = await singlePassSummary(
|
|
642
|
+
chunks[i],
|
|
643
|
+
model,
|
|
644
|
+
reserveTokens,
|
|
645
|
+
apiKey,
|
|
646
|
+
signal,
|
|
647
|
+
customInstructions,
|
|
648
|
+
retryPreviousSummary,
|
|
649
|
+
complete,
|
|
650
|
+
);
|
|
651
|
+
if (!isDegenerateSummary(retry)) {
|
|
652
|
+
runningSummary = retry;
|
|
653
|
+
continue;
|
|
654
|
+
}
|
|
655
|
+
// Both attempts degenerate — log and skip without poisoning the chain.
|
|
656
|
+
// Using process.stderr directly so this doesn't require the logger
|
|
657
|
+
// dependency graph. Visible to operators reviewing compaction health.
|
|
658
|
+
process.stderr.write(
|
|
659
|
+
`[compaction] WARN: chunk ${i + 1}/${chunks.length} produced a degenerate summary on both attempts; dropping chunk content from summary.\n`,
|
|
660
|
+
);
|
|
661
|
+
continue;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
runningSummary = chunkSummary;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
// R6 (issue #4665 follow-up): if every chunk was degenerate and we have no
|
|
668
|
+
// runningSummary, do NOT silently return "" — the caller would write an
|
|
669
|
+
// empty compaction entry, destroying all context with no signal. Fall back
|
|
670
|
+
// to the original previousSummary if available; otherwise throw a named
|
|
671
|
+
// error so the compaction pipeline can skip appending the entry.
|
|
672
|
+
if (runningSummary === undefined) {
|
|
673
|
+
if (previousSummary !== undefined) {
|
|
674
|
+
process.stderr.write(
|
|
675
|
+
"[compaction] WARN: every chunk produced a degenerate summary; falling back to existing previousSummary.\n",
|
|
676
|
+
);
|
|
677
|
+
return previousSummary;
|
|
678
|
+
}
|
|
679
|
+
throw new CompactionProducedNoSummaryError(
|
|
680
|
+
`Compaction produced no usable summary: all ${chunks.length} chunk(s) were degenerate and no previousSummary was available.`,
|
|
681
|
+
);
|
|
579
682
|
}
|
|
580
683
|
|
|
581
|
-
return runningSummary
|
|
684
|
+
return runningSummary;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
/**
|
|
688
|
+
* Thrown when `generateSummary` could not produce any non-degenerate summary
|
|
689
|
+
* from the provided messages AND no previous summary was available to fall
|
|
690
|
+
* back to. Callers should catch this and skip writing a compaction entry
|
|
691
|
+
* rather than writing an empty string to the session history (issue #4665).
|
|
692
|
+
*/
|
|
693
|
+
export class CompactionProducedNoSummaryError extends Error {
|
|
694
|
+
constructor(message: string) {
|
|
695
|
+
super(message);
|
|
696
|
+
this.name = "CompactionProducedNoSummaryError";
|
|
697
|
+
}
|
|
582
698
|
}
|
|
583
699
|
|
|
584
700
|
/**
|
|
@@ -3,8 +3,14 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import type { AgentMessage } from "@gsd/pi-agent-core";
|
|
6
|
-
import type { Message } from "@gsd/pi-ai";
|
|
6
|
+
import type { AssistantMessage, Message } from "@gsd/pi-ai";
|
|
7
7
|
import { TOOL_RESULT_MAX_CHARS } from "../constants.js";
|
|
8
|
+
|
|
9
|
+
// Head/tail split for head+tail truncation. Keeps first half + last half up to
|
|
10
|
+
// TOOL_RESULT_MAX_CHARS total. Tool results and other large blocks put their
|
|
11
|
+
// information-dense content (exit codes, verdicts, commit hashes, pass/fail
|
|
12
|
+
// counts) at the tail — pure head-slicing discards that signal. See issue #4665.
|
|
13
|
+
const HEAD_TAIL_HALF = Math.floor(TOOL_RESULT_MAX_CHARS / 2);
|
|
8
14
|
import {
|
|
9
15
|
createBranchSummaryMessage,
|
|
10
16
|
createCompactionSummaryMessage,
|
|
@@ -189,13 +195,20 @@ export function createSummarizationMessage(promptText: string): [{ role: "user";
|
|
|
189
195
|
// TOOL_RESULT_MAX_CHARS imported from ../constants.js
|
|
190
196
|
|
|
191
197
|
/**
|
|
192
|
-
* Truncate text to a maximum character length for summarization
|
|
193
|
-
*
|
|
198
|
+
* Truncate text to a maximum character length for summarization, keeping both
|
|
199
|
+
* the head AND the tail. The tail is where information density lives for tool
|
|
200
|
+
* output (exit codes, verdicts, pass/fail counts, commit hashes), so pure
|
|
201
|
+
* head-slicing produced degenerate summaries (see issue #4665).
|
|
202
|
+
*
|
|
203
|
+
* Exported for test access only.
|
|
194
204
|
*/
|
|
195
|
-
function truncateForSummary(text: string, maxChars: number): string {
|
|
205
|
+
export function truncateForSummary(text: string, maxChars: number): string {
|
|
196
206
|
if (text.length <= maxChars) return text;
|
|
197
|
-
const
|
|
198
|
-
|
|
207
|
+
const half = Math.floor(maxChars / 2);
|
|
208
|
+
const head = text.slice(0, half);
|
|
209
|
+
const tail = text.slice(text.length - half);
|
|
210
|
+
const truncatedChars = text.length - (head.length + tail.length);
|
|
211
|
+
return `${head}\n\n[... ${truncatedChars} more characters truncated ...]\n\n${tail}`;
|
|
199
212
|
}
|
|
200
213
|
|
|
201
214
|
/**
|
|
@@ -203,11 +216,15 @@ function truncateForSummary(text: string, maxChars: number): string {
|
|
|
203
216
|
* This prevents the model from treating it as a conversation to continue.
|
|
204
217
|
* Call convertToLlm() first to handle custom message types.
|
|
205
218
|
*
|
|
206
|
-
*
|
|
207
|
-
*
|
|
219
|
+
* Every content block with a character count above TOOL_RESULT_MAX_CHARS is
|
|
220
|
+
* head+tail truncated. The issue #4665 fix broadened this from tool-results-
|
|
221
|
+
* only to every block type — large user pastes, assistant thinking, tool-call
|
|
222
|
+
* args, and bashExecution-derived blocks also bloat summarization input if
|
|
223
|
+
* uncapped.
|
|
208
224
|
*/
|
|
209
225
|
export function serializeConversation(messages: Message[]): string {
|
|
210
226
|
const parts: string[] = [];
|
|
227
|
+
const cap = TOOL_RESULT_MAX_CHARS;
|
|
211
228
|
|
|
212
229
|
for (const msg of messages) {
|
|
213
230
|
if (msg.role === "user") {
|
|
@@ -218,7 +235,7 @@ export function serializeConversation(messages: Message[]): string {
|
|
|
218
235
|
.filter((c): c is { type: "text"; text: string } => c.type === "text")
|
|
219
236
|
.map((c) => c.text)
|
|
220
237
|
.join("");
|
|
221
|
-
if (content) parts.push(`**User said:** ${content}`);
|
|
238
|
+
if (content) parts.push(`**User said:** ${truncateForSummary(content, cap)}`);
|
|
222
239
|
} else if (msg.role === "assistant") {
|
|
223
240
|
const textParts: string[] = [];
|
|
224
241
|
const thinkingParts: string[] = [];
|
|
@@ -239,13 +256,13 @@ export function serializeConversation(messages: Message[]): string {
|
|
|
239
256
|
}
|
|
240
257
|
|
|
241
258
|
if (thinkingParts.length > 0) {
|
|
242
|
-
parts.push(`**Assistant thinking:** ${thinkingParts.join("\n")}`);
|
|
259
|
+
parts.push(`**Assistant thinking:** ${truncateForSummary(thinkingParts.join("\n"), cap)}`);
|
|
243
260
|
}
|
|
244
261
|
if (textParts.length > 0) {
|
|
245
|
-
parts.push(`**Assistant responded:** ${textParts.join("\n")}`);
|
|
262
|
+
parts.push(`**Assistant responded:** ${truncateForSummary(textParts.join("\n"), cap)}`);
|
|
246
263
|
}
|
|
247
264
|
if (toolCalls.length > 0) {
|
|
248
|
-
parts.push(`**Assistant tool calls:** ${toolCalls.join("; ")}`);
|
|
265
|
+
parts.push(`**Assistant tool calls:** ${truncateForSummary(toolCalls.join("; "), cap)}`);
|
|
249
266
|
}
|
|
250
267
|
} else if (msg.role === "toolResult") {
|
|
251
268
|
const content = msg.content
|
|
@@ -253,7 +270,7 @@ export function serializeConversation(messages: Message[]): string {
|
|
|
253
270
|
.map((c) => c.text)
|
|
254
271
|
.join("");
|
|
255
272
|
if (content) {
|
|
256
|
-
parts.push(`**Tool result:** ${truncateForSummary(content,
|
|
273
|
+
parts.push(`**Tool result:** ${truncateForSummary(content, cap)}`);
|
|
257
274
|
}
|
|
258
275
|
}
|
|
259
276
|
}
|
|
@@ -261,6 +278,87 @@ export function serializeConversation(messages: Message[]): string {
|
|
|
261
278
|
return parts.join("\n\n");
|
|
262
279
|
}
|
|
263
280
|
|
|
281
|
+
// ============================================================================
|
|
282
|
+
// Token estimation for post-serialization size
|
|
283
|
+
// ============================================================================
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Estimate tokens for a message AFTER the summarization serializer will have
|
|
287
|
+
* capped its large content blocks. Use this when deciding chunk sizes for
|
|
288
|
+
* summarization — NOT when deciding whether to compact in the first place
|
|
289
|
+
* (that needs the real in-memory content size via `estimateTokens`).
|
|
290
|
+
*
|
|
291
|
+
* See issue #4665: the old chunker used real content size but the serializer
|
|
292
|
+
* truncated tool results to 2000 chars, so a single 400K-char tool result
|
|
293
|
+
* looked like 100K tokens (triggering tens of unnecessary chunks) but actually
|
|
294
|
+
* serialized to ~600 tokens.
|
|
295
|
+
*
|
|
296
|
+
* Colocated with `truncateForSummary` / `serializeConversation` so the two
|
|
297
|
+
* stay in sync — if the serialization cap changes, both functions pick it up
|
|
298
|
+
* from `TOOL_RESULT_MAX_CHARS`.
|
|
299
|
+
*/
|
|
300
|
+
export function estimateSerializedTokens(message: AgentMessage): number {
|
|
301
|
+
const cap = TOOL_RESULT_MAX_CHARS;
|
|
302
|
+
const capLen = (len: number) => Math.min(len, cap);
|
|
303
|
+
let chars = 0;
|
|
304
|
+
|
|
305
|
+
switch (message.role) {
|
|
306
|
+
case "user": {
|
|
307
|
+
const content = (message as { content: string | Array<{ type: string; text?: string }> }).content;
|
|
308
|
+
if (typeof content === "string") {
|
|
309
|
+
chars = capLen(content.length);
|
|
310
|
+
} else if (Array.isArray(content)) {
|
|
311
|
+
let total = 0;
|
|
312
|
+
for (const block of content) {
|
|
313
|
+
if (block.type === "text" && block.text) total += block.text.length;
|
|
314
|
+
}
|
|
315
|
+
chars = capLen(total);
|
|
316
|
+
}
|
|
317
|
+
return Math.ceil(chars / 4);
|
|
318
|
+
}
|
|
319
|
+
case "assistant": {
|
|
320
|
+
const assistant = message as AssistantMessage;
|
|
321
|
+
let textLen = 0;
|
|
322
|
+
let thinkingLen = 0;
|
|
323
|
+
let toolCallsLen = 0;
|
|
324
|
+
for (const block of assistant.content) {
|
|
325
|
+
if (block.type === "text") textLen += block.text.length;
|
|
326
|
+
else if (block.type === "thinking") thinkingLen += block.thinking.length;
|
|
327
|
+
else if (block.type === "toolCall") toolCallsLen += block.name.length + JSON.stringify(block.arguments).length;
|
|
328
|
+
}
|
|
329
|
+
chars = capLen(textLen) + capLen(thinkingLen) + capLen(toolCallsLen);
|
|
330
|
+
return Math.ceil(chars / 4);
|
|
331
|
+
}
|
|
332
|
+
case "custom":
|
|
333
|
+
case "toolResult": {
|
|
334
|
+
if (typeof message.content === "string") {
|
|
335
|
+
chars = capLen(message.content.length);
|
|
336
|
+
} else {
|
|
337
|
+
let textLen = 0;
|
|
338
|
+
let imageChars = 0;
|
|
339
|
+
for (const block of message.content) {
|
|
340
|
+
if (block.type === "text" && block.text) textLen += block.text.length;
|
|
341
|
+
if (block.type === "image") imageChars += 4800;
|
|
342
|
+
}
|
|
343
|
+
chars = capLen(textLen) + imageChars;
|
|
344
|
+
}
|
|
345
|
+
return Math.ceil(chars / 4);
|
|
346
|
+
}
|
|
347
|
+
case "bashExecution": {
|
|
348
|
+
chars = capLen(message.command.length + message.output.length);
|
|
349
|
+
return Math.ceil(chars / 4);
|
|
350
|
+
}
|
|
351
|
+
case "branchSummary":
|
|
352
|
+
case "compactionSummary": {
|
|
353
|
+
// Summary messages are already concise; don't truncate them.
|
|
354
|
+
chars = message.summary.length;
|
|
355
|
+
return Math.ceil(chars / 4);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
return 0;
|
|
360
|
+
}
|
|
361
|
+
|
|
264
362
|
// ============================================================================
|
|
265
363
|
// Summarization System Prompt
|
|
266
364
|
// ============================================================================
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { describe, it, mock, type Mock } from "node:test";
|
|
6
|
+
|
|
7
|
+
import type { Agent } from "@gsd/pi-agent-core";
|
|
8
|
+
import type { Api, AssistantMessage, Model } from "@gsd/pi-ai";
|
|
9
|
+
|
|
10
|
+
import { CompactionOrchestrator, type CompactionOrchestratorDeps } from "./compaction-orchestrator.js";
|
|
11
|
+
import { SessionManager } from "./session-manager.js";
|
|
12
|
+
|
|
13
|
+
function createMockModel(): Model<Api> {
|
|
14
|
+
return {
|
|
15
|
+
id: "claude-opus-4-6",
|
|
16
|
+
name: "Claude Opus 4.6",
|
|
17
|
+
api: "anthropic-messages" as Api,
|
|
18
|
+
provider: "anthropic",
|
|
19
|
+
baseUrl: "https://api.anthropic.com",
|
|
20
|
+
reasoning: false,
|
|
21
|
+
input: ["text"],
|
|
22
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
23
|
+
contextWindow: 200_000,
|
|
24
|
+
maxTokens: 16_384,
|
|
25
|
+
} as Model<Api>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function createAssistantMessage(
|
|
29
|
+
stopReason: AssistantMessage["stopReason"],
|
|
30
|
+
contentText: string,
|
|
31
|
+
): AssistantMessage {
|
|
32
|
+
return {
|
|
33
|
+
role: "assistant",
|
|
34
|
+
content: [{ type: "text", text: contentText }],
|
|
35
|
+
api: "anthropic-messages",
|
|
36
|
+
provider: "anthropic",
|
|
37
|
+
model: "claude-opus-4-6",
|
|
38
|
+
usage: {
|
|
39
|
+
input: 100,
|
|
40
|
+
output: 100,
|
|
41
|
+
cacheRead: 0,
|
|
42
|
+
cacheWrite: 0,
|
|
43
|
+
totalTokens: 200,
|
|
44
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
45
|
+
},
|
|
46
|
+
stopReason,
|
|
47
|
+
timestamp: Date.now(),
|
|
48
|
+
errorMessage: stopReason === "error" ? contentText : undefined,
|
|
49
|
+
} as AssistantMessage;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function wait(ms: number): Promise<void> {
|
|
53
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function createHarness(overrides?: {
|
|
57
|
+
cancelResult?: boolean;
|
|
58
|
+
willRetry?: boolean;
|
|
59
|
+
hasQueuedMessages?: boolean;
|
|
60
|
+
}) {
|
|
61
|
+
const dir = mkdtempSync(join(tmpdir(), "compaction-orchestrator-test-"));
|
|
62
|
+
const sessionManager = SessionManager.create(dir, dir);
|
|
63
|
+
sessionManager.appendMessage({ role: "user", content: "First user message" } as any);
|
|
64
|
+
sessionManager.appendMessage(createAssistantMessage("stop", "First assistant message"));
|
|
65
|
+
sessionManager.appendMessage({ role: "user", content: "Second user message" } as any);
|
|
66
|
+
|
|
67
|
+
const emittedEvents: Array<Record<string, unknown>> = [];
|
|
68
|
+
const continueFn = mock.fn(async () => {});
|
|
69
|
+
const replaceMessages = mock.fn((nextMessages: unknown[]) => {
|
|
70
|
+
(agent.state.messages as unknown[]) = nextMessages;
|
|
71
|
+
});
|
|
72
|
+
const agent = {
|
|
73
|
+
state: {
|
|
74
|
+
messages: [
|
|
75
|
+
{ role: "user", content: "queued follow-up" },
|
|
76
|
+
createAssistantMessage("error", "context overflow"),
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
continue: continueFn,
|
|
80
|
+
replaceMessages,
|
|
81
|
+
hasQueuedMessages: () => overrides?.hasQueuedMessages ?? false,
|
|
82
|
+
} as unknown as Agent;
|
|
83
|
+
|
|
84
|
+
const extensionRunner = {
|
|
85
|
+
hasHandlers: mock.fn(() => true),
|
|
86
|
+
emit: mock.fn(async () => ({ cancel: overrides?.cancelResult ?? true })),
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const deps: CompactionOrchestratorDeps = {
|
|
90
|
+
agent,
|
|
91
|
+
sessionManager,
|
|
92
|
+
settingsManager: {
|
|
93
|
+
getCompactionSettings: () => ({
|
|
94
|
+
enabled: true,
|
|
95
|
+
reserveTokens: 16_384,
|
|
96
|
+
keepRecentTokens: 1,
|
|
97
|
+
}),
|
|
98
|
+
} as any,
|
|
99
|
+
modelRegistry: {
|
|
100
|
+
isProviderRequestReady: () => true,
|
|
101
|
+
getApiKey: async () => undefined,
|
|
102
|
+
} as any,
|
|
103
|
+
getModel: () => createMockModel(),
|
|
104
|
+
getSessionId: () => "test-session",
|
|
105
|
+
getExtensionRunner: () => extensionRunner as any,
|
|
106
|
+
emit: (event) => emittedEvents.push(event as unknown as Record<string, unknown>),
|
|
107
|
+
disconnectFromAgent: () => {},
|
|
108
|
+
reconnectToAgent: () => {},
|
|
109
|
+
abort: async () => {},
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
dir,
|
|
114
|
+
agent,
|
|
115
|
+
continueFn,
|
|
116
|
+
replaceMessages,
|
|
117
|
+
emittedEvents,
|
|
118
|
+
extensionRunner,
|
|
119
|
+
orchestrator: new CompactionOrchestrator(deps),
|
|
120
|
+
cleanup: () => rmSync(dir, { recursive: true, force: true }),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
describe("CompactionOrchestrator", () => {
|
|
125
|
+
it("overflow cancel keeps retry intent and resumes the agent (#3971)", async (t) => {
|
|
126
|
+
const harness = createHarness({ willRetry: true });
|
|
127
|
+
t.after(harness.cleanup);
|
|
128
|
+
|
|
129
|
+
await (harness.orchestrator as any)._runAutoCompaction("overflow", true);
|
|
130
|
+
await wait(150);
|
|
131
|
+
|
|
132
|
+
const endEvent = harness.emittedEvents.find((event) => event.type === "auto_compaction_end");
|
|
133
|
+
assert.ok(endEvent, "should emit auto_compaction_end");
|
|
134
|
+
assert.equal(endEvent?.aborted, true, "cancelled compaction should be marked aborted");
|
|
135
|
+
assert.equal(endEvent?.willRetry, true, "overflow cancel should preserve retry intent");
|
|
136
|
+
assert.equal(harness.continueFn.mock.callCount(), 1, "overflow cancel should resume the agent");
|
|
137
|
+
assert.equal(harness.replaceMessages.mock.callCount(), 1, "retry follow-up should trim the error message when present");
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("threshold cancel stays non-retrying when no queued messages exist", async (t) => {
|
|
141
|
+
const harness = createHarness({ willRetry: false, hasQueuedMessages: false });
|
|
142
|
+
t.after(harness.cleanup);
|
|
143
|
+
|
|
144
|
+
await (harness.orchestrator as any)._runAutoCompaction("threshold", false);
|
|
145
|
+
await wait(150);
|
|
146
|
+
|
|
147
|
+
const endEvent = harness.emittedEvents.find((event) => event.type === "auto_compaction_end");
|
|
148
|
+
assert.ok(endEvent, "should emit auto_compaction_end");
|
|
149
|
+
assert.equal(endEvent?.aborted, true, "cancelled compaction should be marked aborted");
|
|
150
|
+
assert.equal(endEvent?.willRetry, false, "threshold cancel should stay non-retrying");
|
|
151
|
+
assert.equal(harness.continueFn.mock.callCount(), 0, "threshold cancel should not resume the agent without queued work");
|
|
152
|
+
assert.equal(harness.replaceMessages.mock.callCount(), 0, "non-retry cancel should not trim messages");
|
|
153
|
+
});
|
|
154
|
+
});
|
|
@@ -14,6 +14,7 @@ import type { AssistantMessage, Model } from "@gsd/pi-ai";
|
|
|
14
14
|
import { isContextOverflow } from "@gsd/pi-ai";
|
|
15
15
|
import {
|
|
16
16
|
type CompactionResult,
|
|
17
|
+
CompactionProducedNoSummaryError,
|
|
17
18
|
calculateContextTokens,
|
|
18
19
|
compact,
|
|
19
20
|
estimateContextTokens,
|
|
@@ -332,8 +333,9 @@ export class CompactionOrchestrator {
|
|
|
332
333
|
type: "auto_compaction_end",
|
|
333
334
|
result: undefined,
|
|
334
335
|
aborted: true,
|
|
335
|
-
willRetry
|
|
336
|
+
willRetry,
|
|
336
337
|
});
|
|
338
|
+
this._scheduleAutoCompactionFollowup(willRetry);
|
|
337
339
|
return;
|
|
338
340
|
}
|
|
339
341
|
|
|
@@ -391,24 +393,15 @@ export class CompactionOrchestrator {
|
|
|
391
393
|
|
|
392
394
|
const result: CompactionResult = { summary, firstKeptEntryId, tokensBefore, details };
|
|
393
395
|
this._deps.emit({ type: "auto_compaction_end", result, aborted: false, willRetry });
|
|
394
|
-
|
|
395
|
-
if (willRetry) {
|
|
396
|
-
const messages = this._deps.agent.state.messages;
|
|
397
|
-
const lastMsg = messages[messages.length - 1];
|
|
398
|
-
if (lastMsg?.role === "assistant" && (lastMsg as AssistantMessage).stopReason === "error") {
|
|
399
|
-
this._deps.agent.replaceMessages(messages.slice(0, -1));
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
setTimeout(() => {
|
|
403
|
-
this._deps.agent.continue().catch(() => {});
|
|
404
|
-
}, 100);
|
|
405
|
-
} else if (this._deps.agent.hasQueuedMessages()) {
|
|
406
|
-
setTimeout(() => {
|
|
407
|
-
this._deps.agent.continue().catch(() => {});
|
|
408
|
-
}, 100);
|
|
409
|
-
}
|
|
396
|
+
this._scheduleAutoCompactionFollowup(willRetry);
|
|
410
397
|
} catch (error) {
|
|
411
|
-
|
|
398
|
+
// Distinguish the "no usable summary" failure (issue #4665) so the UI
|
|
399
|
+
// can surface a clearer message than a generic compaction failure.
|
|
400
|
+
// Either way we drop the would-be compaction entry rather than writing
|
|
401
|
+
// an empty string to the session history.
|
|
402
|
+
const errorMessage = error instanceof CompactionProducedNoSummaryError
|
|
403
|
+
? `Compaction produced no usable summary — session history preserved as-is. (${error.message})`
|
|
404
|
+
: getErrorMessage(error);
|
|
412
405
|
this._deps.emit({
|
|
413
406
|
type: "auto_compaction_end",
|
|
414
407
|
result: undefined,
|
|
@@ -423,4 +416,25 @@ export class CompactionOrchestrator {
|
|
|
423
416
|
this._autoCompactionAbortController = undefined;
|
|
424
417
|
}
|
|
425
418
|
}
|
|
419
|
+
|
|
420
|
+
private _scheduleAutoCompactionFollowup(willRetry: boolean): void {
|
|
421
|
+
if (willRetry) {
|
|
422
|
+
const messages = this._deps.agent.state.messages;
|
|
423
|
+
const lastMsg = messages[messages.length - 1];
|
|
424
|
+
if (lastMsg?.role === "assistant" && (lastMsg as AssistantMessage).stopReason === "error") {
|
|
425
|
+
this._deps.agent.replaceMessages(messages.slice(0, -1));
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
setTimeout(() => {
|
|
429
|
+
this._deps.agent.continue().catch(() => {});
|
|
430
|
+
}, 100);
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
if (this._deps.agent.hasQueuedMessages()) {
|
|
435
|
+
setTimeout(() => {
|
|
436
|
+
this._deps.agent.continue().catch(() => {});
|
|
437
|
+
}, 100);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
426
440
|
}
|
|
@@ -3,7 +3,7 @@ import test from "node:test";
|
|
|
3
3
|
|
|
4
4
|
import type { Message } from "@gsd/pi-ai";
|
|
5
5
|
|
|
6
|
-
import { serializeConversation } from "./compaction/index.js";
|
|
6
|
+
import { serializeConversation, truncateForSummary } from "./compaction/index.js";
|
|
7
7
|
|
|
8
8
|
test("serializeConversation uses narrative role markers instead of chat-style delimiters (#4054)", () => {
|
|
9
9
|
const messages: Message[] = [
|
|
@@ -48,3 +48,70 @@ test("serializeConversation uses narrative role markers instead of chat-style de
|
|
|
48
48
|
assert.ok(!serialized.includes("[Assistant]:"), "chat-style [Assistant]: markers should not remain");
|
|
49
49
|
assert.ok(!serialized.includes("[Tool result]:"), "chat-style [Tool result]: markers should not remain");
|
|
50
50
|
});
|
|
51
|
+
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// #4665 regression: head+tail truncation keeps verdicts/results
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
|
|
56
|
+
test("(#4665) truncateForSummary keeps both head AND tail — tail carries result/verdict text", () => {
|
|
57
|
+
// Construct a 10K-char fixture where the HEAD is "setup noise" and the TAIL
|
|
58
|
+
// contains a result line. The old head-only truncation would drop the tail
|
|
59
|
+
// and lose the result. The fix preserves both.
|
|
60
|
+
const head = "setup log line A\n".repeat(500); // ~8500 chars of setup
|
|
61
|
+
const tail = "RESULT: 258 passed, 0 failed. exit_code=0 commit=abc1234";
|
|
62
|
+
const input = head + tail;
|
|
63
|
+
|
|
64
|
+
const out = truncateForSummary(input, 2_000);
|
|
65
|
+
|
|
66
|
+
assert.ok(out.length < input.length, "must truncate when over cap");
|
|
67
|
+
assert.ok(out.includes("setup log line A"), "head content preserved");
|
|
68
|
+
assert.ok(out.includes("RESULT: 258 passed"), "tail content preserved (issue #4665)");
|
|
69
|
+
assert.match(out, /more characters truncated/, "emits an elision marker");
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test("(#4665) truncateForSummary is a no-op when input is within the cap", () => {
|
|
73
|
+
const input = "short enough";
|
|
74
|
+
assert.equal(truncateForSummary(input, 2_000), input);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test("(#4665) serializeConversation caps large user content, not just tool results", () => {
|
|
78
|
+
// Pre-fix, only toolResult blocks were capped. A large user paste could
|
|
79
|
+
// still blow out the chunker's token math and the LLM's input budget.
|
|
80
|
+
const hugeUserText = "U".repeat(100_000);
|
|
81
|
+
const hugeAssistantText = "A".repeat(100_000);
|
|
82
|
+
const hugeToolResult = "T".repeat(100_000);
|
|
83
|
+
|
|
84
|
+
const messages: Message[] = [
|
|
85
|
+
{ role: "user", content: hugeUserText } as Message,
|
|
86
|
+
{
|
|
87
|
+
role: "assistant",
|
|
88
|
+
content: [{ type: "text", text: hugeAssistantText }],
|
|
89
|
+
api: "anthropic-messages",
|
|
90
|
+
provider: "anthropic",
|
|
91
|
+
model: "claude-sonnet-4-6",
|
|
92
|
+
usage: {
|
|
93
|
+
input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0,
|
|
94
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
95
|
+
},
|
|
96
|
+
stopReason: "stop",
|
|
97
|
+
timestamp: Date.now(),
|
|
98
|
+
} as Message,
|
|
99
|
+
{
|
|
100
|
+
role: "toolResult",
|
|
101
|
+
content: [{ type: "text", text: hugeToolResult }],
|
|
102
|
+
toolName: "Bash",
|
|
103
|
+
toolCallId: "tool-huge",
|
|
104
|
+
} as Message,
|
|
105
|
+
];
|
|
106
|
+
|
|
107
|
+
const serialized = serializeConversation(messages);
|
|
108
|
+
|
|
109
|
+
// Each block is truncated independently to TOOL_RESULT_MAX_CHARS plus the
|
|
110
|
+
// framing marker, so the serialized output should be a tiny fraction of
|
|
111
|
+
// the raw 300K chars of content.
|
|
112
|
+
assert.ok(
|
|
113
|
+
serialized.length < 10_000,
|
|
114
|
+
`serialized output should be small after capping all blocks, got ${serialized.length} chars`,
|
|
115
|
+
);
|
|
116
|
+
assert.match(serialized, /more characters truncated/, "truncation marker present");
|
|
117
|
+
});
|