@chances-ai/client 24.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/dist/client-core/client.d.ts +145 -0
  2. package/dist/client-core/client.d.ts.map +1 -0
  3. package/dist/client-core/client.js +533 -0
  4. package/dist/client-core/client.js.map +1 -0
  5. package/dist/client-core/index.d.ts +16 -0
  6. package/dist/client-core/index.d.ts.map +1 -0
  7. package/dist/client-core/index.js +15 -0
  8. package/dist/client-core/index.js.map +1 -0
  9. package/dist/client-core/reverse-map.d.ts +66 -0
  10. package/dist/client-core/reverse-map.d.ts.map +1 -0
  11. package/dist/client-core/reverse-map.js +86 -0
  12. package/dist/client-core/reverse-map.js.map +1 -0
  13. package/dist/client-core/store.d.ts +144 -0
  14. package/dist/client-core/store.d.ts.map +1 -0
  15. package/dist/client-core/store.js +36 -0
  16. package/dist/client-core/store.js.map +1 -0
  17. package/dist/client-core/transport.d.ts +53 -0
  18. package/dist/client-core/transport.d.ts.map +1 -0
  19. package/dist/client-core/transport.js +103 -0
  20. package/dist/client-core/transport.js.map +1 -0
  21. package/dist/web-ui/approval-badge.d.ts +17 -0
  22. package/dist/web-ui/approval-badge.d.ts.map +1 -0
  23. package/dist/web-ui/approval-badge.js +24 -0
  24. package/dist/web-ui/approval-badge.js.map +1 -0
  25. package/dist/web-ui/button.d.ts +10 -0
  26. package/dist/web-ui/button.d.ts.map +1 -0
  27. package/dist/web-ui/button.js +16 -0
  28. package/dist/web-ui/button.js.map +1 -0
  29. package/dist/web-ui/code-view.d.ts +6 -0
  30. package/dist/web-ui/code-view.d.ts.map +1 -0
  31. package/dist/web-ui/code-view.js +14 -0
  32. package/dist/web-ui/code-view.js.map +1 -0
  33. package/dist/web-ui/code-viewer.d.ts +11 -0
  34. package/dist/web-ui/code-viewer.d.ts.map +1 -0
  35. package/dist/web-ui/code-viewer.js +55 -0
  36. package/dist/web-ui/code-viewer.js.map +1 -0
  37. package/dist/web-ui/commands.d.ts +23 -0
  38. package/dist/web-ui/commands.d.ts.map +1 -0
  39. package/dist/web-ui/commands.js +26 -0
  40. package/dist/web-ui/commands.js.map +1 -0
  41. package/dist/web-ui/control-panel.d.ts +9 -0
  42. package/dist/web-ui/control-panel.d.ts.map +1 -0
  43. package/dist/web-ui/control-panel.js +70 -0
  44. package/dist/web-ui/control-panel.js.map +1 -0
  45. package/dist/web-ui/diff-view.d.ts +8 -0
  46. package/dist/web-ui/diff-view.d.ts.map +1 -0
  47. package/dist/web-ui/diff-view.js +28 -0
  48. package/dist/web-ui/diff-view.js.map +1 -0
  49. package/dist/web-ui/environment-panel.d.ts +9 -0
  50. package/dist/web-ui/environment-panel.d.ts.map +1 -0
  51. package/dist/web-ui/environment-panel.js +38 -0
  52. package/dist/web-ui/environment-panel.js.map +1 -0
  53. package/dist/web-ui/file-tree.d.ts +9 -0
  54. package/dist/web-ui/file-tree.d.ts.map +1 -0
  55. package/dist/web-ui/file-tree.js +77 -0
  56. package/dist/web-ui/file-tree.js.map +1 -0
  57. package/dist/web-ui/help-view.d.ts +13 -0
  58. package/dist/web-ui/help-view.d.ts.map +1 -0
  59. package/dist/web-ui/help-view.js +15 -0
  60. package/dist/web-ui/help-view.js.map +1 -0
  61. package/dist/web-ui/helpers.d.ts +77 -0
  62. package/dist/web-ui/helpers.d.ts.map +1 -0
  63. package/dist/web-ui/helpers.js +176 -0
  64. package/dist/web-ui/helpers.js.map +1 -0
  65. package/dist/web-ui/hooks.d.ts +7 -0
  66. package/dist/web-ui/hooks.d.ts.map +1 -0
  67. package/dist/web-ui/hooks.js +26 -0
  68. package/dist/web-ui/hooks.js.map +1 -0
  69. package/dist/web-ui/index.d.ts +32 -0
  70. package/dist/web-ui/index.d.ts.map +1 -0
  71. package/dist/web-ui/index.js +38 -0
  72. package/dist/web-ui/index.js.map +1 -0
  73. package/dist/web-ui/markdown.d.ts +12 -0
  74. package/dist/web-ui/markdown.d.ts.map +1 -0
  75. package/dist/web-ui/markdown.js +55 -0
  76. package/dist/web-ui/markdown.js.map +1 -0
  77. package/dist/web-ui/model-picker.d.ts +9 -0
  78. package/dist/web-ui/model-picker.d.ts.map +1 -0
  79. package/dist/web-ui/model-picker.js +119 -0
  80. package/dist/web-ui/model-picker.js.map +1 -0
  81. package/dist/web-ui/permission.d.ts +7 -0
  82. package/dist/web-ui/permission.d.ts.map +1 -0
  83. package/dist/web-ui/permission.js +25 -0
  84. package/dist/web-ui/permission.js.map +1 -0
  85. package/dist/web-ui/primitives.d.ts +59 -0
  86. package/dist/web-ui/primitives.d.ts.map +1 -0
  87. package/dist/web-ui/primitives.js +38 -0
  88. package/dist/web-ui/primitives.js.map +1 -0
  89. package/dist/web-ui/progress.d.ts +28 -0
  90. package/dist/web-ui/progress.d.ts.map +1 -0
  91. package/dist/web-ui/progress.js +45 -0
  92. package/dist/web-ui/progress.js.map +1 -0
  93. package/dist/web-ui/prompt-input.d.ts +15 -0
  94. package/dist/web-ui/prompt-input.d.ts.map +1 -0
  95. package/dist/web-ui/prompt-input.js +129 -0
  96. package/dist/web-ui/prompt-input.js.map +1 -0
  97. package/dist/web-ui/question-view.d.ts +7 -0
  98. package/dist/web-ui/question-view.d.ts.map +1 -0
  99. package/dist/web-ui/question-view.js +60 -0
  100. package/dist/web-ui/question-view.js.map +1 -0
  101. package/dist/web-ui/segments.d.ts +8 -0
  102. package/dist/web-ui/segments.d.ts.map +1 -0
  103. package/dist/web-ui/segments.js +19 -0
  104. package/dist/web-ui/segments.js.map +1 -0
  105. package/dist/web-ui/session-sidebar.d.ts +15 -0
  106. package/dist/web-ui/session-sidebar.d.ts.map +1 -0
  107. package/dist/web-ui/session-sidebar.js +10 -0
  108. package/dist/web-ui/session-sidebar.js.map +1 -0
  109. package/dist/web-ui/status-bar.d.ts +10 -0
  110. package/dist/web-ui/status-bar.d.ts.map +1 -0
  111. package/dist/web-ui/status-bar.js +10 -0
  112. package/dist/web-ui/status-bar.js.map +1 -0
  113. package/dist/web-ui/theme-context.d.ts +13 -0
  114. package/dist/web-ui/theme-context.d.ts.map +1 -0
  115. package/dist/web-ui/theme-context.js +31 -0
  116. package/dist/web-ui/theme-context.js.map +1 -0
  117. package/dist/web-ui/transcript.d.ts +27 -0
  118. package/dist/web-ui/transcript.d.ts.map +1 -0
  119. package/dist/web-ui/transcript.js +56 -0
  120. package/dist/web-ui/transcript.js.map +1 -0
  121. package/package.json +56 -0
@@ -0,0 +1,66 @@
1
+ /**
2
+ * (v20 M3 / docs/6.4a §3) The client-side inverse of the agent's ACP projection:
3
+ * an ACP `session/update`'s `SessionUpdate` → internal `AppEvent`, so the
4
+ * browser/desktop client feeds the SAME `ChatViewModel` the TUI uses (no forked
5
+ * transcript logic). Replaces M1's `EventFrame → AppEvent` now that the wire is
6
+ * ACP.
7
+ *
8
+ * client-core stays **SDK-free** (browser-light, no `@agentclientprotocol/sdk`
9
+ * dependency): it reads the handful of fields it needs off a minimal structural
10
+ * {@link AcpUpdate} shape. The full typed wire contract is asserted AGENT-side
11
+ * by the golden fixtures against the real SDK types — the client only consumes.
12
+ *
13
+ * Mapping (only what `ChatViewModel` renders):
14
+ * agent_message_chunk / user_message_chunk → assistant:delta (text)
15
+ * tool_call → tool:call
16
+ * tool_call_update + _meta.chances.chunk → tool:chunk (live PTY preview)
17
+ * tool_call_update + status completed/failed → tool:result
18
+ * everything else (thought/plan/usage_update/in-progress) → null
19
+ * (usage_update is handled at the store by RpcClient, not the transcript).
20
+ */
21
+ import type { AppEvent } from "@chances-ai/runtime";
22
+ /** Minimal structural view of the `SessionUpdate` fields the client reads. */
23
+ export interface AcpUpdate {
24
+ sessionUpdate: string;
25
+ content?: AcpContentBlock | AcpToolContent[] | null;
26
+ toolCallId?: string;
27
+ title?: string | null;
28
+ kind?: string | null;
29
+ status?: string | null;
30
+ rawInput?: unknown;
31
+ rawOutput?: unknown;
32
+ _meta?: {
33
+ chances?: {
34
+ chunk?: AcpChunkMeta;
35
+ };
36
+ } | null;
37
+ }
38
+ interface AcpContentBlock {
39
+ type?: string;
40
+ text?: string;
41
+ }
42
+ interface AcpToolContent {
43
+ type?: string;
44
+ content?: AcpContentBlock;
45
+ }
46
+ interface AcpChunkMeta {
47
+ seq?: number;
48
+ bytes?: number;
49
+ dropped?: number;
50
+ terminal?: boolean;
51
+ state?: string;
52
+ exitCode?: number;
53
+ reason?: string;
54
+ }
55
+ export declare function sessionUpdateToAppEvent(u: AcpUpdate): AppEvent | null;
56
+ /** Synthesize a `tool:permission` AppEvent from an ACP permission request's
57
+ * `toolCall`, so the shared `ChatViewModel` stashes the write/edit diff for the
58
+ * `⎿` branch (transcript parity). Feeds ONLY the diff stash — the answer travels
59
+ * back over the wire as the ACP permission response, not a local resolver. */
60
+ export declare function acpPermissionToAppEvent(p: {
61
+ toolCallId?: string;
62
+ name?: string;
63
+ summary?: string;
64
+ }): AppEvent;
65
+ export {};
66
+ //# sourceMappingURL=reverse-map.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reverse-map.d.ts","sourceRoot":"","sources":["../../src/client-core/reverse-map.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD,8EAA8E;AAC9E,MAAM,WAAW,SAAS;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,eAAe,GAAG,cAAc,EAAE,GAAG,IAAI,CAAC;IACpD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE;YAAE,KAAK,CAAC,EAAE,YAAY,CAAA;SAAE,CAAA;KAAE,GAAG,IAAI,CAAC;CACvD;AACD,UAAU,eAAe;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AACD,UAAU,cAAc;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,eAAe,CAAC;CAC3B;AACD,UAAU,YAAY;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,SAAS,GAAG,QAAQ,GAAG,IAAI,CA0CrE;AAED;;;+EAG+E;AAC/E,wBAAgB,uBAAuB,CAAC,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,QAAQ,CAO7G"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * (v20 M3 / docs/6.4a §3) The client-side inverse of the agent's ACP projection:
3
+ * an ACP `session/update`'s `SessionUpdate` → internal `AppEvent`, so the
4
+ * browser/desktop client feeds the SAME `ChatViewModel` the TUI uses (no forked
5
+ * transcript logic). Replaces M1's `EventFrame → AppEvent` now that the wire is
6
+ * ACP.
7
+ *
8
+ * client-core stays **SDK-free** (browser-light, no `@agentclientprotocol/sdk`
9
+ * dependency): it reads the handful of fields it needs off a minimal structural
10
+ * {@link AcpUpdate} shape. The full typed wire contract is asserted AGENT-side
11
+ * by the golden fixtures against the real SDK types — the client only consumes.
12
+ *
13
+ * Mapping (only what `ChatViewModel` renders):
14
+ * agent_message_chunk / user_message_chunk → assistant:delta (text)
15
+ * tool_call → tool:call
16
+ * tool_call_update + _meta.chances.chunk → tool:chunk (live PTY preview)
17
+ * tool_call_update + status completed/failed → tool:result
18
+ * everything else (thought/plan/usage_update/in-progress) → null
19
+ * (usage_update is handled at the store by RpcClient, not the transcript).
20
+ */
21
+ export function sessionUpdateToAppEvent(u) {
22
+ switch (u.sessionUpdate) {
23
+ case "agent_message_chunk":
24
+ case "user_message_chunk": {
25
+ const text = chunkText(u.content);
26
+ return text ? { type: "assistant:delta", turnId: "", text } : null;
27
+ }
28
+ case "tool_call":
29
+ return {
30
+ type: "tool:call",
31
+ callId: u.toolCallId ?? "",
32
+ name: u.title ?? u.kind ?? "tool",
33
+ args: (u.rawInput ?? {}),
34
+ };
35
+ case "tool_call_update": {
36
+ const chunk = u._meta?.chances?.chunk;
37
+ if (chunk) {
38
+ // Live-PTY chunk (our `tool:chunk` fidelity rode `_meta.chances.chunk`).
39
+ return {
40
+ type: "tool:chunk",
41
+ callId: u.toolCallId ?? "",
42
+ sessionId: "",
43
+ seq: chunk.seq ?? 0,
44
+ text: toolContentText(u.content),
45
+ bytes: chunk.bytes ?? 0,
46
+ ...(chunk.dropped !== undefined ? { dropped: chunk.dropped } : {}),
47
+ ...(chunk.terminal !== undefined ? { terminal: chunk.terminal } : {}),
48
+ ...(chunk.state !== undefined ? { state: chunk.state } : {}),
49
+ ...(chunk.exitCode !== undefined ? { exitCode: chunk.exitCode } : {}),
50
+ ...(chunk.reason !== undefined ? { reason: chunk.reason } : {}),
51
+ };
52
+ }
53
+ if (u.status === "completed" || u.status === "failed") {
54
+ return { type: "tool:result", callId: u.toolCallId ?? "", name: "", ok: u.status === "completed", output: toolContentText(u.content) };
55
+ }
56
+ return null; // in-progress with no chunk → no transcript meaning
57
+ }
58
+ default:
59
+ // agent_thought_chunk / plan / usage_update / *_update — no ChatViewModel
60
+ // equivalent (usage is recorded on the store by RpcClient, not here).
61
+ return null;
62
+ }
63
+ }
64
+ /** Synthesize a `tool:permission` AppEvent from an ACP permission request's
65
+ * `toolCall`, so the shared `ChatViewModel` stashes the write/edit diff for the
66
+ * `⎿` branch (transcript parity). Feeds ONLY the diff stash — the answer travels
67
+ * back over the wire as the ACP permission response, not a local resolver. */
68
+ export function acpPermissionToAppEvent(p) {
69
+ return {
70
+ type: "tool:permission",
71
+ callId: p.toolCallId ?? "",
72
+ name: p.name ?? "tool",
73
+ summary: p.summary ?? "",
74
+ };
75
+ }
76
+ function chunkText(content) {
77
+ if (content && !Array.isArray(content) && content.type === "text")
78
+ return content.text ?? "";
79
+ return "";
80
+ }
81
+ function toolContentText(content) {
82
+ if (Array.isArray(content))
83
+ return content.map((c) => (c.type === "content" ? (c.content?.text ?? "") : "")).join("");
84
+ return "";
85
+ }
86
+ //# sourceMappingURL=reverse-map.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reverse-map.js","sourceRoot":"","sources":["../../src/client-core/reverse-map.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,144 @@
1
+ /**
2
+ * (v17 M1) The client connection/control store — vanilla zustand so it is
3
+ * framework-agnostic (consumed by React via `useStore` in web-ui, or any other
4
+ * surface). It holds everything that is NOT the transcript; the transcript
5
+ * lives in the reused `ChatViewModel` (subscribed separately). Splitting them
6
+ * keeps the hard-won transcript logic shared with the TUI and this store small.
7
+ */
8
+ import { type StoreApi } from "zustand/vanilla";
9
+ import type { ModelInfo } from "@chances-ai/wire/rpc";
10
+ import type { ApprovalMode, JSONValue } from "@chances-ai/runtime";
11
+ /** `reconnecting` (M2): the transport dropped without a user close — the client
12
+ * is backing off + retrying onto the SAME live session, keeping its transcript
13
+ * + pending permission. `closed`/`error` are now reserved for a USER close or
14
+ * an exhausted reconnect budget (a real terminal). */
15
+ export type ConnectionStatus = "connecting" | "ready" | "reconnecting" | "closed" | "error";
16
+ /** A permission ask awaiting the user's answer. The UI renders a modal and
17
+ * calls `RpcClient.answerPermission`; M2 fans out, so more than one local tab
18
+ * may show it (first answer wins — engine dedup). */
19
+ export interface PendingPermission {
20
+ id: string;
21
+ callId?: string;
22
+ tool: string;
23
+ category: string;
24
+ summary: string;
25
+ args: JSONValue;
26
+ }
27
+ export interface QuestionOption {
28
+ label: string;
29
+ description?: string;
30
+ /** Optional Markdown preview (single-select). */
31
+ preview?: string;
32
+ }
33
+ export interface QuestionSpec {
34
+ question: string;
35
+ header: string;
36
+ options: QuestionOption[];
37
+ multiSelect?: boolean;
38
+ }
39
+ /** A structured question ask awaiting the user's answer. */
40
+ export interface PendingQuestion {
41
+ id: string;
42
+ questions: QuestionSpec[];
43
+ }
44
+ /** The user's answer carried back over the wire (mirror of tools' QuestionDecision). */
45
+ export interface QuestionAnswer {
46
+ answers: Record<string, string[]>;
47
+ annotations?: Record<string, {
48
+ preview?: string;
49
+ notes?: string;
50
+ }>;
51
+ declined?: boolean;
52
+ }
53
+ export interface Usage {
54
+ inputTokens: number;
55
+ outputTokens: number;
56
+ costUsd: number;
57
+ }
58
+ export interface FileEntry {
59
+ name: string;
60
+ kind: "dir" | "file";
61
+ }
62
+ export interface ListFilesResult {
63
+ dir: string;
64
+ entries: FileEntry[];
65
+ }
66
+ export interface ReadFileResult {
67
+ path: string;
68
+ content: string;
69
+ truncated: boolean;
70
+ binary: boolean;
71
+ }
72
+ export interface GitFileStatus {
73
+ path: string;
74
+ status: string;
75
+ }
76
+ export interface GitStatusResult {
77
+ repo: boolean;
78
+ branch: string | null;
79
+ ahead: number;
80
+ behind: number;
81
+ files: GitFileStatus[];
82
+ }
83
+ export interface GitDiffResult {
84
+ diff: string;
85
+ truncated: boolean;
86
+ shortstat: {
87
+ added: number;
88
+ removed: number;
89
+ };
90
+ }
91
+ export interface ClientState {
92
+ status: ConnectionStatus;
93
+ sessionId: string | null;
94
+ models: ModelInfo[];
95
+ /** The active model (defaults to the first advertised; updated by `set_model`). */
96
+ selected: ModelInfo | null;
97
+ /** (v22) Session approval mode, learned from the `initialize` handshake +
98
+ * updated by `setApprovalMode`/`cycleApprovalMode` (the GUI twin of the TUI
99
+ * Shift+Tab). `"default"` until the wire reports otherwise. */
100
+ approvalMode: ApprovalMode;
101
+ /** (v22 / codex SHOULD) Whether the connected agent supports `set_approval`
102
+ * (the `approvalSelection` capability). A plain ACP server reports false ⇒ the
103
+ * UI disables the approval badge instead of showing a mode the server rejects. */
104
+ approvalSupported: boolean;
105
+ /** A turn is running (set on `turn_start`/optimistically on `prompt`, cleared on `result`). */
106
+ busy: boolean;
107
+ pendingPermission: PendingPermission | null;
108
+ /** (v22) A structured `ask_user_question` awaiting the user's answer (null when
109
+ * none). Fanned out like a permission; the first answer wins (engine dedup). */
110
+ pendingQuestion: PendingQuestion | null;
111
+ /** Last error message surfaced to the UI (turn error / rejected command). */
112
+ lastError: string | null;
113
+ /** The ACP `stopReason` of the last finished turn (`end_turn`/`cancelled`/…). */
114
+ lastStopReason: string | null;
115
+ /** Most recent usage (per-call `usage` frame or the turn total on `result`). */
116
+ lastUsage: Usage | null;
117
+ /** (M2) Highest relay cursor (`rseq`) seen — the `Last-Event-ID` a reconnect
118
+ * resumes from. `max`-merged on every stamped frame; reset to 0 on `reset`. */
119
+ lastSeq: number;
120
+ /** (M2) Per-attach fencing token from `relay_welcome` (null before the first). */
121
+ epoch: number | null;
122
+ /** (v21 M4 §5) Controller-lease UI state. `leaseEnabled` mirrors the relay's
123
+ * lease toggle; `isController` is true when this client may drive (the lease is
124
+ * off ⇒ everyone drives, OR this client holds it); `controlEpoch` bumps on each
125
+ * handoff. Learned from `relay_welcome` + `_chances/unstable/control`. */
126
+ leaseEnabled: boolean;
127
+ isController: boolean;
128
+ controlEpoch: number;
129
+ /** (v23 M5) Whether the agent advertises read-only workspace queries
130
+ * (`workspaceQueries` capability) — the 3-pane IDE shows the file tree / code
131
+ * viewer / environment panel only when true (a plain ACP server reports false). */
132
+ workspaceQueriesSupported: boolean;
133
+ /** (v23 M5) Latest `git_status` (branch + ahead/behind + changed files), shared
134
+ * by the environment panel + the file tree's change badges; null until first
135
+ * fetched / when not a repo. Refreshed via `RpcClient.refreshGitStatus`. */
136
+ gitStatus: GitStatusResult | null;
137
+ /** (v23 M5) The file currently open in the code viewer (null when none). Set by
138
+ * `RpcClient.openFile`; the file tree's lazy listing stays component-local. */
139
+ openFile: ReadFileResult | null;
140
+ }
141
+ export declare function initialClientState(): ClientState;
142
+ export type ClientStore = StoreApi<ClientState>;
143
+ export declare function createClientStore(): ClientStore;
144
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/client-core/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * (v17 M1) The client connection/control store — vanilla zustand so it is
3
+ * framework-agnostic (consumed by React via `useStore` in web-ui, or any other
4
+ * surface). It holds everything that is NOT the transcript; the transcript
5
+ * lives in the reused `ChatViewModel` (subscribed separately). Splitting them
6
+ * keeps the hard-won transcript logic shared with the TUI and this store small.
7
+ */
8
+ import { createStore } from "zustand/vanilla";
9
+ export function initialClientState() {
10
+ return {
11
+ status: "connecting",
12
+ sessionId: null,
13
+ models: [],
14
+ selected: null,
15
+ approvalMode: "default",
16
+ approvalSupported: false,
17
+ busy: false,
18
+ pendingPermission: null,
19
+ pendingQuestion: null,
20
+ lastError: null,
21
+ lastStopReason: null,
22
+ lastUsage: null,
23
+ lastSeq: 0,
24
+ epoch: null,
25
+ leaseEnabled: false,
26
+ isController: true, // lease off by default ⇒ this client may drive
27
+ controlEpoch: 0,
28
+ workspaceQueriesSupported: false,
29
+ gitStatus: null,
30
+ openFile: null,
31
+ };
32
+ }
33
+ export function createClientStore() {
34
+ return createStore(() => initialClientState());
35
+ }
36
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/client-core/store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,WAAW,EAAiB,MAAM,iBAAiB,CAAC;AA6I7D,MAAM,UAAU,kBAAkB;IAChC,OAAO;QACL,MAAM,EAAE,YAAY;QACpB,SAAS,EAAE,IAAI;QACf,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE,IAAI;QACd,YAAY,EAAE,SAAS;QACvB,iBAAiB,EAAE,KAAK;QACxB,IAAI,EAAE,KAAK;QACX,iBAAiB,EAAE,IAAI;QACvB,eAAe,EAAE,IAAI;QACrB,SAAS,EAAE,IAAI;QACf,cAAc,EAAE,IAAI;QACpB,SAAS,EAAE,IAAI;QACf,OAAO,EAAE,CAAC;QACV,KAAK,EAAE,IAAI;QACX,YAAY,EAAE,KAAK;QACnB,YAAY,EAAE,IAAI,EAAE,+CAA+C;QACnE,YAAY,EAAE,CAAC;QACf,yBAAyB,EAAE,KAAK;QAChC,SAAS,EAAE,IAAI;QACf,QAAQ,EAAE,IAAI;KACf,CAAC;AACJ,CAAC;AAID,MAAM,UAAU,iBAAiB;IAC/B,OAAO,WAAW,CAAc,GAAG,EAAE,CAAC,kBAAkB,EAAE,CAAC,CAAC;AAC9D,CAAC"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * (v17 M1 / docs/6.1 §3.2) The client-side transport seam. `RpcClient` drives a
3
+ * {@link Transport} (send/close) and reacts to {@link TransportHandlers}
4
+ * (open/message/close/error). It is pluggable so the same client logic runs
5
+ * over WebSocket (web/desktop now) and SSE+POST (mobile, M5) — the client never
6
+ * touches `WebSocket` directly, which keeps it testable against a scripted fake
7
+ * (no real socket, §11).
8
+ */
9
+ export interface TransportHandlers {
10
+ /** The transport is connected (the protocol `ready` frame still follows). */
11
+ onOpen(): void;
12
+ /** One inbound text frame (one NDJSON line / one WS message). */
13
+ onMessage(data: string): void;
14
+ /** The transport closed (clean or not). */
15
+ onClose(): void;
16
+ /** A transport-level error (the close handler usually follows). */
17
+ onError(err: unknown): void;
18
+ }
19
+ export interface Transport {
20
+ /** Send one command line. Buffered until the transport is open. */
21
+ send(line: string): void;
22
+ /** Close the transport. Idempotent. */
23
+ close(): void;
24
+ }
25
+ /** Builds a {@link Transport} bound to the given handlers. Injected into
26
+ * `RpcClient`, so tests pass a fake and production passes
27
+ * {@link webSocketTransport}. The optional `lastSeq` (M2) is the reconnect
28
+ * cursor the client wants to resume from; the WS transport carries it as the
29
+ * `?last_event_id=N` query param (a browser `WebSocket` cannot set headers).
30
+ * `RpcClient` calls the factory once per (re)connect, passing its current
31
+ * `lastSeq`. */
32
+ export type TransportFactory = (handlers: TransportHandlers, lastSeq?: number, clientId?: string) => Transport;
33
+ /**
34
+ * WebSocket transport over the global `WebSocket` (present in browsers and
35
+ * Bun). Commands sent before the socket opens are buffered and flushed on open,
36
+ * so the caller never has to await readiness. A terminal event (remote close,
37
+ * error, or an explicit `close()`) marks the transport dead and drops the
38
+ * buffer, so a post-close `send` is discarded rather than queued into a buffer
39
+ * that will never flush (codex M1 SHOULD-5/6).
40
+ *
41
+ * `createSocket` is injectable so the lifecycle edges can be unit-tested with a
42
+ * fake socket (no real network).
43
+ */
44
+ export declare function webSocketTransport(url: string, createSocket?: (url: string) => WebSocket): TransportFactory;
45
+ /**
46
+ * (v21 M4) Append a pairing token to a relay URL (preserving any existing query).
47
+ * The token rides the connect URL because a browser WebSocket can't set an auth
48
+ * header (the same constraint as the replay cursor). It then survives reconnect
49
+ * for free: `webSocketTransport`'s base url is reused on every (re)dial, and
50
+ * `appendLastEventId` only `&`-appends the cursor — so the token stays put.
51
+ */
52
+ export declare function withPairingToken(url: string, token: string | undefined): string;
53
+ //# sourceMappingURL=transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/client-core/transport.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,iBAAiB;IAChC,6EAA6E;IAC7E,MAAM,IAAI,IAAI,CAAC;IACf,iEAAiE;IACjE,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,2CAA2C;IAC3C,OAAO,IAAI,IAAI,CAAC;IAChB,mEAAmE;IACnE,OAAO,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,SAAS;IACxB,mEAAmE;IACnE,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,uCAAuC;IACvC,KAAK,IAAI,IAAI,CAAC;CACf;AAED;;;;;;iBAMiB;AACjB,MAAM,MAAM,gBAAgB,GAAG,CAAC,QAAQ,EAAE,iBAAiB,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,SAAS,CAAC;AAE/G;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,YAAY,GAAE,CAAC,GAAG,EAAE,MAAM,KAAK,SAAmC,GACjE,gBAAgB,CAuDlB;AAcD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAI/E"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * (v17 M1 / docs/6.1 §3.2) The client-side transport seam. `RpcClient` drives a
3
+ * {@link Transport} (send/close) and reacts to {@link TransportHandlers}
4
+ * (open/message/close/error). It is pluggable so the same client logic runs
5
+ * over WebSocket (web/desktop now) and SSE+POST (mobile, M5) — the client never
6
+ * touches `WebSocket` directly, which keeps it testable against a scripted fake
7
+ * (no real socket, §11).
8
+ */
9
+ /**
10
+ * WebSocket transport over the global `WebSocket` (present in browsers and
11
+ * Bun). Commands sent before the socket opens are buffered and flushed on open,
12
+ * so the caller never has to await readiness. A terminal event (remote close,
13
+ * error, or an explicit `close()`) marks the transport dead and drops the
14
+ * buffer, so a post-close `send` is discarded rather than queued into a buffer
15
+ * that will never flush (codex M1 SHOULD-5/6).
16
+ *
17
+ * `createSocket` is injectable so the lifecycle edges can be unit-tested with a
18
+ * fake socket (no real network).
19
+ */
20
+ export function webSocketTransport(url, createSocket = (u) => new WebSocket(u)) {
21
+ return (handlers, lastSeq, clientId) => {
22
+ // Carry the reconnect cursor + clientId as query params (a browser WebSocket
23
+ // can't set headers). Cursor omitted on a fresh connect; clientId lets the
24
+ // relay attribute commands to a client for the controller lease (§5).
25
+ let target = lastSeq && lastSeq > 0 ? appendLastEventId(url, lastSeq) : url;
26
+ if (clientId)
27
+ target = appendQuery(target, "client_id", clientId);
28
+ const ws = createSocket(target);
29
+ const pending = [];
30
+ let open = false;
31
+ let closed = false;
32
+ let notified = false;
33
+ /** Fire the terminal notification AT MOST ONCE per transport. A real
34
+ * WebSocket emits `error` THEN `close` on a network failure (codex M2
35
+ * MUST-1); without this the client would handle two down events and
36
+ * schedule TWO reconnects → duplicate transports + double replay/dispatch. */
37
+ const die = (notify) => {
38
+ open = false;
39
+ closed = true;
40
+ pending.length = 0;
41
+ if (notified)
42
+ return;
43
+ notified = true;
44
+ notify();
45
+ };
46
+ ws.addEventListener("open", () => {
47
+ open = true;
48
+ for (const line of pending.splice(0))
49
+ ws.send(line);
50
+ handlers.onOpen();
51
+ });
52
+ ws.addEventListener("message", (e) => {
53
+ handlers.onMessage(typeof e.data === "string" ? e.data : String(e.data));
54
+ });
55
+ ws.addEventListener("close", () => die(() => handlers.onClose()));
56
+ ws.addEventListener("error", (e) => die(() => handlers.onError(e)));
57
+ return {
58
+ send(line) {
59
+ if (closed)
60
+ return;
61
+ if (open)
62
+ ws.send(line);
63
+ else
64
+ pending.push(line);
65
+ },
66
+ close() {
67
+ // Mark dead + drop the buffer; `ws.close()` still fires the WS `close`
68
+ // event, which `die` delivers as a single `onClose` (the client uses it
69
+ // to reach the terminal state when it initiated the close).
70
+ if (closed)
71
+ return;
72
+ open = false;
73
+ closed = true;
74
+ pending.length = 0;
75
+ ws.close();
76
+ },
77
+ };
78
+ };
79
+ }
80
+ /** Append `last_event_id=N` to a ws:// URL, preserving any existing query. */
81
+ function appendLastEventId(url, lastSeq) {
82
+ const sep = url.includes("?") ? "&" : "?";
83
+ return `${url}${sep}last_event_id=${lastSeq}`;
84
+ }
85
+ /** Append an URL-encoded `key=value` query param, preserving any existing query. */
86
+ function appendQuery(url, key, value) {
87
+ const sep = url.includes("?") ? "&" : "?";
88
+ return `${url}${sep}${key}=${encodeURIComponent(value)}`;
89
+ }
90
+ /**
91
+ * (v21 M4) Append a pairing token to a relay URL (preserving any existing query).
92
+ * The token rides the connect URL because a browser WebSocket can't set an auth
93
+ * header (the same constraint as the replay cursor). It then survives reconnect
94
+ * for free: `webSocketTransport`'s base url is reused on every (re)dial, and
95
+ * `appendLastEventId` only `&`-appends the cursor — so the token stays put.
96
+ */
97
+ export function withPairingToken(url, token) {
98
+ if (!token)
99
+ return url;
100
+ const sep = url.includes("?") ? "&" : "?";
101
+ return `${url}${sep}token=${encodeURIComponent(token)}`;
102
+ }
103
+ //# sourceMappingURL=transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.js","sourceRoot":"","sources":["../../src/client-core/transport.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * (v22 / docs/6.5b §C7) Approval-mode badge — the web twin of the TUI footer
3
+ * `ModeBadge`. Shows the current default / auto-edit / plan / yolo mode (glyph +
4
+ * label, tinted by role) and cycles it on click via `client.cycleApprovalMode`
5
+ * (the GUI equivalent of the TUI Shift+Tab — on the web, Shift+Tab is reverse-tab
6
+ * focus navigation, so a click badge is the platform-appropriate control). The
7
+ * mode is learned over the wire (`get_state` on handshake, `set_approval` to
8
+ * change) — see client-core + the engine-driver extension.
9
+ */
10
+ import type { ApprovalMode } from "@chances-ai/runtime";
11
+ export interface ApprovalBadgeProps {
12
+ mode: ApprovalMode;
13
+ onCycle: () => void;
14
+ disabled?: boolean;
15
+ }
16
+ export declare function ApprovalBadge({ mode, onCycle, disabled }: ApprovalBadgeProps): import("react/jsx-runtime").JSX.Element;
17
+ //# sourceMappingURL=approval-badge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval-badge.d.ts","sourceRoot":"","sources":["../../src/web-ui/approval-badge.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAYxD,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,aAAa,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,QAAgB,EAAE,EAAE,kBAAkB,2CA0BpF"}
@@ -0,0 +1,24 @@
1
+ import { jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { GLYPHS, useUiTheme } from "./theme-context.js";
3
+ const MODE_DISPLAY = {
4
+ default: { glyph: "○", role: "synComment", label: "default" },
5
+ "auto-edit": { glyph: GLYPHS.accept, role: "autoAccept", label: "auto-edit" },
6
+ plan: { glyph: GLYPHS.plan, role: "planMode", label: "plan" },
7
+ yolo: { glyph: GLYPHS.accept, role: "error", label: "yolo" },
8
+ };
9
+ export function ApprovalBadge({ mode, onCycle, disabled = false }) {
10
+ const theme = useUiTheme();
11
+ const d = MODE_DISPLAY[mode];
12
+ const color = theme[d.role] ?? theme.synComment;
13
+ return (_jsxs("button", { type: "button", disabled: disabled, onClick: disabled ? undefined : onCycle, title: "cycle approval mode", "aria-label": `approval mode: ${d.label}`, className: disabled ? "" : "transition-opacity hover:opacity-70", style: {
14
+ background: "transparent",
15
+ border: `1px solid ${color ?? "currentColor"}`,
16
+ borderRadius: 6,
17
+ padding: "2px 8px",
18
+ color,
19
+ cursor: disabled ? "default" : "pointer",
20
+ opacity: disabled ? 0.5 : 1,
21
+ fontSize: 12,
22
+ }, children: [d.glyph, " ", d.label] }));
23
+ }
24
+ //# sourceMappingURL=approval-badge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval-badge.js","sourceRoot":"","sources":["../../src/web-ui/approval-badge.tsx"],"names":[],"mappings":";AAUA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAIxD,MAAM,YAAY,GAAuE;IACvF,OAAO,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE;IAC7D,WAAW,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,WAAW,EAAE;IAC7E,IAAI,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE;IAC7D,IAAI,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE;CAC7D,CAAC;AAQF,MAAM,UAAU,aAAa,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,GAAG,KAAK,EAAsB;IACnF,MAAM,KAAK,GAAG,UAAU,EAAE,CAAC;IAC3B,MAAM,CAAC,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAC7B,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC;IAChD,OAAO,CACL,kBACE,IAAI,EAAC,QAAQ,EACb,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,EACvC,KAAK,EAAC,qBAAqB,gBACf,kBAAkB,CAAC,CAAC,KAAK,EAAE,EACvC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,qCAAqC,EAChE,KAAK,EAAE;YACL,UAAU,EAAE,aAAa;YACzB,MAAM,EAAE,aAAa,KAAK,IAAI,cAAc,EAAE;YAC9C,YAAY,EAAE,CAAC;YACf,OAAO,EAAE,SAAS;YAClB,KAAK;YACL,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;YACxC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAC3B,QAAQ,EAAE,EAAE;SACb,aAEA,CAAC,CAAC,KAAK,OAAG,CAAC,CAAC,KAAK,IACX,CACV,CAAC;AACJ,CAAC"}
@@ -0,0 +1,10 @@
1
+ export interface ButtonProps {
2
+ label: string;
3
+ onPress: () => void;
4
+ /** Tint (border + text). Omitted ⇒ inherit. */
5
+ color?: string;
6
+ disabled?: boolean;
7
+ fontSize?: number;
8
+ }
9
+ export declare function Button({ label, onPress, color, disabled, fontSize }: ButtonProps): import("react/jsx-runtime").JSX.Element;
10
+ //# sourceMappingURL=button.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"button.d.ts","sourceRoot":"","sources":["../../src/web-ui/button.tsx"],"names":[],"mappings":"AAWA,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,+CAA+C;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,MAAM,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,QAAgB,EAAE,QAAa,EAAE,EAAE,WAAW,2CAuB7F"}
@@ -0,0 +1,16 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ export function Button({ label, onPress, color, disabled = false, fontSize = 13 }) {
3
+ const style = {
4
+ border: `1px solid ${color ?? "currentColor"}`,
5
+ borderRadius: 6,
6
+ padding: "6px 12px",
7
+ background: "transparent",
8
+ color,
9
+ fontWeight: 600,
10
+ fontSize,
11
+ cursor: disabled ? "default" : "pointer",
12
+ opacity: disabled ? 0.5 : 1,
13
+ };
14
+ return (_jsx("button", { type: "button", disabled: disabled, onClick: disabled ? undefined : onPress, className: disabled ? "" : "transition-opacity hover:opacity-70", style: style, children: label }));
15
+ }
16
+ //# sourceMappingURL=button.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"button.js","sourceRoot":"","sources":["../../src/web-ui/button.tsx"],"names":[],"mappings":";AAoBA,MAAM,UAAU,MAAM,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,GAAG,KAAK,EAAE,QAAQ,GAAG,EAAE,EAAe;IAC5F,MAAM,KAAK,GAAkB;QAC3B,MAAM,EAAE,aAAa,KAAK,IAAI,cAAc,EAAE;QAC9C,YAAY,EAAE,CAAC;QACf,OAAO,EAAE,UAAU;QACnB,UAAU,EAAE,aAAa;QACzB,KAAK;QACL,UAAU,EAAE,GAAG;QACf,QAAQ;QACR,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;QACxC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;KAC5B,CAAC;IACF,OAAO,CACL,iBACE,IAAI,EAAC,QAAQ,EACb,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,EACvC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,qCAAqC,EAChE,KAAK,EAAE,KAAK,YAEX,KAAK,GACC,CACV,CAAC;AACJ,CAAC"}
@@ -0,0 +1,6 @@
1
+ export interface CodeViewProps {
2
+ code: string;
3
+ lang?: string;
4
+ }
5
+ export declare function CodeView({ code, lang }: CodeViewProps): import("react/jsx-runtime").JSX.Element;
6
+ //# sourceMappingURL=code-view.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-view.d.ts","sourceRoot":"","sources":["../../src/web-ui/code-view.tsx"],"names":[],"mappings":"AASA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,QAAQ,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,aAAa,2CAOrD"}
@@ -0,0 +1,14 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * (v22 / docs/6.5b §C3) Fenced code block — the web twin of the TUI `CodeView`:
4
+ * indented, no border/background (claude-code doesn't box code), syntax-highlit
5
+ * via the shared `highlightToSegments` (reused through `CodeSegments`). A trailing
6
+ * newline is dropped so the block doesn't render an extra blank line.
7
+ */
8
+ import { Box } from "./primitives.js";
9
+ import { CodeSegments } from "./segments.js";
10
+ export function CodeView({ code, lang }) {
11
+ const body = code.endsWith("\n") ? code.slice(0, -1) : code;
12
+ return (_jsx(Box, { paddingLeft: 8, marginTop: 2, children: _jsx(CodeSegments, { code: body, lang: lang, fontSize: 13 }) }));
13
+ }
14
+ //# sourceMappingURL=code-view.js.map