gsd-pi 2.78.0 → 2.78.1-dev.9d08d820b
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 +59 -23
- package/dist/bundled-resource-path.d.ts +7 -0
- package/dist/bundled-resource-path.js +34 -2
- package/dist/claude-cli-check.js +104 -33
- package/dist/cli-policy.d.ts +13 -0
- package/dist/cli-policy.js +17 -0
- package/dist/cli.js +95 -55
- package/dist/headless-query.d.ts +22 -0
- package/dist/headless-query.js +43 -8
- package/dist/headless.d.ts +10 -0
- package/dist/headless.js +16 -1
- package/dist/loader.js +9 -13
- package/dist/onboarding.d.ts +10 -0
- package/dist/onboarding.js +2 -2
- package/dist/provider-migrations.d.ts +2 -2
- package/dist/provider-migrations.js +5 -2
- package/dist/resource-loader.d.ts +5 -2
- package/dist/resource-loader.js +30 -13
- package/dist/resources/.managed-resources-content-hash +1 -0
- package/dist/resources/extensions/claude-code-cli/readiness.js +128 -32
- package/dist/resources/extensions/gsd/auto/loop.js +23 -0
- package/dist/resources/extensions/gsd/auto/phases.js +5 -13
- package/dist/resources/extensions/gsd/auto/run-unit.js +3 -1
- package/dist/resources/extensions/gsd/auto/session.js +5 -6
- package/dist/resources/extensions/gsd/auto-dashboard.js +3 -2
- package/dist/resources/extensions/gsd/auto-dispatch.js +18 -6
- package/dist/resources/extensions/gsd/auto-prompts.js +63 -2
- package/dist/resources/extensions/gsd/auto-recovery.js +43 -4
- package/dist/resources/extensions/gsd/auto-runtime-state.js +31 -0
- package/dist/resources/extensions/gsd/auto-start.js +1 -1
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +2 -2
- package/dist/resources/extensions/gsd/auto-worktree.js +60 -13
- package/dist/resources/extensions/gsd/auto.js +14 -5
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +14 -2
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +7 -5
- package/dist/resources/extensions/gsd/bootstrap/query-tools.js +2 -2
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +5 -4
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +100 -31
- package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +11 -6
- package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +22 -0
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +34 -8
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +121 -3
- package/dist/resources/extensions/gsd/commands/catalog.js +69 -5
- package/dist/resources/extensions/gsd/commands/handlers/core.js +22 -1
- package/dist/resources/extensions/gsd/commands-config.js +3 -2
- package/dist/resources/extensions/gsd/commands-extensions.js +46 -3
- package/dist/resources/extensions/gsd/commands-handlers.js +3 -2
- package/dist/resources/extensions/gsd/commands-mcp-status.js +3 -1
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +10 -1
- package/dist/resources/extensions/gsd/dashboard-overlay.js +1 -1
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +10 -0
- package/dist/resources/extensions/gsd/doctor-providers.js +2 -1
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +39 -1
- package/dist/resources/extensions/gsd/error-classifier.js +1 -1
- package/dist/resources/extensions/gsd/forensics.js +10 -8
- package/dist/resources/extensions/gsd/git-service.js +12 -5
- package/dist/resources/extensions/gsd/gsd-db.js +11 -2
- package/dist/resources/extensions/gsd/guided-flow.js +25 -24
- package/dist/resources/extensions/gsd/home-dir.js +16 -0
- package/dist/resources/extensions/gsd/key-manager.js +2 -1
- package/dist/resources/extensions/gsd/memory-store.js +66 -31
- package/dist/resources/extensions/gsd/migrate/command.js +3 -2
- package/dist/resources/extensions/gsd/milestone-id-reservation.js +36 -0
- package/dist/resources/extensions/gsd/model-router.js +114 -9
- package/dist/resources/extensions/gsd/native-git-bridge.js +7 -1
- package/dist/resources/extensions/gsd/preferences-models.js +91 -15
- package/dist/resources/extensions/gsd/preferences-types.js +2 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +32 -0
- package/dist/resources/extensions/gsd/preferences.js +5 -3
- package/dist/resources/extensions/gsd/prompt-loader.js +23 -12
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +10 -0
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +10 -0
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +10 -0
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +10 -0
- package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +9 -3
- package/dist/resources/extensions/gsd/state.js +42 -0
- package/dist/resources/extensions/gsd/templates/PREFERENCES.md +1 -0
- package/dist/resources/extensions/gsd/tools/memory-tools.js +18 -1
- package/dist/resources/extensions/gsd/unit-context-manifest.js +29 -4
- package/dist/resources/extensions/gsd/visualizer-overlay.js +1 -1
- package/dist/resources/extensions/gsd/watch/header-renderer.js +3 -1
- package/dist/resources/extensions/gsd/worktree-command.js +26 -46
- package/dist/resources/extensions/gsd/worktree-manager.js +20 -1
- package/dist/resources/extensions/gsd/worktree-resolver.js +4 -13
- package/dist/resources/extensions/gsd/worktree-root.js +124 -0
- package/dist/resources/extensions/gsd/worktree-session-state.js +33 -0
- package/dist/resources/extensions/gsd/worktree.js +4 -115
- package/dist/resources/extensions/mcp-client/index.js +6 -3
- package/dist/resources/extensions/ollama/index.js +15 -2
- package/dist/resources/extensions/ollama/model-capabilities.js +31 -0
- package/dist/resources/extensions/ollama/ollama-client.js +40 -4
- package/dist/resources/extensions/slash-commands/create-extension.js +36 -22
- package/dist/resources/extensions/subagent/index.js +324 -178
- package/dist/resources/skills/create-gsd-extension/SKILL.md +9 -5
- package/dist/resources/skills/create-gsd-extension/references/custom-commands.md +1 -1
- package/dist/resources/skills/create-gsd-extension/references/custom-rendering.md +5 -5
- package/dist/resources/skills/create-gsd-extension/references/custom-tools.md +4 -4
- package/dist/resources/skills/create-gsd-extension/references/custom-ui.md +6 -6
- package/dist/resources/skills/create-gsd-extension/references/events-reference.md +3 -3
- package/dist/resources/skills/create-gsd-extension/references/packaging-distribution.md +1 -1
- package/dist/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +3 -3
- package/dist/resources/skills/create-gsd-extension/workflows/create-extension.md +32 -12
- package/dist/rtk-shared.d.ts +3 -0
- package/dist/rtk-shared.js +17 -0
- package/dist/rtk.d.ts +2 -5
- package/dist/rtk.js +3 -20
- package/dist/runtime-checks.d.ts +27 -0
- package/dist/runtime-checks.js +38 -0
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
- package/dist/web/standalone/.next/build-manifest.json +4 -4
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +44 -4
- package/dist/web/standalone/.next/required-server-files.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
- 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 +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
- 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 +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
- 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.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.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.js +2 -2
- 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.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.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.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.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.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/notifications/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route.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.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.js +2 -2
- 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.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.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.js +4 -2
- 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.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.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.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.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.js +2 -2
- 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.js +2 -2
- 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.js +2 -2
- 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.js +4 -4
- 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.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 +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
- 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 +3 -3
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/page.js +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 +11 -11
- package/dist/web/standalone/.next/server/chunks/63.js +3 -3
- package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware.js +2 -2
- package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/server/webpack-runtime.js +1 -1
- package/dist/web/standalone/.next/static/chunks/2556.0527fea66e123b7f.js +1 -0
- package/dist/web/standalone/.next/static/chunks/2824.08296bc2f9654698.js +1 -0
- package/dist/web/standalone/.next/static/chunks/3026.3af53b279375f082.js +1 -0
- package/dist/web/standalone/.next/static/chunks/315.6f68ae79b67d25cf.js +1 -0
- package/dist/web/standalone/.next/static/chunks/3497.4bfc60a3b3dea717.js +1 -0
- package/dist/web/standalone/.next/static/chunks/5516.4a07c872b5c3a663.js +1 -0
- package/dist/web/standalone/.next/static/chunks/8336.31b019697882acfb.js +10 -0
- package/dist/web/standalone/.next/static/chunks/8845.c9702695e8c5a9c5.js +2 -0
- package/dist/web/standalone/.next/static/chunks/9058.01ef3a463bda88f1.js +20 -0
- package/dist/web/standalone/.next/static/chunks/9441.1081da1125d1764f.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/page-9bf2e0c50fb2ca05.js +1 -0
- package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
- package/dist/web/standalone/.next/static/chunks/webpack-f9f0dc45e4f3ac10.js +1 -0
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
- package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
- package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
- package/dist/web/standalone/package.json +2 -1
- package/dist/web/standalone/server.js +1 -1
- package/dist/worktree-cli.d.ts +1 -0
- package/dist/worktree-cli.js +9 -3
- package/dist/worktree-status-banner.d.ts +1 -0
- package/dist/worktree-status-banner.js +132 -0
- package/package.json +1 -3
- package/packages/daemon/package.json +2 -2
- package/packages/mcp-server/dist/alias-telemetry.d.ts +8 -0
- package/packages/mcp-server/dist/alias-telemetry.d.ts.map +1 -0
- package/packages/mcp-server/dist/alias-telemetry.js +30 -0
- package/packages/mcp-server/dist/alias-telemetry.js.map +1 -0
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +74 -46
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +2 -2
- package/packages/mcp-server/src/alias-telemetry.test.ts +78 -0
- package/packages/mcp-server/src/alias-telemetry.ts +30 -0
- package/packages/mcp-server/src/workflow-tools.test.ts +78 -0
- package/packages/mcp-server/src/workflow-tools.ts +93 -58
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/package.json +1 -1
- package/packages/native/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.cache-breakpoint.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/anthropic-shared.cache-breakpoint.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/anthropic-shared.cache-breakpoint.test.js +231 -0
- package/packages/pi-ai/dist/providers/anthropic-shared.cache-breakpoint.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.js +48 -19
- package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
- package/packages/pi-ai/dist/types.d.ts +13 -0
- 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/repair-tool-json.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/repair-tool-json.js +24 -3
- package/packages/pi-ai/dist/utils/repair-tool-json.js.map +1 -1
- package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js +26 -0
- package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-ai/src/providers/anthropic-shared.cache-breakpoint.test.ts +289 -0
- package/packages/pi-ai/src/providers/anthropic-shared.ts +52 -20
- package/packages/pi-ai/src/types.ts +13 -0
- package/packages/pi-ai/src/utils/repair-tool-json.ts +24 -3
- package/packages/pi-ai/src/utils/tests/repair-tool-json.test.ts +32 -0
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +6 -0
- package/packages/pi-coding-agent/dist/core/agent-session.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 +4 -0
- package/packages/pi-coding-agent/dist/core/messages.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +19 -2
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts +10 -0
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +18 -0
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +13 -0
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +20 -16
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/token-telemetry.d.ts +37 -0
- package/packages/pi-coding-agent/dist/core/token-telemetry.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/token-telemetry.js +49 -0
- package/packages/pi-coding-agent/dist/core/token-telemetry.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js +133 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +14 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/tests/system-prompt-cache-stability.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-cache-stability.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-cache-stability.test.js +78 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-cache-stability.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/tests/token-telemetry.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/tests/token-telemetry.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/tests/token-telemetry.test.js +181 -0
- package/packages/pi-coding-agent/dist/tests/token-telemetry.test.js.map +1 -0
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +7 -0
- package/packages/pi-coding-agent/src/core/messages.ts +4 -0
- package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +32 -2
- package/packages/pi-coding-agent/src/core/model-registry.ts +21 -0
- package/packages/pi-coding-agent/src/core/system-prompt.ts +33 -15
- package/packages/pi-coding-agent/src/core/token-telemetry.ts +77 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.ts +212 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +17 -1
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +1 -1
- package/packages/pi-coding-agent/src/tests/system-prompt-cache-stability.test.ts +102 -0
- package/packages/pi-coding-agent/src/tests/token-telemetry.test.ts +200 -0
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/__tests__/autocomplete.test.js +17 -3
- package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
- package/packages/pi-tui/dist/components/__tests__/leak-fixes-runtime.test.d.ts +2 -0
- package/packages/pi-tui/dist/components/__tests__/leak-fixes-runtime.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/components/__tests__/leak-fixes-runtime.test.js +161 -0
- package/packages/pi-tui/dist/components/__tests__/leak-fixes-runtime.test.js.map +1 -0
- package/packages/pi-tui/package.json +1 -1
- package/packages/pi-tui/src/__tests__/autocomplete.test.ts +20 -3
- package/packages/pi-tui/src/components/__tests__/leak-fixes-runtime.test.ts +219 -0
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/packages/rpc-client/package.json +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/claude-code-cli/readiness.ts +130 -30
- package/src/resources/extensions/gsd/auto/loop.ts +24 -2
- package/src/resources/extensions/gsd/auto/phases.ts +6 -14
- package/src/resources/extensions/gsd/auto/run-unit.ts +3 -1
- package/src/resources/extensions/gsd/auto/session.ts +5 -6
- package/src/resources/extensions/gsd/auto/types.ts +1 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +3 -2
- package/src/resources/extensions/gsd/auto-dispatch.ts +18 -6
- package/src/resources/extensions/gsd/auto-prompts.ts +60 -2
- package/src/resources/extensions/gsd/auto-recovery.ts +46 -8
- package/src/resources/extensions/gsd/auto-runtime-state.ts +51 -0
- package/src/resources/extensions/gsd/auto-start.ts +1 -1
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +2 -4
- package/src/resources/extensions/gsd/auto-worktree.ts +82 -12
- package/src/resources/extensions/gsd/auto.ts +14 -4
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +15 -13
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +8 -7
- package/src/resources/extensions/gsd/bootstrap/query-tools.ts +2 -2
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +10 -9
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +108 -31
- package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +12 -6
- package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +20 -0
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +39 -8
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +141 -11
- package/src/resources/extensions/gsd/commands/catalog.ts +75 -5
- package/src/resources/extensions/gsd/commands/handlers/core.ts +22 -1
- package/src/resources/extensions/gsd/commands-config.ts +3 -2
- package/src/resources/extensions/gsd/commands-extensions.ts +43 -3
- package/src/resources/extensions/gsd/commands-handlers.ts +3 -2
- package/src/resources/extensions/gsd/commands-mcp-status.ts +3 -1
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +15 -1
- package/src/resources/extensions/gsd/dashboard-overlay.ts +1 -1
- package/src/resources/extensions/gsd/docs/preferences-reference.md +10 -0
- package/src/resources/extensions/gsd/doctor-providers.ts +2 -1
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +39 -1
- package/src/resources/extensions/gsd/doctor-types.ts +3 -1
- package/src/resources/extensions/gsd/error-classifier.ts +1 -1
- package/src/resources/extensions/gsd/forensics.ts +12 -7
- package/src/resources/extensions/gsd/git-service.ts +13 -5
- package/src/resources/extensions/gsd/gsd-db.ts +12 -2
- package/src/resources/extensions/gsd/guided-flow.ts +27 -26
- package/src/resources/extensions/gsd/home-dir.ts +19 -0
- package/src/resources/extensions/gsd/journal.ts +4 -1
- package/src/resources/extensions/gsd/key-manager.ts +2 -1
- package/src/resources/extensions/gsd/memory-store.ts +81 -28
- package/src/resources/extensions/gsd/migrate/command.ts +3 -2
- package/src/resources/extensions/gsd/milestone-id-reservation.ts +47 -0
- package/src/resources/extensions/gsd/model-router.ts +172 -9
- package/src/resources/extensions/gsd/native-git-bridge.ts +7 -1
- package/src/resources/extensions/gsd/preferences-models.ts +101 -15
- package/src/resources/extensions/gsd/preferences-types.ts +6 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +35 -0
- package/src/resources/extensions/gsd/preferences.ts +16 -2
- package/src/resources/extensions/gsd/prompt-loader.ts +26 -12
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +10 -0
- package/src/resources/extensions/gsd/prompts/complete-slice.md +10 -0
- package/src/resources/extensions/gsd/prompts/plan-slice.md +10 -0
- package/src/resources/extensions/gsd/prompts/refine-slice.md +10 -0
- package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +9 -3
- package/src/resources/extensions/gsd/state.ts +42 -0
- package/src/resources/extensions/gsd/templates/PREFERENCES.md +1 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +178 -1
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +58 -0
- package/src/resources/extensions/gsd/tests/auto-session-encapsulation.test.ts +24 -5
- package/src/resources/extensions/gsd/tests/auto-supervisor.test.mjs +21 -4
- package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/budget-prediction.test.ts +138 -211
- package/src/resources/extensions/gsd/tests/commands-extensions-version-compare.test.ts +58 -0
- package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +142 -59
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +7 -4
- package/src/resources/extensions/gsd/tests/completed-at-reconcile.test.ts +89 -32
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +41 -23
- package/src/resources/extensions/gsd/tests/db-path-worktree-symlink.test.ts +3 -43
- package/src/resources/extensions/gsd/tests/debug-logger.test.ts +5 -3
- package/src/resources/extensions/gsd/tests/deferred-milestone-dir-4996.test.ts +116 -0
- package/src/resources/extensions/gsd/tests/discuss-empty-db-fallback.test.ts +22 -87
- package/src/resources/extensions/gsd/tests/discuss-queued-milestones.test.ts +7 -118
- package/src/resources/extensions/gsd/tests/discuss-tool-scope-leak.test.ts +18 -60
- package/src/resources/extensions/gsd/tests/doctor-orphan-milestone-4996.test.ts +100 -0
- package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +14 -76
- package/src/resources/extensions/gsd/tests/ensure-preconditions-guard-4996.test.ts +93 -0
- package/src/resources/extensions/gsd/tests/false-degraded-mode-warning.test.ts +22 -83
- package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +1 -63
- package/src/resources/extensions/gsd/tests/find-missing-summaries-closed-runtime.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/forensics-stuck-loops.test.ts +26 -1
- package/src/resources/extensions/gsd/tests/gitignore-bg-shell-runtime.test.ts +63 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/gsd-no-project-error-runtime.test.ts +81 -0
- package/src/resources/extensions/gsd/tests/headless-answers.test.ts +14 -4
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +22 -12
- package/src/resources/extensions/gsd/tests/help-menu-coverage.test.ts +57 -0
- package/src/resources/extensions/gsd/tests/home-dir.test.ts +52 -0
- package/src/resources/extensions/gsd/tests/import-done-milestones-runtime.test.ts +145 -0
- package/src/resources/extensions/gsd/tests/init-prefs-routing.test.ts +64 -1
- package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +72 -1
- package/src/resources/extensions/gsd/tests/integration/token-savings.test.ts +0 -23
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +128 -0
- package/src/resources/extensions/gsd/tests/memory-tools.test.ts +33 -1
- package/src/resources/extensions/gsd/tests/merge-self-branch-guard.test.ts +124 -0
- package/src/resources/extensions/gsd/tests/milestone-id-gap-reuse-4996.test.ts +152 -0
- package/src/resources/extensions/gsd/tests/milestone-report-path.test.ts +18 -1
- package/src/resources/extensions/gsd/tests/model-router.test.ts +169 -8
- package/src/resources/extensions/gsd/tests/native-git-infra-errors.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +32 -43
- package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +4 -10
- package/src/resources/extensions/gsd/tests/preferences.test.ts +127 -0
- package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/quick-turn-end-cleanup.test.ts +6 -6
- package/src/resources/extensions/gsd/tests/register-hooks-compaction-checkpoint.test.ts +93 -0
- package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +168 -19
- package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +23 -1
- package/src/resources/extensions/gsd/tests/steer-worktree-path.test.ts +17 -1
- package/src/resources/extensions/gsd/tests/system-context-message-routing.test.ts +101 -0
- package/src/resources/extensions/gsd/tests/token-profile.test.ts +51 -4
- package/src/resources/extensions/gsd/tests/turn-epoch.test.ts +7 -16
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +38 -3
- package/src/resources/extensions/gsd/tests/unstructured-continue-context-injection.test.ts +5 -7
- package/src/resources/extensions/gsd/tests/uok-gitops-turn-action.test.ts +15 -1
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +6 -6
- package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +34 -33
- package/src/resources/extensions/gsd/tests/worktree.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +131 -1
- package/src/resources/extensions/gsd/tools/memory-tools.ts +17 -1
- package/src/resources/extensions/gsd/unit-context-manifest.ts +44 -12
- package/src/resources/extensions/gsd/visualizer-overlay.ts +1 -1
- package/src/resources/extensions/gsd/watch/header-renderer.ts +3 -1
- package/src/resources/extensions/gsd/workflow-logger.ts +1 -0
- package/src/resources/extensions/gsd/worktree-command.ts +31 -44
- package/src/resources/extensions/gsd/worktree-manager.ts +40 -1
- package/src/resources/extensions/gsd/worktree-resolver.ts +4 -14
- package/src/resources/extensions/gsd/worktree-root.ts +144 -0
- package/src/resources/extensions/gsd/worktree-session-state.ts +35 -0
- package/src/resources/extensions/gsd/worktree.ts +8 -119
- package/src/resources/extensions/mcp-client/index.ts +6 -3
- package/src/resources/extensions/mcp-client/tests/global-config.test.ts +91 -0
- package/src/resources/extensions/ollama/index.ts +16 -2
- package/src/resources/extensions/ollama/model-capabilities.ts +34 -0
- package/src/resources/extensions/ollama/ollama-client.ts +41 -4
- package/src/resources/extensions/ollama/tests/model-capabilities.test.ts +96 -0
- package/src/resources/extensions/ollama/tests/ollama-client-timeout-env.test.ts +147 -0
- package/src/resources/extensions/slash-commands/create-extension.ts +38 -24
- package/src/resources/extensions/subagent/index.ts +165 -7
- package/src/resources/skills/create-gsd-extension/SKILL.md +9 -5
- package/src/resources/skills/create-gsd-extension/references/custom-commands.md +1 -1
- package/src/resources/skills/create-gsd-extension/references/custom-rendering.md +5 -5
- package/src/resources/skills/create-gsd-extension/references/custom-tools.md +4 -4
- package/src/resources/skills/create-gsd-extension/references/custom-ui.md +6 -6
- package/src/resources/skills/create-gsd-extension/references/events-reference.md +3 -3
- package/src/resources/skills/create-gsd-extension/references/packaging-distribution.md +1 -1
- package/src/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +3 -3
- package/src/resources/skills/create-gsd-extension/templates/extension-skeleton.ts +2 -2
- package/src/resources/skills/create-gsd-extension/templates/stateful-tool-skeleton.ts +3 -3
- package/src/resources/skills/create-gsd-extension/templates/templates.test.ts +58 -0
- package/src/resources/skills/create-gsd-extension/workflows/create-extension.md +32 -12
- package/dist/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +0 -601
- package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +0 -651
- package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +0 -91
- package/dist/resources/extensions/gsd/tests/auto-supervisor.test.mjs +0 -53
- package/dist/resources/extensions/gsd/tests/dist-redirect.mjs +0 -112
- package/dist/resources/extensions/gsd/tests/resolve-ts-hooks.mjs +0 -23
- package/dist/resources/extensions/gsd/tests/resolve-ts.mjs +0 -5
- package/dist/resources/skills/github-workflows/references/gh/tests/__init__.py +0 -0
- package/dist/resources/skills/github-workflows/references/gh/tests/test_github_project_setup.py +0 -608
- package/dist/web/standalone/.next/static/chunks/2826.e9f5195e91f9cad2.js +0 -11
- package/dist/web/standalone/.next/static/chunks/3621.fc7480022c972438.js +0 -20
- package/dist/web/standalone/.next/static/chunks/app/page-151349214571e2b6.js +0 -1
- package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
- package/dist/web/standalone/.next/static/chunks/webpack-2e68521d7c82f7c2.js +0 -1
- package/src/resources/extensions/gsd/tests/copy-planning-artifacts-samepath.test.ts +0 -22
- package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +0 -47
- package/src/resources/extensions/gsd/tests/empty-content-abort-loop.test.ts +0 -75
- /package/dist/web/standalone/.next/static/{C1zT2kEfoLhDdbWPWKrXd → -Ukk6_YxRd4GY4iUOnRUE}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{C1zT2kEfoLhDdbWPWKrXd → -Ukk6_YxRd4GY4iUOnRUE}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
// Runtime regression tests for the post-compaction tool-card cleanup and the
|
|
2
|
+
// green-bordered success-notification rendering. Replaces the source-grep
|
|
3
|
+
// `src/tests/tui-running-and-success-box.test.ts` that was deleted in #4875
|
|
4
|
+
// (tracked as #4872).
|
|
5
|
+
//
|
|
6
|
+
// The previous tests asserted on identifier presence and method signature
|
|
7
|
+
// shape via regex. A regression that routed `success` notifications through
|
|
8
|
+
// `showStatus` (dim text) by accident would not have failed because the
|
|
9
|
+
// `showSuccess` method would still exist and still match the regex. These
|
|
10
|
+
// tests instead drive the components through the actual scenario and assert
|
|
11
|
+
// on rendered output.
|
|
12
|
+
|
|
13
|
+
import assert from "node:assert/strict";
|
|
14
|
+
import { describe, it, before } from "node:test";
|
|
15
|
+
|
|
16
|
+
import { Container, Text } from "@gsd/pi-tui";
|
|
17
|
+
import stripAnsi from "strip-ansi";
|
|
18
|
+
|
|
19
|
+
import { initTheme, theme } from "../theme/theme.js";
|
|
20
|
+
import { DynamicBorder } from "./dynamic-border.js";
|
|
21
|
+
import { ToolExecutionComponent } from "./tool-execution.js";
|
|
22
|
+
|
|
23
|
+
// Theme is a globalThis-shared singleton that throws if not initialized.
|
|
24
|
+
// Initialize once before any test that exercises themed rendering.
|
|
25
|
+
before(() => {
|
|
26
|
+
initTheme("dark");
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
interface MockTui {
|
|
30
|
+
renderCount: number;
|
|
31
|
+
requestRender(): void;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function makeMockTUI(): MockTui {
|
|
35
|
+
return {
|
|
36
|
+
renderCount: 0,
|
|
37
|
+
requestRender() {
|
|
38
|
+
this.renderCount++;
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// ─── Bug 1: tool cards stuck in "Running" after compaction ──────────────
|
|
44
|
+
|
|
45
|
+
describe("ToolExecutionComponent post-compaction cleanup", () => {
|
|
46
|
+
it("renders 'Running' status while the tool call has no result", () => {
|
|
47
|
+
// Baseline: a freshly-constructed component (mid-stream) must show
|
|
48
|
+
// the running badge — this is the state we need to flip OUT of when
|
|
49
|
+
// compaction removes the result message.
|
|
50
|
+
const ui = makeMockTUI();
|
|
51
|
+
const c = new ToolExecutionComponent(
|
|
52
|
+
"read_file",
|
|
53
|
+
{ path: "/tmp/x.txt" },
|
|
54
|
+
{},
|
|
55
|
+
undefined,
|
|
56
|
+
ui as never,
|
|
57
|
+
);
|
|
58
|
+
const rendered = c.render(60).map(stripAnsi).join("\n");
|
|
59
|
+
assert.ok(
|
|
60
|
+
rendered.includes("Running"),
|
|
61
|
+
"freshly constructed component should render 'Running' badge",
|
|
62
|
+
);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("markHistoricalNoResult flips a stuck tool card OUT of 'Running'", () => {
|
|
66
|
+
// Real bug: after session-history replay (post-compaction or session
|
|
67
|
+
// switch), tool calls without matching tool_result messages stay in
|
|
68
|
+
// isPartial = true forever. markHistoricalNoResult must produce a
|
|
69
|
+
// rendered output that no longer reads "Running".
|
|
70
|
+
const ui = makeMockTUI();
|
|
71
|
+
const c = new ToolExecutionComponent(
|
|
72
|
+
"read_file",
|
|
73
|
+
{ path: "/tmp/x.txt" },
|
|
74
|
+
{},
|
|
75
|
+
undefined,
|
|
76
|
+
ui as never,
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
c.markHistoricalNoResult();
|
|
80
|
+
|
|
81
|
+
const rendered = c.render(60).map(stripAnsi).join("\n");
|
|
82
|
+
assert.ok(
|
|
83
|
+
!rendered.includes("Running"),
|
|
84
|
+
"after markHistoricalNoResult, the tool card must NOT render 'Running' — got:\n" +
|
|
85
|
+
rendered,
|
|
86
|
+
);
|
|
87
|
+
assert.ok(
|
|
88
|
+
rendered.includes("Done"),
|
|
89
|
+
"flipped card should render 'Done' status (no-result success)",
|
|
90
|
+
);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("markHistoricalNoResult is idempotent when a real result already exists", () => {
|
|
94
|
+
// Late-arriving stream events must not clobber legitimate results.
|
|
95
|
+
// We observe the no-clobber via behaviour: a card that completed
|
|
96
|
+
// with a real result keeps its "Done" badge and content even if
|
|
97
|
+
// markHistoricalNoResult fires again afterwards.
|
|
98
|
+
const ui = makeMockTUI();
|
|
99
|
+
const c = new ToolExecutionComponent(
|
|
100
|
+
"read_file",
|
|
101
|
+
{ path: "/tmp/x.txt" },
|
|
102
|
+
{},
|
|
103
|
+
undefined,
|
|
104
|
+
ui as never,
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
// Use the public completion path the runtime calls.
|
|
108
|
+
c.updateResult(
|
|
109
|
+
{
|
|
110
|
+
content: [{ type: "text", text: "real-result-payload" }],
|
|
111
|
+
isError: false,
|
|
112
|
+
},
|
|
113
|
+
false, // isPartial = false → "Done"
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
const before = c.render(60).map(stripAnsi).join("\n");
|
|
117
|
+
assert.ok(before.includes("Done"), "after complete(), card shows 'Done'");
|
|
118
|
+
|
|
119
|
+
c.markHistoricalNoResult(); // must early-return
|
|
120
|
+
const after = c.render(60).map(stripAnsi).join("\n");
|
|
121
|
+
assert.equal(
|
|
122
|
+
after,
|
|
123
|
+
before,
|
|
124
|
+
"markHistoricalNoResult must NOT mutate state when a real result is already present",
|
|
125
|
+
);
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// ─── Bug 2: success notifications render as a green bordered box ────────
|
|
130
|
+
|
|
131
|
+
describe("Success-notification rendering — DynamicBorder + success theme", () => {
|
|
132
|
+
// We drive the same component composition that interactive-mode.showSuccess
|
|
133
|
+
// builds (DynamicBorder + Text + DynamicBorder, all themed with
|
|
134
|
+
// theme.fg("success", …)) and assert on the rendered output, rather than
|
|
135
|
+
// trying to instantiate the full InteractiveMode (which requires a real
|
|
136
|
+
// session, bridge, and TUI runtime).
|
|
137
|
+
function buildSuccessNotification(message: string): Container {
|
|
138
|
+
const c = new Container();
|
|
139
|
+
const successColor = (text: string) => theme.fg("success", text);
|
|
140
|
+
c.addChild(new DynamicBorder(successColor));
|
|
141
|
+
c.addChild(new Text(theme.fg("success", message), 1, 0));
|
|
142
|
+
c.addChild(new DynamicBorder(successColor));
|
|
143
|
+
return c;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
it("renders a top and bottom horizontal border framing the message", () => {
|
|
147
|
+
const c = buildSuccessNotification("Milestone M042 ready.");
|
|
148
|
+
const lines = c.render(40);
|
|
149
|
+
|
|
150
|
+
// First and last lines should be horizontal-rule borders
|
|
151
|
+
// (DynamicBorder renders a row of "─" characters).
|
|
152
|
+
const firstStripped = stripAnsi(lines[0]);
|
|
153
|
+
const lastStripped = stripAnsi(lines[lines.length - 1]);
|
|
154
|
+
|
|
155
|
+
assert.ok(
|
|
156
|
+
firstStripped.includes("─"),
|
|
157
|
+
`first line should be a border (got: ${JSON.stringify(firstStripped)})`,
|
|
158
|
+
);
|
|
159
|
+
assert.ok(
|
|
160
|
+
lastStripped.includes("─"),
|
|
161
|
+
`last line should be a border (got: ${JSON.stringify(lastStripped)})`,
|
|
162
|
+
);
|
|
163
|
+
assert.ok(
|
|
164
|
+
lines.length >= 3,
|
|
165
|
+
`success notification must have at least 3 lines (top border, message, bottom border) — got ${lines.length}`,
|
|
166
|
+
);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it("the message text appears between the two borders", () => {
|
|
170
|
+
const c = buildSuccessNotification("Milestone M042 ready.");
|
|
171
|
+
const lines = c.render(40);
|
|
172
|
+
|
|
173
|
+
const messageRow = lines.findIndex((l) => stripAnsi(l).includes("Milestone M042 ready."));
|
|
174
|
+
assert.ok(messageRow > 0, "message must appear after the top border");
|
|
175
|
+
assert.ok(
|
|
176
|
+
messageRow < lines.length - 1,
|
|
177
|
+
"message must appear before the bottom border",
|
|
178
|
+
);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it("borders carry ANSI styling (not plain dim text like showStatus)", () => {
|
|
182
|
+
// Goodhart-resistant: if a regression routed success through
|
|
183
|
+
// showStatus, the borders would be missing AND the rendered text
|
|
184
|
+
// would be plain (or only dim-styled, not success-colored). We
|
|
185
|
+
// observe the border lines carry ANSI escape codes — the literal
|
|
186
|
+
// foreground color depends on the theme (which is system-dependent
|
|
187
|
+
// in CI), so we don't pin a specific code but DO require styling
|
|
188
|
+
// to be present.
|
|
189
|
+
const c = buildSuccessNotification("ok");
|
|
190
|
+
const lines = c.render(40);
|
|
191
|
+
const top = lines[0];
|
|
192
|
+
assert.ok(
|
|
193
|
+
top !== stripAnsi(top),
|
|
194
|
+
"top border must contain ANSI styling — a plain unstyled border " +
|
|
195
|
+
"would indicate the rendering bypassed theme.fg('success', ...)",
|
|
196
|
+
);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it("plain Text status (the showStatus path) does NOT produce a bordered box", () => {
|
|
200
|
+
// Counter-test: this is what the bug looked like — a single dim Text
|
|
201
|
+
// with no surrounding border. If anyone ever "fixes" the showSuccess
|
|
202
|
+
// regression by also adding borders to showStatus, this test will
|
|
203
|
+
// surface the conflation.
|
|
204
|
+
const plain = new Text(theme.fg("dim", "Milestone M042 ready."), 1, 0);
|
|
205
|
+
const lines = plain.render(40);
|
|
206
|
+
const joined = lines.map(stripAnsi).join("\n");
|
|
207
|
+
assert.ok(
|
|
208
|
+
!joined.includes("─"),
|
|
209
|
+
"plain Text (showStatus path) must NOT contain border characters",
|
|
210
|
+
);
|
|
211
|
+
});
|
|
212
|
+
});
|
|
@@ -159,6 +159,7 @@ function getSlashCommandName(text: string): string {
|
|
|
159
159
|
|
|
160
160
|
function createHost(options: HostOptions = {}) {
|
|
161
161
|
const prompted: string[] = [];
|
|
162
|
+
const promptOptions: any[] = [];
|
|
162
163
|
const errors: string[] = [];
|
|
163
164
|
const warnings: string[] = [];
|
|
164
165
|
const tips: string[] = [];
|
|
@@ -186,8 +187,9 @@ function createHost(options: HostOptions = {}) {
|
|
|
186
187
|
isBashRunning: false,
|
|
187
188
|
isCompacting: false,
|
|
188
189
|
isStreaming: false,
|
|
189
|
-
prompt: async (text: string) => {
|
|
190
|
+
prompt: async (text: string, options?: any) => {
|
|
190
191
|
prompted.push(text);
|
|
192
|
+
promptOptions.push(options);
|
|
191
193
|
},
|
|
192
194
|
},
|
|
193
195
|
ui: {
|
|
@@ -235,6 +237,7 @@ function createHost(options: HostOptions = {}) {
|
|
|
235
237
|
return {
|
|
236
238
|
host: host as typeof host & { defaultEditor: typeof editor & { onSubmit: (text: string) => Promise<void> } },
|
|
237
239
|
prompted,
|
|
240
|
+
promptOptions,
|
|
238
241
|
errors,
|
|
239
242
|
warnings,
|
|
240
243
|
tips,
|
|
@@ -244,6 +247,19 @@ function createHost(options: HostOptions = {}) {
|
|
|
244
247
|
};
|
|
245
248
|
}
|
|
246
249
|
|
|
250
|
+
test("input-controller: regular prompt submit preserves pending images", async () => {
|
|
251
|
+
const { host, prompted, promptOptions } = createHost();
|
|
252
|
+
host.pendingImages.push({ ...TEST_IMAGE });
|
|
253
|
+
|
|
254
|
+
await host.defaultEditor.onSubmit("describe this image [Image #1]");
|
|
255
|
+
|
|
256
|
+
assert.deepEqual(prompted, ["describe this image [Image #1]"]);
|
|
257
|
+
assert.equal(promptOptions[0]?.images?.length, 1);
|
|
258
|
+
assert.equal(promptOptions[0].images[0].mimeType, "image/png");
|
|
259
|
+
assert.equal(promptOptions[0].images[0].data, TEST_IMAGE.data);
|
|
260
|
+
assert.equal(host.pendingImages.length, 0);
|
|
261
|
+
});
|
|
262
|
+
|
|
247
263
|
test("input-controller: built-in slash commands stay in TUI dispatch", async () => {
|
|
248
264
|
const { host, prompted, errors, getSettingsOpened, getEditorText } = createHost();
|
|
249
265
|
|
|
@@ -133,7 +133,7 @@ export function setupEditorSubmitHandler(host: InteractiveModeStateHost & {
|
|
|
133
133
|
// submitPromptsDirectly is false — still dispatch via session.prompt so user input
|
|
134
134
|
// is not silently discarded.
|
|
135
135
|
try {
|
|
136
|
-
await host.session.prompt(text);
|
|
136
|
+
await host.session.prompt(text, { images });
|
|
137
137
|
} catch (error: unknown) {
|
|
138
138
|
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
139
139
|
host.showError(errorMessage);
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// @gsd/pi-coding-agent + system-prompt-cache-stability.test — regression
|
|
2
|
+
// coverage for #5019. The system prompt must NOT include a per-call timestamp
|
|
3
|
+
// by default; embedding `Date.toLocaleString()` in the cached prefix
|
|
4
|
+
// invalidates Anthropic prompt-cache hits on every request and incurs the
|
|
5
|
+
// cache-write premium. The opt-in `includeDateTime` flag preserves the prior
|
|
6
|
+
// behavior for callers that explicitly want clock awareness.
|
|
7
|
+
|
|
8
|
+
import test from "node:test";
|
|
9
|
+
import assert from "node:assert/strict";
|
|
10
|
+
|
|
11
|
+
import { buildSystemPrompt } from "../core/system-prompt.js";
|
|
12
|
+
|
|
13
|
+
// ─── Default branch (no customPrompt) ──────────────────────────────────────
|
|
14
|
+
|
|
15
|
+
test("buildSystemPrompt: default omits 'Current date and time' line", () => {
|
|
16
|
+
const prompt = buildSystemPrompt({ selectedTools: ["read", "edit"] });
|
|
17
|
+
assert.ok(
|
|
18
|
+
!prompt.includes("Current date and time:"),
|
|
19
|
+
`prompt should not include the dateTime line by default. Got:\n${prompt}`,
|
|
20
|
+
);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test("buildSystemPrompt: includeDateTime=true emits 'Current date and time' line", () => {
|
|
24
|
+
const prompt = buildSystemPrompt({
|
|
25
|
+
selectedTools: ["read", "edit"],
|
|
26
|
+
includeDateTime: true,
|
|
27
|
+
});
|
|
28
|
+
assert.match(
|
|
29
|
+
prompt,
|
|
30
|
+
/Current date and time: /,
|
|
31
|
+
"prompt should include the dateTime line when explicitly opted in",
|
|
32
|
+
);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test("buildSystemPrompt: includeDateTime=false explicit also omits the line", () => {
|
|
36
|
+
const prompt = buildSystemPrompt({
|
|
37
|
+
selectedTools: ["read", "edit"],
|
|
38
|
+
includeDateTime: false,
|
|
39
|
+
});
|
|
40
|
+
assert.ok(!prompt.includes("Current date and time:"));
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// ─── Custom-prompt branch ──────────────────────────────────────────────────
|
|
44
|
+
|
|
45
|
+
test("buildSystemPrompt (customPrompt): default omits 'Current date and time' line", () => {
|
|
46
|
+
const prompt = buildSystemPrompt({
|
|
47
|
+
customPrompt: "CUSTOM BASE",
|
|
48
|
+
selectedTools: ["read"],
|
|
49
|
+
});
|
|
50
|
+
assert.ok(!prompt.includes("Current date and time:"));
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test("buildSystemPrompt (customPrompt): includeDateTime=true emits the line", () => {
|
|
54
|
+
const prompt = buildSystemPrompt({
|
|
55
|
+
customPrompt: "CUSTOM BASE",
|
|
56
|
+
selectedTools: ["read"],
|
|
57
|
+
includeDateTime: true,
|
|
58
|
+
});
|
|
59
|
+
assert.match(prompt, /Current date and time: /);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// ─── Cache-stability invariant ─────────────────────────────────────────────
|
|
63
|
+
|
|
64
|
+
test("buildSystemPrompt: two back-to-back default calls produce identical prompts", async () => {
|
|
65
|
+
// The bug: the previous default-on `dateTime` line included `second: "2-digit"`,
|
|
66
|
+
// so two calls within the same second could match but any longer gap busted
|
|
67
|
+
// the cache. Asserting equality across a deliberate sub-second sleep proves
|
|
68
|
+
// the byte-for-byte stability that Anthropic prompt caching requires.
|
|
69
|
+
const first = buildSystemPrompt({ selectedTools: ["read", "edit"], cwd: "/tmp/example" });
|
|
70
|
+
await new Promise((resolve) => setTimeout(resolve, 1100));
|
|
71
|
+
const second = buildSystemPrompt({ selectedTools: ["read", "edit"], cwd: "/tmp/example" });
|
|
72
|
+
assert.equal(
|
|
73
|
+
first,
|
|
74
|
+
second,
|
|
75
|
+
"system prompt must be byte-for-byte stable across calls so the prompt cache can hit",
|
|
76
|
+
);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("buildSystemPrompt: includeDateTime=true intentionally produces different prompts across the second boundary", async () => {
|
|
80
|
+
// Inverse of the cache-stability test: when callers opt in, the dateTime
|
|
81
|
+
// line is expected to vary. This documents the trade-off the flag exists
|
|
82
|
+
// to surface.
|
|
83
|
+
const first = buildSystemPrompt({
|
|
84
|
+
selectedTools: ["read"],
|
|
85
|
+
cwd: "/tmp/example",
|
|
86
|
+
includeDateTime: true,
|
|
87
|
+
});
|
|
88
|
+
await new Promise((resolve) => setTimeout(resolve, 1100));
|
|
89
|
+
const second = buildSystemPrompt({
|
|
90
|
+
selectedTools: ["read"],
|
|
91
|
+
cwd: "/tmp/example",
|
|
92
|
+
includeDateTime: true,
|
|
93
|
+
});
|
|
94
|
+
assert.notEqual(first, second, "opt-in dateTime is expected to vary across the second boundary");
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// ─── Cwd preservation ──────────────────────────────────────────────────────
|
|
98
|
+
|
|
99
|
+
test("buildSystemPrompt: 'Current working directory' line is preserved (only dateTime is removed)", () => {
|
|
100
|
+
const prompt = buildSystemPrompt({ selectedTools: ["read"], cwd: "/tmp/example" });
|
|
101
|
+
assert.match(prompt, /Current working directory: \/tmp\/example/);
|
|
102
|
+
});
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
// @gsd/pi-coding-agent + token-telemetry.test — coverage for #5023.
|
|
2
|
+
// Verifies the env-gated emitter:
|
|
3
|
+
// - is silent by default (no behavior change for existing users)
|
|
4
|
+
// - emits a single valid JSON line when PI_TOKEN_TELEMETRY=1
|
|
5
|
+
// - record shape captures the cache breakdown the providers already extract
|
|
6
|
+
// - cacheHitRatio math is correct, including the no-input edge case
|
|
7
|
+
|
|
8
|
+
import { describe, test, beforeEach, afterEach } from "node:test";
|
|
9
|
+
import assert from "node:assert/strict";
|
|
10
|
+
|
|
11
|
+
import type { AssistantMessage } from "@gsd/pi-ai";
|
|
12
|
+
|
|
13
|
+
import { buildTokenTelemetryRecord, emitTokenTelemetry } from "../core/token-telemetry.js";
|
|
14
|
+
|
|
15
|
+
function makeAssistantMessage(overrides: Partial<AssistantMessage> = {}): AssistantMessage {
|
|
16
|
+
return {
|
|
17
|
+
role: "assistant",
|
|
18
|
+
content: [],
|
|
19
|
+
api: "anthropic-messages",
|
|
20
|
+
provider: "anthropic",
|
|
21
|
+
model: "claude-sonnet-4-6",
|
|
22
|
+
usage: {
|
|
23
|
+
input: 100,
|
|
24
|
+
output: 50,
|
|
25
|
+
cacheRead: 0,
|
|
26
|
+
cacheWrite: 0,
|
|
27
|
+
totalTokens: 150,
|
|
28
|
+
cost: { input: 0.3, output: 0.75, cacheRead: 0, cacheWrite: 0, total: 1.05 },
|
|
29
|
+
},
|
|
30
|
+
stopReason: "stop",
|
|
31
|
+
timestamp: 1700000000000,
|
|
32
|
+
...overrides,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// ─── buildTokenTelemetryRecord ─────────────────────────────────────────────
|
|
37
|
+
|
|
38
|
+
describe("buildTokenTelemetryRecord", () => {
|
|
39
|
+
test("captures all fields from a typical message", () => {
|
|
40
|
+
const msg = makeAssistantMessage();
|
|
41
|
+
const record = buildTokenTelemetryRecord(msg);
|
|
42
|
+
assert.deepEqual(record, {
|
|
43
|
+
ts: 1700000000000,
|
|
44
|
+
model: "claude-sonnet-4-6",
|
|
45
|
+
stopReason: "stop",
|
|
46
|
+
input: 100,
|
|
47
|
+
output: 50,
|
|
48
|
+
cacheRead: 0,
|
|
49
|
+
cacheWrite: 0,
|
|
50
|
+
costTotal: 1.05,
|
|
51
|
+
cacheHitRatio: 0,
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test("cacheHitRatio = read / (read + input) when both present", () => {
|
|
56
|
+
const msg = makeAssistantMessage({
|
|
57
|
+
usage: {
|
|
58
|
+
input: 200,
|
|
59
|
+
output: 50,
|
|
60
|
+
cacheRead: 800,
|
|
61
|
+
cacheWrite: 0,
|
|
62
|
+
totalTokens: 1050,
|
|
63
|
+
cost: { input: 0.6, output: 0.75, cacheRead: 0.24, cacheWrite: 0, total: 1.59 },
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
const record = buildTokenTelemetryRecord(msg);
|
|
67
|
+
assert.equal(record.cacheRead, 800);
|
|
68
|
+
assert.equal(record.input, 200);
|
|
69
|
+
assert.equal(record.cacheHitRatio, 0.8);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test("cacheHitRatio = 0 when both read and input are 0 (no division-by-zero)", () => {
|
|
73
|
+
const msg = makeAssistantMessage({
|
|
74
|
+
usage: {
|
|
75
|
+
input: 0,
|
|
76
|
+
output: 50,
|
|
77
|
+
cacheRead: 0,
|
|
78
|
+
cacheWrite: 0,
|
|
79
|
+
totalTokens: 50,
|
|
80
|
+
cost: { input: 0, output: 0.75, cacheRead: 0, cacheWrite: 0, total: 0.75 },
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
const record = buildTokenTelemetryRecord(msg);
|
|
84
|
+
assert.equal(record.cacheHitRatio, 0);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test("cacheHitRatio = 1 when only cacheRead present (full hit)", () => {
|
|
88
|
+
const msg = makeAssistantMessage({
|
|
89
|
+
usage: {
|
|
90
|
+
input: 0,
|
|
91
|
+
output: 50,
|
|
92
|
+
cacheRead: 5000,
|
|
93
|
+
cacheWrite: 0,
|
|
94
|
+
totalTokens: 5050,
|
|
95
|
+
cost: { input: 0, output: 0.75, cacheRead: 1.5, cacheWrite: 0, total: 2.25 },
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
const record = buildTokenTelemetryRecord(msg);
|
|
99
|
+
assert.equal(record.cacheHitRatio, 1);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test("cacheWrite is captured (the cache-miss-with-cache-control case from #5019)", () => {
|
|
103
|
+
const msg = makeAssistantMessage({
|
|
104
|
+
usage: {
|
|
105
|
+
input: 50,
|
|
106
|
+
output: 100,
|
|
107
|
+
cacheRead: 0,
|
|
108
|
+
cacheWrite: 5000,
|
|
109
|
+
totalTokens: 5150,
|
|
110
|
+
cost: { input: 0.15, output: 1.5, cacheRead: 0, cacheWrite: 18.75, total: 20.4 },
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
const record = buildTokenTelemetryRecord(msg);
|
|
114
|
+
assert.equal(record.cacheWrite, 5000);
|
|
115
|
+
assert.equal(record.cacheHitRatio, 0, "no read = ratio 0 even when write is large");
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test("error stopReason is captured verbatim", () => {
|
|
119
|
+
const msg = makeAssistantMessage({ stopReason: "error", errorMessage: "rate_limit" });
|
|
120
|
+
assert.equal(buildTokenTelemetryRecord(msg).stopReason, "error");
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// ─── emitTokenTelemetry ────────────────────────────────────────────────────
|
|
125
|
+
|
|
126
|
+
describe("emitTokenTelemetry", () => {
|
|
127
|
+
let captured: string[];
|
|
128
|
+
let originalWrite: typeof process.stderr.write;
|
|
129
|
+
let originalEnv: string | undefined;
|
|
130
|
+
|
|
131
|
+
beforeEach(() => {
|
|
132
|
+
captured = [];
|
|
133
|
+
originalWrite = process.stderr.write.bind(process.stderr);
|
|
134
|
+
// Replace stderr.write with a capture; preserve the same return contract.
|
|
135
|
+
process.stderr.write = ((chunk: string | Uint8Array): boolean => {
|
|
136
|
+
captured.push(typeof chunk === "string" ? chunk : Buffer.from(chunk).toString());
|
|
137
|
+
return true;
|
|
138
|
+
}) as typeof process.stderr.write;
|
|
139
|
+
originalEnv = process.env.PI_TOKEN_TELEMETRY;
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
afterEach(() => {
|
|
143
|
+
process.stderr.write = originalWrite;
|
|
144
|
+
if (originalEnv === undefined) {
|
|
145
|
+
delete process.env.PI_TOKEN_TELEMETRY;
|
|
146
|
+
} else {
|
|
147
|
+
process.env.PI_TOKEN_TELEMETRY = originalEnv;
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
test("silent by default (env var unset)", () => {
|
|
152
|
+
delete process.env.PI_TOKEN_TELEMETRY;
|
|
153
|
+
emitTokenTelemetry(makeAssistantMessage());
|
|
154
|
+
assert.equal(captured.length, 0);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
test("silent when env var has any non-'1' value", () => {
|
|
158
|
+
process.env.PI_TOKEN_TELEMETRY = "true"; // not literally "1"
|
|
159
|
+
emitTokenTelemetry(makeAssistantMessage());
|
|
160
|
+
assert.equal(captured.length, 0, "only literal '1' should enable telemetry");
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
test("emits a single JSON line when PI_TOKEN_TELEMETRY=1", () => {
|
|
164
|
+
process.env.PI_TOKEN_TELEMETRY = "1";
|
|
165
|
+
emitTokenTelemetry(makeAssistantMessage());
|
|
166
|
+
assert.equal(captured.length, 1);
|
|
167
|
+
assert.ok(captured[0].endsWith("\n"), "line must terminate with newline");
|
|
168
|
+
const parsed = JSON.parse(captured[0].trimEnd());
|
|
169
|
+
assert.equal(parsed.model, "claude-sonnet-4-6");
|
|
170
|
+
assert.equal(parsed.input, 100);
|
|
171
|
+
assert.equal(parsed.output, 50);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
test("emitted JSON has the documented shape", () => {
|
|
175
|
+
process.env.PI_TOKEN_TELEMETRY = "1";
|
|
176
|
+
emitTokenTelemetry(makeAssistantMessage());
|
|
177
|
+
const parsed = JSON.parse(captured[0].trimEnd());
|
|
178
|
+
const keys = Object.keys(parsed).sort();
|
|
179
|
+
assert.deepEqual(keys, [
|
|
180
|
+
"cacheHitRatio",
|
|
181
|
+
"cacheRead",
|
|
182
|
+
"cacheWrite",
|
|
183
|
+
"costTotal",
|
|
184
|
+
"input",
|
|
185
|
+
"model",
|
|
186
|
+
"output",
|
|
187
|
+
"stopReason",
|
|
188
|
+
"ts",
|
|
189
|
+
]);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
test("never throws — telemetry must not break the agent loop", () => {
|
|
193
|
+
process.env.PI_TOKEN_TELEMETRY = "1";
|
|
194
|
+
// Force a write failure to exercise the swallow path.
|
|
195
|
+
process.stderr.write = (() => {
|
|
196
|
+
throw new Error("simulated stderr failure");
|
|
197
|
+
}) as typeof process.stderr.write;
|
|
198
|
+
assert.doesNotThrow(() => emitTokenTelemetry(makeAssistantMessage()));
|
|
199
|
+
});
|
|
200
|
+
});
|