gsd-pi 2.46.1-dev.9d471d1 → 2.46.1-dev.eee1457

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.
Files changed (91) hide show
  1. package/README.md +46 -29
  2. package/dist/resources/extensions/claude-code-cli/index.js +25 -0
  3. package/dist/resources/extensions/claude-code-cli/models.js +40 -0
  4. package/dist/resources/extensions/claude-code-cli/package.json +11 -0
  5. package/dist/resources/extensions/claude-code-cli/partial-builder.js +223 -0
  6. package/dist/resources/extensions/claude-code-cli/readiness.js +26 -0
  7. package/dist/resources/extensions/claude-code-cli/sdk-types.js +8 -0
  8. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +309 -0
  9. package/dist/resources/extensions/gsd/auto-start.js +9 -8
  10. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  11. package/dist/resources/extensions/gsd/prompts/guided-plan-milestone.md +2 -2
  12. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +2 -2
  13. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  14. package/dist/resources/extensions/gsd/prompts/research-milestone.md +2 -2
  15. package/dist/resources/extensions/gsd/prompts/run-uat.md +2 -2
  16. package/dist/resources/extensions/gsd/repo-identity.js +5 -2
  17. package/dist/resources/extensions/gsd/state.js +29 -2
  18. package/dist/resources/extensions/gsd/workflow-events.js +1 -1
  19. package/dist/web/standalone/.next/BUILD_ID +1 -1
  20. package/dist/web/standalone/.next/app-path-routes-manifest.json +18 -18
  21. package/dist/web/standalone/.next/build-manifest.json +2 -2
  22. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  23. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  24. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  25. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  26. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  27. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  28. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  29. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  30. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  31. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  32. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  33. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  34. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  35. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  36. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  37. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  38. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  39. package/dist/web/standalone/.next/server/app/index.html +1 -1
  40. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  41. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  42. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  43. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  44. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  45. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  46. package/dist/web/standalone/.next/server/app-paths-manifest.json +18 -18
  47. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  48. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  49. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  50. package/package.json +3 -1
  51. package/packages/pi-agent-core/dist/agent-loop.js +26 -1
  52. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  53. package/packages/pi-agent-core/dist/agent.d.ts +7 -0
  54. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  55. package/packages/pi-agent-core/dist/agent.js +2 -0
  56. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  57. package/packages/pi-agent-core/dist/types.d.ts +9 -0
  58. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  59. package/packages/pi-agent-core/dist/types.js.map +1 -1
  60. package/packages/pi-agent-core/src/agent-loop.ts +25 -1
  61. package/packages/pi-agent-core/src/agent.ts +10 -0
  62. package/packages/pi-agent-core/src/types.ts +10 -0
  63. package/packages/pi-coding-agent/dist/core/auth-storage.test.js +27 -2
  64. package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
  65. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  66. package/packages/pi-coding-agent/dist/core/sdk.js +1 -0
  67. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  68. package/packages/pi-coding-agent/src/core/auth-storage.test.ts +27 -2
  69. package/packages/pi-coding-agent/src/core/sdk.ts +1 -0
  70. package/src/resources/extensions/claude-code-cli/index.ts +28 -0
  71. package/src/resources/extensions/claude-code-cli/models.ts +42 -0
  72. package/src/resources/extensions/claude-code-cli/package.json +11 -0
  73. package/src/resources/extensions/claude-code-cli/partial-builder.ts +258 -0
  74. package/src/resources/extensions/claude-code-cli/readiness.ts +30 -0
  75. package/src/resources/extensions/claude-code-cli/sdk-types.ts +149 -0
  76. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +370 -0
  77. package/src/resources/extensions/gsd/auto-start.ts +8 -7
  78. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  79. package/src/resources/extensions/gsd/prompts/guided-plan-milestone.md +2 -2
  80. package/src/resources/extensions/gsd/prompts/plan-milestone.md +2 -2
  81. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  82. package/src/resources/extensions/gsd/prompts/research-milestone.md +2 -2
  83. package/src/resources/extensions/gsd/prompts/run-uat.md +2 -2
  84. package/src/resources/extensions/gsd/repo-identity.ts +5 -2
  85. package/src/resources/extensions/gsd/state.ts +33 -1
  86. package/src/resources/extensions/gsd/tests/inherited-repo-home-dir.test.ts +70 -0
  87. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +40 -0
  88. package/src/resources/extensions/gsd/tests/run-uat.test.ts +25 -0
  89. package/src/resources/extensions/gsd/workflow-events.ts +1 -1
  90. /package/dist/web/standalone/.next/static/{_zz1oqjzv1VmV-zmxlJPF → MN4KAhNleSmucaEc-vzTu}/_buildManifest.js +0 -0
  91. /package/dist/web/standalone/.next/static/{_zz1oqjzv1VmV-zmxlJPF → MN4KAhNleSmucaEc-vzTu}/_ssgManifest.js +0 -0
package/README.md CHANGED
@@ -25,40 +25,55 @@ One command. Walk away. Come back to a built project with clean git history.
25
25
 
26
26
  ---
27
27
 
28
- ## What's New in v2.44.0
28
+ ## What's New in v2.46.0
29
29
 
30
- ### New Features
30
+ ### Single-Writer State Engine
31
31
 
32
- - **Non-API-key provider extensions** support for provider extensions like Claude Code CLI that don't require traditional API keys. (#2382)
33
- - **Docker sandbox template** — official Docker template for running GSD auto mode in an isolated container. (#2360)
34
- - **Per-prompt token cost display** — opt-in `show_token_cost` preference shows per-prompt and cumulative session cost in the footer. (#2357)
35
- - **"Change project root" in web UI** — switch project directories from the web interface without restarting. (#2355)
36
- - **DB-backed planning tools** — write-side state transitions now use atomic SQLite tool calls instead of markdown mutation, improving reliability and enabling structured queries. (#2141)
32
+ The biggest architectural change since DB-backed planning tools. The single-writer engine enforces disciplined state transitions through three iterations:
37
33
 
38
- ### Key Fixes
34
+ - **v2 — discipline layer** — adds a write-side discipline layer on top of the DB architecture, ensuring all state mutations flow through controlled tool calls.
35
+ - **v3 — state machine guards, actor identity, reversibility** — introduces formal state machine guards, tracks which actor (human vs agent) initiated each transition, and makes transitions reversible.
36
+ - **Hardened** — closes TOCTOU race conditions, intercepts bypass attempts, and resolves status inconsistencies.
37
+
38
+ All prompts are now aligned with the single-writer tool API, and a new **workflow-logger** is wired into the engine, tool, manifest, and reconcile paths for full observability. (#2494)
39
39
 
40
- - **Post-migration cleanup** pragmas, rollbacks, tool gaps, and stale code cleaned up after DB migration. (#2410)
41
- - **Planning data loss prevention** — destructive upsert and post-unit re-import no longer overwrite planning data. (#2370)
42
- - **Memory and resource leaks** — fixes across TUI, LSP, DB, and automation subsystems. (#2314)
43
- - **DECISIONS.md preservation** — freeform content in DECISIONS.md is no longer overwritten on decision save. (#2319)
44
- - **Auto-stash before squash merge** — dirty files are automatically stashed before merge, with filenames surfaced in errors. (#2298)
45
- - **Extension TypeScript detection** — `.js` extension files containing TypeScript syntax are detected with a suggestion to rename. (#2386)
40
+ ### v2.45.0New Commands and Capabilities
46
41
 
47
- ### v2.43.0 Highlights
42
+ - **`/gsd rethink`** — conversational project reorganization. Rethink your milestone structure, slice decomposition, or overall approach through guided discussion. (#2459)
43
+ - **`/gsd mcp`** — MCP server status and connectivity. Check which MCP servers are configured, connected, and healthy. (#2362)
44
+ - **Complete offline mode** — GSD now works fully offline with local models. (#2429)
45
+ - **Global KNOWLEDGE.md injection** — `~/.gsd/agent/KNOWLEDGE.md` is injected into the system prompt, so cross-project knowledge persists globally. (#2331)
46
+ - **Mobile-responsive web UI** — the browser interface now works on phones and tablets. (#2354)
47
+ - **DB tool previews** — `renderCall`/`renderResult` previews on DB tools show what each tool call does before and after execution. (#2273)
48
+ - **Message timestamps** — user and assistant messages now include timestamps. (#2368)
48
49
 
49
- - **Forensics dedup** — opt-in duplicate detection before issue creation. (#2105)
50
- - **Fast service tier outside auto-mode** — `/gsd fast` now applies in interactive sessions too. (#2126)
51
- - **Startup optimizations** — pre-compiled extensions, compile cache, and batch discovery for faster boot. (#2125)
52
- - **Stale process cleanup** — web server kills stale process before launch to prevent EADDRINUSE. (#2034)
50
+ ### Key Changes
53
51
 
54
- ### v2.42.0 Highlights
52
+ - **Default isolation mode changed to `none`** — `git.isolation` now defaults to `none` instead of `worktree`. Projects that rely on worktree isolation should set `git.isolation: worktree` explicitly in preferences. (#2481)
53
+ - **Startup checks** — GSD now validates Node.js version and git availability at startup, with clear error messages. (#2463)
54
+ - **Worktree lifecycle journaling** — worktree create, switch, merge, and remove events are recorded in the event journal. (#2486)
55
+ - **Milestone verification gate** — milestone completion is blocked when verification fails, preventing premature closure. (#2500)
56
+
57
+ ### Key Fixes
55
58
 
56
- - **Declarative workflow engine** — define YAML workflows that execute through auto-loop, enabling repeatable multi-step automations without code. (#2024)
57
- - **Unified rule registry & event journal** — centralized rule registry, event journal with query tool, and standardized tool naming convention. (#1928)
58
- - **PR risk checker** — CI classifies changed files by system area and surfaces risk level on pull requests. (#1930)
59
- - **`/gsd fast`** toggle service tier for supported models, enabling prioritized API routing for faster responses. (#1862)
60
- - **Web mode CLI flags** — `--host`, `--port`, and `--allowed-origins` flags give full control over the web server bind address and CORS policy. (#1873)
61
- - **ADR attribution** — architecture decision records now distinguish human, agent, and collaborative authorship. (#1830)
59
+ - **Auto-mode stability** — recovery attempts reset on unit re-dispatch (#2424), survivor branch recovery handles `phase=complete` (#2427), and auto mode stops on real merge conflicts (#2428).
60
+ - **Supervision timeouts** — now respect task `est:` annotations, so complex tasks get proportionally longer timeouts. (#2434)
61
+ - **`auto_pr: true` fixed** — three interacting bugs prevented auto-PR creation; all three are resolved. (#2433)
62
+ - **Rich task plan preservation** plans survive DB roundtrip without losing structured content. (#2453)
63
+ - **Artifact truncation prevention** — `saveArtifactToDb` no longer overwrites larger files with truncated content. (#2447)
64
+ - **Worktree teardown** — submodule state is detected and preserved during teardown (#2425), and worktree merge back to main works after `stopAuto` on milestone completion (#2430).
65
+ - **Windows portability** — `retentionDays=0` handling and CRLF fixes on Windows. (#2460)
66
+ - **Voice on Linux** — misleading portaudio error on PEP 668 systems replaced with actionable guidance. (#2407)
67
+
68
+ ### Previous highlights (v2.42–v2.44)
69
+
70
+ - **Non-API-key provider extensions** — support for Claude Code CLI and similar providers. (#2382)
71
+ - **Docker sandbox template** — official Docker template for isolated auto mode. (#2360)
72
+ - **DB-backed planning tools** — write-side state transitions use atomic SQLite tool calls. (#2141)
73
+ - **Declarative workflow engine** — YAML workflows through auto-loop. (#2024)
74
+ - **`/gsd fast`** — toggle service tier for prioritized API routing. (#1862)
75
+ - **Forensics dedup** — duplicate detection before issue creation. (#2105)
76
+ - **Startup optimizations** — pre-compiled extensions, compile cache, batch discovery. (#2125)
62
77
 
63
78
  ---
64
79
 
@@ -138,7 +153,7 @@ See the full [Changelog](./CHANGELOG.md) for all 70+ fixes in this release.
138
153
 
139
154
  ## Documentation
140
155
 
141
- Full documentation is available in the [`docs/`](./docs/) directory:
156
+ Full documentation is available at **[gsd.build](https://gsd.build)** (powered by Mintlify) and in the [`docs/`](./docs/) directory:
142
157
 
143
158
  - **[Getting Started](./docs/getting-started.md)** — install, first run, basic usage
144
159
  - **[Auto Mode](./docs/auto-mode.md)** — autonomous execution deep-dive
@@ -260,7 +275,7 @@ Auto mode is a state machine driven by files on disk. It reads `.gsd/STATE.md`,
260
275
 
261
276
  2. **Context pre-loading** — The dispatch prompt includes inlined task plans, slice plans, prior task summaries, dependency summaries, roadmap excerpts, and decisions register. The LLM starts with everything it needs instead of spending tool calls reading files.
262
277
 
263
- 3. **Git worktree isolation** — Each milestone runs in its own git worktree with a `milestone/<MID>` branch. All slice work commits sequentially — no branch switching, no merge conflicts. When the milestone completes, it's squash-merged to main as one clean commit.
278
+ 3. **Git isolation** — When `git.isolation` is set to `worktree` or `branch`, each milestone runs on its own `milestone/<MID>` branch (in a worktree or in-place). All slice work commits sequentially — no branch switching, no merge conflicts. When the milestone completes, it's squash-merged to main as one clean commit. The default is `none` (work on the current branch), configurable via preferences.
264
279
 
265
280
  4. **Crash recovery** — A lock file tracks the current unit. If the session dies, the next `/gsd auto` reads the surviving session file, synthesizes a recovery briefing from every tool call that made it to disk, and resumes with full context. Parallel orchestrator state is persisted to disk with PID liveness detection, so multi-worker sessions survive crashes too. In headless mode, crashes trigger automatic restart with exponential backoff (default 3 attempts).
266
281
 
@@ -396,6 +411,8 @@ On first run, GSD launches a branded setup wizard that walks you through LLM pro
396
411
  | `/gsd stop` | Stop auto mode gracefully |
397
412
  | `/gsd steer` | Hard-steer plan documents during execution |
398
413
  | `/gsd discuss` | Discuss architecture and decisions (works alongside auto mode) |
414
+ | `/gsd rethink` | Conversational project reorganization |
415
+ | `/gsd mcp` | MCP server status and connectivity |
399
416
  | `/gsd status` | Progress dashboard |
400
417
  | `/gsd queue` | Queue future milestones (safe during auto mode) |
401
418
  | `/gsd prefs` | Model selection, timeouts, budget ceiling |
@@ -543,7 +560,7 @@ auto_report: true
543
560
  | `skill_rules` | Situational rules for skill routing |
544
561
  | `skill_staleness_days` | Skills unused for N days get deprioritized (default: 60, 0 = disabled) |
545
562
  | `unique_milestone_ids` | Uses unique milestone names to avoid clashes when working in teams of people |
546
- | `git.isolation` | `worktree` (default), `branch`, or `none` — disable worktree isolation for projects that don't need it |
563
+ | `git.isolation` | `none` (default), `worktree`, or `branch` — enable worktree or branch isolation for milestone work |
547
564
  | `git.manage_gitignore` | Set `false` to prevent GSD from modifying `.gitignore` |
548
565
  | `verification_commands`| Array of shell commands to run after task execution (e.g., `["npm run lint", "npm run test"]`) |
549
566
  | `verification_auto_fix`| Auto-retry on verification failures (default: true) |
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Claude Code CLI Provider Extension
3
+ *
4
+ * Registers a model provider that delegates inference to the user's
5
+ * locally-installed Claude Code CLI via the official Agent SDK.
6
+ *
7
+ * Users with a Claude Code subscription (Pro/Max/Team) get access to
8
+ * subsidized inference through GSD's UI — no API key required.
9
+ *
10
+ * TOS-compliant: uses Anthropic's official `@anthropic-ai/claude-agent-sdk`,
11
+ * never touches credentials, never offers a login flow.
12
+ */
13
+ import { CLAUDE_CODE_MODELS } from "./models.js";
14
+ import { isClaudeCodeReady } from "./readiness.js";
15
+ import { streamViaClaudeCode } from "./stream-adapter.js";
16
+ export default function claudeCodeCli(pi) {
17
+ pi.registerProvider("claude-code", {
18
+ authMode: "externalCli",
19
+ api: "anthropic-messages",
20
+ baseUrl: "local://claude-code",
21
+ isReady: isClaudeCodeReady,
22
+ streamSimple: streamViaClaudeCode,
23
+ models: CLAUDE_CODE_MODELS,
24
+ });
25
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Model definitions for the Claude Code CLI provider.
3
+ *
4
+ * Costs are zero because inference is covered by the user's Claude Code
5
+ * subscription. The SDK's `result` message still provides token counts
6
+ * for display in the TUI.
7
+ *
8
+ * Context windows and max tokens match the Anthropic API definitions
9
+ * in models.generated.ts.
10
+ */
11
+ const ZERO_COST = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
12
+ export const CLAUDE_CODE_MODELS = [
13
+ {
14
+ id: "claude-opus-4-6",
15
+ name: "Claude Opus 4.6 (via Claude Code)",
16
+ reasoning: true,
17
+ input: ["text", "image"],
18
+ cost: ZERO_COST,
19
+ contextWindow: 1_000_000,
20
+ maxTokens: 128_000,
21
+ },
22
+ {
23
+ id: "claude-sonnet-4-6",
24
+ name: "Claude Sonnet 4.6 (via Claude Code)",
25
+ reasoning: true,
26
+ input: ["text", "image"],
27
+ cost: ZERO_COST,
28
+ contextWindow: 1_000_000,
29
+ maxTokens: 64_000,
30
+ },
31
+ {
32
+ id: "claude-haiku-4-5",
33
+ name: "Claude Haiku 4.5 (via Claude Code)",
34
+ reasoning: true,
35
+ input: ["text", "image"],
36
+ cost: ZERO_COST,
37
+ contextWindow: 200_000,
38
+ maxTokens: 64_000,
39
+ },
40
+ ];
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "@gsd/claude-code-cli",
3
+ "private": true,
4
+ "version": "1.0.0",
5
+ "type": "module",
6
+ "pi": {
7
+ "extensions": [
8
+ "./index.js"
9
+ ]
10
+ }
11
+ }
@@ -0,0 +1,223 @@
1
+ /**
2
+ * Content-block mapping helpers and streaming state tracker.
3
+ *
4
+ * Translates the Claude Agent SDK's `BetaRawMessageStreamEvent` sequence
5
+ * into GSD's `AssistantMessageEvent` deltas for incremental TUI rendering.
6
+ */
7
+ // ---------------------------------------------------------------------------
8
+ // Content-block mapping helpers
9
+ // ---------------------------------------------------------------------------
10
+ /**
11
+ * Convert a single BetaContentBlock to the corresponding GSD content type.
12
+ */
13
+ export function mapContentBlock(block) {
14
+ switch (block.type) {
15
+ case "text":
16
+ return { type: "text", text: block.text };
17
+ case "thinking":
18
+ return {
19
+ type: "thinking",
20
+ thinking: block.thinking,
21
+ ...(block.signature ? { thinkingSignature: block.signature } : {}),
22
+ };
23
+ case "tool_use":
24
+ return {
25
+ type: "toolCall",
26
+ id: block.id,
27
+ name: block.name,
28
+ arguments: block.input,
29
+ };
30
+ case "server_tool_use":
31
+ return {
32
+ type: "serverToolUse",
33
+ id: block.id,
34
+ name: block.name,
35
+ input: block.input,
36
+ };
37
+ case "web_search_tool_result":
38
+ return {
39
+ type: "webSearchResult",
40
+ toolUseId: block.tool_use_id,
41
+ content: block.content,
42
+ };
43
+ default: {
44
+ const unknown = block;
45
+ return { type: "text", text: `[unknown content block: ${JSON.stringify(unknown)}]` };
46
+ }
47
+ }
48
+ }
49
+ export function mapStopReason(reason) {
50
+ switch (reason) {
51
+ case "end_turn":
52
+ case "stop_sequence":
53
+ return "stop";
54
+ case "max_tokens":
55
+ return "length";
56
+ case "tool_use":
57
+ return "toolUse";
58
+ default:
59
+ return "stop";
60
+ }
61
+ }
62
+ /**
63
+ * Convert SDK usage + total_cost_usd into GSD's Usage shape.
64
+ *
65
+ * The SDK does not break cost down per-bucket, so all cost is
66
+ * attributed to `cost.total`.
67
+ */
68
+ export function mapUsage(sdkUsage, totalCostUsd) {
69
+ return {
70
+ input: sdkUsage.input_tokens,
71
+ output: sdkUsage.output_tokens,
72
+ cacheRead: sdkUsage.cache_read_input_tokens,
73
+ cacheWrite: sdkUsage.cache_creation_input_tokens,
74
+ totalTokens: sdkUsage.input_tokens +
75
+ sdkUsage.output_tokens +
76
+ sdkUsage.cache_read_input_tokens +
77
+ sdkUsage.cache_creation_input_tokens,
78
+ cost: {
79
+ input: 0,
80
+ output: 0,
81
+ cacheRead: 0,
82
+ cacheWrite: 0,
83
+ total: totalCostUsd,
84
+ },
85
+ };
86
+ }
87
+ // ---------------------------------------------------------------------------
88
+ // Zero-cost usage constant
89
+ // ---------------------------------------------------------------------------
90
+ export const ZERO_USAGE = {
91
+ input: 0,
92
+ output: 0,
93
+ cacheRead: 0,
94
+ cacheWrite: 0,
95
+ totalTokens: 0,
96
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
97
+ };
98
+ // ---------------------------------------------------------------------------
99
+ // Streaming partial-message state tracker
100
+ // ---------------------------------------------------------------------------
101
+ /**
102
+ * Mutable accumulator that tracks the partial AssistantMessage being built
103
+ * from a sequence of stream_event messages. Produces AssistantMessageEvent
104
+ * deltas that the TUI can render incrementally.
105
+ */
106
+ export class PartialMessageBuilder {
107
+ partial;
108
+ /** Map from stream-event `index` to our content array index. */
109
+ indexMap = new Map();
110
+ /** Accumulated JSON input string per tool_use block (keyed by stream index). */
111
+ toolJsonAccum = new Map();
112
+ constructor(model) {
113
+ this.partial = {
114
+ role: "assistant",
115
+ content: [],
116
+ api: "anthropic-messages",
117
+ provider: "claude-code",
118
+ model,
119
+ usage: { ...ZERO_USAGE },
120
+ stopReason: "stop",
121
+ timestamp: Date.now(),
122
+ };
123
+ }
124
+ get message() {
125
+ return this.partial;
126
+ }
127
+ /**
128
+ * Feed a BetaRawMessageStreamEvent and return the corresponding
129
+ * AssistantMessageEvent (or null if the event is not mapped).
130
+ */
131
+ handleEvent(event) {
132
+ const streamIndex = event.index ?? 0;
133
+ switch (event.type) {
134
+ // ---- Block start ----
135
+ case "content_block_start": {
136
+ const block = event.content_block;
137
+ if (!block)
138
+ return null;
139
+ const contentIndex = this.partial.content.length;
140
+ this.indexMap.set(streamIndex, contentIndex);
141
+ if (block.type === "text") {
142
+ this.partial.content.push({ type: "text", text: "" });
143
+ return { type: "text_start", contentIndex, partial: this.partial };
144
+ }
145
+ if (block.type === "thinking") {
146
+ this.partial.content.push({ type: "thinking", thinking: "" });
147
+ return { type: "thinking_start", contentIndex, partial: this.partial };
148
+ }
149
+ if (block.type === "tool_use") {
150
+ this.toolJsonAccum.set(streamIndex, "");
151
+ this.partial.content.push({
152
+ type: "toolCall",
153
+ id: block.id,
154
+ name: block.name,
155
+ arguments: {},
156
+ });
157
+ return { type: "toolcall_start", contentIndex, partial: this.partial };
158
+ }
159
+ if (block.type === "server_tool_use") {
160
+ this.partial.content.push({
161
+ type: "serverToolUse",
162
+ id: block.id,
163
+ name: block.name,
164
+ input: block.input,
165
+ });
166
+ return { type: "server_tool_use", contentIndex, partial: this.partial };
167
+ }
168
+ return null;
169
+ }
170
+ // ---- Block delta ----
171
+ case "content_block_delta": {
172
+ const contentIndex = this.indexMap.get(streamIndex);
173
+ if (contentIndex === undefined)
174
+ return null;
175
+ const delta = event.delta;
176
+ if (!delta)
177
+ return null;
178
+ if (delta.type === "text_delta" && typeof delta.text === "string") {
179
+ const existing = this.partial.content[contentIndex];
180
+ existing.text += delta.text;
181
+ return { type: "text_delta", contentIndex, delta: delta.text, partial: this.partial };
182
+ }
183
+ if (delta.type === "thinking_delta" && typeof delta.thinking === "string") {
184
+ const existing = this.partial.content[contentIndex];
185
+ existing.thinking += delta.thinking;
186
+ return { type: "thinking_delta", contentIndex, delta: delta.thinking, partial: this.partial };
187
+ }
188
+ if (delta.type === "input_json_delta" && typeof delta.partial_json === "string") {
189
+ const accum = (this.toolJsonAccum.get(streamIndex) ?? "") + delta.partial_json;
190
+ this.toolJsonAccum.set(streamIndex, accum);
191
+ return { type: "toolcall_delta", contentIndex, delta: delta.partial_json, partial: this.partial };
192
+ }
193
+ return null;
194
+ }
195
+ // ---- Block stop ----
196
+ case "content_block_stop": {
197
+ const contentIndex = this.indexMap.get(streamIndex);
198
+ if (contentIndex === undefined)
199
+ return null;
200
+ const block = this.partial.content[contentIndex];
201
+ if (block.type === "text") {
202
+ return { type: "text_end", contentIndex, content: block.text, partial: this.partial };
203
+ }
204
+ if (block.type === "thinking") {
205
+ return { type: "thinking_end", contentIndex, content: block.thinking, partial: this.partial };
206
+ }
207
+ if (block.type === "toolCall") {
208
+ const jsonStr = this.toolJsonAccum.get(streamIndex) ?? "{}";
209
+ try {
210
+ block.arguments = JSON.parse(jsonStr);
211
+ }
212
+ catch {
213
+ block.arguments = { _raw: jsonStr };
214
+ }
215
+ return { type: "toolcall_end", contentIndex, toolCall: block, partial: this.partial };
216
+ }
217
+ return null;
218
+ }
219
+ default:
220
+ return null;
221
+ }
222
+ }
223
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Readiness check for the Claude Code CLI provider.
3
+ *
4
+ * Verifies the `claude` binary is installed and responsive.
5
+ * Result is cached for 30 seconds to avoid shelling out on every
6
+ * model-availability check.
7
+ */
8
+ import { execSync } from "node:child_process";
9
+ let cachedReady = null;
10
+ let lastCheckMs = 0;
11
+ const CHECK_INTERVAL_MS = 30_000;
12
+ export function isClaudeCodeReady() {
13
+ const now = Date.now();
14
+ if (cachedReady !== null && now - lastCheckMs < CHECK_INTERVAL_MS) {
15
+ return cachedReady;
16
+ }
17
+ try {
18
+ execSync("claude --version", { timeout: 5_000, stdio: "pipe" });
19
+ cachedReady = true;
20
+ }
21
+ catch {
22
+ cachedReady = false;
23
+ }
24
+ lastCheckMs = now;
25
+ return cachedReady;
26
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Lightweight type mirrors for the Claude Agent SDK.
3
+ *
4
+ * These stubs allow the extension to compile without a hard dependency on
5
+ * `@anthropic-ai/claude-agent-sdk`. The real SDK is imported dynamically
6
+ * at runtime in stream-adapter.ts.
7
+ */
8
+ export {};