gsd-pi 2.58.0-dev.778d6ac → 2.58.0-dev.d63175c
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cli.js +35 -49
- package/dist/headless-ui.d.ts +0 -17
- package/dist/headless-ui.js +3 -97
- package/dist/headless.js +6 -67
- package/dist/help-text.js +0 -1
- package/dist/onboarding.js +0 -44
- package/dist/resource-loader.js +1 -16
- package/dist/resources/agents/researcher.md +1 -1
- package/dist/resources/extensions/ask-user-questions.js +3 -16
- package/dist/resources/extensions/async-jobs/extension-manifest.json +1 -1
- package/dist/resources/extensions/bg-shell/extension-manifest.json +1 -1
- package/dist/resources/extensions/browser-tools/extension-manifest.json +1 -1
- package/dist/resources/extensions/claude-code-cli/partial-builder.js +6 -14
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +36 -59
- package/dist/resources/extensions/context7/extension-manifest.json +1 -1
- package/dist/resources/extensions/get-secrets-from-user.js +5 -8
- package/dist/resources/extensions/google-search/extension-manifest.json +1 -1
- package/dist/resources/extensions/google-search/index.js +1 -2
- package/dist/resources/extensions/gsd/auto/phases.js +21 -25
- package/dist/resources/extensions/gsd/auto-artifact-paths.js +2 -2
- package/dist/resources/extensions/gsd/auto-dashboard.js +20 -37
- package/dist/resources/extensions/gsd/auto-dispatch.js +2 -17
- package/dist/resources/extensions/gsd/auto-model-selection.js +3 -26
- package/dist/resources/extensions/gsd/auto-post-unit.js +4 -16
- package/dist/resources/extensions/gsd/auto-prompts.js +1 -1
- package/dist/resources/extensions/gsd/auto-recovery.js +5 -13
- package/dist/resources/extensions/gsd/auto-start.js +22 -35
- package/dist/resources/extensions/gsd/auto-worktree.js +12 -196
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +0 -32
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +8 -80
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +1 -32
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +18 -33
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +11 -44
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +0 -67
- package/dist/resources/extensions/gsd/captures.js +4 -56
- package/dist/resources/extensions/gsd/db-writer.js +8 -116
- package/dist/resources/extensions/gsd/doctor-git-checks.js +0 -28
- package/dist/resources/extensions/gsd/doctor-providers.js +1 -2
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +4 -5
- package/dist/resources/extensions/gsd/doctor.js +1 -3
- package/dist/resources/extensions/gsd/error-classifier.js +10 -13
- package/dist/resources/extensions/gsd/extension-manifest.json +1 -16
- package/dist/resources/extensions/gsd/forensics.js +20 -123
- package/dist/resources/extensions/gsd/git-service.js +1 -23
- package/dist/resources/extensions/gsd/gitignore.js +0 -33
- package/dist/resources/extensions/gsd/gsd-db.js +9 -36
- package/dist/resources/extensions/gsd/guided-flow.js +44 -106
- package/dist/resources/extensions/gsd/health-widget-core.js +0 -31
- package/dist/resources/extensions/gsd/health-widget.js +0 -17
- package/dist/resources/extensions/gsd/index.js +1 -1
- package/dist/resources/extensions/gsd/memory-extractor.js +0 -7
- package/dist/resources/extensions/gsd/migrate-external.js +1 -8
- package/dist/resources/extensions/gsd/model-cost-table.js +0 -18
- package/dist/resources/extensions/gsd/model-router.js +1 -35
- package/dist/resources/extensions/gsd/native-git-bridge.js +0 -17
- package/dist/resources/extensions/gsd/notifications.js +1 -16
- package/dist/resources/extensions/gsd/parallel-eligibility.js +2 -13
- package/dist/resources/extensions/gsd/parallel-merge.js +5 -78
- package/dist/resources/extensions/gsd/parsers-legacy.js +3 -20
- package/dist/resources/extensions/gsd/paths.js +0 -43
- package/dist/resources/extensions/gsd/preferences-models.js +1 -14
- package/dist/resources/extensions/gsd/preferences-types.js +1 -2
- package/dist/resources/extensions/gsd/preferences.js +16 -13
- package/dist/resources/extensions/gsd/prompt-loader.js +1 -4
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +2 -4
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +1 -1
- package/dist/resources/extensions/gsd/prompts/discuss.md +1 -1
- package/dist/resources/extensions/gsd/prompts/execute-task.md +1 -3
- package/dist/resources/extensions/gsd/prompts/forensics.md +2 -2
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +0 -2
- package/dist/resources/extensions/gsd/prompts/rethink.md +1 -1
- package/dist/resources/extensions/gsd/prompts/triage-captures.md +0 -1
- package/dist/resources/extensions/gsd/repo-identity.js +11 -205
- package/dist/resources/extensions/gsd/rethink.js +0 -5
- package/dist/resources/extensions/gsd/roadmap-slices.js +4 -5
- package/dist/resources/extensions/gsd/state.js +27 -85
- package/dist/resources/extensions/gsd/tests/dist-redirect.mjs +1 -20
- package/dist/resources/extensions/gsd/tools/complete-task.js +71 -34
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +2 -12
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +1 -29
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +3 -14
- package/dist/resources/extensions/gsd/triage-resolution.js +7 -22
- package/dist/resources/extensions/gsd/undo.js +2 -2
- package/dist/resources/extensions/gsd/unit-ownership.js +33 -164
- package/dist/resources/extensions/gsd/verdict-parser.js +8 -20
- package/dist/resources/extensions/gsd/workflow-manifest.js +5 -24
- package/dist/resources/extensions/gsd/workflow-projections.js +63 -95
- package/dist/resources/extensions/gsd/workflow-reconcile.js +5 -35
- package/dist/resources/extensions/gsd/workspace-index.js +0 -24
- package/dist/resources/extensions/gsd/worktree-manager.js +1 -105
- package/dist/resources/extensions/gsd/worktree-resolver.js +3 -20
- package/dist/resources/extensions/mcp-client/index.js +7 -11
- package/dist/resources/extensions/search-the-web/extension-manifest.json +1 -1
- package/dist/resources/extensions/shared/interview-ui.js +1 -11
- package/dist/resources/skills/create-gsd-extension/SKILL.md +3 -5
- package/dist/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +4 -5
- package/dist/resources/skills/create-gsd-extension/workflows/add-capability.md +2 -2
- package/dist/resources/skills/create-gsd-extension/workflows/create-extension.md +4 -4
- package/dist/resources/skills/create-gsd-extension/workflows/debug-extension.md +3 -5
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +17 -17
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
- package/dist/web/standalone/.next/required-server-files.json +1 -1
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +2 -2
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- 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 +2 -2
- 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 +2 -2
- package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +2 -2
- 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 +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +17 -17
- package/dist/web/standalone/.next/server/chunks/2229.js +2 -2
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/6502.8b732f67a11b11b4.js +9 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-a1c1e452c6b32d04.js → webpack-61d3afac6d0f0ce7.js} +1 -1
- package/dist/web/standalone/.next/static/css/a58ef8a151aa0493.css +1 -0
- package/dist/web/standalone/server.js +1 -1
- package/dist/web-mode.js +1 -2
- package/package.json +2 -2
- package/packages/native/dist/ast/index.js +5 -9
- package/packages/native/dist/ast/types.js +1 -2
- package/packages/native/dist/clipboard/index.js +7 -12
- package/packages/native/dist/clipboard/types.js +1 -2
- package/packages/native/dist/diff/index.js +7 -12
- package/packages/native/dist/diff/types.js +1 -2
- package/packages/native/dist/fd/index.js +3 -6
- package/packages/native/dist/fd/types.js +1 -2
- package/packages/native/dist/glob/index.js +5 -9
- package/packages/native/dist/glob/types.js +1 -2
- package/packages/native/dist/grep/index.js +5 -9
- package/packages/native/dist/grep/types.js +1 -2
- package/packages/native/dist/gsd-parser/index.js +11 -18
- package/packages/native/dist/gsd-parser/types.js +1 -2
- package/packages/native/dist/highlight/index.js +7 -12
- package/packages/native/dist/highlight/types.js +1 -2
- package/packages/native/dist/html/index.js +3 -6
- package/packages/native/dist/html/types.js +1 -2
- package/packages/native/dist/image/index.js +5 -10
- package/packages/native/dist/image/types.js +4 -7
- package/packages/native/dist/index.js +17 -70
- package/packages/native/dist/json-parse/index.js +8 -13
- package/packages/native/dist/native.js +10 -47
- package/packages/native/dist/ps/index.js +9 -15
- package/packages/native/dist/ps/types.js +1 -2
- package/packages/native/dist/stream-process/index.js +7 -12
- package/packages/native/dist/text/index.js +14 -24
- package/packages/native/dist/text/types.js +2 -5
- package/packages/native/dist/truncate/index.js +7 -12
- package/packages/native/dist/ttsr/index.js +7 -12
- package/packages/native/dist/ttsr/types.js +1 -2
- package/packages/native/dist/xxhash/index.js +5 -9
- package/packages/native/package.json +19 -19
- package/packages/native/src/native.ts +8 -9
- package/packages/pi-agent-core/dist/agent-loop.js +2 -3
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/dist/proxy.d.ts +1 -1
- package/packages/pi-agent-core/dist/proxy.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/proxy.js.map +1 -1
- package/packages/pi-agent-core/src/agent-loop.ts +2 -3
- package/packages/pi-agent-core/src/proxy.ts +1 -1
- package/packages/pi-ai/dist/env-api-keys.js +0 -1
- package/packages/pi-ai/dist/env-api-keys.js.map +1 -1
- package/packages/pi-ai/dist/index.d.ts +0 -1
- package/packages/pi-ai/dist/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/index.js +0 -1
- package/packages/pi-ai/dist/index.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.js +2 -19
- package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
- package/packages/pi-ai/dist/types.d.ts +3 -3
- package/packages/pi-ai/dist/types.d.ts.map +1 -1
- package/packages/pi-ai/dist/types.js.map +1 -1
- package/packages/pi-ai/dist/utils/json-parse.d.ts +0 -3
- package/packages/pi-ai/dist/utils/json-parse.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/json-parse.js +1 -24
- package/packages/pi-ai/dist/utils/json-parse.js.map +1 -1
- package/packages/pi-ai/src/env-api-keys.ts +0 -1
- package/packages/pi-ai/src/index.ts +0 -1
- package/packages/pi-ai/src/providers/anthropic-shared.ts +2 -17
- package/packages/pi-ai/src/types.ts +2 -3
- package/packages/pi-ai/src/utils/json-parse.ts +1 -28
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +0 -4
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +0 -31
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +1 -17
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js +2 -62
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/exec.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/exec.js +1 -3
- package/packages/pi-coding-agent/dist/core/exec.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/index.d.ts +0 -4
- package/packages/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/index.js +0 -2
- package/packages/pi-coding-agent/dist/core/extensions/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +0 -5
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +0 -5
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/core/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/index.js +1 -1
- package/packages/pi-coding-agent/dist/core/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/index.js +0 -3
- package/packages/pi-coding-agent/dist/core/lsp/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/lspmux.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/lspmux.js +0 -3
- package/packages/pi-coding-agent/dist/core/lsp/lspmux.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/messages.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/messages.js +2 -31
- package/packages/pi-coding-agent/dist/core/messages.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js +0 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.d.ts +0 -10
- package/packages/pi-coding-agent/dist/core/resource-loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.js +1 -12
- package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts +0 -6
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js +1 -48
- package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/hashline-read.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/hashline-read.js +3 -10
- package/packages/pi-coding-agent/dist/core/tools/hashline-read.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/read.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/read.js +4 -13
- package/packages/pi-coding-agent/dist/core/tools/read.js.map +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts +2 -2
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +1 -1
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +0 -4
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/remote-terminal.d.ts +0 -1
- package/packages/pi-coding-agent/dist/modes/rpc/remote-terminal.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/remote-terminal.js +0 -5
- package/packages/pi-coding-agent/dist/modes/rpc/remote-terminal.js.map +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +1 -38
- package/packages/pi-coding-agent/src/core/compaction/compaction.ts +1 -94
- package/packages/pi-coding-agent/src/core/exec.ts +1 -3
- package/packages/pi-coding-agent/src/core/extensions/index.ts +0 -4
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +0 -5
- package/packages/pi-coding-agent/src/core/index.ts +0 -6
- package/packages/pi-coding-agent/src/core/lsp/index.ts +0 -3
- package/packages/pi-coding-agent/src/core/lsp/lspmux.ts +0 -3
- package/packages/pi-coding-agent/src/core/messages.ts +2 -29
- package/packages/pi-coding-agent/src/core/model-resolver.ts +0 -1
- package/packages/pi-coding-agent/src/core/resource-loader.ts +1 -20
- package/packages/pi-coding-agent/src/core/retry-handler.ts +1 -52
- package/packages/pi-coding-agent/src/core/tools/hashline-read.ts +3 -11
- package/packages/pi-coding-agent/src/core/tools/read.ts +4 -14
- package/packages/pi-coding-agent/src/index.ts +0 -6
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +0 -7
- package/packages/pi-coding-agent/src/modes/rpc/remote-terminal.ts +0 -6
- package/packages/pi-tui/dist/terminal.d.ts +0 -2
- package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
- package/packages/pi-tui/dist/terminal.js +0 -9
- package/packages/pi-tui/dist/terminal.js.map +1 -1
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +0 -9
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/src/terminal.ts +0 -14
- package/packages/pi-tui/src/tui.ts +0 -8
- package/scripts/ensure-workspace-builds.cjs +14 -45
- package/src/resources/agents/researcher.md +1 -1
- package/src/resources/extensions/ask-user-questions.ts +3 -21
- package/src/resources/extensions/async-jobs/extension-manifest.json +1 -1
- package/src/resources/extensions/bg-shell/extension-manifest.json +1 -1
- package/src/resources/extensions/browser-tools/extension-manifest.json +1 -1
- package/src/resources/extensions/claude-code-cli/partial-builder.ts +6 -13
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +35 -63
- package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +0 -28
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +1 -108
- package/src/resources/extensions/context7/extension-manifest.json +1 -1
- package/src/resources/extensions/get-secrets-from-user.ts +5 -8
- package/src/resources/extensions/google-search/extension-manifest.json +1 -1
- package/src/resources/extensions/google-search/index.ts +1 -2
- package/src/resources/extensions/gsd/auto/loop-deps.ts +0 -1
- package/src/resources/extensions/gsd/auto/phases.ts +34 -43
- package/src/resources/extensions/gsd/auto-artifact-paths.ts +2 -2
- package/src/resources/extensions/gsd/auto-dashboard.ts +19 -37
- package/src/resources/extensions/gsd/auto-dispatch.ts +2 -18
- package/src/resources/extensions/gsd/auto-model-selection.ts +5 -26
- package/src/resources/extensions/gsd/auto-post-unit.ts +4 -18
- package/src/resources/extensions/gsd/auto-prompts.ts +1 -1
- package/src/resources/extensions/gsd/auto-recovery.ts +5 -12
- package/src/resources/extensions/gsd/auto-start.ts +26 -35
- package/src/resources/extensions/gsd/auto-worktree.ts +9 -190
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +0 -31
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +8 -85
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +1 -38
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +19 -31
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +11 -50
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +0 -75
- package/src/resources/extensions/gsd/captures.ts +3 -63
- package/src/resources/extensions/gsd/db-writer.ts +7 -140
- package/src/resources/extensions/gsd/doctor-git-checks.ts +0 -26
- package/src/resources/extensions/gsd/doctor-providers.ts +1 -2
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +4 -5
- package/src/resources/extensions/gsd/doctor.ts +1 -3
- package/src/resources/extensions/gsd/error-classifier.ts +11 -14
- package/src/resources/extensions/gsd/extension-manifest.json +1 -16
- package/src/resources/extensions/gsd/forensics.ts +20 -144
- package/src/resources/extensions/gsd/git-service.ts +3 -26
- package/src/resources/extensions/gsd/gitignore.ts +0 -33
- package/src/resources/extensions/gsd/gsd-db.ts +7 -43
- package/src/resources/extensions/gsd/guided-flow.ts +45 -114
- package/src/resources/extensions/gsd/health-widget-core.ts +0 -34
- package/src/resources/extensions/gsd/health-widget.ts +0 -17
- package/src/resources/extensions/gsd/index.ts +0 -1
- package/src/resources/extensions/gsd/memory-extractor.ts +0 -8
- package/src/resources/extensions/gsd/migrate-external.ts +1 -9
- package/src/resources/extensions/gsd/model-cost-table.ts +0 -19
- package/src/resources/extensions/gsd/model-router.ts +1 -35
- package/src/resources/extensions/gsd/native-git-bridge.ts +0 -17
- package/src/resources/extensions/gsd/notifications.ts +0 -16
- package/src/resources/extensions/gsd/parallel-eligibility.ts +2 -15
- package/src/resources/extensions/gsd/parallel-merge.ts +4 -87
- package/src/resources/extensions/gsd/parsers-legacy.ts +3 -22
- package/src/resources/extensions/gsd/paths.ts +0 -42
- package/src/resources/extensions/gsd/preferences-models.ts +1 -14
- package/src/resources/extensions/gsd/preferences-types.ts +1 -2
- package/src/resources/extensions/gsd/preferences.ts +15 -13
- package/src/resources/extensions/gsd/prompt-loader.ts +1 -4
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/complete-slice.md +2 -4
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +1 -1
- package/src/resources/extensions/gsd/prompts/discuss.md +1 -1
- package/src/resources/extensions/gsd/prompts/execute-task.md +1 -3
- package/src/resources/extensions/gsd/prompts/forensics.md +2 -2
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +0 -2
- package/src/resources/extensions/gsd/prompts/rethink.md +1 -1
- package/src/resources/extensions/gsd/prompts/triage-captures.md +0 -1
- package/src/resources/extensions/gsd/repo-identity.ts +11 -186
- package/src/resources/extensions/gsd/rethink.ts +0 -6
- package/src/resources/extensions/gsd/roadmap-slices.ts +4 -5
- package/src/resources/extensions/gsd/state.ts +32 -84
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +0 -29
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +1 -71
- package/src/resources/extensions/gsd/tests/captures.test.ts +0 -103
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +0 -27
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +0 -21
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +12 -7
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +5 -78
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +0 -29
- package/src/resources/extensions/gsd/tests/discuss-queued-milestones.test.ts +0 -40
- package/src/resources/extensions/gsd/tests/dist-redirect.mjs +1 -20
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +0 -117
- package/src/resources/extensions/gsd/tests/empty-db-reconciliation.test.ts +79 -0
- package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +0 -31
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +12 -125
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +0 -67
- package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +1 -111
- package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +0 -101
- package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +0 -59
- package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +0 -110
- package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +2 -85
- package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +0 -34
- package/src/resources/extensions/gsd/tests/model-router.test.ts +3 -68
- package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +0 -28
- package/src/resources/extensions/gsd/tests/notifications.test.ts +0 -45
- package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +1 -33
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +0 -29
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +0 -38
- package/src/resources/extensions/gsd/tests/reassess-handler.test.ts +0 -117
- package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +0 -97
- package/src/resources/extensions/gsd/tests/secure-env-collect.test.ts +0 -134
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +1 -2
- package/src/resources/extensions/gsd/tests/triage-resolution.test.ts +0 -8
- package/src/resources/extensions/gsd/tests/unit-ownership.test.ts +17 -100
- package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +1 -4
- package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +0 -48
- package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +0 -92
- package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +2 -4
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +1 -48
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +5 -29
- package/src/resources/extensions/gsd/tools/complete-task.ts +74 -36
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +1 -13
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +0 -36
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +2 -20
- package/src/resources/extensions/gsd/triage-resolution.ts +6 -23
- package/src/resources/extensions/gsd/types.ts +2 -4
- package/src/resources/extensions/gsd/undo.ts +2 -2
- package/src/resources/extensions/gsd/unit-ownership.ts +35 -206
- package/src/resources/extensions/gsd/verdict-parser.ts +6 -21
- package/src/resources/extensions/gsd/workflow-logger.ts +1 -3
- package/src/resources/extensions/gsd/workflow-manifest.ts +5 -22
- package/src/resources/extensions/gsd/workflow-projections.ts +64 -97
- package/src/resources/extensions/gsd/workflow-reconcile.ts +10 -39
- package/src/resources/extensions/gsd/workspace-index.ts +0 -30
- package/src/resources/extensions/gsd/worktree-manager.ts +1 -120
- package/src/resources/extensions/gsd/worktree-resolver.ts +3 -22
- package/src/resources/extensions/mcp-client/index.ts +7 -13
- package/src/resources/extensions/search-the-web/extension-manifest.json +1 -1
- package/src/resources/extensions/shared/interview-ui.ts +1 -12
- package/src/resources/skills/create-gsd-extension/SKILL.md +3 -5
- package/src/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +4 -5
- package/src/resources/skills/create-gsd-extension/workflows/add-capability.md +2 -2
- package/src/resources/skills/create-gsd-extension/workflows/create-extension.md +4 -4
- package/src/resources/skills/create-gsd-extension/workflows/debug-extension.md +3 -5
- package/dist/resources/extensions/gsd/milestone-validation-gates.js +0 -45
- package/dist/resources/extensions/ollama/index.js +0 -112
- package/dist/resources/extensions/ollama/model-capabilities.js +0 -115
- package/dist/resources/extensions/ollama/ollama-client.js +0 -168
- package/dist/resources/extensions/ollama/ollama-commands.js +0 -194
- package/dist/resources/extensions/ollama/ollama-discovery.js +0 -69
- package/dist/resources/extensions/ollama/ollama-tool.js +0 -184
- package/dist/resources/extensions/ollama/types.js +0 -2
- package/dist/startup-model-validation.d.ts +0 -39
- package/dist/startup-model-validation.js +0 -50
- package/dist/web/standalone/.next/static/chunks/6502.7593d7797a4b3999.js +0 -9
- package/dist/web/standalone/.next/static/css/f6e8833d46e738d8.css +0 -1
- package/packages/native/src/__tests__/module-compat.test.mjs +0 -91
- package/packages/pi-agent-core/src/agent-loop.test.ts +0 -45
- package/packages/pi-ai/dist/providers/anthropic-shared.test.d.ts +0 -2
- package/packages/pi-ai/dist/providers/anthropic-shared.test.d.ts.map +0 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.test.js +0 -25
- package/packages/pi-ai/dist/providers/anthropic-shared.test.js.map +0 -1
- package/packages/pi-ai/dist/utils/repair-tool-json.d.ts +0 -37
- package/packages/pi-ai/dist/utils/repair-tool-json.d.ts.map +0 -1
- package/packages/pi-ai/dist/utils/repair-tool-json.js +0 -75
- package/packages/pi-ai/dist/utils/repair-tool-json.js.map +0 -1
- package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.d.ts +0 -2
- package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.d.ts.map +0 -1
- package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js +0 -73
- package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js.map +0 -1
- package/packages/pi-ai/src/providers/anthropic-shared.test.ts +0 -29
- package/packages/pi-ai/src/utils/repair-tool-json.ts +0 -88
- package/packages/pi-ai/src/utils/tests/repair-tool-json.test.ts +0 -102
- package/packages/pi-coding-agent/dist/core/compaction/compaction.test.d.ts +0 -6
- package/packages/pi-coding-agent/dist/core/compaction/compaction.test.d.ts.map +0 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.test.js +0 -176
- package/packages/pi-coding-agent/dist/core/compaction/compaction.test.js.map +0 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.d.ts +0 -28
- package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.d.ts.map +0 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.js +0 -37
- package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.js.map +0 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.test.d.ts +0 -2
- package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.test.d.ts.map +0 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.test.js +0 -63
- package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.test.js.map +0 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-sort.d.ts +0 -19
- package/packages/pi-coding-agent/dist/core/extensions/extension-sort.d.ts.map +0 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-sort.js +0 -115
- package/packages/pi-coding-agent/dist/core/extensions/extension-sort.js.map +0 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-sort.test.d.ts +0 -2
- package/packages/pi-coding-agent/dist/core/extensions/extension-sort.test.d.ts.map +0 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-sort.test.js +0 -109
- package/packages/pi-coding-agent/dist/core/extensions/extension-sort.test.js.map +0 -1
- package/packages/pi-coding-agent/dist/core/image-overflow-recovery.d.ts +0 -44
- package/packages/pi-coding-agent/dist/core/image-overflow-recovery.d.ts.map +0 -1
- package/packages/pi-coding-agent/dist/core/image-overflow-recovery.js +0 -97
- package/packages/pi-coding-agent/dist/core/image-overflow-recovery.js.map +0 -1
- package/packages/pi-coding-agent/dist/core/image-overflow-recovery.test.d.ts +0 -2
- package/packages/pi-coding-agent/dist/core/image-overflow-recovery.test.d.ts.map +0 -1
- package/packages/pi-coding-agent/dist/core/image-overflow-recovery.test.js +0 -181
- package/packages/pi-coding-agent/dist/core/image-overflow-recovery.test.js.map +0 -1
- package/packages/pi-coding-agent/dist/core/messages.test.d.ts +0 -9
- package/packages/pi-coding-agent/dist/core/messages.test.d.ts.map +0 -1
- package/packages/pi-coding-agent/dist/core/messages.test.js +0 -86
- package/packages/pi-coding-agent/dist/core/messages.test.js.map +0 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.test.d.ts +0 -9
- package/packages/pi-coding-agent/dist/core/retry-handler.test.d.ts.map +0 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js +0 -193
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +0 -1
- package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.d.ts +0 -16
- package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.d.ts.map +0 -1
- package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js +0 -80
- package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js.map +0 -1
- package/packages/pi-coding-agent/src/core/compaction/compaction.test.ts +0 -236
- package/packages/pi-coding-agent/src/core/extensions/extension-manifest.test.ts +0 -77
- package/packages/pi-coding-agent/src/core/extensions/extension-manifest.ts +0 -62
- package/packages/pi-coding-agent/src/core/extensions/extension-sort.test.ts +0 -134
- package/packages/pi-coding-agent/src/core/extensions/extension-sort.ts +0 -137
- package/packages/pi-coding-agent/src/core/image-overflow-recovery.test.ts +0 -228
- package/packages/pi-coding-agent/src/core/image-overflow-recovery.ts +0 -118
- package/packages/pi-coding-agent/src/core/messages.test.ts +0 -114
- package/packages/pi-coding-agent/src/core/retry-handler.test.ts +0 -255
- package/packages/pi-coding-agent/src/core/tools/spawn-shell-windows.test.ts +0 -92
- package/src/resources/extensions/gsd/milestone-validation-gates.ts +0 -56
- package/src/resources/extensions/gsd/tests/auto-mode-interactive-guard.test.ts +0 -71
- package/src/resources/extensions/gsd/tests/cli-provider-rate-limit.test.ts +0 -47
- package/src/resources/extensions/gsd/tests/completion-hierarchy-guards.test.ts +0 -192
- package/src/resources/extensions/gsd/tests/db-path-worktree-symlink.test.ts +0 -131
- package/src/resources/extensions/gsd/tests/discord-invite-links.test.ts +0 -47
- package/src/resources/extensions/gsd/tests/discuss-empty-db-fallback.test.ts +0 -127
- package/src/resources/extensions/gsd/tests/dynamic-routing-default.test.ts +0 -20
- package/src/resources/extensions/gsd/tests/empty-content-abort-loop.test.ts +0 -74
- package/src/resources/extensions/gsd/tests/event-replay-idempotency.test.ts +0 -140
- package/src/resources/extensions/gsd/tests/forensics-context-persist.test.ts +0 -129
- package/src/resources/extensions/gsd/tests/forensics-db-completion.test.ts +0 -96
- package/src/resources/extensions/gsd/tests/gsdroot-worktree-detection.test.ts +0 -164
- package/src/resources/extensions/gsd/tests/guided-flow-dynamic-routing.test.ts +0 -135
- package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +0 -97
- package/src/resources/extensions/gsd/tests/hook-key-parsing.test.ts +0 -107
- package/src/resources/extensions/gsd/tests/integration/doctor-false-positives.test.ts +0 -243
- package/src/resources/extensions/gsd/tests/integration/gitignore-staging-2570.test.ts +0 -150
- package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +0 -959
- package/src/resources/extensions/gsd/tests/migrate-external-worktree.test.ts +0 -105
- package/src/resources/extensions/gsd/tests/milestone-status-authoritative.test.ts +0 -116
- package/src/resources/extensions/gsd/tests/parallel-commit-scope.test.ts +0 -159
- package/src/resources/extensions/gsd/tests/parallel-eligibility-ghost.test.ts +0 -150
- package/src/resources/extensions/gsd/tests/plan-milestone-title.test.ts +0 -70
- package/src/resources/extensions/gsd/tests/project-relocation-recovery.test.ts +0 -297
- package/src/resources/extensions/gsd/tests/prompt-loader-replacement.test.ts +0 -178
- package/src/resources/extensions/gsd/tests/prompt-tool-names.test.ts +0 -69
- package/src/resources/extensions/gsd/tests/queue-execution-guard.test.ts +0 -157
- package/src/resources/extensions/gsd/tests/quick-turn-end-cleanup.test.ts +0 -90
- package/src/resources/extensions/gsd/tests/reconciliation-edge-cases.test.ts +0 -162
- package/src/resources/extensions/gsd/tests/slice-disk-reconcile.test.ts +0 -233
- package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +0 -305
- package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +0 -405
- package/src/resources/extensions/gsd/tests/state-derivation-parity.test.ts +0 -257
- package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +0 -1628
- package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +0 -106
- package/src/resources/extensions/gsd/tests/stuck-detection-coverage.test.ts +0 -174
- package/src/resources/extensions/gsd/tests/summary-render-parity.test.ts +0 -221
- package/src/resources/extensions/gsd/tests/uat-stuck-loop-orphaned-worktree.test.ts +0 -289
- package/src/resources/extensions/gsd/tests/vacuum-recovery.test.ts +0 -154
- package/src/resources/extensions/gsd/tests/verdict-parser.test.ts +0 -156
- package/src/resources/extensions/gsd/tests/verification-operational-gate.test.ts +0 -82
- package/src/resources/extensions/gsd/tests/worktree-db-respawn-truncation.test.ts +0 -140
- package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +0 -101
- package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +0 -95
- package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +0 -55
- package/src/resources/extensions/ollama/index.ts +0 -130
- package/src/resources/extensions/ollama/model-capabilities.ts +0 -145
- package/src/resources/extensions/ollama/ollama-client.ts +0 -196
- package/src/resources/extensions/ollama/ollama-commands.ts +0 -248
- package/src/resources/extensions/ollama/ollama-discovery.ts +0 -106
- package/src/resources/extensions/ollama/ollama-tool.ts +0 -218
- package/src/resources/extensions/ollama/tests/model-capabilities.test.ts +0 -162
- package/src/resources/extensions/ollama/tests/ollama-client.test.ts +0 -38
- package/src/resources/extensions/ollama/tests/ollama-discovery.test.ts +0 -28
- package/src/resources/extensions/ollama/types.ts +0 -130
- package/src/resources/extensions/shared/tests/ask-user-freetext.test.ts +0 -156
- /package/dist/web/standalone/.next/static/{R0D4xaIPl5kg93edN7Oo0 → 5DLsjFHdSB6_a1EDQVjr7}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{R0D4xaIPl5kg93edN7Oo0 → 5DLsjFHdSB6_a1EDQVjr7}/_ssgManifest.js +0 -0
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Repair malformed JSON in LLM tool-call arguments.
|
|
3
|
-
*
|
|
4
|
-
* LLMs sometimes copy YAML template formatting into JSON tool arguments,
|
|
5
|
-
* producing patterns like:
|
|
6
|
-
*
|
|
7
|
-
* "keyDecisions": - Used Web Notification API...,
|
|
8
|
-
* "keyFiles": - src-tauri/src/lib.rs — Extended...
|
|
9
|
-
*
|
|
10
|
-
* instead of valid JSON arrays:
|
|
11
|
-
*
|
|
12
|
-
* "keyDecisions": ["Used Web Notification API..."],
|
|
13
|
-
* "keyFiles": ["src-tauri/src/lib.rs — Extended..."]
|
|
14
|
-
*
|
|
15
|
-
* This module detects and repairs such patterns before JSON.parse is called.
|
|
16
|
-
*
|
|
17
|
-
* @see https://github.com/gsd-build/gsd-2/issues/2660
|
|
18
|
-
*/
|
|
19
|
-
/**
|
|
20
|
-
* Detect whether a JSON string contains YAML-style bullet-list values
|
|
21
|
-
* (i.e. `"key": - item` instead of `"key": ["item"]`).
|
|
22
|
-
*/
|
|
23
|
-
export function hasYamlBulletLists(json) {
|
|
24
|
-
// Match: "key": followed by whitespace then a dash-space pattern (YAML bullet)
|
|
25
|
-
// The negative lookahead excludes negative numbers (e.g. "key": -1)
|
|
26
|
-
return /"\s*:\s*-\s+(?!\d)/.test(json);
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Attempt to repair YAML-style bullet lists embedded in a JSON string.
|
|
30
|
-
*
|
|
31
|
-
* Converts patterns like:
|
|
32
|
-
* "keyDecisions": - Used Web Notification API..., "keyFiles": - file1
|
|
33
|
-
*
|
|
34
|
-
* Into:
|
|
35
|
-
* "keyDecisions": ["Used Web Notification API..."], "keyFiles": ["file1"]
|
|
36
|
-
*
|
|
37
|
-
* Returns the original string unchanged if no YAML patterns are detected
|
|
38
|
-
* or if the repair itself would produce invalid JSON.
|
|
39
|
-
*/
|
|
40
|
-
export function repairToolJson(json) {
|
|
41
|
-
if (!hasYamlBulletLists(json)) {
|
|
42
|
-
return json;
|
|
43
|
-
}
|
|
44
|
-
// Strategy: find each `"key": - item1\n - item2\n - item3` region and
|
|
45
|
-
// wrap items in a JSON array.
|
|
46
|
-
//
|
|
47
|
-
// We work on the raw string because the JSON is not parseable yet.
|
|
48
|
-
// The pattern we target:
|
|
49
|
-
// "someKey":\s*- item text (possibly multiline)
|
|
50
|
-
// optionally followed by more `- item` lines
|
|
51
|
-
// terminated by the next `"key":` or `}` or end of string.
|
|
52
|
-
let repaired = json;
|
|
53
|
-
// Match a key followed by YAML-style bullet list.
|
|
54
|
-
// Capture: (1) the key portion including colon, (2) the bullet-list body,
|
|
55
|
-
// (3) the separator (comma or empty) before the next key/bracket.
|
|
56
|
-
// The bullet list body ends at the next `"key":` or `}` or `]` or end of string.
|
|
57
|
-
const keyBulletPattern = /("(?:[^"\\]|\\.)*"\s*:\s*)(- .+?)(,?\s*)(?="(?:[^"\\]|\\.)*"\s*:|[}\]]|$)/gs;
|
|
58
|
-
repaired = repaired.replace(keyBulletPattern, (_match, keyPart, bulletBody, separator) => {
|
|
59
|
-
// Split the bullet body into individual items on `- ` boundaries.
|
|
60
|
-
// Items may contain embedded newlines for multi-line values.
|
|
61
|
-
const items = bulletBody
|
|
62
|
-
.split(/\n?\s*- /)
|
|
63
|
-
.filter((s) => s.trim().length > 0)
|
|
64
|
-
.map((s) => s.replace(/,\s*$/, "").trim());
|
|
65
|
-
// JSON-encode each item as a string, then wrap in an array.
|
|
66
|
-
const jsonArray = "[" + items.map((item) => JSON.stringify(item)).join(", ") + "]";
|
|
67
|
-
// Re-emit the separator (comma) so the next key is properly delimited
|
|
68
|
-
const sep = separator.trim() ? separator : (/^\s*"/.test(separator + "x") ? ", " : "");
|
|
69
|
-
return keyPart + jsonArray + sep;
|
|
70
|
-
});
|
|
71
|
-
// Strip trailing commas before } or ] (common in repaired JSON)
|
|
72
|
-
repaired = repaired.replace(/,(\s*[}\]])/g, "$1");
|
|
73
|
-
return repaired;
|
|
74
|
-
}
|
|
75
|
-
//# sourceMappingURL=repair-tool-json.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"repair-tool-json.js","sourceRoot":"","sources":["../../src/utils/repair-tool-json.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC9C,+EAA+E;IAC/E,oEAAoE;IACpE,OAAO,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IAC1C,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC;IACb,CAAC;IAED,wEAAwE;IACxE,8BAA8B;IAC9B,EAAE;IACF,mEAAmE;IACnE,yBAAyB;IACzB,kDAAkD;IAClD,+CAA+C;IAC/C,6DAA6D;IAE7D,IAAI,QAAQ,GAAG,IAAI,CAAC;IAEpB,kDAAkD;IAClD,0EAA0E;IAC1E,kEAAkE;IAClE,iFAAiF;IACjF,MAAM,gBAAgB,GACrB,6EAA6E,CAAC;IAE/E,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAC1B,gBAAgB,EAChB,CAAC,MAAM,EAAE,OAAe,EAAE,UAAkB,EAAE,SAAiB,EAAE,EAAE;QAClE,kEAAkE;QAClE,6DAA6D;QAC7D,MAAM,KAAK,GAAG,UAAU;aACtB,KAAK,CAAC,UAAU,CAAC;aACjB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;aAClC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QAE5C,4DAA4D;QAC5D,MAAM,SAAS,GAAG,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC;QAEnF,sEAAsE;QACtE,MAAM,GAAG,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACvF,OAAO,OAAO,GAAG,SAAS,GAAG,GAAG,CAAC;IAClC,CAAC,CACD,CAAC;IAEF,gEAAgE;IAChE,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC;IAElD,OAAO,QAAQ,CAAC;AACjB,CAAC","sourcesContent":["/**\n * Repair malformed JSON in LLM tool-call arguments.\n *\n * LLMs sometimes copy YAML template formatting into JSON tool arguments,\n * producing patterns like:\n *\n * \"keyDecisions\": - Used Web Notification API...,\n * \"keyFiles\": - src-tauri/src/lib.rs — Extended...\n *\n * instead of valid JSON arrays:\n *\n * \"keyDecisions\": [\"Used Web Notification API...\"],\n * \"keyFiles\": [\"src-tauri/src/lib.rs — Extended...\"]\n *\n * This module detects and repairs such patterns before JSON.parse is called.\n *\n * @see https://github.com/gsd-build/gsd-2/issues/2660\n */\n\n/**\n * Detect whether a JSON string contains YAML-style bullet-list values\n * (i.e. `\"key\": - item` instead of `\"key\": [\"item\"]`).\n */\nexport function hasYamlBulletLists(json: string): boolean {\n\t// Match: \"key\": followed by whitespace then a dash-space pattern (YAML bullet)\n\t// The negative lookahead excludes negative numbers (e.g. \"key\": -1)\n\treturn /\"\\s*:\\s*-\\s+(?!\\d)/.test(json);\n}\n\n/**\n * Attempt to repair YAML-style bullet lists embedded in a JSON string.\n *\n * Converts patterns like:\n * \"keyDecisions\": - Used Web Notification API..., \"keyFiles\": - file1\n *\n * Into:\n * \"keyDecisions\": [\"Used Web Notification API...\"], \"keyFiles\": [\"file1\"]\n *\n * Returns the original string unchanged if no YAML patterns are detected\n * or if the repair itself would produce invalid JSON.\n */\nexport function repairToolJson(json: string): string {\n\tif (!hasYamlBulletLists(json)) {\n\t\treturn json;\n\t}\n\n\t// Strategy: find each `\"key\": - item1\\n - item2\\n - item3` region and\n\t// wrap items in a JSON array.\n\t//\n\t// We work on the raw string because the JSON is not parseable yet.\n\t// The pattern we target:\n\t// \"someKey\":\\s*- item text (possibly multiline)\n\t// optionally followed by more `- item` lines\n\t// terminated by the next `\"key\":` or `}` or end of string.\n\n\tlet repaired = json;\n\n\t// Match a key followed by YAML-style bullet list.\n\t// Capture: (1) the key portion including colon, (2) the bullet-list body,\n\t// (3) the separator (comma or empty) before the next key/bracket.\n\t// The bullet list body ends at the next `\"key\":` or `}` or `]` or end of string.\n\tconst keyBulletPattern =\n\t\t/(\"(?:[^\"\\\\]|\\\\.)*\"\\s*:\\s*)(- .+?)(,?\\s*)(?=\"(?:[^\"\\\\]|\\\\.)*\"\\s*:|[}\\]]|$)/gs;\n\n\trepaired = repaired.replace(\n\t\tkeyBulletPattern,\n\t\t(_match, keyPart: string, bulletBody: string, separator: string) => {\n\t\t\t// Split the bullet body into individual items on `- ` boundaries.\n\t\t\t// Items may contain embedded newlines for multi-line values.\n\t\t\tconst items = bulletBody\n\t\t\t\t.split(/\\n?\\s*- /)\n\t\t\t\t.filter((s) => s.trim().length > 0)\n\t\t\t\t.map((s) => s.replace(/,\\s*$/, \"\").trim());\n\n\t\t\t// JSON-encode each item as a string, then wrap in an array.\n\t\t\tconst jsonArray = \"[\" + items.map((item) => JSON.stringify(item)).join(\", \") + \"]\";\n\n\t\t\t// Re-emit the separator (comma) so the next key is properly delimited\n\t\t\tconst sep = separator.trim() ? separator : (/^\\s*\"/.test(separator + \"x\") ? \", \" : \"\");\n\t\t\treturn keyPart + jsonArray + sep;\n\t\t},\n\t);\n\n\t// Strip trailing commas before } or ] (common in repaired JSON)\n\trepaired = repaired.replace(/,(\\s*[}\\]])/g, \"$1\");\n\n\treturn repaired;\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"repair-tool-json.test.d.ts","sourceRoot":"","sources":["../../../src/utils/tests/repair-tool-json.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { describe, test } from "node:test";
|
|
2
|
-
import assert from "node:assert/strict";
|
|
3
|
-
import { repairToolJson, hasYamlBulletLists } from "../repair-tool-json.js";
|
|
4
|
-
describe("repairToolJson — YAML bullet list repair (#2660)", () => {
|
|
5
|
-
// ── Detection ──────────────────────────────────────────────────────────
|
|
6
|
-
test("hasYamlBulletLists detects YAML-style bullets", () => {
|
|
7
|
-
assert.equal(hasYamlBulletLists('"keyDecisions": - Used Web Notification API'), true);
|
|
8
|
-
});
|
|
9
|
-
test("hasYamlBulletLists ignores negative numbers", () => {
|
|
10
|
-
assert.equal(hasYamlBulletLists('"offset": -1'), false, "negative number should not be detected as YAML bullet");
|
|
11
|
-
});
|
|
12
|
-
test("hasYamlBulletLists returns false for valid JSON", () => {
|
|
13
|
-
assert.equal(hasYamlBulletLists('{"keyDecisions": ["item1", "item2"]}'), false);
|
|
14
|
-
});
|
|
15
|
-
// ── Single bullet item ────────────────────────────────────────────────
|
|
16
|
-
test("repairs single YAML bullet to JSON array", () => {
|
|
17
|
-
const malformed = '{"keyDecisions": - Used Web Notification API}';
|
|
18
|
-
const repaired = repairToolJson(malformed);
|
|
19
|
-
const parsed = JSON.parse(repaired);
|
|
20
|
-
assert.deepEqual(parsed.keyDecisions, ["Used Web Notification API"]);
|
|
21
|
-
});
|
|
22
|
-
// ── Multiple bullet items (newline-separated) ─────────────────────────
|
|
23
|
-
test("repairs multiple YAML bullets separated by newlines", () => {
|
|
24
|
-
const malformed = '{"keyDecisions": - Used Web Notification API\n - Chose Tauri over Electron\n - Adopted SQLite for storage, "title": "M005"}';
|
|
25
|
-
const repaired = repairToolJson(malformed);
|
|
26
|
-
const parsed = JSON.parse(repaired);
|
|
27
|
-
assert.deepEqual(parsed.keyDecisions, [
|
|
28
|
-
"Used Web Notification API",
|
|
29
|
-
"Chose Tauri over Electron",
|
|
30
|
-
"Adopted SQLite for storage",
|
|
31
|
-
]);
|
|
32
|
-
assert.equal(parsed.title, "M005");
|
|
33
|
-
});
|
|
34
|
-
// ── Multiple fields with YAML bullets ─────────────────────────────────
|
|
35
|
-
test("repairs multiple fields each with YAML bullet lists", () => {
|
|
36
|
-
const malformed = '{"keyDecisions": - decision one\n - decision two, "keyFiles": - src/lib.rs — Extended menu\n - src/main.ts — Entry point, "title": "done"}';
|
|
37
|
-
const repaired = repairToolJson(malformed);
|
|
38
|
-
const parsed = JSON.parse(repaired);
|
|
39
|
-
assert.deepEqual(parsed.keyDecisions, ["decision one", "decision two"]);
|
|
40
|
-
assert.deepEqual(parsed.keyFiles, [
|
|
41
|
-
"src/lib.rs \u2014 Extended menu",
|
|
42
|
-
"src/main.ts \u2014 Entry point",
|
|
43
|
-
]);
|
|
44
|
-
assert.equal(parsed.title, "done");
|
|
45
|
-
});
|
|
46
|
-
// ── Exact reproduction from issue #2660 ───────────────────────────────
|
|
47
|
-
test("repairs the exact malformed JSON from issue #2660", () => {
|
|
48
|
-
const malformed = `{"milestoneId": "M005", "title": "Native Desktop Polish", "oneLiner": "summary", "narrative": "details", "successCriteriaResults": "all pass", "definitionOfDoneResults": "all done", "requirementOutcomes": "met", "keyDecisions": - Used Web Notification API (new window.Notification()) instead of Tauri sendNotification wrapper, "keyFiles": - src-tauri/src/lib.rs \u2014 Extended menu builder with notification toggle, "lessonsLearned": - Always test notification permissions before sending, "followUps": "none", "deviations": "none", "verificationPassed": true}`;
|
|
49
|
-
const repaired = repairToolJson(malformed);
|
|
50
|
-
const parsed = JSON.parse(repaired);
|
|
51
|
-
assert.equal(parsed.milestoneId, "M005");
|
|
52
|
-
assert.equal(parsed.title, "Native Desktop Polish");
|
|
53
|
-
assert.ok(Array.isArray(parsed.keyDecisions), "keyDecisions should be an array");
|
|
54
|
-
assert.ok(parsed.keyDecisions[0].includes("Web Notification API"));
|
|
55
|
-
assert.ok(Array.isArray(parsed.keyFiles), "keyFiles should be an array");
|
|
56
|
-
assert.ok(parsed.keyFiles[0].includes("src-tauri/src/lib.rs"));
|
|
57
|
-
assert.ok(Array.isArray(parsed.lessonsLearned), "lessonsLearned should be an array");
|
|
58
|
-
assert.equal(parsed.verificationPassed, true);
|
|
59
|
-
});
|
|
60
|
-
// ── Passthrough for valid JSON ────────────────────────────────────────
|
|
61
|
-
test("returns valid JSON unchanged", () => {
|
|
62
|
-
const valid = '{"keyDecisions": ["item1", "item2"], "count": -5}';
|
|
63
|
-
const result = repairToolJson(valid);
|
|
64
|
-
assert.equal(result, valid, "valid JSON should be returned unchanged");
|
|
65
|
-
});
|
|
66
|
-
// ── Negative numbers are preserved ────────────────────────────────────
|
|
67
|
-
test("does not mangle negative numbers", () => {
|
|
68
|
-
const valid = '{"offset": -1, "limit": -100}';
|
|
69
|
-
const result = repairToolJson(valid);
|
|
70
|
-
assert.equal(result, valid);
|
|
71
|
-
});
|
|
72
|
-
});
|
|
73
|
-
//# sourceMappingURL=repair-tool-json.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"repair-tool-json.test.js","sourceRoot":"","sources":["../../../src/utils/tests/repair-tool-json.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, test } from \"node:test\";\nimport assert from \"node:assert/strict\";\nimport { repairToolJson, hasYamlBulletLists } from \"../repair-tool-json.js\";\n\ndescribe(\"repairToolJson — YAML bullet list repair (#2660)\", () => {\n\t// ── Detection ──────────────────────────────────────────────────────────\n\n\ttest(\"hasYamlBulletLists detects YAML-style bullets\", () => {\n\t\tassert.equal(\n\t\t\thasYamlBulletLists('\"keyDecisions\": - Used Web Notification API'),\n\t\t\ttrue,\n\t\t);\n\t});\n\n\ttest(\"hasYamlBulletLists ignores negative numbers\", () => {\n\t\tassert.equal(\n\t\t\thasYamlBulletLists('\"offset\": -1'),\n\t\t\tfalse,\n\t\t\t\"negative number should not be detected as YAML bullet\",\n\t\t);\n\t});\n\n\ttest(\"hasYamlBulletLists returns false for valid JSON\", () => {\n\t\tassert.equal(\n\t\t\thasYamlBulletLists('{\"keyDecisions\": [\"item1\", \"item2\"]}'),\n\t\t\tfalse,\n\t\t);\n\t});\n\n\t// ── Single bullet item ────────────────────────────────────────────────\n\n\ttest(\"repairs single YAML bullet to JSON array\", () => {\n\t\tconst malformed = '{\"keyDecisions\": - Used Web Notification API}';\n\t\tconst repaired = repairToolJson(malformed);\n\t\tconst parsed = JSON.parse(repaired);\n\t\tassert.deepEqual(parsed.keyDecisions, [\"Used Web Notification API\"]);\n\t});\n\n\t// ── Multiple bullet items (newline-separated) ─────────────────────────\n\n\ttest(\"repairs multiple YAML bullets separated by newlines\", () => {\n\t\tconst malformed =\n\t\t\t'{\"keyDecisions\": - Used Web Notification API\\n - Chose Tauri over Electron\\n - Adopted SQLite for storage, \"title\": \"M005\"}';\n\t\tconst repaired = repairToolJson(malformed);\n\t\tconst parsed = JSON.parse(repaired);\n\t\tassert.deepEqual(parsed.keyDecisions, [\n\t\t\t\"Used Web Notification API\",\n\t\t\t\"Chose Tauri over Electron\",\n\t\t\t\"Adopted SQLite for storage\",\n\t\t]);\n\t\tassert.equal(parsed.title, \"M005\");\n\t});\n\n\t// ── Multiple fields with YAML bullets ─────────────────────────────────\n\n\ttest(\"repairs multiple fields each with YAML bullet lists\", () => {\n\t\tconst malformed =\n\t\t\t'{\"keyDecisions\": - decision one\\n - decision two, \"keyFiles\": - src/lib.rs — Extended menu\\n - src/main.ts — Entry point, \"title\": \"done\"}';\n\t\tconst repaired = repairToolJson(malformed);\n\t\tconst parsed = JSON.parse(repaired);\n\t\tassert.deepEqual(parsed.keyDecisions, [\"decision one\", \"decision two\"]);\n\t\tassert.deepEqual(parsed.keyFiles, [\n\t\t\t\"src/lib.rs \\u2014 Extended menu\",\n\t\t\t\"src/main.ts \\u2014 Entry point\",\n\t\t]);\n\t\tassert.equal(parsed.title, \"done\");\n\t});\n\n\t// ── Exact reproduction from issue #2660 ───────────────────────────────\n\n\ttest(\"repairs the exact malformed JSON from issue #2660\", () => {\n\t\tconst malformed = `{\"milestoneId\": \"M005\", \"title\": \"Native Desktop Polish\", \"oneLiner\": \"summary\", \"narrative\": \"details\", \"successCriteriaResults\": \"all pass\", \"definitionOfDoneResults\": \"all done\", \"requirementOutcomes\": \"met\", \"keyDecisions\": - Used Web Notification API (new window.Notification()) instead of Tauri sendNotification wrapper, \"keyFiles\": - src-tauri/src/lib.rs \\u2014 Extended menu builder with notification toggle, \"lessonsLearned\": - Always test notification permissions before sending, \"followUps\": \"none\", \"deviations\": \"none\", \"verificationPassed\": true}`;\n\n\t\tconst repaired = repairToolJson(malformed);\n\t\tconst parsed = JSON.parse(repaired);\n\n\t\tassert.equal(parsed.milestoneId, \"M005\");\n\t\tassert.equal(parsed.title, \"Native Desktop Polish\");\n\t\tassert.ok(Array.isArray(parsed.keyDecisions), \"keyDecisions should be an array\");\n\t\tassert.ok(parsed.keyDecisions[0].includes(\"Web Notification API\"));\n\t\tassert.ok(Array.isArray(parsed.keyFiles), \"keyFiles should be an array\");\n\t\tassert.ok(parsed.keyFiles[0].includes(\"src-tauri/src/lib.rs\"));\n\t\tassert.ok(Array.isArray(parsed.lessonsLearned), \"lessonsLearned should be an array\");\n\t\tassert.equal(parsed.verificationPassed, true);\n\t});\n\n\t// ── Passthrough for valid JSON ────────────────────────────────────────\n\n\ttest(\"returns valid JSON unchanged\", () => {\n\t\tconst valid = '{\"keyDecisions\": [\"item1\", \"item2\"], \"count\": -5}';\n\t\tconst result = repairToolJson(valid);\n\t\tassert.equal(result, valid, \"valid JSON should be returned unchanged\");\n\t});\n\n\t// ── Negative numbers are preserved ────────────────────────────────────\n\n\ttest(\"does not mangle negative numbers\", () => {\n\t\tconst valid = '{\"offset\": -1, \"limit\": -100}';\n\t\tconst result = repairToolJson(valid);\n\t\tassert.equal(result, valid);\n\t});\n});\n"]}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { describe, it } from "node:test";
|
|
2
|
-
import assert from "node:assert/strict";
|
|
3
|
-
import { mapStopReason } from "./anthropic-shared.js";
|
|
4
|
-
|
|
5
|
-
describe("mapStopReason", () => {
|
|
6
|
-
it("maps end_turn to stop", () => {
|
|
7
|
-
assert.equal(mapStopReason("end_turn"), "stop");
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
it("maps max_tokens to length", () => {
|
|
11
|
-
assert.equal(mapStopReason("max_tokens"), "length");
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
it("maps tool_use to toolUse", () => {
|
|
15
|
-
assert.equal(mapStopReason("tool_use"), "toolUse");
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it("maps pause_turn to pauseTurn (not stop)", () => {
|
|
19
|
-
// pause_turn means the server paused a long-running turn (e.g. native
|
|
20
|
-
// web search hit its iteration limit). Mapping it to "stop" causes the
|
|
21
|
-
// agent loop to exit, leaving an incomplete server_tool_use block in
|
|
22
|
-
// history which triggers a 400 on the next request.
|
|
23
|
-
assert.equal(mapStopReason("pause_turn"), "pauseTurn");
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it("throws on unknown stop reason", () => {
|
|
27
|
-
assert.throws(() => mapStopReason("bogus"), /Unhandled stop reason/);
|
|
28
|
-
});
|
|
29
|
-
});
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Repair malformed JSON in LLM tool-call arguments.
|
|
3
|
-
*
|
|
4
|
-
* LLMs sometimes copy YAML template formatting into JSON tool arguments,
|
|
5
|
-
* producing patterns like:
|
|
6
|
-
*
|
|
7
|
-
* "keyDecisions": - Used Web Notification API...,
|
|
8
|
-
* "keyFiles": - src-tauri/src/lib.rs — Extended...
|
|
9
|
-
*
|
|
10
|
-
* instead of valid JSON arrays:
|
|
11
|
-
*
|
|
12
|
-
* "keyDecisions": ["Used Web Notification API..."],
|
|
13
|
-
* "keyFiles": ["src-tauri/src/lib.rs — Extended..."]
|
|
14
|
-
*
|
|
15
|
-
* This module detects and repairs such patterns before JSON.parse is called.
|
|
16
|
-
*
|
|
17
|
-
* @see https://github.com/gsd-build/gsd-2/issues/2660
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Detect whether a JSON string contains YAML-style bullet-list values
|
|
22
|
-
* (i.e. `"key": - item` instead of `"key": ["item"]`).
|
|
23
|
-
*/
|
|
24
|
-
export function hasYamlBulletLists(json: string): boolean {
|
|
25
|
-
// Match: "key": followed by whitespace then a dash-space pattern (YAML bullet)
|
|
26
|
-
// The negative lookahead excludes negative numbers (e.g. "key": -1)
|
|
27
|
-
return /"\s*:\s*-\s+(?!\d)/.test(json);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Attempt to repair YAML-style bullet lists embedded in a JSON string.
|
|
32
|
-
*
|
|
33
|
-
* Converts patterns like:
|
|
34
|
-
* "keyDecisions": - Used Web Notification API..., "keyFiles": - file1
|
|
35
|
-
*
|
|
36
|
-
* Into:
|
|
37
|
-
* "keyDecisions": ["Used Web Notification API..."], "keyFiles": ["file1"]
|
|
38
|
-
*
|
|
39
|
-
* Returns the original string unchanged if no YAML patterns are detected
|
|
40
|
-
* or if the repair itself would produce invalid JSON.
|
|
41
|
-
*/
|
|
42
|
-
export function repairToolJson(json: string): string {
|
|
43
|
-
if (!hasYamlBulletLists(json)) {
|
|
44
|
-
return json;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Strategy: find each `"key": - item1\n - item2\n - item3` region and
|
|
48
|
-
// wrap items in a JSON array.
|
|
49
|
-
//
|
|
50
|
-
// We work on the raw string because the JSON is not parseable yet.
|
|
51
|
-
// The pattern we target:
|
|
52
|
-
// "someKey":\s*- item text (possibly multiline)
|
|
53
|
-
// optionally followed by more `- item` lines
|
|
54
|
-
// terminated by the next `"key":` or `}` or end of string.
|
|
55
|
-
|
|
56
|
-
let repaired = json;
|
|
57
|
-
|
|
58
|
-
// Match a key followed by YAML-style bullet list.
|
|
59
|
-
// Capture: (1) the key portion including colon, (2) the bullet-list body,
|
|
60
|
-
// (3) the separator (comma or empty) before the next key/bracket.
|
|
61
|
-
// The bullet list body ends at the next `"key":` or `}` or `]` or end of string.
|
|
62
|
-
const keyBulletPattern =
|
|
63
|
-
/("(?:[^"\\]|\\.)*"\s*:\s*)(- .+?)(,?\s*)(?="(?:[^"\\]|\\.)*"\s*:|[}\]]|$)/gs;
|
|
64
|
-
|
|
65
|
-
repaired = repaired.replace(
|
|
66
|
-
keyBulletPattern,
|
|
67
|
-
(_match, keyPart: string, bulletBody: string, separator: string) => {
|
|
68
|
-
// Split the bullet body into individual items on `- ` boundaries.
|
|
69
|
-
// Items may contain embedded newlines for multi-line values.
|
|
70
|
-
const items = bulletBody
|
|
71
|
-
.split(/\n?\s*- /)
|
|
72
|
-
.filter((s) => s.trim().length > 0)
|
|
73
|
-
.map((s) => s.replace(/,\s*$/, "").trim());
|
|
74
|
-
|
|
75
|
-
// JSON-encode each item as a string, then wrap in an array.
|
|
76
|
-
const jsonArray = "[" + items.map((item) => JSON.stringify(item)).join(", ") + "]";
|
|
77
|
-
|
|
78
|
-
// Re-emit the separator (comma) so the next key is properly delimited
|
|
79
|
-
const sep = separator.trim() ? separator : (/^\s*"/.test(separator + "x") ? ", " : "");
|
|
80
|
-
return keyPart + jsonArray + sep;
|
|
81
|
-
},
|
|
82
|
-
);
|
|
83
|
-
|
|
84
|
-
// Strip trailing commas before } or ] (common in repaired JSON)
|
|
85
|
-
repaired = repaired.replace(/,(\s*[}\]])/g, "$1");
|
|
86
|
-
|
|
87
|
-
return repaired;
|
|
88
|
-
}
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import { describe, test } from "node:test";
|
|
2
|
-
import assert from "node:assert/strict";
|
|
3
|
-
import { repairToolJson, hasYamlBulletLists } from "../repair-tool-json.js";
|
|
4
|
-
|
|
5
|
-
describe("repairToolJson — YAML bullet list repair (#2660)", () => {
|
|
6
|
-
// ── Detection ──────────────────────────────────────────────────────────
|
|
7
|
-
|
|
8
|
-
test("hasYamlBulletLists detects YAML-style bullets", () => {
|
|
9
|
-
assert.equal(
|
|
10
|
-
hasYamlBulletLists('"keyDecisions": - Used Web Notification API'),
|
|
11
|
-
true,
|
|
12
|
-
);
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
test("hasYamlBulletLists ignores negative numbers", () => {
|
|
16
|
-
assert.equal(
|
|
17
|
-
hasYamlBulletLists('"offset": -1'),
|
|
18
|
-
false,
|
|
19
|
-
"negative number should not be detected as YAML bullet",
|
|
20
|
-
);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
test("hasYamlBulletLists returns false for valid JSON", () => {
|
|
24
|
-
assert.equal(
|
|
25
|
-
hasYamlBulletLists('{"keyDecisions": ["item1", "item2"]}'),
|
|
26
|
-
false,
|
|
27
|
-
);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
// ── Single bullet item ────────────────────────────────────────────────
|
|
31
|
-
|
|
32
|
-
test("repairs single YAML bullet to JSON array", () => {
|
|
33
|
-
const malformed = '{"keyDecisions": - Used Web Notification API}';
|
|
34
|
-
const repaired = repairToolJson(malformed);
|
|
35
|
-
const parsed = JSON.parse(repaired);
|
|
36
|
-
assert.deepEqual(parsed.keyDecisions, ["Used Web Notification API"]);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
// ── Multiple bullet items (newline-separated) ─────────────────────────
|
|
40
|
-
|
|
41
|
-
test("repairs multiple YAML bullets separated by newlines", () => {
|
|
42
|
-
const malformed =
|
|
43
|
-
'{"keyDecisions": - Used Web Notification API\n - Chose Tauri over Electron\n - Adopted SQLite for storage, "title": "M005"}';
|
|
44
|
-
const repaired = repairToolJson(malformed);
|
|
45
|
-
const parsed = JSON.parse(repaired);
|
|
46
|
-
assert.deepEqual(parsed.keyDecisions, [
|
|
47
|
-
"Used Web Notification API",
|
|
48
|
-
"Chose Tauri over Electron",
|
|
49
|
-
"Adopted SQLite for storage",
|
|
50
|
-
]);
|
|
51
|
-
assert.equal(parsed.title, "M005");
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
// ── Multiple fields with YAML bullets ─────────────────────────────────
|
|
55
|
-
|
|
56
|
-
test("repairs multiple fields each with YAML bullet lists", () => {
|
|
57
|
-
const malformed =
|
|
58
|
-
'{"keyDecisions": - decision one\n - decision two, "keyFiles": - src/lib.rs — Extended menu\n - src/main.ts — Entry point, "title": "done"}';
|
|
59
|
-
const repaired = repairToolJson(malformed);
|
|
60
|
-
const parsed = JSON.parse(repaired);
|
|
61
|
-
assert.deepEqual(parsed.keyDecisions, ["decision one", "decision two"]);
|
|
62
|
-
assert.deepEqual(parsed.keyFiles, [
|
|
63
|
-
"src/lib.rs \u2014 Extended menu",
|
|
64
|
-
"src/main.ts \u2014 Entry point",
|
|
65
|
-
]);
|
|
66
|
-
assert.equal(parsed.title, "done");
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
// ── Exact reproduction from issue #2660 ───────────────────────────────
|
|
70
|
-
|
|
71
|
-
test("repairs the exact malformed JSON from issue #2660", () => {
|
|
72
|
-
const malformed = `{"milestoneId": "M005", "title": "Native Desktop Polish", "oneLiner": "summary", "narrative": "details", "successCriteriaResults": "all pass", "definitionOfDoneResults": "all done", "requirementOutcomes": "met", "keyDecisions": - Used Web Notification API (new window.Notification()) instead of Tauri sendNotification wrapper, "keyFiles": - src-tauri/src/lib.rs \u2014 Extended menu builder with notification toggle, "lessonsLearned": - Always test notification permissions before sending, "followUps": "none", "deviations": "none", "verificationPassed": true}`;
|
|
73
|
-
|
|
74
|
-
const repaired = repairToolJson(malformed);
|
|
75
|
-
const parsed = JSON.parse(repaired);
|
|
76
|
-
|
|
77
|
-
assert.equal(parsed.milestoneId, "M005");
|
|
78
|
-
assert.equal(parsed.title, "Native Desktop Polish");
|
|
79
|
-
assert.ok(Array.isArray(parsed.keyDecisions), "keyDecisions should be an array");
|
|
80
|
-
assert.ok(parsed.keyDecisions[0].includes("Web Notification API"));
|
|
81
|
-
assert.ok(Array.isArray(parsed.keyFiles), "keyFiles should be an array");
|
|
82
|
-
assert.ok(parsed.keyFiles[0].includes("src-tauri/src/lib.rs"));
|
|
83
|
-
assert.ok(Array.isArray(parsed.lessonsLearned), "lessonsLearned should be an array");
|
|
84
|
-
assert.equal(parsed.verificationPassed, true);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
// ── Passthrough for valid JSON ────────────────────────────────────────
|
|
88
|
-
|
|
89
|
-
test("returns valid JSON unchanged", () => {
|
|
90
|
-
const valid = '{"keyDecisions": ["item1", "item2"], "count": -5}';
|
|
91
|
-
const result = repairToolJson(valid);
|
|
92
|
-
assert.equal(result, valid, "valid JSON should be returned unchanged");
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
// ── Negative numbers are preserved ────────────────────────────────────
|
|
96
|
-
|
|
97
|
-
test("does not mangle negative numbers", () => {
|
|
98
|
-
const valid = '{"offset": -1, "limit": -100}';
|
|
99
|
-
const result = repairToolJson(valid);
|
|
100
|
-
assert.equal(result, valid);
|
|
101
|
-
});
|
|
102
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"compaction.test.d.ts","sourceRoot":"","sources":["../../../src/core/compaction/compaction.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -1,176 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for chunked compaction fallback when messages exceed model context window.
|
|
3
|
-
* Regression test for #2932.
|
|
4
|
-
*/
|
|
5
|
-
import assert from "node:assert/strict";
|
|
6
|
-
import { describe, it, mock } from "node:test";
|
|
7
|
-
import { generateSummary, estimateTokens, chunkMessages } from "./compaction.js";
|
|
8
|
-
// ---------------------------------------------------------------------------
|
|
9
|
-
// Helpers
|
|
10
|
-
// ---------------------------------------------------------------------------
|
|
11
|
-
/** Create a user message with approximately `tokenCount` tokens (chars = tokens * 4). */
|
|
12
|
-
function makeUserMessage(tokenCount) {
|
|
13
|
-
const text = "x".repeat(tokenCount * 4);
|
|
14
|
-
return { role: "user", content: text };
|
|
15
|
-
}
|
|
16
|
-
/** Create a mock model with a given context window. */
|
|
17
|
-
function makeModel(contextWindow) {
|
|
18
|
-
return {
|
|
19
|
-
id: "test-model",
|
|
20
|
-
name: "Test Model",
|
|
21
|
-
api: "anthropic-messages",
|
|
22
|
-
provider: "anthropic",
|
|
23
|
-
baseUrl: "https://api.test",
|
|
24
|
-
reasoning: false,
|
|
25
|
-
input: ["text"],
|
|
26
|
-
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
27
|
-
contextWindow,
|
|
28
|
-
maxTokens: 4096,
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
function makeFakeResponse(text) {
|
|
32
|
-
return {
|
|
33
|
-
content: [{ type: "text", text }],
|
|
34
|
-
stopReason: "end_turn",
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
// ---------------------------------------------------------------------------
|
|
38
|
-
// chunkMessages tests
|
|
39
|
-
// ---------------------------------------------------------------------------
|
|
40
|
-
describe("chunkMessages", () => {
|
|
41
|
-
it("returns a single chunk when messages fit in budget", () => {
|
|
42
|
-
const messages = [
|
|
43
|
-
makeUserMessage(1_000),
|
|
44
|
-
makeUserMessage(1_000),
|
|
45
|
-
];
|
|
46
|
-
const chunks = chunkMessages(messages, 100_000);
|
|
47
|
-
assert.equal(chunks.length, 1);
|
|
48
|
-
assert.equal(chunks[0].length, 2);
|
|
49
|
-
});
|
|
50
|
-
it("splits messages into multiple chunks when they exceed budget", () => {
|
|
51
|
-
const messages = [
|
|
52
|
-
makeUserMessage(50_000),
|
|
53
|
-
makeUserMessage(50_000),
|
|
54
|
-
makeUserMessage(50_000),
|
|
55
|
-
];
|
|
56
|
-
// Budget of 80k tokens means each 50k message gets its own chunk
|
|
57
|
-
// (or two fit together if budget allows)
|
|
58
|
-
const chunks = chunkMessages(messages, 80_000);
|
|
59
|
-
assert.ok(chunks.length > 1, `Expected multiple chunks, got ${chunks.length}`);
|
|
60
|
-
// All messages should be present across chunks
|
|
61
|
-
const totalMessages = chunks.reduce((sum, c) => sum + c.length, 0);
|
|
62
|
-
assert.equal(totalMessages, 3);
|
|
63
|
-
});
|
|
64
|
-
it("puts a single oversized message in its own chunk", () => {
|
|
65
|
-
const messages = [
|
|
66
|
-
makeUserMessage(200_000), // Way over any reasonable budget
|
|
67
|
-
];
|
|
68
|
-
const chunks = chunkMessages(messages, 80_000);
|
|
69
|
-
assert.equal(chunks.length, 1);
|
|
70
|
-
assert.equal(chunks[0].length, 1);
|
|
71
|
-
});
|
|
72
|
-
it("preserves message order across chunks", () => {
|
|
73
|
-
// Create messages with identifiable sizes
|
|
74
|
-
const messages = [
|
|
75
|
-
makeUserMessage(30_000), // ~30k tokens
|
|
76
|
-
makeUserMessage(30_000),
|
|
77
|
-
makeUserMessage(30_000),
|
|
78
|
-
makeUserMessage(30_000),
|
|
79
|
-
];
|
|
80
|
-
const chunks = chunkMessages(messages, 50_000);
|
|
81
|
-
// Reconstruct original order
|
|
82
|
-
const flat = chunks.flat();
|
|
83
|
-
assert.equal(flat.length, 4);
|
|
84
|
-
for (let i = 0; i < flat.length; i++) {
|
|
85
|
-
assert.strictEqual(flat[i], messages[i], `Message ${i} should be in order`);
|
|
86
|
-
}
|
|
87
|
-
});
|
|
88
|
-
});
|
|
89
|
-
// ---------------------------------------------------------------------------
|
|
90
|
-
// generateSummary chunked fallback tests
|
|
91
|
-
// ---------------------------------------------------------------------------
|
|
92
|
-
describe("generateSummary — chunked fallback (#2932)", () => {
|
|
93
|
-
it("calls _completeFn multiple times when messages exceed model context window", async () => {
|
|
94
|
-
// Arrange: 3 messages of ~80k tokens each = ~240k total, model has 200k window
|
|
95
|
-
const messages = [
|
|
96
|
-
makeUserMessage(80_000),
|
|
97
|
-
makeUserMessage(80_000),
|
|
98
|
-
makeUserMessage(80_000),
|
|
99
|
-
];
|
|
100
|
-
const model = makeModel(200_000);
|
|
101
|
-
const reserveTokens = 16_384;
|
|
102
|
-
// Verify our test setup: messages really do exceed the model window
|
|
103
|
-
let totalTokens = 0;
|
|
104
|
-
for (const m of messages)
|
|
105
|
-
totalTokens += estimateTokens(m);
|
|
106
|
-
assert.ok(totalTokens > model.contextWindow, `Test setup: ${totalTokens} tokens should exceed ${model.contextWindow} context window`);
|
|
107
|
-
// Track calls
|
|
108
|
-
const calls = [];
|
|
109
|
-
const mockComplete = mock.fn(async (_model, context, _options) => {
|
|
110
|
-
const userMsg = context.messages?.[0];
|
|
111
|
-
const text = typeof userMsg?.content === "string"
|
|
112
|
-
? userMsg.content
|
|
113
|
-
: userMsg?.content?.[0]?.text ?? "";
|
|
114
|
-
if (text.includes("<previous-summary>")) {
|
|
115
|
-
calls.push("update");
|
|
116
|
-
}
|
|
117
|
-
else {
|
|
118
|
-
calls.push("initial");
|
|
119
|
-
}
|
|
120
|
-
return makeFakeResponse("Summary of chunk");
|
|
121
|
-
});
|
|
122
|
-
const summary = await generateSummary(messages, model, reserveTokens, undefined, // apiKey
|
|
123
|
-
undefined, // signal
|
|
124
|
-
undefined, // customInstructions
|
|
125
|
-
undefined, // previousSummary
|
|
126
|
-
mockComplete);
|
|
127
|
-
// Assert: should have called completeSimple more than once (chunked)
|
|
128
|
-
assert.ok(mockComplete.mock.callCount() > 1, `Expected multiple calls for chunked summarization, got ${mockComplete.mock.callCount()}`);
|
|
129
|
-
// First call should be an initial summary, subsequent should be updates
|
|
130
|
-
assert.equal(calls[0], "initial", "First chunk should use initial summarization prompt");
|
|
131
|
-
for (let i = 1; i < calls.length; i++) {
|
|
132
|
-
assert.equal(calls[i], "update", `Chunk ${i + 1} should use update summarization prompt`);
|
|
133
|
-
}
|
|
134
|
-
// Should return a non-empty summary
|
|
135
|
-
assert.ok(summary.length > 0, "Summary should not be empty");
|
|
136
|
-
});
|
|
137
|
-
it("uses single-pass when messages fit within model context window", async () => {
|
|
138
|
-
const messages = [
|
|
139
|
-
makeUserMessage(10_000),
|
|
140
|
-
makeUserMessage(10_000),
|
|
141
|
-
];
|
|
142
|
-
const model = makeModel(200_000);
|
|
143
|
-
const reserveTokens = 16_384;
|
|
144
|
-
// Verify test setup
|
|
145
|
-
let totalTokens = 0;
|
|
146
|
-
for (const m of messages)
|
|
147
|
-
totalTokens += estimateTokens(m);
|
|
148
|
-
assert.ok(totalTokens < model.contextWindow, `Test setup: ${totalTokens} tokens should fit in ${model.contextWindow} context window`);
|
|
149
|
-
const mockComplete = mock.fn(async () => makeFakeResponse("Single pass summary"));
|
|
150
|
-
await generateSummary(messages, model, reserveTokens, undefined, undefined, undefined, undefined, mockComplete);
|
|
151
|
-
assert.equal(mockComplete.mock.callCount(), 1, "Should use single-pass summarization when messages fit in context window");
|
|
152
|
-
});
|
|
153
|
-
it("passes previousSummary through chunked summarization", async () => {
|
|
154
|
-
const messages = [
|
|
155
|
-
makeUserMessage(80_000),
|
|
156
|
-
makeUserMessage(80_000),
|
|
157
|
-
makeUserMessage(80_000),
|
|
158
|
-
];
|
|
159
|
-
const model = makeModel(200_000);
|
|
160
|
-
const reserveTokens = 16_384;
|
|
161
|
-
const previousSummary = "Previous session summary content";
|
|
162
|
-
const prompts = [];
|
|
163
|
-
const mockComplete = mock.fn(async (_model, context) => {
|
|
164
|
-
const userMsg = context.messages?.[0];
|
|
165
|
-
const text = typeof userMsg?.content === "string"
|
|
166
|
-
? userMsg.content
|
|
167
|
-
: userMsg?.content?.[0]?.text ?? "";
|
|
168
|
-
prompts.push(text);
|
|
169
|
-
return makeFakeResponse("Chunk summary");
|
|
170
|
-
});
|
|
171
|
-
await generateSummary(messages, model, reserveTokens, undefined, undefined, undefined, previousSummary, mockComplete);
|
|
172
|
-
// First chunk should include the previousSummary
|
|
173
|
-
assert.ok(prompts[0].includes(previousSummary), "First chunk should incorporate the previousSummary");
|
|
174
|
-
});
|
|
175
|
-
});
|
|
176
|
-
//# sourceMappingURL=compaction.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"compaction.test.js","sourceRoot":"","sources":["../../../src/core/compaction/compaction.test.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Tests for chunked compaction fallback when messages exceed model context window.\n * Regression test for #2932.\n */\n\nimport assert from \"node:assert/strict\";\nimport { describe, it, mock } from \"node:test\";\n\nimport type { AgentMessage } from \"@gsd/pi-agent-core\";\nimport type { Model, AssistantMessage } from \"@gsd/pi-ai\";\n\nimport { generateSummary, estimateTokens, chunkMessages } from \"./compaction.js\";\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Create a user message with approximately `tokenCount` tokens (chars = tokens * 4). */\nfunction makeUserMessage(tokenCount: number): AgentMessage {\n\tconst text = \"x\".repeat(tokenCount * 4);\n\treturn { role: \"user\", content: text } as unknown as AgentMessage;\n}\n\n/** Create a mock model with a given context window. */\nfunction makeModel(contextWindow: number): Model<any> {\n\treturn {\n\t\tid: \"test-model\",\n\t\tname: \"Test Model\",\n\t\tapi: \"anthropic-messages\",\n\t\tprovider: \"anthropic\",\n\t\tbaseUrl: \"https://api.test\",\n\t\treasoning: false,\n\t\tinput: [\"text\"],\n\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n\t\tcontextWindow,\n\t\tmaxTokens: 4096,\n\t} as Model<any>;\n}\n\nfunction makeFakeResponse(text: string): AssistantMessage {\n\treturn {\n\t\tcontent: [{ type: \"text\", text }],\n\t\tstopReason: \"end_turn\",\n\t} as unknown as AssistantMessage;\n}\n\n// ---------------------------------------------------------------------------\n// chunkMessages tests\n// ---------------------------------------------------------------------------\n\ndescribe(\"chunkMessages\", () => {\n\tit(\"returns a single chunk when messages fit in budget\", () => {\n\t\tconst messages: AgentMessage[] = [\n\t\t\tmakeUserMessage(1_000),\n\t\t\tmakeUserMessage(1_000),\n\t\t];\n\t\tconst chunks = chunkMessages(messages, 100_000);\n\t\tassert.equal(chunks.length, 1);\n\t\tassert.equal(chunks[0].length, 2);\n\t});\n\n\tit(\"splits messages into multiple chunks when they exceed budget\", () => {\n\t\tconst messages: AgentMessage[] = [\n\t\t\tmakeUserMessage(50_000),\n\t\t\tmakeUserMessage(50_000),\n\t\t\tmakeUserMessage(50_000),\n\t\t];\n\t\t// Budget of 80k tokens means each 50k message gets its own chunk\n\t\t// (or two fit together if budget allows)\n\t\tconst chunks = chunkMessages(messages, 80_000);\n\t\tassert.ok(chunks.length > 1, `Expected multiple chunks, got ${chunks.length}`);\n\t\t// All messages should be present across chunks\n\t\tconst totalMessages = chunks.reduce((sum, c) => sum + c.length, 0);\n\t\tassert.equal(totalMessages, 3);\n\t});\n\n\tit(\"puts a single oversized message in its own chunk\", () => {\n\t\tconst messages: AgentMessage[] = [\n\t\t\tmakeUserMessage(200_000), // Way over any reasonable budget\n\t\t];\n\t\tconst chunks = chunkMessages(messages, 80_000);\n\t\tassert.equal(chunks.length, 1);\n\t\tassert.equal(chunks[0].length, 1);\n\t});\n\n\tit(\"preserves message order across chunks\", () => {\n\t\t// Create messages with identifiable sizes\n\t\tconst messages: AgentMessage[] = [\n\t\t\tmakeUserMessage(30_000), // ~30k tokens\n\t\t\tmakeUserMessage(30_000),\n\t\t\tmakeUserMessage(30_000),\n\t\t\tmakeUserMessage(30_000),\n\t\t];\n\t\tconst chunks = chunkMessages(messages, 50_000);\n\t\t// Reconstruct original order\n\t\tconst flat = chunks.flat();\n\t\tassert.equal(flat.length, 4);\n\t\tfor (let i = 0; i < flat.length; i++) {\n\t\t\tassert.strictEqual(flat[i], messages[i], `Message ${i} should be in order`);\n\t\t}\n\t});\n});\n\n// ---------------------------------------------------------------------------\n// generateSummary chunked fallback tests\n// ---------------------------------------------------------------------------\n\ndescribe(\"generateSummary — chunked fallback (#2932)\", () => {\n\tit(\"calls _completeFn multiple times when messages exceed model context window\", async () => {\n\t\t// Arrange: 3 messages of ~80k tokens each = ~240k total, model has 200k window\n\t\tconst messages: AgentMessage[] = [\n\t\t\tmakeUserMessage(80_000),\n\t\t\tmakeUserMessage(80_000),\n\t\t\tmakeUserMessage(80_000),\n\t\t];\n\t\tconst model = makeModel(200_000);\n\t\tconst reserveTokens = 16_384;\n\n\t\t// Verify our test setup: messages really do exceed the model window\n\t\tlet totalTokens = 0;\n\t\tfor (const m of messages) totalTokens += estimateTokens(m);\n\t\tassert.ok(\n\t\t\ttotalTokens > model.contextWindow,\n\t\t\t`Test setup: ${totalTokens} tokens should exceed ${model.contextWindow} context window`,\n\t\t);\n\n\t\t// Track calls\n\t\tconst calls: string[] = [];\n\t\tconst mockComplete = mock.fn(async (_model: any, context: any, _options: any) => {\n\t\t\tconst userMsg = context.messages?.[0];\n\t\t\tconst text =\n\t\t\t\ttypeof userMsg?.content === \"string\"\n\t\t\t\t\t? userMsg.content\n\t\t\t\t\t: userMsg?.content?.[0]?.text ?? \"\";\n\n\t\t\tif (text.includes(\"<previous-summary>\")) {\n\t\t\t\tcalls.push(\"update\");\n\t\t\t} else {\n\t\t\t\tcalls.push(\"initial\");\n\t\t\t}\n\t\t\treturn makeFakeResponse(\"Summary of chunk\");\n\t\t});\n\n\t\tconst summary = await generateSummary(\n\t\t\tmessages,\n\t\t\tmodel,\n\t\t\treserveTokens,\n\t\t\tundefined, // apiKey\n\t\t\tundefined, // signal\n\t\t\tundefined, // customInstructions\n\t\t\tundefined, // previousSummary\n\t\t\tmockComplete, // _completeFn override for testing\n\t\t);\n\n\t\t// Assert: should have called completeSimple more than once (chunked)\n\t\tassert.ok(\n\t\t\tmockComplete.mock.callCount() > 1,\n\t\t\t`Expected multiple calls for chunked summarization, got ${mockComplete.mock.callCount()}`,\n\t\t);\n\n\t\t// First call should be an initial summary, subsequent should be updates\n\t\tassert.equal(calls[0], \"initial\", \"First chunk should use initial summarization prompt\");\n\t\tfor (let i = 1; i < calls.length; i++) {\n\t\t\tassert.equal(calls[i], \"update\", `Chunk ${i + 1} should use update summarization prompt`);\n\t\t}\n\n\t\t// Should return a non-empty summary\n\t\tassert.ok(summary.length > 0, \"Summary should not be empty\");\n\t});\n\n\tit(\"uses single-pass when messages fit within model context window\", async () => {\n\t\tconst messages: AgentMessage[] = [\n\t\t\tmakeUserMessage(10_000),\n\t\t\tmakeUserMessage(10_000),\n\t\t];\n\t\tconst model = makeModel(200_000);\n\t\tconst reserveTokens = 16_384;\n\n\t\t// Verify test setup\n\t\tlet totalTokens = 0;\n\t\tfor (const m of messages) totalTokens += estimateTokens(m);\n\t\tassert.ok(\n\t\t\ttotalTokens < model.contextWindow,\n\t\t\t`Test setup: ${totalTokens} tokens should fit in ${model.contextWindow} context window`,\n\t\t);\n\n\t\tconst mockComplete = mock.fn(async () => makeFakeResponse(\"Single pass summary\"));\n\n\t\tawait generateSummary(messages, model, reserveTokens, undefined, undefined, undefined, undefined, mockComplete);\n\n\t\tassert.equal(\n\t\t\tmockComplete.mock.callCount(),\n\t\t\t1,\n\t\t\t\"Should use single-pass summarization when messages fit in context window\",\n\t\t);\n\t});\n\n\tit(\"passes previousSummary through chunked summarization\", async () => {\n\t\tconst messages: AgentMessage[] = [\n\t\t\tmakeUserMessage(80_000),\n\t\t\tmakeUserMessage(80_000),\n\t\t\tmakeUserMessage(80_000),\n\t\t];\n\t\tconst model = makeModel(200_000);\n\t\tconst reserveTokens = 16_384;\n\t\tconst previousSummary = \"Previous session summary content\";\n\n\t\tconst prompts: string[] = [];\n\t\tconst mockComplete = mock.fn(async (_model: any, context: any) => {\n\t\t\tconst userMsg = context.messages?.[0];\n\t\t\tconst text =\n\t\t\t\ttypeof userMsg?.content === \"string\"\n\t\t\t\t\t? userMsg.content\n\t\t\t\t\t: userMsg?.content?.[0]?.text ?? \"\";\n\t\t\tprompts.push(text);\n\t\t\treturn makeFakeResponse(\"Chunk summary\");\n\t\t});\n\n\t\tawait generateSummary(\n\t\t\tmessages,\n\t\t\tmodel,\n\t\t\treserveTokens,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\tpreviousSummary,\n\t\t\tmockComplete,\n\t\t);\n\n\t\t// First chunk should include the previousSummary\n\t\tassert.ok(\n\t\t\tprompts[0].includes(previousSummary),\n\t\t\t\"First chunk should incorporate the previousSummary\",\n\t\t);\n\t});\n});\n"]}
|