@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.
- package/dist/client-core/client.d.ts +145 -0
- package/dist/client-core/client.d.ts.map +1 -0
- package/dist/client-core/client.js +533 -0
- package/dist/client-core/client.js.map +1 -0
- package/dist/client-core/index.d.ts +16 -0
- package/dist/client-core/index.d.ts.map +1 -0
- package/dist/client-core/index.js +15 -0
- package/dist/client-core/index.js.map +1 -0
- package/dist/client-core/reverse-map.d.ts +66 -0
- package/dist/client-core/reverse-map.d.ts.map +1 -0
- package/dist/client-core/reverse-map.js +86 -0
- package/dist/client-core/reverse-map.js.map +1 -0
- package/dist/client-core/store.d.ts +144 -0
- package/dist/client-core/store.d.ts.map +1 -0
- package/dist/client-core/store.js +36 -0
- package/dist/client-core/store.js.map +1 -0
- package/dist/client-core/transport.d.ts +53 -0
- package/dist/client-core/transport.d.ts.map +1 -0
- package/dist/client-core/transport.js +103 -0
- package/dist/client-core/transport.js.map +1 -0
- package/dist/web-ui/approval-badge.d.ts +17 -0
- package/dist/web-ui/approval-badge.d.ts.map +1 -0
- package/dist/web-ui/approval-badge.js +24 -0
- package/dist/web-ui/approval-badge.js.map +1 -0
- package/dist/web-ui/button.d.ts +10 -0
- package/dist/web-ui/button.d.ts.map +1 -0
- package/dist/web-ui/button.js +16 -0
- package/dist/web-ui/button.js.map +1 -0
- package/dist/web-ui/code-view.d.ts +6 -0
- package/dist/web-ui/code-view.d.ts.map +1 -0
- package/dist/web-ui/code-view.js +14 -0
- package/dist/web-ui/code-view.js.map +1 -0
- package/dist/web-ui/code-viewer.d.ts +11 -0
- package/dist/web-ui/code-viewer.d.ts.map +1 -0
- package/dist/web-ui/code-viewer.js +55 -0
- package/dist/web-ui/code-viewer.js.map +1 -0
- package/dist/web-ui/commands.d.ts +23 -0
- package/dist/web-ui/commands.d.ts.map +1 -0
- package/dist/web-ui/commands.js +26 -0
- package/dist/web-ui/commands.js.map +1 -0
- package/dist/web-ui/control-panel.d.ts +9 -0
- package/dist/web-ui/control-panel.d.ts.map +1 -0
- package/dist/web-ui/control-panel.js +70 -0
- package/dist/web-ui/control-panel.js.map +1 -0
- package/dist/web-ui/diff-view.d.ts +8 -0
- package/dist/web-ui/diff-view.d.ts.map +1 -0
- package/dist/web-ui/diff-view.js +28 -0
- package/dist/web-ui/diff-view.js.map +1 -0
- package/dist/web-ui/environment-panel.d.ts +9 -0
- package/dist/web-ui/environment-panel.d.ts.map +1 -0
- package/dist/web-ui/environment-panel.js +38 -0
- package/dist/web-ui/environment-panel.js.map +1 -0
- package/dist/web-ui/file-tree.d.ts +9 -0
- package/dist/web-ui/file-tree.d.ts.map +1 -0
- package/dist/web-ui/file-tree.js +77 -0
- package/dist/web-ui/file-tree.js.map +1 -0
- package/dist/web-ui/help-view.d.ts +13 -0
- package/dist/web-ui/help-view.d.ts.map +1 -0
- package/dist/web-ui/help-view.js +15 -0
- package/dist/web-ui/help-view.js.map +1 -0
- package/dist/web-ui/helpers.d.ts +77 -0
- package/dist/web-ui/helpers.d.ts.map +1 -0
- package/dist/web-ui/helpers.js +176 -0
- package/dist/web-ui/helpers.js.map +1 -0
- package/dist/web-ui/hooks.d.ts +7 -0
- package/dist/web-ui/hooks.d.ts.map +1 -0
- package/dist/web-ui/hooks.js +26 -0
- package/dist/web-ui/hooks.js.map +1 -0
- package/dist/web-ui/index.d.ts +32 -0
- package/dist/web-ui/index.d.ts.map +1 -0
- package/dist/web-ui/index.js +38 -0
- package/dist/web-ui/index.js.map +1 -0
- package/dist/web-ui/markdown.d.ts +12 -0
- package/dist/web-ui/markdown.d.ts.map +1 -0
- package/dist/web-ui/markdown.js +55 -0
- package/dist/web-ui/markdown.js.map +1 -0
- package/dist/web-ui/model-picker.d.ts +9 -0
- package/dist/web-ui/model-picker.d.ts.map +1 -0
- package/dist/web-ui/model-picker.js +119 -0
- package/dist/web-ui/model-picker.js.map +1 -0
- package/dist/web-ui/permission.d.ts +7 -0
- package/dist/web-ui/permission.d.ts.map +1 -0
- package/dist/web-ui/permission.js +25 -0
- package/dist/web-ui/permission.js.map +1 -0
- package/dist/web-ui/primitives.d.ts +59 -0
- package/dist/web-ui/primitives.d.ts.map +1 -0
- package/dist/web-ui/primitives.js +38 -0
- package/dist/web-ui/primitives.js.map +1 -0
- package/dist/web-ui/progress.d.ts +28 -0
- package/dist/web-ui/progress.d.ts.map +1 -0
- package/dist/web-ui/progress.js +45 -0
- package/dist/web-ui/progress.js.map +1 -0
- package/dist/web-ui/prompt-input.d.ts +15 -0
- package/dist/web-ui/prompt-input.d.ts.map +1 -0
- package/dist/web-ui/prompt-input.js +129 -0
- package/dist/web-ui/prompt-input.js.map +1 -0
- package/dist/web-ui/question-view.d.ts +7 -0
- package/dist/web-ui/question-view.d.ts.map +1 -0
- package/dist/web-ui/question-view.js +60 -0
- package/dist/web-ui/question-view.js.map +1 -0
- package/dist/web-ui/segments.d.ts +8 -0
- package/dist/web-ui/segments.d.ts.map +1 -0
- package/dist/web-ui/segments.js +19 -0
- package/dist/web-ui/segments.js.map +1 -0
- package/dist/web-ui/session-sidebar.d.ts +15 -0
- package/dist/web-ui/session-sidebar.d.ts.map +1 -0
- package/dist/web-ui/session-sidebar.js +10 -0
- package/dist/web-ui/session-sidebar.js.map +1 -0
- package/dist/web-ui/status-bar.d.ts +10 -0
- package/dist/web-ui/status-bar.d.ts.map +1 -0
- package/dist/web-ui/status-bar.js +10 -0
- package/dist/web-ui/status-bar.js.map +1 -0
- package/dist/web-ui/theme-context.d.ts +13 -0
- package/dist/web-ui/theme-context.d.ts.map +1 -0
- package/dist/web-ui/theme-context.js +31 -0
- package/dist/web-ui/theme-context.js.map +1 -0
- package/dist/web-ui/transcript.d.ts +27 -0
- package/dist/web-ui/transcript.d.ts.map +1 -0
- package/dist/web-ui/transcript.js +56 -0
- package/dist/web-ui/transcript.js.map +1 -0
- 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 @@
|
|
|
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
|