@workerdeck/react 2.12.0 → 2.14.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/build/index.d.mts +50 -2
- package/build/index.mjs +236 -4
- package/build/index.mjs.map +1 -1
- package/package.json +6 -6
package/build/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AttachedFrame, ByModel, ChecklistItem, ContextUsage, EngineCapabilities, FilePatch, HostDirEntry, HostFileMatch, MessageAttachment, MessageOrigin, ModelOption, PermissionMode, PermissionRequest, PricingTable, ProfileEngine, ProfileSpend, ProfileUsage, RateLimitInfo, SessionEvent, SessionInfo, SessionRow, SessionStatus, SkillInfo, SlashCommandInfo, ToolExecutionBackend, UsageWindowRow } from "@workerdeck/protocol";
|
|
1
|
+
import { AttachedFrame, ByModel, ChecklistItem, ContextUsage, EngineCapabilities, FilePatch, HostDirEntry, HostFileMatch, MessageAttachment, MessageOrigin, ModelOption, PermissionMode, PermissionRequest, PricingTable, ProfileEngine, ProfileSpend, ProfileUsage, RateLimitInfo, SessionEvent, SessionInfo, SessionRow, SessionStatus, ShellInfo, SkillInfo, SlashCommandInfo, ToolExecutionBackend, UsageWindowRow } from "@workerdeck/protocol";
|
|
2
2
|
import { SessionHandle, WorkerDeckClient } from "@workerdeck/client";
|
|
3
3
|
import { RunScriptResult, SandboxEngine, SandboxVfs } from "@workerdeck/sandbox";
|
|
4
4
|
//#region src/lib/transcript.d.ts
|
|
@@ -75,6 +75,14 @@ type TranscriptItem = {
|
|
|
75
75
|
path: string;
|
|
76
76
|
bytes: number;
|
|
77
77
|
description?: string;
|
|
78
|
+
} | {
|
|
79
|
+
kind: 'shell';
|
|
80
|
+
id: string;
|
|
81
|
+
shell: ShellInfo;
|
|
82
|
+
text: string;
|
|
83
|
+
truncated: boolean;
|
|
84
|
+
expanded?: string;
|
|
85
|
+
missing?: boolean;
|
|
78
86
|
};
|
|
79
87
|
type ProducedFileRef = {
|
|
80
88
|
fileId: string;
|
|
@@ -110,9 +118,18 @@ type TranscriptState = {
|
|
|
110
118
|
lastSeq: number;
|
|
111
119
|
};
|
|
112
120
|
declare const initialTranscriptState: TranscriptState;
|
|
121
|
+
type ShellItem = Extract<TranscriptItem, {
|
|
122
|
+
kind: 'shell';
|
|
123
|
+
}>;
|
|
124
|
+
declare function shellRowText(shell: ShellInfo, text: string): {
|
|
125
|
+
text: string;
|
|
126
|
+
truncated: boolean;
|
|
127
|
+
};
|
|
113
128
|
declare function seedFromSessionInfo(state: TranscriptState, info: SessionInfo): TranscriptState;
|
|
114
129
|
declare function rateLimitWindows(state: TranscriptState): UsageWindowRow[];
|
|
115
130
|
declare function hydrateToolResult(state: TranscriptState, toolUseId: string, text: string): TranscriptState;
|
|
131
|
+
declare function hydrateShellRow(state: TranscriptState, shellId: string, shell: ShellInfo | undefined): TranscriptState;
|
|
132
|
+
declare function hydrateShellOutput(state: TranscriptState, shellId: string, text: string): TranscriptState;
|
|
116
133
|
declare function applyEvent(state: TranscriptState, event: SessionEvent): TranscriptState;
|
|
117
134
|
//#endregion
|
|
118
135
|
//#region src/hooks/use-session.d.ts
|
|
@@ -146,6 +163,9 @@ type UseClaudeSessionResult = {
|
|
|
146
163
|
closeSession: () => void;
|
|
147
164
|
reconnectNow: () => void;
|
|
148
165
|
loadFullResult: (toolUseId: string) => Promise<boolean>;
|
|
166
|
+
loadShellOutput: (shellId: string) => Promise<boolean>;
|
|
167
|
+
verifyShell: (shellId: string) => Promise<boolean>;
|
|
168
|
+
killShell: (shellId: string) => Promise<boolean>;
|
|
149
169
|
};
|
|
150
170
|
declare function useClaudeSession(client: WorkerDeckClient, sessionId: string | undefined, options?: UseClaudeSessionOptions): UseClaudeSessionResult;
|
|
151
171
|
//#endregion
|
|
@@ -452,5 +472,33 @@ type RecapInput = {
|
|
|
452
472
|
declare function summarizeSince(state: RecapInput, fromIndex: number): RecapSummary;
|
|
453
473
|
declare function recapLine(summary: RecapSummary): string | undefined;
|
|
454
474
|
//#endregion
|
|
455
|
-
|
|
475
|
+
//#region src/hooks/use-shell-terminal.d.ts
|
|
476
|
+
type ShellTerminalSize = {
|
|
477
|
+
cols: number;
|
|
478
|
+
rows: number;
|
|
479
|
+
};
|
|
480
|
+
type ShellTerminalStatus = 'idle' | 'attaching' | 'attached' | 'detached';
|
|
481
|
+
type ShellAttachment = {
|
|
482
|
+
shell: ShellInfo;
|
|
483
|
+
cols: number;
|
|
484
|
+
rows: number;
|
|
485
|
+
scrollback: string;
|
|
486
|
+
};
|
|
487
|
+
type UseShellTerminalOptions = {
|
|
488
|
+
onData: (data: string) => void;
|
|
489
|
+
onEnded?: (reason: string) => void;
|
|
490
|
+
onAttached?: (attachment: ShellAttachment) => void;
|
|
491
|
+
};
|
|
492
|
+
type UseShellTerminalResult = {
|
|
493
|
+
status: ShellTerminalStatus;
|
|
494
|
+
shell: ShellInfo | undefined;
|
|
495
|
+
reason: string | undefined;
|
|
496
|
+
attach: (size: ShellTerminalSize) => void;
|
|
497
|
+
write: (data: string) => void;
|
|
498
|
+
resize: (size: ShellTerminalSize) => void;
|
|
499
|
+
detach: () => void;
|
|
500
|
+
};
|
|
501
|
+
declare function useShellTerminal(handle: SessionHandle | undefined, shellId: string | undefined, options: UseShellTerminalOptions): UseShellTerminalResult;
|
|
502
|
+
//#endregion
|
|
503
|
+
export { type AttachmentKind, type ClientForHost, type ClientToolHandler, type ClientToolResult, type ConnectionState, type HostDirState, type HostTreeRow, type OpenFile, type OpenFilesAction, type OpenFilesState, type PeerSessionOption, type ProducedFileRef, type PromptToken, type PromptTokenOptions, REPLAY_HOLD_MAX_MS, type RecapInput, type RecapSummary, type ShellAttachment, type ShellItem, type ShellTerminalSize, type ShellTerminalStatus, type StagedAttachment, type ToolCallHostOptions, type ToolHostExecution, type ToolHostRunner, type ToolResultImageRef, type TranscriptItem, type TranscriptState, type UseAttachmentsOptions, type UseAttachmentsResult, type UseClaudeSessionOptions, type UseClaudeSessionResult, type UseDraftResult, type UseHostFileRootsResult, type UseHostFileSearchResult, type UseHostFileTreeResult, type UseOpenFilesResult, type UsePeerSessionsResult, type UseProfileUsageOptions, type UseProfileUsageResult, type UseSessionInfoResult, type UseShellTerminalOptions, type UseShellTerminalResult, type UseToolCallHostOptions, ancestorsWithin, applyEvent, attachmentKind, clearDrafts, clearProfileUsageCache, clearTranscriptCache, createToolCallHost, currentText, flattenHostTree, hydrateShellOutput, hydrateShellRow, hydrateToolResult, initialOpenFilesState, initialReplayTarget, initialTranscriptState, isDirty, openFilesReducer, rateLimitWindows, recapLine, scanPromptTokens, seedFromSessionInfo, shellRowText, staleAttach, summarizeSince, useAttachments, useClaudeSession, useDraft, useHostFileRoots, useHostFileSearch, useHostFileTree, useOpenFiles, usePeerSessions, useProfileUsage, useProjectIcons, useSessionInfo, useShellTerminal, useToolCallHost };
|
|
456
504
|
//# sourceMappingURL=index.d.mts.map
|
package/build/index.mjs
CHANGED
|
@@ -15,6 +15,36 @@ const STREAMING_THINKING_ID = "streaming-thinking";
|
|
|
15
15
|
const LOCAL_COMMAND_OUTPUT = /^<local-command-(stdout|stderr)>([\s\S]*?)<\/local-command-\1>$/;
|
|
16
16
|
const LOCAL_COMMAND_ELEMENT = /<local-command-(stdout|stderr)>([\s\S]*?)<\/local-command-\1>/g;
|
|
17
17
|
const LOCAL_COMMAND_CAVEAT = "<local-command-caveat>";
|
|
18
|
+
const SHELL_MORE_OUTPUT = /^\[\.\.\. more output \.\.\.\]$/;
|
|
19
|
+
const SHELL_END_LINE = /^\[(exit -?\d+|killed|timed out|ended|failed to start)[^\]]*\]$/;
|
|
20
|
+
function shellRowText(shell, text) {
|
|
21
|
+
const lines = (LOCAL_COMMAND_OUTPUT.exec(text.trim())?.[2] ?? text).split("\n");
|
|
22
|
+
if (lines[0]?.startsWith("$ ")) lines.shift();
|
|
23
|
+
if (shell.status === "exited" && lines.length > 0 && SHELL_END_LINE.test(lines[lines.length - 1])) lines.pop();
|
|
24
|
+
let truncated = false;
|
|
25
|
+
return {
|
|
26
|
+
text: lines.filter((line) => {
|
|
27
|
+
if (!SHELL_MORE_OUTPUT.test(line)) return true;
|
|
28
|
+
truncated = true;
|
|
29
|
+
return false;
|
|
30
|
+
}).join("\n").trimEnd(),
|
|
31
|
+
truncated
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function shellItem(id, shell, text, previous) {
|
|
35
|
+
const row = shellRowText(shell, text);
|
|
36
|
+
return {
|
|
37
|
+
kind: "shell",
|
|
38
|
+
id,
|
|
39
|
+
shell,
|
|
40
|
+
text: row.text,
|
|
41
|
+
truncated: row.truncated,
|
|
42
|
+
...previous?.expanded !== void 0 && { expanded: previous.expanded }
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function findShell(items, shellId) {
|
|
46
|
+
return items.find((item) => item.kind === "shell" && item.shell.id === shellId);
|
|
47
|
+
}
|
|
18
48
|
const COMMAND_NAME = /<command-name>([\s\S]*?)<\/command-name>/;
|
|
19
49
|
const COMMAND_ARGS = /<command-args>([\s\S]*?)<\/command-args>/;
|
|
20
50
|
function carriesCaveat(content) {
|
|
@@ -113,6 +143,34 @@ function hydrateToolResult(state, toolUseId, text) {
|
|
|
113
143
|
items
|
|
114
144
|
} : state;
|
|
115
145
|
}
|
|
146
|
+
function hydrateShellRow(state, shellId, shell) {
|
|
147
|
+
const current = findShell(state.items, shellId);
|
|
148
|
+
if (!current) return state;
|
|
149
|
+
const next = shell === void 0 ? {
|
|
150
|
+
...current,
|
|
151
|
+
missing: true
|
|
152
|
+
} : {
|
|
153
|
+
...current,
|
|
154
|
+
shell,
|
|
155
|
+
missing: void 0
|
|
156
|
+
};
|
|
157
|
+
return {
|
|
158
|
+
...state,
|
|
159
|
+
items: state.items.map((item) => item === current ? next : item)
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
function hydrateShellOutput(state, shellId, text) {
|
|
163
|
+
const current = findShell(state.items, shellId);
|
|
164
|
+
if (!current) return state;
|
|
165
|
+
return {
|
|
166
|
+
...state,
|
|
167
|
+
items: state.items.map((item) => item === current ? {
|
|
168
|
+
...current,
|
|
169
|
+
expanded: text,
|
|
170
|
+
missing: void 0
|
|
171
|
+
} : item)
|
|
172
|
+
};
|
|
173
|
+
}
|
|
116
174
|
function applyEvent(state, event) {
|
|
117
175
|
if (event.seq <= state.lastSeq) return state;
|
|
118
176
|
const base = {
|
|
@@ -236,7 +294,10 @@ function applyEvent(state, event) {
|
|
|
236
294
|
const text = block.text;
|
|
237
295
|
const rowId = event.uuid ?? `user-${event.seq}`;
|
|
238
296
|
const localOutput = LOCAL_COMMAND_OUTPUT.exec(text.trim());
|
|
239
|
-
if (
|
|
297
|
+
if (event.shell) {
|
|
298
|
+
const existing = items.find((item) => item.kind === "shell" && item.id === rowId);
|
|
299
|
+
items = upsert(items, shellItem(rowId, event.shell, text, existing));
|
|
300
|
+
} else if (localOutput) items = upsert(items, {
|
|
240
301
|
kind: "notice",
|
|
241
302
|
id: rowId,
|
|
242
303
|
level: localOutput[1] === "stderr" ? "error" : "info",
|
|
@@ -490,6 +551,8 @@ function shouldWriteParting(input) {
|
|
|
490
551
|
function reduce(state, action) {
|
|
491
552
|
if (action.type === "transcript_seed") return action.state;
|
|
492
553
|
if (action.type === "transcript_hydrate_result") return hydrateToolResult(state, action.toolUseId, action.text);
|
|
554
|
+
if (action.type === "transcript_hydrate_shell") return hydrateShellRow(state, action.shellId, action.shell);
|
|
555
|
+
if (action.type === "transcript_hydrate_shell_output") return hydrateShellOutput(state, action.shellId, action.text);
|
|
493
556
|
return action.type === "attached" ? seedFromSessionInfo(state, action.session) : applyEvent(state, action);
|
|
494
557
|
}
|
|
495
558
|
const OFFLINE_AFTER_ATTEMPTS = 3;
|
|
@@ -620,6 +683,63 @@ function useClaudeSession(client, sessionId, options) {
|
|
|
620
683
|
return false;
|
|
621
684
|
}
|
|
622
685
|
}, [client, sessionId]);
|
|
686
|
+
const verifiedRef = useRef(/* @__PURE__ */ new Set());
|
|
687
|
+
useEffect(() => {
|
|
688
|
+
verifiedRef.current = /* @__PURE__ */ new Set();
|
|
689
|
+
}, [sessionId]);
|
|
690
|
+
const loadShellOutput = useCallback(async (shellId) => {
|
|
691
|
+
if (!sessionId) return false;
|
|
692
|
+
try {
|
|
693
|
+
const text = await client.shellOutput(sessionId, shellId, { view: "text" });
|
|
694
|
+
dispatch({
|
|
695
|
+
type: "transcript_hydrate_shell_output",
|
|
696
|
+
shellId,
|
|
697
|
+
text
|
|
698
|
+
});
|
|
699
|
+
return true;
|
|
700
|
+
} catch {
|
|
701
|
+
dispatch({
|
|
702
|
+
type: "transcript_hydrate_shell",
|
|
703
|
+
shellId,
|
|
704
|
+
shell: void 0
|
|
705
|
+
});
|
|
706
|
+
return false;
|
|
707
|
+
}
|
|
708
|
+
}, [client, sessionId]);
|
|
709
|
+
const verifyShell = useCallback(async (shellId) => {
|
|
710
|
+
if (!sessionId || verifiedRef.current.has(shellId)) return false;
|
|
711
|
+
verifiedRef.current.add(shellId);
|
|
712
|
+
try {
|
|
713
|
+
const record = await client.getShell(sessionId, shellId);
|
|
714
|
+
dispatch({
|
|
715
|
+
type: "transcript_hydrate_shell",
|
|
716
|
+
shellId,
|
|
717
|
+
shell: record
|
|
718
|
+
});
|
|
719
|
+
return true;
|
|
720
|
+
} catch {
|
|
721
|
+
dispatch({
|
|
722
|
+
type: "transcript_hydrate_shell",
|
|
723
|
+
shellId,
|
|
724
|
+
shell: void 0
|
|
725
|
+
});
|
|
726
|
+
return false;
|
|
727
|
+
}
|
|
728
|
+
}, [client, sessionId]);
|
|
729
|
+
const killShell = useCallback(async (shellId) => {
|
|
730
|
+
if (!sessionId) return false;
|
|
731
|
+
try {
|
|
732
|
+
const record = await client.killShell(sessionId, shellId);
|
|
733
|
+
dispatch({
|
|
734
|
+
type: "transcript_hydrate_shell",
|
|
735
|
+
shellId,
|
|
736
|
+
shell: record
|
|
737
|
+
});
|
|
738
|
+
return true;
|
|
739
|
+
} catch {
|
|
740
|
+
return false;
|
|
741
|
+
}
|
|
742
|
+
}, [client, sessionId]);
|
|
623
743
|
return useMemo(() => ({
|
|
624
744
|
state,
|
|
625
745
|
connected,
|
|
@@ -641,7 +761,10 @@ function useClaudeSession(client, sessionId, options) {
|
|
|
641
761
|
setModel: (model) => handleRef.current?.setModel(model),
|
|
642
762
|
closeSession: () => handleRef.current?.closeSession(),
|
|
643
763
|
reconnectNow,
|
|
644
|
-
loadFullResult
|
|
764
|
+
loadFullResult,
|
|
765
|
+
loadShellOutput,
|
|
766
|
+
verifyShell,
|
|
767
|
+
killShell
|
|
645
768
|
}), [
|
|
646
769
|
state,
|
|
647
770
|
connected,
|
|
@@ -653,7 +776,10 @@ function useClaudeSession(client, sessionId, options) {
|
|
|
653
776
|
models,
|
|
654
777
|
handleState,
|
|
655
778
|
reconnectNow,
|
|
656
|
-
loadFullResult
|
|
779
|
+
loadFullResult,
|
|
780
|
+
loadShellOutput,
|
|
781
|
+
verifyShell,
|
|
782
|
+
killShell
|
|
657
783
|
]);
|
|
658
784
|
}
|
|
659
785
|
function useProfileModelFallback(client, sessionId, state) {
|
|
@@ -1934,6 +2060,112 @@ function plural(count, one, many = `${one}s`) {
|
|
|
1934
2060
|
return `${count} ${count === 1 ? one : many}`;
|
|
1935
2061
|
}
|
|
1936
2062
|
//#endregion
|
|
1937
|
-
|
|
2063
|
+
//#region src/hooks/use-shell-terminal.ts
|
|
2064
|
+
function useShellTerminal(handle, shellId, options) {
|
|
2065
|
+
const [status, setStatus] = useState("idle");
|
|
2066
|
+
const [shell, setShell] = useState(void 0);
|
|
2067
|
+
const [reason, setReason] = useState(void 0);
|
|
2068
|
+
const optionsRef = useRef(options);
|
|
2069
|
+
optionsRef.current = options;
|
|
2070
|
+
const sizeRef = useRef({
|
|
2071
|
+
cols: 80,
|
|
2072
|
+
rows: 24
|
|
2073
|
+
});
|
|
2074
|
+
const wantAttachRef = useRef(false);
|
|
2075
|
+
useEffect(() => {
|
|
2076
|
+
wantAttachRef.current = false;
|
|
2077
|
+
setStatus("idle");
|
|
2078
|
+
setShell(void 0);
|
|
2079
|
+
setReason(void 0);
|
|
2080
|
+
}, [handle, shellId]);
|
|
2081
|
+
useEffect(() => {
|
|
2082
|
+
if (!handle || shellId === void 0) return;
|
|
2083
|
+
const offAttached = handle.on("shellAttached", (frame) => {
|
|
2084
|
+
if (frame.shellId !== shellId) return;
|
|
2085
|
+
sizeRef.current = {
|
|
2086
|
+
cols: frame.cols,
|
|
2087
|
+
rows: frame.rows
|
|
2088
|
+
};
|
|
2089
|
+
setShell(frame.shell);
|
|
2090
|
+
setReason(void 0);
|
|
2091
|
+
setStatus("attached");
|
|
2092
|
+
const attachment = {
|
|
2093
|
+
shell: frame.shell,
|
|
2094
|
+
cols: frame.cols,
|
|
2095
|
+
rows: frame.rows,
|
|
2096
|
+
scrollback: frame.scrollback
|
|
2097
|
+
};
|
|
2098
|
+
if (optionsRef.current.onAttached) optionsRef.current.onAttached(attachment);
|
|
2099
|
+
else if (frame.scrollback) optionsRef.current.onData(frame.scrollback);
|
|
2100
|
+
});
|
|
2101
|
+
const offOutput = handle.on("shellOutput", (frame) => {
|
|
2102
|
+
if (frame.shellId === shellId) optionsRef.current.onData(frame.data);
|
|
2103
|
+
});
|
|
2104
|
+
const offDetached = handle.on("shellDetached", (frame) => {
|
|
2105
|
+
if (frame.shellId !== shellId) return;
|
|
2106
|
+
wantAttachRef.current = false;
|
|
2107
|
+
setReason(frame.reason);
|
|
2108
|
+
setStatus("detached");
|
|
2109
|
+
optionsRef.current.onEnded?.(frame.reason);
|
|
2110
|
+
});
|
|
2111
|
+
const offConnection = handle.on("connectionChange", (connected) => {
|
|
2112
|
+
if (!wantAttachRef.current) return;
|
|
2113
|
+
if (connected) {
|
|
2114
|
+
setStatus("attaching");
|
|
2115
|
+
handle.attachShell(shellId, sizeRef.current);
|
|
2116
|
+
} else setStatus((current) => current === "attached" ? "attaching" : current);
|
|
2117
|
+
});
|
|
2118
|
+
return () => {
|
|
2119
|
+
offAttached();
|
|
2120
|
+
offOutput();
|
|
2121
|
+
offDetached();
|
|
2122
|
+
offConnection();
|
|
2123
|
+
if (wantAttachRef.current) {
|
|
2124
|
+
wantAttachRef.current = false;
|
|
2125
|
+
handle.detachShell(shellId);
|
|
2126
|
+
}
|
|
2127
|
+
};
|
|
2128
|
+
}, [handle, shellId]);
|
|
2129
|
+
const attach = useCallback((size) => {
|
|
2130
|
+
if (!handle || shellId === void 0) return;
|
|
2131
|
+
sizeRef.current = size;
|
|
2132
|
+
wantAttachRef.current = true;
|
|
2133
|
+
setReason(void 0);
|
|
2134
|
+
setStatus("attaching");
|
|
2135
|
+
handle.attachShell(shellId, size);
|
|
2136
|
+
}, [handle, shellId]);
|
|
2137
|
+
const write = useCallback((data) => {
|
|
2138
|
+
if (handle && shellId !== void 0) handle.writeShell(shellId, data);
|
|
2139
|
+
}, [handle, shellId]);
|
|
2140
|
+
const resize = useCallback((size) => {
|
|
2141
|
+
if (size.cols === sizeRef.current.cols && size.rows === sizeRef.current.rows) return;
|
|
2142
|
+
sizeRef.current = size;
|
|
2143
|
+
if (handle && shellId !== void 0 && wantAttachRef.current) handle.resizeShell(shellId, size);
|
|
2144
|
+
}, [handle, shellId]);
|
|
2145
|
+
const detach = useCallback(() => {
|
|
2146
|
+
if (handle && shellId !== void 0 && wantAttachRef.current) handle.detachShell(shellId);
|
|
2147
|
+
wantAttachRef.current = false;
|
|
2148
|
+
setStatus("idle");
|
|
2149
|
+
}, [handle, shellId]);
|
|
2150
|
+
return useMemo(() => ({
|
|
2151
|
+
status,
|
|
2152
|
+
shell,
|
|
2153
|
+
reason,
|
|
2154
|
+
attach,
|
|
2155
|
+
write,
|
|
2156
|
+
resize,
|
|
2157
|
+
detach
|
|
2158
|
+
}), [
|
|
2159
|
+
status,
|
|
2160
|
+
shell,
|
|
2161
|
+
reason,
|
|
2162
|
+
attach,
|
|
2163
|
+
write,
|
|
2164
|
+
resize,
|
|
2165
|
+
detach
|
|
2166
|
+
]);
|
|
2167
|
+
}
|
|
2168
|
+
//#endregion
|
|
2169
|
+
export { REPLAY_HOLD_MAX_MS, ancestorsWithin, applyEvent, attachmentKind, clearDrafts, clearProfileUsageCache, clearTranscriptCache, createToolCallHost, currentText, flattenHostTree, hydrateShellOutput, hydrateShellRow, hydrateToolResult, initialOpenFilesState, initialReplayTarget, initialTranscriptState, isDirty, openFilesReducer, rateLimitWindows, recapLine, scanPromptTokens, seedFromSessionInfo, shellRowText, staleAttach, summarizeSince, useAttachments, useClaudeSession, useDraft, useHostFileRoots, useHostFileSearch, useHostFileTree, useOpenFiles, usePeerSessions, useProfileUsage, useProjectIcons, useSessionInfo, useShellTerminal, useToolCallHost };
|
|
1938
2170
|
|
|
1939
2171
|
//# sourceMappingURL=index.mjs.map
|
package/build/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["entries"],"sources":["../src/lib/transcript.ts","../src/lib/transcript-cache.ts","../src/lib/attach-plan.ts","../src/hooks/use-session.ts","../src/lib/profile-usage-cache.ts","../src/lib/draft-store.ts","../src/hooks/use-attachments.ts","../src/lib/prompt-tokens.ts","../src/lib/async-guards.ts","../src/lib/host-tree.ts","../src/hooks/use-host-files.ts","../src/hooks/use-peer-sessions.ts","../src/hooks/use-project-icons.ts","../src/hooks/use-draft.ts","../src/hooks/use-profile-usage.ts","../src/hooks/use-session-info.ts","../src/lib/open-files.ts","../src/hooks/use-open-files.ts","../src/lib/tool-host.ts","../src/hooks/use-tool-host.ts","../src/lib/recap.ts"],"sourcesContent":["import { ENGINE_CAPABILITIES, mergeUsage, orderUsageWindows } from '@workerdeck/protocol'\nimport type {\n ApiMessage,\n ByModel,\n ChecklistItem,\n ContentBlock,\n ContextUsage,\n EngineCapabilities,\n FilePatch,\n MessageAttachment,\n MessageOrigin,\n ModelOption,\n PermissionMode,\n PermissionRequest,\n ProfileEngine,\n RateLimitInfo,\n SessionEvent,\n SessionInfo,\n SessionStatus,\n SkillInfo,\n SlashCommandInfo,\n ToolExecutionBackend,\n ToolExecutionOutput,\n ToolResultBlock,\n UsageWindowRow,\n} from '@workerdeck/protocol'\n\nexport type ToolResultImageRef = { partIndex: number; mediaType: string; bytes: number; sourceSeq: number }\n\nexport type TranscriptItem =\n | {\n kind: 'user'\n id: string\n text: string\n attachments?: MessageAttachment[]\n origin?: MessageOrigin\n // Optional, not `string | null` like the other kinds: there forgetting to stamp it must not typecheck; here almost every prompt has no parent.\n parentToolUseId?: string\n }\n | {\n kind: 'assistant_text'\n id: string\n text: string\n streaming: boolean\n parentToolUseId: string | null\n }\n | { kind: 'thinking'; id: string; text: string; parentToolUseId: string | null }\n | {\n kind: 'tool_call'\n id: string\n name: string\n input: unknown\n parentToolUseId: string | null\n // The event's own `ts`, never a receive time - replay-stable, stamped at creation only; absent reads as \"no elapsed\", never as the epoch.\n ts?: number\n status: 'running' | 'pending' | 'deferred' | 'settled' | 'failed'\n result?: {\n text: string\n isError: boolean\n truncated?: boolean\n totalChars?: number\n sourceSeq?: number\n images?: ReadonlyArray<ToolResultImageRef>\n }\n patch?: FilePatch\n executionId?: string\n backend?: ToolExecutionBackend\n logs?: string[]\n }\n | {\n kind: 'turn_result'\n id: string\n subtype: string\n isError: boolean\n durationMs: number\n totalCostUsd: number\n costUsd?: number\n errors?: string[]\n }\n | { kind: 'notice'; id: string; level: 'info' | 'error'; text: string }\n | {\n kind: 'compaction'\n id: string\n parentToolUseId: string | null\n pending?: boolean\n trigger?: 'manual' | 'auto'\n preTokens?: number\n postTokens?: number\n error?: string\n }\n | { kind: 'file_delivered'; id: string; path: string; bytes: number; description?: string }\n\nexport type ProducedFileRef = {\n fileId: string\n mediaType?: string\n bytes?: number\n}\n\nexport type TranscriptState = {\n status: SessionStatus\n statusDetail?: string\n model?: string\n cwd?: string\n sdkSessionId?: string\n engine?: ProfileEngine\n capabilities: EngineCapabilities\n session?: SessionInfo\n models?: ModelOption[]\n commands?: SlashCommandInfo[]\n skills?: SkillInfo[]\n checklist?: ChecklistItem[]\n // Only what the client cannot derive: host- and MCP-declared titles. `toolTitle()` folds the\n // built-in table in on top of this.\n toolTitles?: Record<string, string>\n // Keyed by the absolute path the runner reported: a tool card looks up the `savedPath` in its input and resolves it via `client.producedFileUrl`.\n producedFiles?: Record<string, ProducedFileRef>\n\n defaultModel?: string\n permissionMode?: PermissionMode\n contextUsage?: ContextUsage\n rateLimits?: Record<string, RateLimitInfo>\n rateLimitsUpdatedAt?: number\n subscriptionType?: string\n items: TranscriptItem[]\n pendingApprovals: PermissionRequest[]\n totalCostUsd: number\n costUsd?: number\n usageByModel?: ByModel\n lastSeq: number\n}\n\nexport const initialTranscriptState: TranscriptState = {\n status: 'starting',\n capabilities: ENGINE_CAPABILITIES.claude,\n items: [],\n pendingApprovals: [],\n totalCostUsd: 0,\n lastSeq: 0,\n}\n\nconst STREAMING_ID = 'streaming'\nconst STREAMING_THINKING_ID = 'streaming-thinking'\n\nconst LOCAL_COMMAND_OUTPUT = /^<local-command-(stdout|stderr)>([\\s\\S]*?)<\\/local-command-\\1>$/\nconst LOCAL_COMMAND_ELEMENT = /<local-command-(stdout|stderr)>([\\s\\S]*?)<\\/local-command-\\1>/g\nconst LOCAL_COMMAND_CAVEAT = '<local-command-caveat>'\n\nconst COMMAND_NAME = /<command-name>([\\s\\S]*?)<\\/command-name>/\nconst COMMAND_ARGS = /<command-args>([\\s\\S]*?)<\\/command-args>/\n// A message whose first text block is the deferred `!` flush is synthetic as a whole, but the block after it is\n// the person's own message. Only that shape earns the exemption - `<task-notification>` and the rest stay hidden.\nfunction carriesCaveat(content: ApiMessage['content']): boolean {\n return contentToBlocks(content).some(\n (block) => block.type === 'text' && (block as { text: string }).text.trimStart().startsWith(LOCAL_COMMAND_CAVEAT),\n )\n}\n\nfunction streamingTextId(parentToolUseId: string | null): string {\n return parentToolUseId == null ? STREAMING_ID : `${STREAMING_ID}:${parentToolUseId}`\n}\nfunction streamingThinkingId(parentToolUseId: string | null): string {\n return parentToolUseId == null ? STREAMING_THINKING_ID : `${STREAMING_THINKING_ID}:${parentToolUseId}`\n}\nfunction isStreamingItem(item: TranscriptItem): boolean {\n return (\n (item.kind === 'assistant_text' && item.id.startsWith(STREAMING_ID)) ||\n (item.kind === 'thinking' && item.id.startsWith(STREAMING_THINKING_ID))\n )\n}\n\nexport function blockText(content: ToolResultBlock['content']): string {\n if (content === undefined) {\n return ''\n }\n if (typeof content === 'string') {\n return content\n }\n return content\n .map((part) => (typeof part.text === 'string' ? part.text : ''))\n .filter(Boolean)\n .join('\\n')\n}\n\nfunction imageRefsOf(content: ToolResultBlock['content'], seq: number): ReadonlyArray<ToolResultImageRef> | undefined {\n if (!Array.isArray(content)) {\n return undefined\n }\n const refs = content.flatMap((part) =>\n part.type === 'image_ref'\n ? [\n {\n partIndex: Number(part.part_index),\n mediaType: String(part.media_type ?? 'application/octet-stream'),\n bytes: Number(part.bytes ?? 0),\n sourceSeq: seq,\n },\n ]\n : [],\n )\n return refs.length > 0 ? refs : undefined\n}\n\nfunction contentToBlocks(content: string | ContentBlock[]): ContentBlock[] {\n return typeof content === 'string' ? [{ type: 'text', text: content }] : content\n}\n\nfunction outputText(output: ToolExecutionOutput): string {\n if (output.type === 'text') {\n return output.value\n }\n try {\n return JSON.stringify(output.value)\n } catch {\n return String(output.value)\n }\n}\n\nfunction slashCommandText(text: string): string | undefined {\n const name = COMMAND_NAME.exec(text)?.[1]?.trim()\n if (!name) {\n return undefined\n }\n const args = COMMAND_ARGS.exec(text)?.[1]?.trim()\n return args ? `${name} ${args}` : name\n}\n\nfunction upsert(items: TranscriptItem[], item: TranscriptItem): TranscriptItem[] {\n const index = items.findIndex((existing) => existing.id === item.id && existing.kind === item.kind)\n if (index === -1) {\n return [...items, item]\n }\n const next = [...items]\n next[index] = item\n return next\n}\n\nexport function seedFromSessionInfo(state: TranscriptState, info: SessionInfo): TranscriptState {\n // No event carries the engine - the snapshot is the only source.\n const engine = info.engine ?? state.engine\n return {\n ...state,\n // With held state (reconnect, warm cache seed) the held status stands: any change since is a `status_changed` in the replay span - events stay the one authority.\n status: state.lastSeq === 0 ? info.status : state.status,\n model: state.model ?? info.model,\n permissionMode: state.permissionMode ?? info.permissionMode,\n cwd: state.cwd ?? info.cwd,\n sdkSessionId: state.sdkSessionId ?? info.sdkSessionId,\n engine,\n capabilities: info.capabilities ?? ENGINE_CAPABILITIES[engine ?? 'claude'],\n // Spend outlives the log a replay is built from: a dormant wake starts a fresh log with no `turn_result` in it,\n // so the snapshot is the only thing that still knows what the session cost before it slept.\n totalCostUsd: state.totalCostUsd || (info.totalCostUsd ?? 0),\n costUsd: state.costUsd ?? info.costUsd,\n usageByModel: state.usageByModel ?? info.usageByModel,\n session: info,\n }\n}\n\nexport function rateLimitWindows(state: TranscriptState): UsageWindowRow[] {\n return orderUsageWindows(mergeUsage({ rateLimits: state.rateLimits, updatedAt: state.rateLimitsUpdatedAt }, undefined))\n}\n\nexport function hydrateToolResult(state: TranscriptState, toolUseId: string, text: string): TranscriptState {\n let changed = false\n const items = state.items.map((item) => {\n if (item.kind !== 'tool_call' || item.id !== toolUseId || !item.result?.truncated) {\n return item\n }\n changed = true\n // `images` survives the text hydration: the refs carry their own `sourceSeq` because the result's clears here, and without them the row's pictures are unloadable.\n return {\n ...item,\n result: {\n text,\n isError: item.result.isError,\n ...(item.result.images && { images: item.result.images }),\n },\n }\n })\n return changed ? { ...state, items } : state\n}\n\nexport function applyEvent(state: TranscriptState, event: SessionEvent): TranscriptState {\n if (event.seq <= state.lastSeq) {\n return state\n }\n const base: TranscriptState = { ...state, lastSeq: event.seq }\n\n switch (event.type) {\n case 'system_init': {\n return {\n ...base,\n model: event.model,\n cwd: event.cwd,\n sdkSessionId: event.sdkSessionId,\n permissionMode: event.permissionMode,\n }\n }\n\n case 'status_changed': {\n return { ...base, status: event.status, statusDetail: event.detail }\n }\n\n case 'capabilities': {\n return {\n ...base,\n models: event.models,\n commands: event.commands,\n defaultModel: event.defaultModel ?? base.defaultModel,\n }\n }\n\n case 'skills': {\n return { ...base, skills: event.skills }\n }\n\n case 'checklist': {\n return { ...base, checklist: event.items.length > 0 ? event.items : undefined }\n }\n\n case 'tool_titles': {\n return { ...base, toolTitles: { ...base.toolTitles, ...event.titles } }\n }\n\n case 'file_produced': {\n return {\n ...base,\n producedFiles: {\n ...base.producedFiles,\n [event.path]: {\n fileId: event.fileId,\n ...(event.mediaType ? { mediaType: event.mediaType } : {}),\n ...(event.bytes !== undefined ? { bytes: event.bytes } : {}),\n },\n },\n }\n }\n\n case 'model_changed': {\n return event.model === undefined ? base : { ...base, model: event.model }\n }\n\n case 'permission_mode_changed': {\n return { ...base, permissionMode: event.mode }\n }\n\n case 'context_usage': {\n return { ...base, contextUsage: event.usage }\n }\n\n case 'rate_limit': {\n const key = event.info.rateLimitType\n if (!key) {\n return base\n }\n return {\n ...base,\n rateLimits: { ...base.rateLimits, [key]: event.info },\n rateLimitsUpdatedAt: event.ts,\n }\n }\n\n case 'plan_info': {\n return { ...base, subscriptionType: event.subscriptionType }\n }\n\n case 'conversation_reset': {\n return {\n ...base,\n items: [],\n contextUsage: undefined,\n checklist: undefined,\n sdkSessionId: event.sdkSessionId ?? base.sdkSessionId,\n }\n }\n\n // Appends where the reset above empties, and leaves `contextUsage` alone: the engine reports post-compaction occupancy itself.\n case 'context_compacted': {\n return {\n ...base,\n items: upsert(base.items, {\n kind: 'compaction',\n id: event.uuid,\n parentToolUseId: event.parentToolUseId ?? null,\n pending: event.pending,\n trigger: event.trigger,\n preTokens: event.preTokens,\n postTokens: event.postTokens,\n error: event.error,\n }),\n }\n }\n\n case 'user_message': {\n let items = base.items\n for (const block of contentToBlocks(event.message.content)) {\n if (block.type === 'tool_result') {\n const toolResult = block as ToolResultBlock\n const isError = toolResult.is_error === true\n items = items.map((item) =>\n item.kind === 'tool_call' && item.id === toolResult.tool_use_id\n ? {\n ...item,\n status: isError ? 'failed' : 'settled',\n result: {\n text: blockText(toolResult.content),\n isError,\n ...(toolResult.truncated && {\n truncated: true as const,\n totalChars: toolResult.total_chars,\n sourceSeq: event.seq,\n }),\n ...(imageRefsOf(toolResult.content, event.seq) && {\n images: imageRefsOf(toolResult.content, event.seq),\n }),\n },\n ...(event.patch && { patch: event.patch }),\n }\n : item,\n )\n } else if (block.type === 'text') {\n const text = (block as { text: string }).text\n const rowId = event.uuid ?? `user-${event.seq}`\n // Both branches sit ahead of the synthetic guard on purpose. A `!` shell run is emitted synthetic so it\n // scores zero activity and zero prose, but it is the one synthetic message a person is meant to see; and\n // on resume the SDK hands back the shell output and the user's own text as one message, which\n // `isSyntheticUserText` then marks synthetic whole. Without this the user's own words vanish on reload.\n const localOutput = LOCAL_COMMAND_OUTPUT.exec(text.trim())\n if (localOutput) {\n items = upsert(items, {\n kind: 'notice',\n id: rowId,\n level: localOutput[1] === 'stderr' ? 'error' : 'info',\n text: localOutput[2].trim(),\n })\n } else if (text.trimStart().startsWith(LOCAL_COMMAND_CAVEAT)) {\n let index = 0\n for (const match of text.matchAll(LOCAL_COMMAND_ELEMENT)) {\n items = upsert(items, {\n kind: 'notice',\n id: `${rowId}#${index++}`,\n level: match[1] === 'stderr' ? 'error' : 'info',\n text: match[2].trim(),\n })\n }\n } else if (!event.synthetic || carriesCaveat(event.message.content)) {\n items = upsert(items, {\n kind: 'user',\n id: event.uuid ?? `user-${event.seq}`,\n text: slashCommandText(text) ?? text,\n attachments: event.attachments,\n ...(event.origin && { origin: event.origin }),\n ...(event.parentToolUseId != null && {\n parentToolUseId: event.parentToolUseId,\n }),\n })\n }\n }\n }\n return { ...base, items }\n }\n\n case 'assistant_message': {\n const streamingText = streamingTextId(event.parentToolUseId)\n const streamingThought = streamingThinkingId(event.parentToolUseId)\n let streamedThinking =\n base.items.find(\n (item): item is Extract<TranscriptItem, { kind: 'thinking' }> => item.kind === 'thinking' && item.id === streamingThought,\n )?.text ?? ''\n let items = base.items.filter(\n (item) =>\n !(item.kind === 'assistant_text' && item.id === streamingText) && !(item.kind === 'thinking' && item.id === streamingThought),\n )\n const blocks = contentToBlocks(event.message.content)\n blocks.forEach((block, index) => {\n const id = `${event.uuid}-${index}`\n if (block.type === 'text') {\n items = upsert(items, {\n kind: 'assistant_text',\n id,\n text: (block as { text: string }).text,\n streaming: false,\n parentToolUseId: event.parentToolUseId,\n })\n } else if (block.type === 'thinking') {\n const text = (block as { thinking: string }).thinking || streamedThinking\n streamedThinking = ''\n if (text.trim() === '') {\n return\n }\n items = upsert(items, {\n kind: 'thinking',\n id,\n text,\n parentToolUseId: event.parentToolUseId,\n })\n } else if (block.type === 'tool_use') {\n const toolUse = block as { id: string; name: string; input: unknown }\n items = upsert(items, {\n kind: 'tool_call',\n id: toolUse.id,\n name: toolUse.name,\n input: toolUse.input,\n parentToolUseId: event.parentToolUseId,\n status: 'running',\n ts: event.ts,\n })\n }\n })\n return { ...base, items }\n }\n\n case 'stream_delta': {\n const delta = event.event as {\n type: string\n delta?: { type?: string; text?: string; thinking?: string }\n }\n if (delta.type !== 'content_block_delta') {\n return base\n }\n if (delta.delta?.type === 'text_delta') {\n const id = streamingTextId(event.parentToolUseId)\n const existing = base.items.find(\n (item): item is Extract<TranscriptItem, { kind: 'assistant_text' }> => item.kind === 'assistant_text' && item.id === id,\n )\n const item: TranscriptItem = {\n kind: 'assistant_text',\n id,\n text: (existing?.text ?? '') + (delta.delta.text ?? ''),\n streaming: true,\n parentToolUseId: event.parentToolUseId,\n }\n return { ...base, items: upsert(base.items, item) }\n }\n if (delta.delta?.type === 'thinking_delta') {\n const id = streamingThinkingId(event.parentToolUseId)\n const existing = base.items.find(\n (item): item is Extract<TranscriptItem, { kind: 'thinking' }> => item.kind === 'thinking' && item.id === id,\n )\n const text = (existing?.text ?? '') + (delta.delta.thinking ?? '')\n // Whitespace-only (encrypted) thinking creates no item - `turn_result` would finalize a permanent empty row; text rebuilds from `existing`, so skipping loses nothing.\n if (text.trim() === '') {\n return base\n }\n const item: TranscriptItem = {\n kind: 'thinking',\n id,\n text,\n parentToolUseId: event.parentToolUseId,\n }\n return { ...base, items: upsert(base.items, item) }\n }\n return base\n }\n\n case 'turn_result': {\n return {\n ...base,\n totalCostUsd: event.totalCostUsd,\n costUsd: event.costUsd ?? base.costUsd,\n usageByModel: event.usageByModel ?? base.usageByModel,\n items: [\n ...base.items.map((item) => {\n if (!isStreamingItem(item)) {\n return item\n }\n const agent = 'parentToolUseId' in item && item.parentToolUseId ? `-${item.parentToolUseId}` : ''\n return item.kind === 'assistant_text'\n ? { ...item, id: `text-${event.seq}${agent}`, streaming: false }\n : { ...item, id: `thinking-${event.seq}${agent}` }\n }),\n {\n kind: 'turn_result',\n id: `turn-${event.seq}`,\n subtype: event.subtype,\n isError: event.isError,\n durationMs: event.durationMs,\n totalCostUsd: event.totalCostUsd,\n costUsd: event.costUsd,\n errors: event.errors,\n },\n ],\n }\n }\n\n case 'permission_requested': {\n return { ...base, pendingApprovals: [...base.pendingApprovals, event.request] }\n }\n\n case 'permission_resolved': {\n return {\n ...base,\n pendingApprovals: base.pendingApprovals.filter((r) => r.id !== event.requestId),\n }\n }\n\n case 'execution_dispatched': {\n return {\n ...base,\n items: base.items.map((item) =>\n item.kind === 'tool_call' && item.id === event.executionId\n ? {\n ...item,\n status: event.deferred ? 'deferred' : 'pending',\n executionId: event.executionId,\n backend: event.backend,\n }\n : item,\n ),\n }\n }\n\n case 'execution_result': {\n return {\n ...base,\n items: base.items.map((item) =>\n item.kind === 'tool_call' && item.id === event.executionId\n ? {\n ...item,\n status: 'settled',\n executionId: event.executionId,\n result: { text: outputText(event.output), isError: false },\n logs: event.logs ?? item.logs,\n }\n : item,\n ),\n }\n }\n\n case 'execution_failed': {\n return {\n ...base,\n items: base.items.map((item) =>\n item.kind === 'tool_call' && item.id === event.executionId\n ? {\n ...item,\n status: 'failed',\n executionId: event.executionId,\n result: { text: `${event.reason}: ${event.error}`, isError: true },\n logs: event.logs ?? item.logs,\n }\n : item,\n ),\n }\n }\n\n case 'file_delivered': {\n return {\n ...base,\n items: [\n ...base.items,\n {\n kind: 'file_delivered',\n id: `file-${event.seq}`,\n path: event.path,\n bytes: event.bytes,\n description: event.description,\n },\n ],\n }\n }\n\n case 'session_error': {\n return {\n ...base,\n items: [...base.items, { kind: 'notice', id: `err-${event.seq}`, level: 'error', text: event.message }],\n }\n }\n\n case 'session_closed': {\n return {\n ...base,\n items: [\n ...base.items,\n {\n kind: 'notice',\n id: `closed-${event.seq}`,\n level: 'info',\n text: `Session closed (${event.reason})`,\n },\n ],\n }\n }\n\n case 'sdk_event':\n default: {\n return base\n }\n }\n}\n","import type { WorkerDeckClient } from '@workerdeck/client'\nimport type { TranscriptState } from './transcript.ts'\n\nconst MAX_ENTRIES = 5\n\nconst entries = new Map<string, TranscriptState>()\n\n// NUL separates unambiguously: `identityKey` is JSON.stringify output, so no two pairs spell one key.\nexport function transcriptCacheKey(client: WorkerDeckClient, sessionId: string): string {\n return `${client.identityKey}\\u0000${sessionId}`\n}\n\nexport function readTranscriptCache(key: string): TranscriptState | undefined {\n return entries.get(key)\n}\n\nexport function writeTranscriptCache(key: string, state: TranscriptState): void {\n entries.delete(key)\n entries.set(key, state)\n if (entries.size > MAX_ENTRIES) {\n const oldest = entries.keys().next().value\n if (oldest !== undefined) {\n entries.delete(oldest)\n }\n }\n}\n\nexport function deleteTranscriptCache(key: string): void {\n entries.delete(key)\n}\n\nexport function clearTranscriptCache(): void {\n entries.clear()\n}\n","import { initialTranscriptState, type TranscriptState } from './transcript.ts'\n\nexport function attachSeedToken(resyncSeq: number, key: string): string {\n return `${resyncSeq}:${key}`\n}\n\nexport type AttachInputs = {\n resyncSeq: number\n key: string\n seededFor: string\n current: TranscriptState\n cacheEnabled: boolean\n skipCache: boolean\n warm: TranscriptState | undefined\n}\n\nexport type AttachPlan = {\n held: TranscriptState\n seed: boolean\n seedToken: string\n afterSeq?: number\n}\n\nexport function planAttach(input: AttachInputs): AttachPlan {\n const seedToken = attachSeedToken(input.resyncSeq, input.key)\n const warm = input.cacheEnabled && !input.skipCache ? input.warm : undefined\n const seed = input.seededFor !== seedToken\n const held = seed ? (warm ?? initialTranscriptState) : input.current\n // `afterSeq` derives from the state held and never from a second cache read, which a racing write could move.\n return { held, seed, seedToken, ...(held.lastSeq > 0 ? { afterSeq: held.lastSeq } : {}) }\n}\n\nexport function shouldWriteParting(input: { cacheEnabled: boolean; skipCache: boolean; parting: TranscriptState }): boolean {\n return input.cacheEnabled && !input.skipCache && input.parting.lastSeq > 0 && input.parting.session !== undefined\n}\n","import { useCallback, useEffect, useMemo, useReducer, useRef, useState } from 'react'\nimport type { WorkerDeckClient, SessionHandle } from '@workerdeck/client'\nimport { DEFAULT_PRICING, PROTOCOL_VERSION, mergePricing } from '@workerdeck/protocol'\nimport type { AttachedFrame, ModelOption, PermissionMode, PricingTable, SessionEvent } from '@workerdeck/protocol'\nimport {\n applyEvent,\n blockText,\n initialTranscriptState,\n hydrateToolResult,\n seedFromSessionInfo,\n type TranscriptState,\n} from '../lib/transcript.ts'\nimport { deleteTranscriptCache, readTranscriptCache, transcriptCacheKey, writeTranscriptCache } from '../lib/transcript-cache.ts'\nimport { attachSeedToken, planAttach, shouldWriteParting } from '../lib/attach-plan.ts'\n\ntype SeedAction = { type: 'transcript_seed'; state: TranscriptState }\ntype HydrateAction = { type: 'transcript_hydrate_result'; toolUseId: string; text: string }\n\nfunction reduce(state: TranscriptState, action: SessionEvent | AttachedFrame | SeedAction | HydrateAction): TranscriptState {\n if (action.type === 'transcript_seed') {\n return action.state\n }\n if (action.type === 'transcript_hydrate_result') {\n return hydrateToolResult(state, action.toolUseId, action.text)\n }\n return action.type === 'attached' ? seedFromSessionInfo(state, action.session) : applyEvent(state, action)\n}\n\nexport type ConnectionState = 'live' | 'reconnecting' | 'offline'\n\n// Three failed attempts is ~3.5s of backoff - past a blip; the iOS client hardcodes the same threshold.\nconst OFFLINE_AFTER_ATTEMPTS = 3\n\nexport function initialReplayTarget(frame: AttachedFrame): number | undefined {\n return frame.replayingFrom === 0 && frame.session.lastSeq > 0 ? frame.session.lastSeq : undefined\n}\n\nexport function staleAttach(frame: AttachedFrame, held: TranscriptState): boolean {\n if (frame.replayingFrom === 0 || held.lastSeq === 0) {\n return false\n }\n if (frame.session.lastSeq < held.lastSeq) {\n return true\n }\n return held.session !== undefined && frame.session.createdAt !== held.session.createdAt\n}\n\nexport const REPLAY_HOLD_MAX_MS = 1500\n\nexport type UseClaudeSessionOptions = {\n onProtocolError?: (message: string) => void\n cacheTranscript?: boolean\n}\n\nexport type UseClaudeSessionResult = {\n state: TranscriptState\n connected: boolean\n connection: ConnectionState\n replaying: boolean\n protocolMismatch?: number\n // The gateway offers `!` shell mode to this principal on this session. Absent from an older gateway, so falsy by default.\n shell: boolean\n // The gateway's rate table, its own overrides merged over the bundled one, for every figure this client prices itself.\n pricing: PricingTable\n models: ModelOption[]\n effectiveModel?: string\n handle: SessionHandle | undefined\n send: (text: string, attachmentIds?: string[]) => void\n approve: (requestId: string, updatedInput?: Record<string, unknown>) => void\n deny: (requestId: string, message?: string, interrupt?: boolean) => void\n interrupt: () => void\n clearContext: () => void\n runShell: (command: string) => void\n setPermissionMode: (mode: PermissionMode) => void\n setModel: (model?: string) => void\n closeSession: () => void\n reconnectNow: () => void\n loadFullResult: (toolUseId: string) => Promise<boolean>\n}\n\nexport function useClaudeSession(\n client: WorkerDeckClient,\n sessionId: string | undefined,\n options?: UseClaudeSessionOptions,\n): UseClaudeSessionResult {\n const [state, dispatch] = useReducer(\n reduce,\n undefined,\n (): TranscriptState =>\n (options?.cacheTranscript !== false && sessionId !== undefined\n ? readTranscriptCache(transcriptCacheKey(client, sessionId))\n : undefined) ?? initialTranscriptState,\n )\n const [connection, setConnection] = useState<ConnectionState>('reconnecting')\n const [protocolMismatch, setProtocolMismatch] = useState<number | undefined>()\n const [shell, setShell] = useState(false)\n const [pricing, setPricing] = useState<PricingTable>(DEFAULT_PRICING)\n const [replayTarget, setReplayTarget] = useState<number | undefined>()\n const [resyncSeq, setResyncSeq] = useState(0)\n // Ref for the stable callbacks below; state so consumers of `handle` re-render when the socket opens or the session switches.\n const [handleState, setHandleState] = useState<SessionHandle | undefined>()\n const handleRef = useRef<SessionHandle | null>(null)\n const optionsRef = useRef(options)\n optionsRef.current = options\n const stateRef = useRef(state)\n stateRef.current = state\n const seededForRef = useRef(attachSeedToken(0, sessionId === undefined ? '' : transcriptCacheKey(client, sessionId)))\n const skipCacheRef = useRef(false)\n\n useEffect(() => {\n if (!sessionId) {\n return\n }\n const cache = optionsRef.current?.cacheTranscript !== false\n const key = transcriptCacheKey(client, sessionId)\n const plan = planAttach({\n resyncSeq,\n key,\n seededFor: seededForRef.current,\n current: stateRef.current,\n cacheEnabled: cache,\n skipCache: skipCacheRef.current,\n warm: readTranscriptCache(key),\n })\n skipCacheRef.current = false\n if (plan.seed) {\n dispatch({ type: 'transcript_seed', state: plan.held })\n seededForRef.current = plan.seedToken\n }\n const handle = client.attach(sessionId, {\n truncateResults: true,\n imageRefs: true,\n ...(plan.afterSeq === undefined ? {} : { afterSeq: plan.afterSeq }),\n })\n handleRef.current = handle\n setHandleState(handle)\n const offEvent = handle.on('event', (event: SessionEvent) => dispatch(event))\n const offAttached = handle.on('attached', (frame: AttachedFrame) => {\n if (staleAttach(frame, stateRef.current)) {\n offEvent()\n deleteTranscriptCache(key)\n skipCacheRef.current = true\n setResyncSeq((n) => n + 1)\n return\n }\n dispatch(frame)\n setReplayTarget(initialReplayTarget(frame))\n setProtocolMismatch(frame.protocolVersion === PROTOCOL_VERSION ? undefined : frame.protocolVersion)\n setShell(frame.shell === true)\n setPricing(mergePricing(frame.pricingOverrides).pricing)\n })\n const offConn = handle.on('connectionChange', (open: boolean) => setConnection(open ? 'live' : 'reconnecting'))\n const offRetry = handle.on('reconnectAttempt', (attempts: number) =>\n setConnection(attempts >= OFFLINE_AFTER_ATTEMPTS ? 'offline' : 'reconnecting'),\n )\n const offProtocolError = handle.on('protocolError', (message: string) => {\n optionsRef.current?.onProtocolError?.(message)\n })\n return () => {\n offEvent()\n offAttached()\n offConn()\n offRetry()\n offProtocolError()\n handle.detach()\n handleRef.current = null\n setHandleState(undefined)\n setConnection('reconnecting')\n setProtocolMismatch(undefined)\n setShell(false)\n setReplayTarget(undefined)\n const parting = stateRef.current\n if (shouldWriteParting({ cacheEnabled: cache, skipCache: skipCacheRef.current, parting })) {\n writeTranscriptCache(key, parting)\n }\n }\n }, [client, sessionId, resyncSeq])\n\n useEffect(() => {\n if (replayTarget === undefined) {\n return\n }\n const timer = setTimeout(() => setReplayTarget(undefined), REPLAY_HOLD_MAX_MS)\n return () => clearTimeout(timer)\n }, [replayTarget])\n useEffect(() => {\n if (replayTarget !== undefined && state.lastSeq >= replayTarget) {\n setReplayTarget(undefined)\n }\n }, [replayTarget, state.lastSeq])\n\n const models = useProfileModelFallback(client, sessionId, state)\n\n const connected = connection === 'live'\n // Derived at render, not in an effect, so the reveal lands in the same commit as the replay's final event - an effect is one visible frame late.\n const replaying = replayTarget !== undefined && state.lastSeq < replayTarget\n const reconnectNow = useCallback(() => handleRef.current?.reconnectNow(), [])\n\n const loadFullResult = useCallback(\n async (toolUseId: string): Promise<boolean> => {\n if (!sessionId) {\n return false\n }\n const item = stateRef.current.items.find((candidate) => candidate.kind === 'tool_call' && candidate.id === toolUseId)\n const result = item?.kind === 'tool_call' ? item.result : undefined\n if (!result?.truncated || result.sourceSeq === undefined) {\n return false\n }\n try {\n const full = await client.toolResult(sessionId, result.sourceSeq, toolUseId)\n dispatch({ type: 'transcript_hydrate_result', toolUseId, text: blockText(full.content) })\n return true\n } catch {\n return false\n }\n },\n [client, sessionId],\n )\n\n return useMemo(\n () => ({\n state,\n connected,\n connection,\n replaying,\n protocolMismatch,\n shell,\n pricing,\n models,\n effectiveModel: state.model ?? state.defaultModel,\n handle: handleState,\n send: (text, attachmentIds) => handleRef.current?.send(text, attachmentIds),\n approve: (requestId, updatedInput) => handleRef.current?.approve(requestId, updatedInput),\n deny: (requestId, message, interrupt) => handleRef.current?.deny(requestId, message, interrupt),\n interrupt: () => handleRef.current?.interrupt(),\n clearContext: () => handleRef.current?.clearContext(),\n runShell: (command) => handleRef.current?.runShell(command),\n setPermissionMode: (mode) => handleRef.current?.setPermissionMode(mode),\n setModel: (model) => handleRef.current?.setModel(model),\n closeSession: () => handleRef.current?.closeSession(),\n reconnectNow,\n loadFullResult,\n }),\n [state, connected, connection, replaying, protocolMismatch, shell, pricing, models, handleState, reconnectNow, loadFullResult],\n )\n}\n\nfunction useProfileModelFallback(client: WorkerDeckClient, sessionId: string | undefined, state: TranscriptState): ModelOption[] {\n const [catalog, setCatalog] = useState<ModelOption[]>([])\n const profile = state.session?.profile\n const reported = state.models\n const hasReported = !!reported?.length\n\n useEffect(() => setCatalog([]), [sessionId])\n\n useEffect(() => {\n if (!profile || hasReported) {\n return\n }\n let cancelled = false\n client\n .listProfiles()\n .then((response) => {\n if (!cancelled) {\n setCatalog(response.profiles.find((p) => p.name === profile)?.models ?? [])\n }\n })\n .catch(() => {})\n return () => {\n cancelled = true\n }\n }, [client, profile, hasReported])\n\n return hasReported ? reported : catalog\n}\n","import type { WorkerDeckClient } from '@workerdeck/client'\nimport type { ProfileUsage } from '@workerdeck/protocol'\n\n// Last known profile usage, kept outside React so a session switch does not blank it.\n//\n// Usage belongs to the *account*, not the session, but it is fetched by a hook that lives inside the per-session\n// panel - so remounting that panel used to drop the authoritative reading to `undefined` for a whole round trip,\n// leaving only the newly-attached session's own replayed (and possibly days-old) numbers to render. That is the\n// \"switching sessions resets my weekly usage to 1%, then it catches up\" report.\n//\n// Keyed by client identity + profile because a different profile is a different account's plan, never a stale view\n// of this one. Same shape and reasoning as `transcript-cache.ts` next door.\nconst entries = new Map<string, ProfileUsage>()\n\n// NUL separates unambiguously: `identityKey` is JSON.stringify output, so no two pairs spell one key.\nexport function profileUsageCacheKey(client: WorkerDeckClient, profile: string): string {\n return `${client.identityKey}\\u0000${profile}`\n}\n\nexport function readProfileUsageCache(key: string): ProfileUsage | undefined {\n return entries.get(key)\n}\n\nexport function writeProfileUsageCache(key: string, usage: ProfileUsage | undefined): void {\n if (usage === undefined) {\n return\n }\n entries.set(key, usage)\n}\n\nexport function clearProfileUsageCache(): void {\n entries.clear()\n}\n","import type { WorkerDeckClient } from '@workerdeck/client'\n\n// Unsent composer text, kept per session on the client that typed it.\n//\n// A draft is not session state: it never reaches the gateway and never syncs between clients. Two people looking at\n// one session are each mid-sentence in their own way, and a half-written prompt is not something either of them\n// asked to publish.\n//\n// It is persisted rather than merely held in memory because the two ways drafts got lost are different failures. A\n// session switch remounts the composer, which a module-scope map alone would survive; a Vite HMR reload or a VS Code\n// `dev:host` webview re-render replaces the whole document, which it would not.\nconst KEY = 'workerdeck.drafts.v1'\n\n// Drafts are a convenience, so the store stays small and drops the least recently touched first.\nconst MAX_DRAFTS = 20\n\ntype Draft = { text: string; savedAt: number }\n\nlet memory: Record<string, Draft> | undefined\n\nfunction storage(): Storage | undefined {\n try {\n // Through globalThis: this package is typechecked with no DOM lib, and a webview may deny storage outright.\n return (globalThis as { localStorage?: Storage }).localStorage\n } catch {\n return undefined\n }\n}\n\nfunction load(): Record<string, Draft> {\n if (memory) {\n return memory\n }\n memory = {}\n const raw = storage()?.getItem(KEY)\n if (raw) {\n try {\n const parsed = JSON.parse(raw) as Record<string, Draft>\n for (const [key, draft] of Object.entries(parsed)) {\n if (typeof draft?.text === 'string' && typeof draft.savedAt === 'number') {\n memory[key] = draft\n }\n }\n } catch {\n // A corrupt blob is not worth a broken composer; start over.\n }\n }\n return memory\n}\n\nfunction persist(drafts: Record<string, Draft>): void {\n const entries = Object.entries(drafts)\n if (entries.length > MAX_DRAFTS) {\n entries.sort((a, b) => b[1].savedAt - a[1].savedAt)\n for (const [key] of entries.slice(MAX_DRAFTS)) {\n delete drafts[key]\n }\n }\n try {\n storage()?.setItem(KEY, JSON.stringify(drafts))\n } catch {\n // Out of quota, or storage denied. The in-memory copy still carries the session switch.\n }\n}\n\n// NUL separates unambiguously: `identityKey` is JSON.stringify output, so no two pairs spell one key.\nexport function draftKey(client: WorkerDeckClient, sessionId: string): string {\n return `${client.identityKey}\\u0000${sessionId}`\n}\n\nexport function readDraft(key: string): string {\n return load()[key]?.text ?? ''\n}\n\nexport function writeDraft(key: string, text: string, now = Date.now()): void {\n const drafts = load()\n // An empty draft is the absence of one: keeping it would evict a real draft under the cap.\n if (text.trim() === '') {\n if (drafts[key] === undefined) {\n return\n }\n delete drafts[key]\n } else {\n drafts[key] = { text, savedAt: now }\n }\n persist(drafts)\n}\n\nexport function clearDrafts(): void {\n memory = {}\n try {\n storage()?.removeItem(KEY)\n } catch {}\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport type { WorkerDeckClient } from '@workerdeck/client'\nimport type { EngineCapabilities, ProfileEngine } from '@workerdeck/protocol'\n\nexport type StagedAttachment = {\n key: string\n name: string\n mediaType: string\n bytes: number\n previewUrl?: string\n status: 'uploading' | 'ready' | 'failed'\n id?: string\n error?: string\n}\n\nexport type AttachmentKind = 'image' | 'pdf' | 'text'\n\nconst TEXTUAL_TYPES = new Set([\n 'application/json',\n 'application/xml',\n 'application/yaml',\n 'application/x-yaml',\n 'application/toml',\n 'application/javascript',\n 'application/typescript',\n 'application/x-sh',\n 'application/sql',\n])\n\nconst MAX_IMAGE_EDGE = 1568\n\nexport function attachmentKind(mediaType: string): AttachmentKind | undefined {\n const type = mediaType.split(';')[0]!.trim().toLowerCase()\n if (type.startsWith('image/')) {\n return 'image'\n }\n if (type === 'application/pdf') {\n return 'pdf'\n }\n if (type.startsWith('text/')) {\n return 'text'\n }\n if (TEXTUAL_TYPES.has(type)) {\n return 'text'\n }\n return undefined\n}\n\nexport type UseAttachmentsOptions = {\n capabilities: EngineCapabilities\n engine?: ProfileEngine\n}\n\nexport type UseAttachmentsResult = {\n items: StagedAttachment[]\n readyIds: string[]\n uploading: boolean\n hasFailure: boolean\n accept: string\n disabled: boolean\n add: (files: Iterable<File>) => void\n retry: (key: string) => void\n remove: (key: string) => void\n clear: () => void\n error?: string\n dismissError: () => void\n}\n\nexport function useAttachments(\n client: WorkerDeckClient,\n sessionId: string | undefined,\n { capabilities, engine }: UseAttachmentsOptions,\n): UseAttachmentsResult {\n const [items, setItems] = useState<StagedAttachment[]>([])\n const [error, setError] = useState<string | undefined>()\n const counter = useRef(0)\n const fileByKey = useRef(new Map<string, File>())\n const previewUrls = useRef<string[]>([])\n previewUrls.current = items.flatMap((item) => (item.previewUrl ? [item.previewUrl] : []))\n const accepts = capabilities.attachments\n\n useEffect(\n () => () => {\n for (const url of previewUrls.current) {\n URL.revokeObjectURL(url)\n }\n },\n [],\n )\n\n const patch = useCallback((key: string, next: Partial<StagedAttachment>) => {\n setItems((current) => current.map((item) => (item.key === key ? { ...item, ...next } : item)))\n }, [])\n\n const upload = useCallback(\n (key: string, file: File) => {\n if (!sessionId) {\n return\n }\n patch(key, { status: 'uploading', error: undefined })\n void (async () => {\n try {\n const data = await prepare(file)\n const uploaded = await client.uploadAttachment(sessionId, {\n name: file.name,\n mediaType: data.mediaType,\n data: data.body,\n })\n patch(key, { status: 'ready', id: uploaded.id, bytes: uploaded.bytes ?? file.size })\n } catch (e) {\n patch(key, { status: 'failed', error: e instanceof Error ? e.message : 'Upload failed' })\n }\n })()\n },\n [client, patch, sessionId],\n )\n\n const add = useCallback(\n (files: Iterable<File>) => {\n const staged: StagedAttachment[] = []\n const pending: Array<{ key: string; file: File }> = []\n for (const file of files) {\n const mediaType = file.type || 'application/octet-stream'\n const kind = attachmentKind(mediaType)\n // An unclassifiable type still goes: the gateway's vocabulary is the authoritative one.\n if (kind && !accepts.includes(kind)) {\n setError(`The ${engine ?? 'claude'} engine does not take ${kind} attachments.`)\n continue\n }\n const key = `att-${++counter.current}`\n staged.push({\n key,\n name: file.name,\n mediaType,\n bytes: file.size,\n previewUrl: kind === 'image' ? URL.createObjectURL(file) : undefined,\n status: 'uploading',\n })\n pending.push({ key, file })\n }\n if (staged.length === 0) {\n return\n }\n setItems((current) => [...current, ...staged])\n fileByKey.current = new Map([...fileByKey.current, ...pending.map(({ key, file }) => [key, file] as const)])\n for (const { key, file } of pending) {\n upload(key, file)\n }\n },\n [accepts, engine, upload],\n )\n\n const forget = useCallback((keys: string[]) => {\n setItems((current) => {\n for (const item of current) {\n if (keys.includes(item.key) && item.previewUrl) {\n URL.revokeObjectURL(item.previewUrl)\n }\n }\n return current.filter((item) => !keys.includes(item.key))\n })\n for (const key of keys) {\n fileByKey.current.delete(key)\n }\n }, [])\n\n const remove = useCallback((key: string) => forget([key]), [forget])\n\n const clear = useCallback(() => {\n setItems((current) => {\n for (const item of current) {\n if (item.previewUrl) {\n URL.revokeObjectURL(item.previewUrl)\n }\n }\n return []\n })\n fileByKey.current.clear()\n }, [])\n\n const retry = useCallback(\n (key: string) => {\n const file = fileByKey.current.get(key)\n if (file) {\n upload(key, file)\n }\n },\n [upload],\n )\n\n return useMemo(\n () => ({\n items,\n readyIds: items.flatMap((item) => (item.id ? [item.id] : [])),\n uploading: items.some((item) => item.status === 'uploading'),\n hasFailure: items.some((item) => item.status === 'failed'),\n accept: acceptAttribute(accepts),\n disabled: accepts.length === 0 || !sessionId,\n add,\n retry,\n remove,\n clear,\n error,\n dismissError: () => setError(undefined),\n }),\n [items, accepts, sessionId, add, retry, remove, clear, error],\n )\n}\n\nfunction acceptAttribute(kinds: readonly AttachmentKind[]): string {\n if (kinds.length === 0) {\n return ''\n }\n const parts: string[] = []\n if (kinds.includes('image')) {\n parts.push('image/*')\n }\n if (kinds.includes('pdf')) {\n parts.push('application/pdf')\n }\n if (kinds.includes('text')) {\n parts.push('text/*', '.md', '.json', '.yaml', '.yml', '.toml')\n }\n // All three kinds is no narrowing at all, and an empty accept leaves the picker open.\n return kinds.length === 3 ? '' : parts.join(',')\n}\n\n// Reached through globalThis, not named directly: smoke/ typechecks this source with no DOM lib.\ntype ImageBitmapLike = { width: number; height: number; close(): void }\ntype CanvasLike = {\n width: number\n height: number\n getContext(contextId: '2d'): {\n drawImage(image: ImageBitmapLike, dx: number, dy: number, dw: number, dh: number): void\n } | null\n toBlob(callback: (blob: Blob | null) => void, type?: string, quality?: number): void\n}\nconst imaging = globalThis as unknown as {\n createImageBitmap?: (source: Blob) => Promise<ImageBitmapLike>\n document?: { createElement(tagName: 'canvas'): CanvasLike }\n}\n\nasync function prepare(file: File): Promise<{ body: Blob; mediaType: string }> {\n const mediaType = file.type || 'application/octet-stream'\n const { createImageBitmap, document } = imaging\n if (!createImageBitmap || !document || !mediaType.startsWith('image/')) {\n return { body: file, mediaType }\n }\n // A redraw of an animation would keep one frame of it.\n if (mediaType === 'image/gif') {\n return { body: file, mediaType }\n }\n try {\n const bitmap = await createImageBitmap(file)\n const longest = Math.max(bitmap.width, bitmap.height)\n if (longest <= MAX_IMAGE_EDGE) {\n bitmap.close()\n return { body: file, mediaType }\n }\n const scale = MAX_IMAGE_EDGE / longest\n const canvas = document.createElement('canvas')\n canvas.width = Math.round(bitmap.width * scale)\n canvas.height = Math.round(bitmap.height * scale)\n const context = canvas.getContext('2d')\n if (!context) {\n bitmap.close()\n return { body: file, mediaType }\n }\n context.drawImage(bitmap, 0, 0, canvas.width, canvas.height)\n bitmap.close()\n const blob = await new Promise<Blob | null>((resolve) => canvas.toBlob(resolve, 'image/jpeg', 0.85))\n return blob ? { body: blob, mediaType: 'image/jpeg' } : { body: file, mediaType }\n } catch {\n return { body: file, mediaType }\n }\n}\n","import { PEER_MENTION_SIGIL, PROMPT_SENTENCE_TAIL, isPeerMentionBody, peerMentionKey } from '@workerdeck/protocol'\n\nexport type PromptToken = {\n kind: 'file' | 'command' | 'skill' | 'session'\n start: number\n end: number\n text: string\n}\n\n// `$name` is codex's skill mention and `#Name` is another session on the gateway; in both cases only\n// a name this client knows is a token, so a dollar amount and a colour literal never badge. The\n// session list is *live*, so a mention drawn today may draw plain once that peer is renamed - the\n// characters never change, only the colour, which is why this does not break the rule that a\n// transcript must read on replay as it did live (that rule binds substituting a name for an id).\nexport type PromptTokenOptions = {\n skills?: readonly string[]\n // Folded slugs (`peerMentionKey(peerMentionSlug(title, id))`), not display titles.\n sessions?: readonly string[]\n}\n\n// No `/`, so a pasted absolute path is not a command; `:` is in for namespaced skills (`dev:wrapup`).\nconst COMMAND_BODY = /^[A-Za-z0-9\\-_.:]+$/\n\n// The same set the gateway peels with, so one boundary answers for every sigil.\nconst SENTENCE_TAIL = PROMPT_SENTENCE_TAIL\n\nexport function scanPromptTokens(text: string, options?: PromptTokenOptions): PromptToken[] {\n const tokens: PromptToken[] = []\n const skills = options?.skills?.length ? new Set(options.skills) : undefined\n const sessions = options?.sessions?.length ? new Set(options.sessions) : undefined\n const words = /\\S+/g\n let match: RegExpExecArray | null\n while ((match = words.exec(text)) !== null) {\n const word = match[0]\n const kind =\n word[0] === '@'\n ? 'file'\n : word[0] === '/'\n ? 'command'\n : word[0] === '$' && skills\n ? 'skill'\n : word[0] === PEER_MENTION_SIGIL && sessions\n ? 'session'\n : undefined\n if (!kind) {\n continue\n }\n let end = match.index + word.length\n while (end > match.index && SENTENCE_TAIL.has(text[end - 1]!)) {\n end--\n }\n const body = text.slice(match.index + 1, end)\n if (!body) {\n continue\n }\n if (kind === 'command' && !COMMAND_BODY.test(body)) {\n continue\n }\n if (kind === 'skill' && !skills!.has(body)) {\n continue\n }\n if (kind === 'session' && !(isPeerMentionBody(body) && sessions!.has(peerMentionKey(body)))) {\n continue\n }\n tokens.push({ kind, start: match.index, end, text: text.slice(match.index, end) })\n }\n return tokens\n}\n","import { useEffect, useRef, type RefObject } from 'react'\nimport { WorkerDeckError } from '@workerdeck/client'\n\n// Set in an effect, not at declaration: StrictMode remounts, and a once-initialised ref stays false.\nexport function useAliveRef(): RefObject<boolean> {\n const alive = useRef(true)\n useEffect(() => {\n alive.current = true\n return () => {\n alive.current = false\n }\n }, [])\n return alive\n}\n\nexport function isRouteUnsupported(e: unknown): boolean {\n return e instanceof WorkerDeckError && e.status === 404\n}\n","import type { HostDirEntry } from '@workerdeck/protocol'\n\nexport type HostDirState = {\n entries: HostDirEntry[]\n truncated?: boolean\n}\n\nexport type HostTreeRow = {\n entry: HostDirEntry\n depth: number\n expanded?: boolean\n loading?: boolean\n truncated?: boolean\n}\n\nexport function flattenHostTree(root: string, dirs: ReadonlyMap<string, HostDirState>, expanded: ReadonlySet<string>): HostTreeRow[] {\n const rows: HostTreeRow[] = []\n const rootState = dirs.get(root)\n if (!rootState) {\n return rows\n }\n // An explicit stack rather than recursion. Depth is bounded by how many directories the user has\n // expanded, not by tree size, so this is a small risk - but it is the user's clicks that set the\n // bound, and an expanded chain deep enough to exhaust the call stack should still just render.\n const stack: { entries: readonly HostDirEntry[]; index: number; depth: number }[] = [{ entries: rootState.entries, index: 0, depth: 0 }]\n while (stack.length > 0) {\n const frame = stack[stack.length - 1]\n const entry = frame.entries[frame.index]\n if (entry === undefined) {\n stack.pop()\n continue\n }\n frame.index += 1\n const depth = frame.depth\n if (entry.type !== 'dir') {\n rows.push({ entry, depth })\n continue\n }\n const isExpanded = expanded.has(entry.path)\n const childState = dirs.get(entry.path)\n rows.push({\n entry,\n depth,\n expanded: isExpanded,\n loading: isExpanded && !childState,\n truncated: isExpanded ? childState?.truncated : undefined,\n })\n if (isExpanded && childState) {\n stack.push({ entries: childState.entries, index: 0, depth: depth + 1 })\n }\n }\n return rows\n}\n\nexport function ancestorsWithin(root: string, path: string): string[] {\n const base = root.endsWith('/') ? root.slice(0, -1) : root\n if (path === base || !path.startsWith(`${base}/`)) {\n return []\n }\n const rest = path.slice(base.length + 1).split('/')\n const out: string[] = []\n let current = base\n for (const segment of rest.slice(0, -1)) {\n current = `${current}/${segment}`\n out.push(current)\n }\n return out\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport type { WorkerDeckClient } from '@workerdeck/client'\nimport { isRouteUnsupported, useAliveRef } from '../lib/async-guards.ts'\nimport type { HostFileMatch } from '@workerdeck/protocol'\nimport { ancestorsWithin, flattenHostTree, type HostDirState, type HostTreeRow } from '../lib/host-tree.ts'\n\nexport type UseHostFileSearchResult = {\n available: boolean\n search: (query: string, options?: { limit?: number; signal?: AbortSignal }) => Promise<HostFileMatch[]>\n}\n\nexport function useHostFileSearch(client: WorkerDeckClient, cwd: string | undefined): UseHostFileSearchResult {\n const [unsupported, setUnsupported] = useState(false)\n const lastCwd = useRef(cwd)\n useEffect(() => {\n if (lastCwd.current !== cwd) {\n lastCwd.current = cwd\n setUnsupported(false)\n }\n }, [cwd])\n\n const search = useCallback(\n async (query: string, options?: { limit?: number; signal?: AbortSignal }) => {\n if (!cwd || unsupported) {\n return []\n }\n try {\n const response = await client.findHostFiles(cwd, query, options?.limit ?? 8)\n return options?.signal?.aborted ? [] : response.matches\n } catch (e) {\n if (isRouteUnsupported(e)) {\n setUnsupported(true)\n }\n return []\n }\n },\n [client, cwd, unsupported],\n )\n\n return { available: !!cwd && !unsupported, search }\n}\n\nexport type UseHostFileRootsResult = {\n available: boolean\n canWrite: boolean\n}\n\nexport function useHostFileRoots(client: WorkerDeckClient): UseHostFileRootsResult {\n const [result, setResult] = useState<UseHostFileRootsResult>({\n available: false,\n canWrite: false,\n })\n useEffect(() => {\n let cancelled = false\n client\n .listHostRoots()\n .then((response) => {\n if (!cancelled) {\n setResult({ available: true, canWrite: response.canWrite })\n }\n })\n .catch(() => {\n if (!cancelled) {\n setResult({ available: false, canWrite: false })\n }\n })\n return () => {\n cancelled = true\n }\n }, [client])\n return result\n}\n\nexport type UseHostFileTreeResult = {\n available: boolean\n root: string | undefined\n rows: HostTreeRow[]\n loading: boolean\n error: string | undefined\n toggle: (path: string) => void\n reveal: (path: string) => void\n refresh: (path?: string) => void\n}\n\nexport function useHostFileTree(client: WorkerDeckClient, cwd: string | undefined): UseHostFileTreeResult {\n const [dirs, setDirs] = useState<Map<string, HostDirState>>(() => new Map())\n const [expanded, setExpanded] = useState<Set<string>>(() => new Set())\n const [unsupported, setUnsupported] = useState(false)\n const [error, setError] = useState<string | undefined>()\n\n const lastCwd = useRef(cwd)\n useEffect(() => {\n if (lastCwd.current === cwd) {\n return\n }\n lastCwd.current = cwd\n setDirs(new Map())\n setExpanded(new Set())\n setUnsupported(false)\n setError(undefined)\n }, [cwd])\n\n const alive = useAliveRef()\n\n const requested = useRef(new Set<string>())\n\n const list = useCallback(\n (target: string, { force = false } = {}) => {\n if (unsupported) {\n return\n }\n if (!force && requested.current.has(target)) {\n return\n }\n requested.current.add(target)\n client\n .listHostDir(target)\n .then((response) => {\n if (!alive.current) {\n return\n }\n setDirs((previous) => {\n const next = new Map(previous)\n // Keyed on the path asked for, never the canonical one answered: re-keying orphans the node that asked.\n next.set(target, { entries: response.entries, truncated: response.truncated })\n return next\n })\n })\n .catch((e: unknown) => {\n if (!alive.current) {\n return\n }\n requested.current.delete(target)\n if (isRouteUnsupported(e)) {\n setUnsupported(true)\n return\n }\n setError(e instanceof Error ? e.message : 'Could not read that directory')\n })\n },\n [client, unsupported],\n )\n\n useEffect(() => {\n if (cwd) {\n list(cwd)\n }\n }, [cwd, list])\n\n const toggle = useCallback(\n (path: string) => {\n setExpanded((previous) => {\n const next = new Set(previous)\n if (next.has(path)) {\n next.delete(path)\n } else {\n next.add(path)\n }\n return next\n })\n // Outside the updater, which React may run twice; `requested` makes this a no-op on the collapse.\n list(path)\n },\n [list],\n )\n\n const reveal = useCallback(\n (path: string) => {\n if (!cwd) {\n return\n }\n const ancestors = ancestorsWithin(cwd, path)\n if (ancestors.length === 0) {\n return\n }\n for (const dir of ancestors) {\n list(dir)\n }\n setExpanded((previous) => {\n const next = new Set(previous)\n for (const dir of ancestors) {\n next.add(dir)\n }\n return next\n })\n },\n [cwd, list],\n )\n\n const refresh = useCallback(\n (path?: string) => {\n const target = path ?? cwd\n if (!target) {\n return\n }\n setError(undefined)\n list(target, { force: true })\n },\n [cwd, list],\n )\n\n const rows = useMemo(() => (cwd ? flattenHostTree(cwd, dirs, expanded) : []), [cwd, dirs, expanded])\n\n return {\n available: !!cwd && !unsupported,\n root: cwd,\n rows,\n loading: !!cwd && !unsupported && !dirs.has(cwd) && !error,\n error,\n toggle,\n reveal,\n refresh,\n }\n}\n","import { useEffect, useMemo, useState } from 'react'\nimport type { WorkerDeckClient } from '@workerdeck/client'\nimport { peerMentionKey, peerMentionSlug, sessionLabel, type SessionInfo } from '@workerdeck/protocol'\nimport { isRouteUnsupported, useAliveRef } from '../lib/async-guards.ts'\n\nexport type PeerSessionOption = {\n id: string\n // What the composer writes after the `#`, and what the gateway folds to resolve it.\n slug: string\n label: string\n engine?: SessionInfo['engine']\n status: SessionInfo['status']\n cwd: string\n project?: string\n lastActivityAt?: number\n}\n\nexport type UsePeerSessionsResult = {\n available: boolean\n peers: PeerSessionOption[]\n // Folded slugs, for `scanPromptTokens`'s `sessions` allowlist.\n names: string[]\n}\n\nconst EMPTY: UsePeerSessionsResult = { available: false, peers: [], names: [] }\n\nconst IDLE_MS = 20_000\n\n// The other sessions this gateway will show, for the composer's `#` picker. Polled slowly on\n// purpose: a name is not a reading, and this list only has to be right when a menu opens. The\n// gateway resolves what was typed against the sender's own scope, so a stale row costs nothing\n// worse than a mention that stays plain text.\nexport function usePeerSessions(client: WorkerDeckClient, sessionId: string | undefined, enabled = true): UsePeerSessionsResult {\n const [sessions, setSessions] = useState<SessionInfo[] | undefined>(undefined)\n const [unsupported, setUnsupported] = useState(false)\n const alive = useAliveRef()\n\n useEffect(() => {\n if (!enabled || unsupported) {\n return\n }\n let timer: ReturnType<typeof setTimeout> | undefined\n const tick = () => {\n client\n .listSessions()\n .then((rows) => {\n if (!alive.current) {\n return\n }\n setSessions(rows)\n })\n .catch((e: unknown) => {\n if (alive.current && isRouteUnsupported(e)) {\n setUnsupported(true)\n }\n })\n .finally(() => {\n if (alive.current) {\n timer = setTimeout(tick, IDLE_MS)\n }\n })\n }\n tick()\n return () => {\n if (timer) {\n clearTimeout(timer)\n }\n }\n }, [client, enabled, unsupported])\n\n return useMemo(() => {\n if (!enabled || unsupported || !sessions) {\n return EMPTY\n }\n const peers = sessions\n .filter((info) => info.id !== sessionId)\n .sort((a, b) => (b.lastActivityAt ?? b.createdAt) - (a.lastActivityAt ?? a.createdAt))\n .map((info) => ({\n id: info.id,\n slug: peerMentionSlug(info.title, info.id),\n label: sessionLabel(info),\n engine: info.engine,\n status: info.status,\n cwd: info.cwd,\n project: info.project?.name,\n lastActivityAt: info.lastActivityAt,\n }))\n return { available: peers.length > 0, peers, names: peers.map((peer) => peerMentionKey(peer.slug)) }\n }, [enabled, sessionId, sessions, unsupported])\n}\n","import { useEffect, useState } from 'react'\nimport type { WorkerDeckClient } from '@workerdeck/client'\nimport type { SessionRow } from '@workerdeck/protocol'\n\nconst byHash = new Map<string, string>()\nconst inFlight = new Set<string>()\nconst failed = new Set<string>()\n\nexport type ClientForHost = (hostId: string) => WorkerDeckClient | undefined\n\nexport function useProjectIcons(rows: readonly SessionRow[], clientFor: ClientForHost): Record<string, string> {\n const [resolved, setResolved] = useState<Record<string, string>>(() => Object.fromEntries(byHash))\n\n useEffect(() => {\n let alive = true\n for (const row of rows) {\n const icon = row.info.project?.icon\n if (icon?.type !== 'image') {\n continue\n }\n const { hash } = icon\n if (byHash.has(hash) || inFlight.has(hash) || failed.has(hash)) {\n continue\n }\n const client = clientFor(row.hostId)\n // An unreachable gateway is not an iconless one: no failure recorded, so a later render retries.\n if (!client) {\n continue\n }\n inFlight.add(hash)\n void client\n .projectIcon(row.info.id)\n .then((blob) => {\n byHash.set(hash, URL.createObjectURL(blob))\n if (alive) {\n setResolved(Object.fromEntries(byHash))\n }\n })\n .catch(() => {\n failed.add(hash)\n })\n .finally(() => inFlight.delete(hash))\n }\n return () => {\n alive = false\n }\n }, [rows, clientFor])\n\n return resolved\n}\n","import { useCallback, useMemo } from 'react'\nimport type { WorkerDeckClient } from '@workerdeck/client'\nimport { draftKey, readDraft, writeDraft } from '../lib/draft-store.ts'\n\nexport type UseDraftResult = {\n // What was left unsent last time, read once so it can seed the composer on mount.\n initialText: string\n save: (text: string) => void\n clear: () => void\n}\n\n// Remember unsent composer text for a session. Purely local: it never reaches the gateway and never syncs between\n// clients, because a half-written prompt is not something anyone asked to publish.\nexport function useDraft(client: WorkerDeckClient, sessionId: string | undefined): UseDraftResult {\n const key = sessionId ? draftKey(client, sessionId) : undefined\n // Read once per key: re-reading on render would fight whatever is being typed.\n const initialText = useMemo(() => (key ? readDraft(key) : ''), [key])\n const save = useCallback(\n (text: string) => {\n if (key) {\n writeDraft(key, text)\n }\n },\n [key],\n )\n const clear = useCallback(() => {\n if (key) {\n writeDraft(key, '')\n }\n }, [key])\n return { initialText, save, clear }\n}\n","import { useCallback, useEffect, useState } from 'react'\nimport type { WorkerDeckClient } from '@workerdeck/client'\nimport { isRouteUnsupported, useAliveRef } from '../lib/async-guards.ts'\nimport { profileUsageCacheKey, readProfileUsageCache, writeProfileUsageCache } from '../lib/profile-usage-cache.ts'\nimport type { ProfileSpend, ProfileUsage } from '@workerdeck/protocol'\n\nexport type UseProfileUsageOptions = {\n intervalMs?: number\n enabled?: boolean\n}\n\nexport type UseProfileUsageResult = {\n usage: ProfileUsage | undefined\n spend: ProfileSpend | undefined\n refresh: () => void\n}\n\nexport function useProfileUsage(\n client: WorkerDeckClient,\n profile: string | undefined,\n options: UseProfileUsageOptions = {},\n): UseProfileUsageResult {\n const { intervalMs = 60_000, enabled = true } = options\n const cacheKey = profile ? profileUsageCacheKey(client, profile) : undefined\n const [usage, setUsage] = useState<ProfileUsage | undefined>(() => (cacheKey ? readProfileUsageCache(cacheKey) : undefined))\n const [spend, setSpend] = useState<ProfileSpend | undefined>(undefined)\n const [unsupported, setUnsupported] = useState(false)\n const [nonce, setNonce] = useState(0)\n const refresh = useCallback(() => setNonce((n) => n + 1), [])\n\n // A previous profile's reading is another account's plan, not a stale view of this one - so switch to what we last\n // knew about *this* profile rather than to nothing. Blanking here is what made a session switch fall back on the\n // newly-attached session's own replayed numbers, which is the usage-reverts report.\n useEffect(() => {\n setUsage(cacheKey ? readProfileUsageCache(cacheKey) : undefined)\n setSpend(undefined)\n }, [cacheKey])\n\n const alive = useAliveRef()\n\n useEffect(() => {\n if (!profile || !enabled || unsupported) {\n return\n }\n let cancelled = false\n const load = () => {\n // `document` through globalThis: the extras project typechecks this source with no DOM lib.\n if ((globalThis as { document?: { hidden?: boolean } }).document?.hidden) {\n return\n }\n client\n .listProfiles()\n .then((res) => {\n if (cancelled || !alive.current) {\n return\n }\n const found = res.profiles.find((p) => p.name === profile)\n const next = found?.usage\n if (cacheKey) {\n writeProfileUsageCache(cacheKey, next)\n }\n setUsage(next)\n setSpend(found?.spend)\n })\n .catch((e: unknown) => {\n if (cancelled || !alive.current) {\n return\n }\n if (isRouteUnsupported(e)) {\n setUnsupported(true)\n }\n })\n }\n load()\n const timer = setInterval(load, intervalMs)\n return () => {\n cancelled = true\n clearInterval(timer)\n }\n }, [client, profile, enabled, unsupported, intervalMs, nonce, cacheKey])\n\n return { usage, spend, refresh }\n}\n","import { useEffect, useState } from 'react'\nimport type { WorkerDeckClient } from '@workerdeck/client'\nimport type { SessionInfo } from '@workerdeck/protocol'\n\nexport type UseSessionInfoResult = {\n info: SessionInfo | undefined\n loading: boolean\n error: string | undefined\n}\n\nexport function useSessionInfo(client: WorkerDeckClient, sessionId: string | undefined): UseSessionInfoResult {\n const [info, setInfo] = useState<SessionInfo | undefined>()\n const [loading, setLoading] = useState(!!sessionId)\n const [error, setError] = useState<string | undefined>()\n\n useEffect(() => {\n if (!sessionId) {\n setInfo(undefined)\n setLoading(false)\n setError(undefined)\n return\n }\n let cancelled = false\n setLoading(true)\n setError(undefined)\n setInfo(undefined)\n client\n .getSession(sessionId)\n .then((next) => {\n if (cancelled) {\n return\n }\n setInfo(next)\n setLoading(false)\n })\n .catch((e: unknown) => {\n if (cancelled) {\n return\n }\n setError(e instanceof Error ? e.message : 'Session not found')\n setLoading(false)\n })\n return () => {\n cancelled = true\n }\n }, [client, sessionId])\n\n return { info, loading, error }\n}\n","export type OpenFile = {\n path: string\n name: string\n status: 'loading' | 'ready' | 'binary' | 'error'\n content?: string\n draft?: string\n bytes?: number\n hash?: string\n modifiedAt?: number\n error?: string\n saving?: boolean\n saveError?: string\n conflict?: boolean\n}\n\nexport function isDirty(file: OpenFile): boolean {\n return file.draft !== undefined && file.draft !== file.content\n}\n\nexport function currentText(file: OpenFile): string {\n return file.draft ?? file.content ?? ''\n}\n\nexport type OpenFilesState = {\n files: OpenFile[]\n activePath?: string\n}\n\nexport type OpenFilesAction =\n | { type: 'open'; path: string }\n | { type: 'close'; path: string }\n | { type: 'closeAll' }\n | { type: 'activate'; path: string }\n | {\n type: 'loaded'\n path: string\n content: string\n encoding: 'utf8' | 'base64'\n bytes: number\n hash: string\n modifiedAt: number\n }\n | { type: 'failed'; path: string; error: string }\n | { type: 'edit'; path: string; content: string }\n | { type: 'revert'; path: string }\n | { type: 'saveStart'; path: string }\n | { type: 'saved'; path: string; content: string; bytes: number; hash: string; modifiedAt: number }\n | { type: 'saveFailed'; path: string; error: string; conflict?: boolean }\n | { type: 'dismissConflict'; path: string }\n\nexport const initialOpenFilesState: OpenFilesState = { files: [] }\n\nexport function openFilesReducer(state: OpenFilesState, action: OpenFilesAction): OpenFilesState {\n switch (action.type) {\n case 'open': {\n if (state.files.some((f) => f.path === action.path)) {\n return state.activePath === action.path ? state : { ...state, activePath: action.path }\n }\n const file: OpenFile = { path: action.path, name: baseName(action.path), status: 'loading' }\n return { files: [...state.files, file], activePath: action.path }\n }\n\n case 'close': {\n const index = state.files.findIndex((f) => f.path === action.path)\n if (index === -1) {\n return state\n }\n const files = state.files.filter((f) => f.path !== action.path)\n if (state.activePath !== action.path) {\n return { ...state, files }\n }\n // The right-hand neighbour has slid into this index; a closed last tab has nothing there.\n const next = files[index] ?? files[index - 1]\n return { files, activePath: next?.path }\n }\n\n case 'closeAll': {\n return initialOpenFilesState\n }\n\n case 'activate': {\n if (!state.files.some((f) => f.path === action.path)) {\n return state\n }\n return state.activePath === action.path ? state : { ...state, activePath: action.path }\n }\n\n case 'loaded': {\n return patch(state, action.path, () => ({\n path: action.path,\n name: baseName(action.path),\n status: action.encoding === 'utf8' ? 'ready' : 'binary',\n content: action.encoding === 'utf8' ? action.content : undefined,\n bytes: action.bytes,\n hash: action.hash,\n modifiedAt: action.modifiedAt,\n }))\n }\n\n case 'failed': {\n return patch(state, action.path, (file) => ({ ...file, status: 'error', error: action.error }))\n }\n\n case 'edit': {\n return patch(state, action.path, (file) => (file.status === 'ready' ? { ...file, draft: action.content } : file))\n }\n\n case 'revert': {\n return patch(state, action.path, (file) => ({\n ...file,\n draft: undefined,\n saveError: undefined,\n conflict: false,\n }))\n }\n\n case 'saveStart': {\n return patch(state, action.path, (file) => ({\n ...file,\n saving: true,\n saveError: undefined,\n conflict: false,\n }))\n }\n\n case 'saved': {\n return patch(state, action.path, (file) => ({\n ...file,\n saving: false,\n saveError: undefined,\n conflict: false,\n content: action.content,\n bytes: action.bytes,\n hash: action.hash,\n modifiedAt: action.modifiedAt,\n draft: file.draft === action.content ? undefined : file.draft,\n }))\n }\n\n case 'saveFailed': {\n return patch(state, action.path, (file) => ({\n ...file,\n saving: false,\n saveError: action.error,\n conflict: action.conflict ?? false,\n }))\n }\n\n case 'dismissConflict': {\n return patch(state, action.path, (file) => ({\n ...file,\n conflict: false,\n saveError: undefined,\n }))\n }\n }\n}\n\nfunction patch(state: OpenFilesState, path: string, next: (file: OpenFile) => OpenFile): OpenFilesState {\n const index = state.files.findIndex((f) => f.path === path)\n if (index === -1) {\n return state\n }\n const current = state.files[index]!\n const updated = next(current)\n if (updated === current) {\n return state\n }\n const files = state.files.slice()\n files[index] = updated\n return { ...state, files }\n}\n\nfunction baseName(path: string): string {\n const trimmed = path.endsWith('/') ? path.slice(0, -1) : path\n return trimmed.slice(trimmed.lastIndexOf('/') + 1) || trimmed || path\n}\n","import { useCallback, useEffect, useMemo, useReducer, useRef } from 'react'\nimport { WorkerDeckError, type WorkerDeckClient } from '@workerdeck/client'\nimport { currentText, initialOpenFilesState, isDirty, openFilesReducer, type OpenFile, type OpenFilesState } from '../lib/open-files.ts'\n\nexport type UseOpenFilesResult = OpenFilesState & {\n active: OpenFile | undefined\n hasUnsaved: boolean\n open: (path: string) => void\n close: (path: string) => void\n closeAll: () => void\n activate: (path: string) => void\n edit: (path: string, content: string) => void\n save: (path: string) => Promise<void>\n revert: (path: string) => void\n reload: (path: string) => void\n overwrite: (path: string) => Promise<void>\n dismissConflict: (path: string) => void\n}\n\nexport function useOpenFiles(client: WorkerDeckClient): UseOpenFilesResult {\n const [state, dispatch] = useReducer(openFilesReducer, initialOpenFilesState)\n\n const requested = useRef(new Set<string>())\n const alive = useRef(true)\n useEffect(() => {\n alive.current = true\n return () => {\n alive.current = false\n }\n }, [])\n\n const latest = useRef(state)\n useEffect(() => {\n latest.current = state\n }, [state])\n\n const loading = state.files.filter((f) => f.status === 'loading')\n // Joined so the effect's identity is the set of pending reads, not the array the reducer rebuilds.\n const pending = loading.map((f) => f.path).join('\\n')\n\n const read = useCallback(\n (path: string) =>\n client.readHostFile(path).then((response) => {\n if (!alive.current) {\n return undefined\n }\n dispatch({\n type: 'loaded',\n // The tab is keyed on the path asked for, never the canonical one the gateway answers with.\n path,\n content: response.content,\n encoding: response.encoding,\n bytes: response.bytes,\n hash: response.hash,\n modifiedAt: response.modifiedAt,\n })\n return response\n }),\n [client],\n )\n\n useEffect(() => {\n for (const path of pending ? pending.split('\\n') : []) {\n if (requested.current.has(path)) {\n continue\n }\n requested.current.add(path)\n read(path).catch((e: unknown) => {\n if (!alive.current) {\n return\n }\n dispatch({\n type: 'failed',\n path,\n error: e instanceof Error ? e.message : 'Could not read that file',\n })\n })\n }\n }, [read, pending])\n\n const open = useCallback((path: string) => dispatch({ type: 'open', path }), [])\n const close = useCallback((path: string) => {\n requested.current.delete(path)\n dispatch({ type: 'close', path })\n }, [])\n const closeAll = useCallback(() => {\n requested.current.clear()\n dispatch({ type: 'closeAll' })\n }, [])\n const activate = useCallback((path: string) => dispatch({ type: 'activate', path }), [])\n const edit = useCallback((path: string, content: string) => dispatch({ type: 'edit', path, content }), [])\n const revert = useCallback((path: string) => dispatch({ type: 'revert', path }), [])\n const dismissConflict = useCallback((path: string) => dispatch({ type: 'dismissConflict', path }), [])\n\n const reload = useCallback(\n (path: string) => {\n requested.current.add(path)\n read(path).catch((e: unknown) => {\n if (!alive.current) {\n return\n }\n dispatch({\n type: 'failed',\n path,\n error: e instanceof Error ? e.message : 'Could not re-read that file',\n })\n })\n },\n [read],\n )\n\n const write = useCallback(\n async (path: string, text: string, expectedHash: string | undefined) => {\n try {\n const response = await client.writeHostFile({ path, content: text, expectedHash })\n if (!alive.current) {\n return\n }\n dispatch({\n type: 'saved',\n path,\n content: text,\n bytes: response.bytes,\n hash: response.hash,\n modifiedAt: response.modifiedAt,\n })\n } catch (e) {\n if (!alive.current) {\n return\n }\n const conflict = e instanceof WorkerDeckError && e.status === 409\n dispatch({\n type: 'saveFailed',\n path,\n conflict,\n error: conflict ? 'This file changed on disk since you opened it.' : e instanceof Error ? e.message : 'Could not save that file',\n })\n }\n },\n [client],\n )\n\n const save = useCallback(\n async (path: string) => {\n const file = latest.current.files.find((f) => f.path === path)\n if (!file || file.saving || !isDirty(file)) {\n return\n }\n dispatch({ type: 'saveStart', path })\n await write(path, currentText(file), file.hash)\n },\n [write],\n )\n\n const overwrite = useCallback(\n async (path: string) => {\n const file = latest.current.files.find((f) => f.path === path)\n if (!file || file.saving) {\n return\n }\n // Captured before the re-read, whose `loaded` clears the draft - the one thing \"take mine\" must not do.\n const mine = currentText(file)\n dispatch({ type: 'saveStart', path })\n try {\n const fresh = await client.readHostFile(path)\n if (!alive.current) {\n return\n }\n await write(path, mine, fresh.hash)\n } catch (e) {\n if (!alive.current) {\n return\n }\n dispatch({\n type: 'saveFailed',\n path,\n error: e instanceof Error ? e.message : 'Could not save that file',\n })\n }\n },\n [client, write],\n )\n\n const active = useMemo(() => state.files.find((f) => f.path === state.activePath), [state.files, state.activePath])\n const hasUnsaved = useMemo(() => state.files.some(isDirty), [state.files])\n\n return {\n ...state,\n active,\n hasUnsaved,\n open,\n close,\n closeAll,\n activate,\n edit,\n save,\n revert,\n reload,\n overwrite,\n dismissConflict,\n }\n}\n","import type { SessionHandle } from '@workerdeck/client'\nimport type { RunScriptResult, SandboxEngine, SandboxVfs } from '@workerdeck/sandbox'\nimport type { ToolCallRequestFrame } from '@workerdeck/protocol'\n\nexport type ToolHostExecution = {\n executionId: string\n toolName: string\n status: 'running' | 'settled' | 'failed' | 'canceled'\n reason?: string\n startedAt: number\n endedAt?: number\n}\n\nexport type ToolHostRunner = (request: {\n script: string\n vfs: SandboxVfs\n timeoutMs: number\n memoryLimitBytes: number\n signal: AbortSignal\n}) => Promise<RunScriptResult>\n\nexport type ClientToolResult = { value: unknown } | { error: string; reason?: string }\n\nexport type ClientToolHandler = (\n input: unknown,\n context: { executionId: string; signal: AbortSignal },\n) => ClientToolResult | Promise<ClientToolResult>\n\nexport type ToolCallHostOptions = {\n tools?: string[]\n clientTools?: Record<string, ClientToolHandler>\n timeoutMs?: number\n memoryLimitBytes?: number\n loadEngine?: () => Promise<SandboxEngine>\n // The guest deadline preempts the interpreter only on the thread it runs on; a Web Worker is the way off this one.\n execute?: ToolHostRunner\n fetchText?: (url: string) => Promise<string>\n onExecution?: (execution: ToolHostExecution) => void\n}\n\nexport function createToolCallHost(handle: SessionHandle, options: ToolCallHostOptions = {}): { dispose: () => void } {\n const inFlight = new Map<string, AbortController>()\n let enginePromise: Promise<SandboxEngine> | undefined\n let disposed = false\n\n const track = (execution: ToolHostExecution) => options.onExecution?.(execution)\n\n const refuse = (frame: ToolCallRequestFrame, reason: string, error: string, startedAt: number) => {\n handle.sendToolCallError(frame.executionId, reason, error)\n track({\n executionId: frame.executionId,\n toolName: frame.toolName,\n status: 'failed',\n reason,\n startedAt,\n endedAt: Date.now(),\n })\n }\n\n const runClientTool = async (frame: ToolCallRequestFrame, handler: ClientToolHandler): Promise<void> => {\n const startedAt = Date.now()\n const controller = new AbortController()\n inFlight.set(frame.executionId, controller)\n track({ executionId: frame.executionId, toolName: frame.toolName, status: 'running', startedAt })\n\n try {\n const result = await handler(frame.input, {\n executionId: frame.executionId,\n signal: controller.signal,\n })\n if (disposed || !inFlight.has(frame.executionId)) {\n return\n }\n if ('error' in result) {\n handle.sendToolCallError(frame.executionId, result.reason ?? 'client_error', result.error)\n track({\n executionId: frame.executionId,\n toolName: frame.toolName,\n status: 'failed',\n reason: result.reason ?? 'client_error',\n startedAt,\n endedAt: Date.now(),\n })\n } else {\n handle.sendToolCallResult(frame.executionId, { type: 'json', value: result.value })\n track({\n executionId: frame.executionId,\n toolName: frame.toolName,\n status: 'settled',\n startedAt,\n endedAt: Date.now(),\n })\n }\n } catch (error) {\n if (disposed || !inFlight.has(frame.executionId)) {\n return\n }\n refuse(frame, 'host_error', error instanceof Error ? error.message : String(error), startedAt)\n } finally {\n inFlight.delete(frame.executionId)\n }\n }\n\n const run = async (frame: ToolCallRequestFrame): Promise<void> => {\n const startedAt = Date.now()\n const clientHandler = options.clientTools?.[frame.toolName]\n if (clientHandler) {\n return runClientTool(frame, clientHandler)\n }\n const allowed = options.tools ?? ['eval_script']\n if (!allowed.includes(frame.toolName)) {\n refuse(frame, 'unsupported_tool', `this client does not execute '${frame.toolName}'`, startedAt)\n return\n }\n const script = (frame.input as { script?: unknown } | undefined)?.script\n if (typeof script !== 'string') {\n refuse(frame, 'invalid_input', 'expected a string `script` input', startedAt)\n return\n }\n\n const controller = new AbortController()\n inFlight.set(frame.executionId, controller)\n track({ executionId: frame.executionId, toolName: frame.toolName, status: 'running', startedAt })\n\n try {\n const sandbox = await import('@workerdeck/sandbox')\n const vfs = sandbox.createVfs(frame.vfsSeed)\n // Never above what the server asked for: it owns the deadline it gives up at.\n const timeoutMs = Math.min(frame.limits?.timeoutMs ?? Number.POSITIVE_INFINITY, options.timeoutMs ?? 5000)\n const memoryLimitBytes = Math.min(\n frame.limits?.memoryLimitBytes ?? Number.POSITIVE_INFINITY,\n options.memoryLimitBytes ?? 64 * 1024 * 1024,\n )\n\n const result = options.execute\n ? await options.execute({ script, vfs, timeoutMs, memoryLimitBytes, signal: controller.signal })\n : await (async () => {\n enginePromise ??= (options.loadEngine ?? defaultLoadEngine)()\n return sandbox.runScript(await enginePromise, {\n script,\n vfs,\n timeoutMs,\n memoryLimitBytes,\n signal: controller.signal,\n fetchText: options.fetchText,\n })\n })()\n\n if (disposed || !inFlight.has(frame.executionId)) {\n return\n }\n const logs = result.logs.map((l) => `[${l.level}] ${l.text}`)\n if (result.ok) {\n handle.sendToolCallResult(frame.executionId, { type: 'json', value: result.value }, logs)\n track({\n executionId: frame.executionId,\n toolName: frame.toolName,\n status: 'settled',\n startedAt,\n endedAt: Date.now(),\n })\n } else {\n handle.sendToolCallError(frame.executionId, result.reason, result.error, logs)\n track({\n executionId: frame.executionId,\n toolName: frame.toolName,\n status: 'failed',\n reason: result.reason,\n startedAt,\n endedAt: Date.now(),\n })\n }\n } catch (error) {\n if (disposed || !inFlight.has(frame.executionId)) {\n return\n }\n refuse(frame, 'host_error', error instanceof Error ? error.message : String(error), startedAt)\n } finally {\n inFlight.delete(frame.executionId)\n }\n }\n\n const offRequest = handle.on('toolCallRequest', (frame) => void run(frame))\n const offCancel = handle.on('toolCallCanceled', ({ executionId, reason }) => {\n const controller = inFlight.get(executionId)\n if (!controller) {\n return\n }\n controller.abort()\n inFlight.delete(executionId)\n track({\n executionId,\n toolName: '',\n status: 'canceled',\n reason,\n startedAt: Date.now(),\n endedAt: Date.now(),\n })\n })\n\n return {\n dispose: () => {\n disposed = true\n offRequest()\n offCancel()\n for (const controller of inFlight.values()) {\n controller.abort()\n }\n inFlight.clear()\n },\n }\n}\n\nasync function defaultLoadEngine(): Promise<SandboxEngine> {\n const [sandbox, variant] = await Promise.all([import('@workerdeck/sandbox'), import('@jitl/quickjs-singlefile-browser-release-asyncify')])\n return sandbox.loadEngine(variant as never)\n}\n","import { useEffect, useRef, useState } from 'react'\nimport type { SessionHandle } from '@workerdeck/client'\nimport { createToolCallHost, type ToolCallHostOptions, type ToolHostExecution } from '../lib/tool-host.ts'\n\nexport type UseToolCallHostOptions = ToolCallHostOptions & {\n enabled?: boolean\n historyLimit?: number\n}\n\nexport function useToolCallHost(\n handle: SessionHandle | undefined,\n options: UseToolCallHostOptions = {},\n): { executions: ToolHostExecution[] } {\n const [executions, setExecutions] = useState<ToolHostExecution[]>([])\n const optionsRef = useRef(options)\n optionsRef.current = options\n\n useEffect(() => {\n if (!handle || options.enabled === false) {\n return\n }\n const host = createToolCallHost(handle, {\n // Getters read the ref at call time, so inline objects and closures never resubscribe.\n get tools() {\n const base = optionsRef.current.tools\n const client = optionsRef.current.clientTools\n if (!client) {\n return base\n }\n const clientNames = Object.keys(client)\n return base ? [...new Set([...base, ...clientNames])] : clientNames\n },\n get clientTools() {\n return optionsRef.current.clientTools\n },\n get timeoutMs() {\n return optionsRef.current.timeoutMs\n },\n get memoryLimitBytes() {\n return optionsRef.current.memoryLimitBytes\n },\n get loadEngine() {\n return optionsRef.current.loadEngine\n },\n get execute() {\n return optionsRef.current.execute\n },\n get fetchText() {\n return optionsRef.current.fetchText\n },\n onExecution: (execution) => {\n optionsRef.current.onExecution?.(execution)\n const limit = optionsRef.current.historyLimit ?? 50\n setExecutions((prev) => [...prev.filter((e) => e.executionId !== execution.executionId), execution].slice(-limit))\n },\n })\n return () => host.dispose()\n }, [handle, options.enabled])\n\n return { executions }\n}\n","import type { TranscriptItem } from './transcript.ts'\n\nexport type RecapSummary = {\n turns: number\n replies: number\n tools: number\n toolNames: string[]\n files: number\n errors: number\n pending: number\n any: boolean\n}\n\nexport type RecapInput = {\n items: readonly TranscriptItem[]\n pendingApprovals?: readonly unknown[]\n}\n\n// The boundary is clamped, never rejected: a transcript can shrink (a `/clear`, a compaction).\nexport function summarizeSince(state: RecapInput, fromIndex: number): RecapSummary {\n const start = Math.max(0, Math.min(fromIndex, state.items.length))\n const fresh = state.items.slice(start)\n const toolCounts = new Map<string, number>()\n let turns = 0\n let replies = 0\n let tools = 0\n let files = 0\n let errors = 0\n\n for (const item of fresh) {\n switch (item.kind) {\n case 'turn_result': {\n turns += 1\n if (item.isError) {\n errors += 1\n }\n break\n }\n case 'assistant_text': {\n replies += 1\n break\n }\n case 'tool_call': {\n tools += 1\n toolCounts.set(item.name, (toolCounts.get(item.name) ?? 0) + 1)\n if (item.status === 'failed' || item.result?.isError) {\n errors += 1\n }\n break\n }\n case 'file_delivered': {\n files += 1\n break\n }\n case 'notice': {\n if (item.level === 'error') {\n errors += 1\n }\n break\n }\n default: {\n break\n }\n }\n }\n\n const toolNames = [...toolCounts.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).map(([name]) => name)\n const pending = state.pendingApprovals?.length ?? 0\n return {\n turns,\n replies,\n tools,\n toolNames,\n files,\n errors,\n pending,\n any: turns + replies + tools + files + errors + pending > 0,\n }\n}\n\nexport function recapLine(summary: RecapSummary): string | undefined {\n if (!summary.any) {\n return undefined\n }\n const parts: string[] = []\n if (summary.turns > 0) {\n parts.push(plural(summary.turns, 'turn'))\n } else if (summary.replies > 0) {\n parts.push(plural(summary.replies, 'reply', 'replies'))\n }\n if (summary.tools > 0) {\n const named = summary.toolNames.slice(0, 3).join(', ')\n const rest = summary.toolNames.length - 3\n parts.push(`${plural(summary.tools, 'tool call')}${named ? ` (${named}${rest > 0 ? `, +${rest}` : ''})` : ''}`)\n }\n if (summary.files > 0) {\n parts.push(plural(summary.files, 'file'))\n }\n if (summary.errors > 0) {\n parts.push(plural(summary.errors, 'error'))\n }\n if (summary.pending > 0) {\n parts.push(`${plural(summary.pending, 'approval')} waiting`)\n }\n return parts.join(' · ')\n}\n\nfunction plural(count: number, one: string, many = `${one}s`): string {\n return `${count} ${count === 1 ? one : many}`\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["entries"],"sources":["../src/lib/transcript.ts","../src/lib/transcript-cache.ts","../src/lib/attach-plan.ts","../src/hooks/use-session.ts","../src/lib/profile-usage-cache.ts","../src/lib/draft-store.ts","../src/hooks/use-attachments.ts","../src/lib/prompt-tokens.ts","../src/lib/async-guards.ts","../src/lib/host-tree.ts","../src/hooks/use-host-files.ts","../src/hooks/use-peer-sessions.ts","../src/hooks/use-project-icons.ts","../src/hooks/use-draft.ts","../src/hooks/use-profile-usage.ts","../src/hooks/use-session-info.ts","../src/lib/open-files.ts","../src/hooks/use-open-files.ts","../src/lib/tool-host.ts","../src/hooks/use-tool-host.ts","../src/lib/recap.ts","../src/hooks/use-shell-terminal.ts"],"sourcesContent":["import { ENGINE_CAPABILITIES, mergeUsage, orderUsageWindows } from '@workerdeck/protocol'\nimport type {\n ApiMessage,\n ByModel,\n ChecklistItem,\n ContentBlock,\n ContextUsage,\n EngineCapabilities,\n FilePatch,\n MessageAttachment,\n MessageOrigin,\n ModelOption,\n PermissionMode,\n PermissionRequest,\n ProfileEngine,\n RateLimitInfo,\n SessionEvent,\n SessionInfo,\n SessionStatus,\n ShellInfo,\n SkillInfo,\n SlashCommandInfo,\n ToolExecutionBackend,\n ToolExecutionOutput,\n ToolResultBlock,\n UsageWindowRow,\n} from '@workerdeck/protocol'\n\nexport type ToolResultImageRef = { partIndex: number; mediaType: string; bytes: number; sourceSeq: number }\n\nexport type TranscriptItem =\n | {\n kind: 'user'\n id: string\n text: string\n attachments?: MessageAttachment[]\n origin?: MessageOrigin\n // Optional, not `string | null` like the other kinds: there forgetting to stamp it must not typecheck; here almost every prompt has no parent.\n parentToolUseId?: string\n }\n | {\n kind: 'assistant_text'\n id: string\n text: string\n streaming: boolean\n parentToolUseId: string | null\n }\n | { kind: 'thinking'; id: string; text: string; parentToolUseId: string | null }\n | {\n kind: 'tool_call'\n id: string\n name: string\n input: unknown\n parentToolUseId: string | null\n // The event's own `ts`, never a receive time - replay-stable, stamped at creation only; absent reads as \"no elapsed\", never as the epoch.\n ts?: number\n status: 'running' | 'pending' | 'deferred' | 'settled' | 'failed'\n result?: {\n text: string\n isError: boolean\n truncated?: boolean\n totalChars?: number\n sourceSeq?: number\n images?: ReadonlyArray<ToolResultImageRef>\n }\n patch?: FilePatch\n executionId?: string\n backend?: ToolExecutionBackend\n logs?: string[]\n }\n | {\n kind: 'turn_result'\n id: string\n subtype: string\n isError: boolean\n durationMs: number\n totalCostUsd: number\n costUsd?: number\n errors?: string[]\n }\n | { kind: 'notice'; id: string; level: 'info' | 'error'; text: string }\n | {\n kind: 'compaction'\n id: string\n parentToolUseId: string | null\n pending?: boolean\n trigger?: 'manual' | 'auto'\n preTokens?: number\n postTokens?: number\n error?: string\n }\n | { kind: 'file_delivered'; id: string; path: string; bytes: number; description?: string }\n | {\n kind: 'shell'\n id: string\n shell: ShellInfo\n text: string\n truncated: boolean\n expanded?: string\n // The record is gone from the gateway: swept past its TTL, or minted by a gateway this client is not talking to.\n missing?: boolean\n }\n\nexport type ProducedFileRef = {\n fileId: string\n mediaType?: string\n bytes?: number\n}\n\nexport type TranscriptState = {\n status: SessionStatus\n statusDetail?: string\n model?: string\n cwd?: string\n sdkSessionId?: string\n engine?: ProfileEngine\n capabilities: EngineCapabilities\n session?: SessionInfo\n models?: ModelOption[]\n commands?: SlashCommandInfo[]\n skills?: SkillInfo[]\n checklist?: ChecklistItem[]\n // Only what the client cannot derive: host- and MCP-declared titles. `toolTitle()` folds the\n // built-in table in on top of this.\n toolTitles?: Record<string, string>\n // Keyed by the absolute path the runner reported: a tool card looks up the `savedPath` in its input and resolves it via `client.producedFileUrl`.\n producedFiles?: Record<string, ProducedFileRef>\n\n defaultModel?: string\n permissionMode?: PermissionMode\n contextUsage?: ContextUsage\n rateLimits?: Record<string, RateLimitInfo>\n rateLimitsUpdatedAt?: number\n subscriptionType?: string\n items: TranscriptItem[]\n pendingApprovals: PermissionRequest[]\n totalCostUsd: number\n costUsd?: number\n usageByModel?: ByModel\n lastSeq: number\n}\n\nexport const initialTranscriptState: TranscriptState = {\n status: 'starting',\n capabilities: ENGINE_CAPABILITIES.claude,\n items: [],\n pendingApprovals: [],\n totalCostUsd: 0,\n lastSeq: 0,\n}\n\nconst STREAMING_ID = 'streaming'\nconst STREAMING_THINKING_ID = 'streaming-thinking'\n\nconst LOCAL_COMMAND_OUTPUT = /^<local-command-(stdout|stderr)>([\\s\\S]*?)<\\/local-command-\\1>$/\nconst LOCAL_COMMAND_ELEMENT = /<local-command-(stdout|stderr)>([\\s\\S]*?)<\\/local-command-\\1>/g\nconst LOCAL_COMMAND_CAVEAT = '<local-command-caveat>'\n\nconst SHELL_MORE_OUTPUT = /^\\[\\.\\.\\. more output \\.\\.\\.\\]$/\nconst SHELL_END_LINE = /^\\[(exit -?\\d+|killed|timed out|ended|failed to start)[^\\]]*\\]$/\n\nexport type ShellItem = Extract<TranscriptItem, { kind: 'shell' }>\n\n// The row's text is core's `shellInlineText`: one framed element whose first line is the command and whose\n// last is the end line, both of which the row draws from the record instead.\nexport function shellRowText(shell: ShellInfo, text: string): { text: string; truncated: boolean } {\n const body = LOCAL_COMMAND_OUTPUT.exec(text.trim())?.[2] ?? text\n const lines = body.split('\\n')\n if (lines[0]?.startsWith('$ ')) {\n lines.shift()\n }\n if (shell.status === 'exited' && lines.length > 0 && SHELL_END_LINE.test(lines[lines.length - 1]!)) {\n lines.pop()\n }\n let truncated = false\n const kept = lines.filter((line) => {\n if (!SHELL_MORE_OUTPUT.test(line)) {\n return true\n }\n truncated = true\n return false\n })\n return { text: kept.join('\\n').trimEnd(), truncated }\n}\n\nfunction shellItem(id: string, shell: ShellInfo, text: string, previous: ShellItem | undefined): ShellItem {\n const row = shellRowText(shell, text)\n return {\n kind: 'shell',\n id,\n shell,\n text: row.text,\n truncated: row.truncated,\n // Carried across the re-emit: a row the reader expanded must not collapse under them when the shell ticks.\n ...(previous?.expanded !== undefined && { expanded: previous.expanded }),\n }\n}\n\nfunction findShell(items: readonly TranscriptItem[], shellId: string): ShellItem | undefined {\n return items.find((item): item is ShellItem => item.kind === 'shell' && item.shell.id === shellId)\n}\n\nconst COMMAND_NAME = /<command-name>([\\s\\S]*?)<\\/command-name>/\nconst COMMAND_ARGS = /<command-args>([\\s\\S]*?)<\\/command-args>/\n// A message whose first text block is the deferred `!` flush is synthetic as a whole, but the block after it is\n// the person's own message. Only that shape earns the exemption - `<task-notification>` and the rest stay hidden.\nfunction carriesCaveat(content: ApiMessage['content']): boolean {\n return contentToBlocks(content).some(\n (block) => block.type === 'text' && (block as { text: string }).text.trimStart().startsWith(LOCAL_COMMAND_CAVEAT),\n )\n}\n\nfunction streamingTextId(parentToolUseId: string | null): string {\n return parentToolUseId == null ? STREAMING_ID : `${STREAMING_ID}:${parentToolUseId}`\n}\nfunction streamingThinkingId(parentToolUseId: string | null): string {\n return parentToolUseId == null ? STREAMING_THINKING_ID : `${STREAMING_THINKING_ID}:${parentToolUseId}`\n}\nfunction isStreamingItem(item: TranscriptItem): boolean {\n return (\n (item.kind === 'assistant_text' && item.id.startsWith(STREAMING_ID)) ||\n (item.kind === 'thinking' && item.id.startsWith(STREAMING_THINKING_ID))\n )\n}\n\nexport function blockText(content: ToolResultBlock['content']): string {\n if (content === undefined) {\n return ''\n }\n if (typeof content === 'string') {\n return content\n }\n return content\n .map((part) => (typeof part.text === 'string' ? part.text : ''))\n .filter(Boolean)\n .join('\\n')\n}\n\nfunction imageRefsOf(content: ToolResultBlock['content'], seq: number): ReadonlyArray<ToolResultImageRef> | undefined {\n if (!Array.isArray(content)) {\n return undefined\n }\n const refs = content.flatMap((part) =>\n part.type === 'image_ref'\n ? [\n {\n partIndex: Number(part.part_index),\n mediaType: String(part.media_type ?? 'application/octet-stream'),\n bytes: Number(part.bytes ?? 0),\n sourceSeq: seq,\n },\n ]\n : [],\n )\n return refs.length > 0 ? refs : undefined\n}\n\nfunction contentToBlocks(content: string | ContentBlock[]): ContentBlock[] {\n return typeof content === 'string' ? [{ type: 'text', text: content }] : content\n}\n\nfunction outputText(output: ToolExecutionOutput): string {\n if (output.type === 'text') {\n return output.value\n }\n try {\n return JSON.stringify(output.value)\n } catch {\n return String(output.value)\n }\n}\n\nfunction slashCommandText(text: string): string | undefined {\n const name = COMMAND_NAME.exec(text)?.[1]?.trim()\n if (!name) {\n return undefined\n }\n const args = COMMAND_ARGS.exec(text)?.[1]?.trim()\n return args ? `${name} ${args}` : name\n}\n\nfunction upsert(items: TranscriptItem[], item: TranscriptItem): TranscriptItem[] {\n const index = items.findIndex((existing) => existing.id === item.id && existing.kind === item.kind)\n if (index === -1) {\n return [...items, item]\n }\n const next = [...items]\n next[index] = item\n return next\n}\n\nexport function seedFromSessionInfo(state: TranscriptState, info: SessionInfo): TranscriptState {\n // No event carries the engine - the snapshot is the only source.\n const engine = info.engine ?? state.engine\n return {\n ...state,\n // With held state (reconnect, warm cache seed) the held status stands: any change since is a `status_changed` in the replay span - events stay the one authority.\n status: state.lastSeq === 0 ? info.status : state.status,\n model: state.model ?? info.model,\n permissionMode: state.permissionMode ?? info.permissionMode,\n cwd: state.cwd ?? info.cwd,\n sdkSessionId: state.sdkSessionId ?? info.sdkSessionId,\n engine,\n capabilities: info.capabilities ?? ENGINE_CAPABILITIES[engine ?? 'claude'],\n // Spend outlives the log a replay is built from: a dormant wake starts a fresh log with no `turn_result` in it,\n // so the snapshot is the only thing that still knows what the session cost before it slept.\n totalCostUsd: state.totalCostUsd || (info.totalCostUsd ?? 0),\n costUsd: state.costUsd ?? info.costUsd,\n usageByModel: state.usageByModel ?? info.usageByModel,\n session: info,\n }\n}\n\nexport function rateLimitWindows(state: TranscriptState): UsageWindowRow[] {\n return orderUsageWindows(mergeUsage({ rateLimits: state.rateLimits, updatedAt: state.rateLimitsUpdatedAt }, undefined))\n}\n\nexport function hydrateToolResult(state: TranscriptState, toolUseId: string, text: string): TranscriptState {\n let changed = false\n const items = state.items.map((item) => {\n if (item.kind !== 'tool_call' || item.id !== toolUseId || !item.result?.truncated) {\n return item\n }\n changed = true\n // `images` survives the text hydration: the refs carry their own `sourceSeq` because the result's clears here, and without them the row's pictures are unloadable.\n return {\n ...item,\n result: {\n text,\n isError: item.result.isError,\n ...(item.result.images && { images: item.result.images }),\n },\n }\n })\n return changed ? { ...state, items } : state\n}\n\n// `shell` absent is the 404: the record was swept or belongs to a gateway generation this one cannot answer for.\nexport function hydrateShellRow(state: TranscriptState, shellId: string, shell: ShellInfo | undefined): TranscriptState {\n const current = findShell(state.items, shellId)\n if (!current) {\n return state\n }\n const next: ShellItem = shell === undefined ? { ...current, missing: true } : { ...current, shell, missing: undefined }\n return { ...state, items: state.items.map((item) => (item === current ? next : item)) }\n}\n\nexport function hydrateShellOutput(state: TranscriptState, shellId: string, text: string): TranscriptState {\n const current = findShell(state.items, shellId)\n if (!current) {\n return state\n }\n return { ...state, items: state.items.map((item) => (item === current ? { ...current, expanded: text, missing: undefined } : item)) }\n}\n\nexport function applyEvent(state: TranscriptState, event: SessionEvent): TranscriptState {\n if (event.seq <= state.lastSeq) {\n return state\n }\n const base: TranscriptState = { ...state, lastSeq: event.seq }\n\n switch (event.type) {\n case 'system_init': {\n return {\n ...base,\n model: event.model,\n cwd: event.cwd,\n sdkSessionId: event.sdkSessionId,\n permissionMode: event.permissionMode,\n }\n }\n\n case 'status_changed': {\n return { ...base, status: event.status, statusDetail: event.detail }\n }\n\n case 'capabilities': {\n return {\n ...base,\n models: event.models,\n commands: event.commands,\n defaultModel: event.defaultModel ?? base.defaultModel,\n }\n }\n\n case 'skills': {\n return { ...base, skills: event.skills }\n }\n\n case 'checklist': {\n return { ...base, checklist: event.items.length > 0 ? event.items : undefined }\n }\n\n case 'tool_titles': {\n return { ...base, toolTitles: { ...base.toolTitles, ...event.titles } }\n }\n\n case 'file_produced': {\n return {\n ...base,\n producedFiles: {\n ...base.producedFiles,\n [event.path]: {\n fileId: event.fileId,\n ...(event.mediaType ? { mediaType: event.mediaType } : {}),\n ...(event.bytes !== undefined ? { bytes: event.bytes } : {}),\n },\n },\n }\n }\n\n case 'model_changed': {\n return event.model === undefined ? base : { ...base, model: event.model }\n }\n\n case 'permission_mode_changed': {\n return { ...base, permissionMode: event.mode }\n }\n\n case 'context_usage': {\n return { ...base, contextUsage: event.usage }\n }\n\n case 'rate_limit': {\n const key = event.info.rateLimitType\n if (!key) {\n return base\n }\n return {\n ...base,\n rateLimits: { ...base.rateLimits, [key]: event.info },\n rateLimitsUpdatedAt: event.ts,\n }\n }\n\n case 'plan_info': {\n return { ...base, subscriptionType: event.subscriptionType }\n }\n\n case 'conversation_reset': {\n return {\n ...base,\n items: [],\n contextUsage: undefined,\n checklist: undefined,\n sdkSessionId: event.sdkSessionId ?? base.sdkSessionId,\n }\n }\n\n // Appends where the reset above empties, and leaves `contextUsage` alone: the engine reports post-compaction occupancy itself.\n case 'context_compacted': {\n return {\n ...base,\n items: upsert(base.items, {\n kind: 'compaction',\n id: event.uuid,\n parentToolUseId: event.parentToolUseId ?? null,\n pending: event.pending,\n trigger: event.trigger,\n preTokens: event.preTokens,\n postTokens: event.postTokens,\n error: event.error,\n }),\n }\n }\n\n case 'user_message': {\n let items = base.items\n for (const block of contentToBlocks(event.message.content)) {\n if (block.type === 'tool_result') {\n const toolResult = block as ToolResultBlock\n const isError = toolResult.is_error === true\n items = items.map((item) =>\n item.kind === 'tool_call' && item.id === toolResult.tool_use_id\n ? {\n ...item,\n status: isError ? 'failed' : 'settled',\n result: {\n text: blockText(toolResult.content),\n isError,\n ...(toolResult.truncated && {\n truncated: true as const,\n totalChars: toolResult.total_chars,\n sourceSeq: event.seq,\n }),\n ...(imageRefsOf(toolResult.content, event.seq) && {\n images: imageRefsOf(toolResult.content, event.seq),\n }),\n },\n ...(event.patch && { patch: event.patch }),\n }\n : item,\n )\n } else if (block.type === 'text') {\n const text = (block as { text: string }).text\n const rowId = event.uuid ?? `user-${event.seq}`\n // Both branches sit ahead of the synthetic guard on purpose. A `!` shell run is emitted synthetic so it\n // scores zero activity and zero prose, but it is the one synthetic message a person is meant to see; and\n // on resume the SDK hands back the shell output and the user's own text as one message, which\n // `isSyntheticUserText` then marks synthetic whole. Without this the user's own words vanish on reload.\n const localOutput = LOCAL_COMMAND_OUTPUT.exec(text.trim())\n if (event.shell) {\n const existing = items.find((item): item is ShellItem => item.kind === 'shell' && item.id === rowId)\n items = upsert(items, shellItem(rowId, event.shell, text, existing))\n } else if (localOutput) {\n items = upsert(items, {\n kind: 'notice',\n id: rowId,\n level: localOutput[1] === 'stderr' ? 'error' : 'info',\n text: localOutput[2].trim(),\n })\n } else if (text.trimStart().startsWith(LOCAL_COMMAND_CAVEAT)) {\n let index = 0\n for (const match of text.matchAll(LOCAL_COMMAND_ELEMENT)) {\n items = upsert(items, {\n kind: 'notice',\n id: `${rowId}#${index++}`,\n level: match[1] === 'stderr' ? 'error' : 'info',\n text: match[2].trim(),\n })\n }\n } else if (!event.synthetic || carriesCaveat(event.message.content)) {\n items = upsert(items, {\n kind: 'user',\n id: event.uuid ?? `user-${event.seq}`,\n text: slashCommandText(text) ?? text,\n attachments: event.attachments,\n ...(event.origin && { origin: event.origin }),\n ...(event.parentToolUseId != null && {\n parentToolUseId: event.parentToolUseId,\n }),\n })\n }\n }\n }\n return { ...base, items }\n }\n\n case 'assistant_message': {\n const streamingText = streamingTextId(event.parentToolUseId)\n const streamingThought = streamingThinkingId(event.parentToolUseId)\n let streamedThinking =\n base.items.find(\n (item): item is Extract<TranscriptItem, { kind: 'thinking' }> => item.kind === 'thinking' && item.id === streamingThought,\n )?.text ?? ''\n let items = base.items.filter(\n (item) =>\n !(item.kind === 'assistant_text' && item.id === streamingText) && !(item.kind === 'thinking' && item.id === streamingThought),\n )\n const blocks = contentToBlocks(event.message.content)\n blocks.forEach((block, index) => {\n const id = `${event.uuid}-${index}`\n if (block.type === 'text') {\n items = upsert(items, {\n kind: 'assistant_text',\n id,\n text: (block as { text: string }).text,\n streaming: false,\n parentToolUseId: event.parentToolUseId,\n })\n } else if (block.type === 'thinking') {\n const text = (block as { thinking: string }).thinking || streamedThinking\n streamedThinking = ''\n if (text.trim() === '') {\n return\n }\n items = upsert(items, {\n kind: 'thinking',\n id,\n text,\n parentToolUseId: event.parentToolUseId,\n })\n } else if (block.type === 'tool_use') {\n const toolUse = block as { id: string; name: string; input: unknown }\n items = upsert(items, {\n kind: 'tool_call',\n id: toolUse.id,\n name: toolUse.name,\n input: toolUse.input,\n parentToolUseId: event.parentToolUseId,\n status: 'running',\n ts: event.ts,\n })\n }\n })\n return { ...base, items }\n }\n\n case 'stream_delta': {\n const delta = event.event as {\n type: string\n delta?: { type?: string; text?: string; thinking?: string }\n }\n if (delta.type !== 'content_block_delta') {\n return base\n }\n if (delta.delta?.type === 'text_delta') {\n const id = streamingTextId(event.parentToolUseId)\n const existing = base.items.find(\n (item): item is Extract<TranscriptItem, { kind: 'assistant_text' }> => item.kind === 'assistant_text' && item.id === id,\n )\n const item: TranscriptItem = {\n kind: 'assistant_text',\n id,\n text: (existing?.text ?? '') + (delta.delta.text ?? ''),\n streaming: true,\n parentToolUseId: event.parentToolUseId,\n }\n return { ...base, items: upsert(base.items, item) }\n }\n if (delta.delta?.type === 'thinking_delta') {\n const id = streamingThinkingId(event.parentToolUseId)\n const existing = base.items.find(\n (item): item is Extract<TranscriptItem, { kind: 'thinking' }> => item.kind === 'thinking' && item.id === id,\n )\n const text = (existing?.text ?? '') + (delta.delta.thinking ?? '')\n // Whitespace-only (encrypted) thinking creates no item - `turn_result` would finalize a permanent empty row; text rebuilds from `existing`, so skipping loses nothing.\n if (text.trim() === '') {\n return base\n }\n const item: TranscriptItem = {\n kind: 'thinking',\n id,\n text,\n parentToolUseId: event.parentToolUseId,\n }\n return { ...base, items: upsert(base.items, item) }\n }\n return base\n }\n\n case 'turn_result': {\n return {\n ...base,\n totalCostUsd: event.totalCostUsd,\n costUsd: event.costUsd ?? base.costUsd,\n usageByModel: event.usageByModel ?? base.usageByModel,\n items: [\n ...base.items.map((item) => {\n if (!isStreamingItem(item)) {\n return item\n }\n const agent = 'parentToolUseId' in item && item.parentToolUseId ? `-${item.parentToolUseId}` : ''\n return item.kind === 'assistant_text'\n ? { ...item, id: `text-${event.seq}${agent}`, streaming: false }\n : { ...item, id: `thinking-${event.seq}${agent}` }\n }),\n {\n kind: 'turn_result',\n id: `turn-${event.seq}`,\n subtype: event.subtype,\n isError: event.isError,\n durationMs: event.durationMs,\n totalCostUsd: event.totalCostUsd,\n costUsd: event.costUsd,\n errors: event.errors,\n },\n ],\n }\n }\n\n case 'permission_requested': {\n return { ...base, pendingApprovals: [...base.pendingApprovals, event.request] }\n }\n\n case 'permission_resolved': {\n return {\n ...base,\n pendingApprovals: base.pendingApprovals.filter((r) => r.id !== event.requestId),\n }\n }\n\n case 'execution_dispatched': {\n return {\n ...base,\n items: base.items.map((item) =>\n item.kind === 'tool_call' && item.id === event.executionId\n ? {\n ...item,\n status: event.deferred ? 'deferred' : 'pending',\n executionId: event.executionId,\n backend: event.backend,\n }\n : item,\n ),\n }\n }\n\n case 'execution_result': {\n return {\n ...base,\n items: base.items.map((item) =>\n item.kind === 'tool_call' && item.id === event.executionId\n ? {\n ...item,\n status: 'settled',\n executionId: event.executionId,\n result: { text: outputText(event.output), isError: false },\n logs: event.logs ?? item.logs,\n }\n : item,\n ),\n }\n }\n\n case 'execution_failed': {\n return {\n ...base,\n items: base.items.map((item) =>\n item.kind === 'tool_call' && item.id === event.executionId\n ? {\n ...item,\n status: 'failed',\n executionId: event.executionId,\n result: { text: `${event.reason}: ${event.error}`, isError: true },\n logs: event.logs ?? item.logs,\n }\n : item,\n ),\n }\n }\n\n case 'file_delivered': {\n return {\n ...base,\n items: [\n ...base.items,\n {\n kind: 'file_delivered',\n id: `file-${event.seq}`,\n path: event.path,\n bytes: event.bytes,\n description: event.description,\n },\n ],\n }\n }\n\n case 'session_error': {\n return {\n ...base,\n items: [...base.items, { kind: 'notice', id: `err-${event.seq}`, level: 'error', text: event.message }],\n }\n }\n\n case 'session_closed': {\n return {\n ...base,\n items: [\n ...base.items,\n {\n kind: 'notice',\n id: `closed-${event.seq}`,\n level: 'info',\n text: `Session closed (${event.reason})`,\n },\n ],\n }\n }\n\n case 'sdk_event':\n default: {\n return base\n }\n }\n}\n","import type { WorkerDeckClient } from '@workerdeck/client'\nimport type { TranscriptState } from './transcript.ts'\n\nconst MAX_ENTRIES = 5\n\nconst entries = new Map<string, TranscriptState>()\n\n// NUL separates unambiguously: `identityKey` is JSON.stringify output, so no two pairs spell one key.\nexport function transcriptCacheKey(client: WorkerDeckClient, sessionId: string): string {\n return `${client.identityKey}\\u0000${sessionId}`\n}\n\nexport function readTranscriptCache(key: string): TranscriptState | undefined {\n return entries.get(key)\n}\n\nexport function writeTranscriptCache(key: string, state: TranscriptState): void {\n entries.delete(key)\n entries.set(key, state)\n if (entries.size > MAX_ENTRIES) {\n const oldest = entries.keys().next().value\n if (oldest !== undefined) {\n entries.delete(oldest)\n }\n }\n}\n\nexport function deleteTranscriptCache(key: string): void {\n entries.delete(key)\n}\n\nexport function clearTranscriptCache(): void {\n entries.clear()\n}\n","import { initialTranscriptState, type TranscriptState } from './transcript.ts'\n\nexport function attachSeedToken(resyncSeq: number, key: string): string {\n return `${resyncSeq}:${key}`\n}\n\nexport type AttachInputs = {\n resyncSeq: number\n key: string\n seededFor: string\n current: TranscriptState\n cacheEnabled: boolean\n skipCache: boolean\n warm: TranscriptState | undefined\n}\n\nexport type AttachPlan = {\n held: TranscriptState\n seed: boolean\n seedToken: string\n afterSeq?: number\n}\n\nexport function planAttach(input: AttachInputs): AttachPlan {\n const seedToken = attachSeedToken(input.resyncSeq, input.key)\n const warm = input.cacheEnabled && !input.skipCache ? input.warm : undefined\n const seed = input.seededFor !== seedToken\n const held = seed ? (warm ?? initialTranscriptState) : input.current\n // `afterSeq` derives from the state held and never from a second cache read, which a racing write could move.\n return { held, seed, seedToken, ...(held.lastSeq > 0 ? { afterSeq: held.lastSeq } : {}) }\n}\n\nexport function shouldWriteParting(input: { cacheEnabled: boolean; skipCache: boolean; parting: TranscriptState }): boolean {\n return input.cacheEnabled && !input.skipCache && input.parting.lastSeq > 0 && input.parting.session !== undefined\n}\n","import { useCallback, useEffect, useMemo, useReducer, useRef, useState } from 'react'\nimport type { WorkerDeckClient, SessionHandle } from '@workerdeck/client'\nimport { DEFAULT_PRICING, PROTOCOL_VERSION, mergePricing } from '@workerdeck/protocol'\nimport type { AttachedFrame, ModelOption, PermissionMode, PricingTable, SessionEvent, ShellInfo } from '@workerdeck/protocol'\nimport {\n applyEvent,\n blockText,\n initialTranscriptState,\n hydrateShellOutput,\n hydrateShellRow,\n hydrateToolResult,\n seedFromSessionInfo,\n type TranscriptState,\n} from '../lib/transcript.ts'\nimport { deleteTranscriptCache, readTranscriptCache, transcriptCacheKey, writeTranscriptCache } from '../lib/transcript-cache.ts'\nimport { attachSeedToken, planAttach, shouldWriteParting } from '../lib/attach-plan.ts'\n\ntype SeedAction = { type: 'transcript_seed'; state: TranscriptState }\ntype HydrateAction = { type: 'transcript_hydrate_result'; toolUseId: string; text: string }\ntype ShellRowAction = { type: 'transcript_hydrate_shell'; shellId: string; shell: ShellInfo | undefined }\ntype ShellOutputAction = { type: 'transcript_hydrate_shell_output'; shellId: string; text: string }\n\ntype TranscriptAction = SessionEvent | AttachedFrame | SeedAction | HydrateAction | ShellRowAction | ShellOutputAction\n\nfunction reduce(state: TranscriptState, action: TranscriptAction): TranscriptState {\n if (action.type === 'transcript_seed') {\n return action.state\n }\n if (action.type === 'transcript_hydrate_result') {\n return hydrateToolResult(state, action.toolUseId, action.text)\n }\n if (action.type === 'transcript_hydrate_shell') {\n return hydrateShellRow(state, action.shellId, action.shell)\n }\n if (action.type === 'transcript_hydrate_shell_output') {\n return hydrateShellOutput(state, action.shellId, action.text)\n }\n return action.type === 'attached' ? seedFromSessionInfo(state, action.session) : applyEvent(state, action)\n}\n\nexport type ConnectionState = 'live' | 'reconnecting' | 'offline'\n\n// Three failed attempts is ~3.5s of backoff - past a blip; the iOS client hardcodes the same threshold.\nconst OFFLINE_AFTER_ATTEMPTS = 3\n\nexport function initialReplayTarget(frame: AttachedFrame): number | undefined {\n return frame.replayingFrom === 0 && frame.session.lastSeq > 0 ? frame.session.lastSeq : undefined\n}\n\nexport function staleAttach(frame: AttachedFrame, held: TranscriptState): boolean {\n if (frame.replayingFrom === 0 || held.lastSeq === 0) {\n return false\n }\n if (frame.session.lastSeq < held.lastSeq) {\n return true\n }\n return held.session !== undefined && frame.session.createdAt !== held.session.createdAt\n}\n\nexport const REPLAY_HOLD_MAX_MS = 1500\n\nexport type UseClaudeSessionOptions = {\n onProtocolError?: (message: string) => void\n cacheTranscript?: boolean\n}\n\nexport type UseClaudeSessionResult = {\n state: TranscriptState\n connected: boolean\n connection: ConnectionState\n replaying: boolean\n protocolMismatch?: number\n // The gateway offers `$` shell mode to this principal on this session. Absent from an older gateway, so falsy by default.\n shell: boolean\n // The gateway's rate table, its own overrides merged over the bundled one, for every figure this client prices itself.\n pricing: PricingTable\n models: ModelOption[]\n effectiveModel?: string\n handle: SessionHandle | undefined\n send: (text: string, attachmentIds?: string[]) => void\n approve: (requestId: string, updatedInput?: Record<string, unknown>) => void\n deny: (requestId: string, message?: string, interrupt?: boolean) => void\n interrupt: () => void\n clearContext: () => void\n runShell: (command: string) => void\n setPermissionMode: (mode: PermissionMode) => void\n setModel: (model?: string) => void\n closeSession: () => void\n reconnectNow: () => void\n loadFullResult: (toolUseId: string) => Promise<boolean>\n // The artifact's text view, fetched for one expanded row. It never reaches the model: the two budgets never touch.\n loadShellOutput: (shellId: string) => Promise<boolean>\n // A `running` row is a claim from the event log, which can be older than the process. Fetched once per shell id.\n verifyShell: (shellId: string) => Promise<boolean>\n killShell: (shellId: string) => Promise<boolean>\n}\n\nexport function useClaudeSession(\n client: WorkerDeckClient,\n sessionId: string | undefined,\n options?: UseClaudeSessionOptions,\n): UseClaudeSessionResult {\n const [state, dispatch] = useReducer(\n reduce,\n undefined,\n (): TranscriptState =>\n (options?.cacheTranscript !== false && sessionId !== undefined\n ? readTranscriptCache(transcriptCacheKey(client, sessionId))\n : undefined) ?? initialTranscriptState,\n )\n const [connection, setConnection] = useState<ConnectionState>('reconnecting')\n const [protocolMismatch, setProtocolMismatch] = useState<number | undefined>()\n const [shell, setShell] = useState(false)\n const [pricing, setPricing] = useState<PricingTable>(DEFAULT_PRICING)\n const [replayTarget, setReplayTarget] = useState<number | undefined>()\n const [resyncSeq, setResyncSeq] = useState(0)\n // Ref for the stable callbacks below; state so consumers of `handle` re-render when the socket opens or the session switches.\n const [handleState, setHandleState] = useState<SessionHandle | undefined>()\n const handleRef = useRef<SessionHandle | null>(null)\n const optionsRef = useRef(options)\n optionsRef.current = options\n const stateRef = useRef(state)\n stateRef.current = state\n const seededForRef = useRef(attachSeedToken(0, sessionId === undefined ? '' : transcriptCacheKey(client, sessionId)))\n const skipCacheRef = useRef(false)\n\n useEffect(() => {\n if (!sessionId) {\n return\n }\n const cache = optionsRef.current?.cacheTranscript !== false\n const key = transcriptCacheKey(client, sessionId)\n const plan = planAttach({\n resyncSeq,\n key,\n seededFor: seededForRef.current,\n current: stateRef.current,\n cacheEnabled: cache,\n skipCache: skipCacheRef.current,\n warm: readTranscriptCache(key),\n })\n skipCacheRef.current = false\n if (plan.seed) {\n dispatch({ type: 'transcript_seed', state: plan.held })\n seededForRef.current = plan.seedToken\n }\n const handle = client.attach(sessionId, {\n truncateResults: true,\n imageRefs: true,\n ...(plan.afterSeq === undefined ? {} : { afterSeq: plan.afterSeq }),\n })\n handleRef.current = handle\n setHandleState(handle)\n const offEvent = handle.on('event', (event: SessionEvent) => dispatch(event))\n const offAttached = handle.on('attached', (frame: AttachedFrame) => {\n if (staleAttach(frame, stateRef.current)) {\n offEvent()\n deleteTranscriptCache(key)\n skipCacheRef.current = true\n setResyncSeq((n) => n + 1)\n return\n }\n dispatch(frame)\n setReplayTarget(initialReplayTarget(frame))\n setProtocolMismatch(frame.protocolVersion === PROTOCOL_VERSION ? undefined : frame.protocolVersion)\n setShell(frame.shell === true)\n setPricing(mergePricing(frame.pricingOverrides).pricing)\n })\n const offConn = handle.on('connectionChange', (open: boolean) => setConnection(open ? 'live' : 'reconnecting'))\n const offRetry = handle.on('reconnectAttempt', (attempts: number) =>\n setConnection(attempts >= OFFLINE_AFTER_ATTEMPTS ? 'offline' : 'reconnecting'),\n )\n const offProtocolError = handle.on('protocolError', (message: string) => {\n optionsRef.current?.onProtocolError?.(message)\n })\n return () => {\n offEvent()\n offAttached()\n offConn()\n offRetry()\n offProtocolError()\n handle.detach()\n handleRef.current = null\n setHandleState(undefined)\n setConnection('reconnecting')\n setProtocolMismatch(undefined)\n setShell(false)\n setReplayTarget(undefined)\n const parting = stateRef.current\n if (shouldWriteParting({ cacheEnabled: cache, skipCache: skipCacheRef.current, parting })) {\n writeTranscriptCache(key, parting)\n }\n }\n }, [client, sessionId, resyncSeq])\n\n useEffect(() => {\n if (replayTarget === undefined) {\n return\n }\n const timer = setTimeout(() => setReplayTarget(undefined), REPLAY_HOLD_MAX_MS)\n return () => clearTimeout(timer)\n }, [replayTarget])\n useEffect(() => {\n if (replayTarget !== undefined && state.lastSeq >= replayTarget) {\n setReplayTarget(undefined)\n }\n }, [replayTarget, state.lastSeq])\n\n const models = useProfileModelFallback(client, sessionId, state)\n\n const connected = connection === 'live'\n // Derived at render, not in an effect, so the reveal lands in the same commit as the replay's final event - an effect is one visible frame late.\n const replaying = replayTarget !== undefined && state.lastSeq < replayTarget\n const reconnectNow = useCallback(() => handleRef.current?.reconnectNow(), [])\n\n const loadFullResult = useCallback(\n async (toolUseId: string): Promise<boolean> => {\n if (!sessionId) {\n return false\n }\n const item = stateRef.current.items.find((candidate) => candidate.kind === 'tool_call' && candidate.id === toolUseId)\n const result = item?.kind === 'tool_call' ? item.result : undefined\n if (!result?.truncated || result.sourceSeq === undefined) {\n return false\n }\n try {\n const full = await client.toolResult(sessionId, result.sourceSeq, toolUseId)\n dispatch({ type: 'transcript_hydrate_result', toolUseId, text: blockText(full.content) })\n return true\n } catch {\n return false\n }\n },\n [client, sessionId],\n )\n\n const verifiedRef = useRef(new Set<string>())\n useEffect(() => {\n verifiedRef.current = new Set<string>()\n }, [sessionId])\n\n const loadShellOutput = useCallback(\n async (shellId: string): Promise<boolean> => {\n if (!sessionId) {\n return false\n }\n try {\n const text = await client.shellOutput(sessionId, shellId, { view: 'text' })\n dispatch({ type: 'transcript_hydrate_shell_output', shellId, text })\n return true\n } catch {\n dispatch({ type: 'transcript_hydrate_shell', shellId, shell: undefined })\n return false\n }\n },\n [client, sessionId],\n )\n\n const verifyShell = useCallback(\n async (shellId: string): Promise<boolean> => {\n if (!sessionId || verifiedRef.current.has(shellId)) {\n return false\n }\n verifiedRef.current.add(shellId)\n try {\n const record = await client.getShell(sessionId, shellId)\n dispatch({ type: 'transcript_hydrate_shell', shellId, shell: record })\n return true\n } catch {\n dispatch({ type: 'transcript_hydrate_shell', shellId, shell: undefined })\n return false\n }\n },\n [client, sessionId],\n )\n\n const killShell = useCallback(\n async (shellId: string): Promise<boolean> => {\n if (!sessionId) {\n return false\n }\n try {\n const record = await client.killShell(sessionId, shellId)\n dispatch({ type: 'transcript_hydrate_shell', shellId, shell: record })\n return true\n } catch {\n return false\n }\n },\n [client, sessionId],\n )\n\n return useMemo(\n () => ({\n state,\n connected,\n connection,\n replaying,\n protocolMismatch,\n shell,\n pricing,\n models,\n effectiveModel: state.model ?? state.defaultModel,\n handle: handleState,\n send: (text, attachmentIds) => handleRef.current?.send(text, attachmentIds),\n approve: (requestId, updatedInput) => handleRef.current?.approve(requestId, updatedInput),\n deny: (requestId, message, interrupt) => handleRef.current?.deny(requestId, message, interrupt),\n interrupt: () => handleRef.current?.interrupt(),\n clearContext: () => handleRef.current?.clearContext(),\n runShell: (command) => handleRef.current?.runShell(command),\n setPermissionMode: (mode) => handleRef.current?.setPermissionMode(mode),\n setModel: (model) => handleRef.current?.setModel(model),\n closeSession: () => handleRef.current?.closeSession(),\n reconnectNow,\n loadFullResult,\n loadShellOutput,\n verifyShell,\n killShell,\n }),\n [\n state,\n connected,\n connection,\n replaying,\n protocolMismatch,\n shell,\n pricing,\n models,\n handleState,\n reconnectNow,\n loadFullResult,\n loadShellOutput,\n verifyShell,\n killShell,\n ],\n )\n}\n\nfunction useProfileModelFallback(client: WorkerDeckClient, sessionId: string | undefined, state: TranscriptState): ModelOption[] {\n const [catalog, setCatalog] = useState<ModelOption[]>([])\n const profile = state.session?.profile\n const reported = state.models\n const hasReported = !!reported?.length\n\n useEffect(() => setCatalog([]), [sessionId])\n\n useEffect(() => {\n if (!profile || hasReported) {\n return\n }\n let cancelled = false\n client\n .listProfiles()\n .then((response) => {\n if (!cancelled) {\n setCatalog(response.profiles.find((p) => p.name === profile)?.models ?? [])\n }\n })\n .catch(() => {})\n return () => {\n cancelled = true\n }\n }, [client, profile, hasReported])\n\n return hasReported ? reported : catalog\n}\n","import type { WorkerDeckClient } from '@workerdeck/client'\nimport type { ProfileUsage } from '@workerdeck/protocol'\n\n// Last known profile usage, kept outside React so a session switch does not blank it.\n//\n// Usage belongs to the *account*, not the session, but it is fetched by a hook that lives inside the per-session\n// panel - so remounting that panel used to drop the authoritative reading to `undefined` for a whole round trip,\n// leaving only the newly-attached session's own replayed (and possibly days-old) numbers to render. That is the\n// \"switching sessions resets my weekly usage to 1%, then it catches up\" report.\n//\n// Keyed by client identity + profile because a different profile is a different account's plan, never a stale view\n// of this one. Same shape and reasoning as `transcript-cache.ts` next door.\nconst entries = new Map<string, ProfileUsage>()\n\n// NUL separates unambiguously: `identityKey` is JSON.stringify output, so no two pairs spell one key.\nexport function profileUsageCacheKey(client: WorkerDeckClient, profile: string): string {\n return `${client.identityKey}\\u0000${profile}`\n}\n\nexport function readProfileUsageCache(key: string): ProfileUsage | undefined {\n return entries.get(key)\n}\n\nexport function writeProfileUsageCache(key: string, usage: ProfileUsage | undefined): void {\n if (usage === undefined) {\n return\n }\n entries.set(key, usage)\n}\n\nexport function clearProfileUsageCache(): void {\n entries.clear()\n}\n","import type { WorkerDeckClient } from '@workerdeck/client'\n\n// Unsent composer text, kept per session on the client that typed it.\n//\n// A draft is not session state: it never reaches the gateway and never syncs between clients. Two people looking at\n// one session are each mid-sentence in their own way, and a half-written prompt is not something either of them\n// asked to publish.\n//\n// It is persisted rather than merely held in memory because the two ways drafts got lost are different failures. A\n// session switch remounts the composer, which a module-scope map alone would survive; a Vite HMR reload or a VS Code\n// `dev:host` webview re-render replaces the whole document, which it would not.\nconst KEY = 'workerdeck.drafts.v1'\n\n// Drafts are a convenience, so the store stays small and drops the least recently touched first.\nconst MAX_DRAFTS = 20\n\ntype Draft = { text: string; savedAt: number }\n\nlet memory: Record<string, Draft> | undefined\n\nfunction storage(): Storage | undefined {\n try {\n // Through globalThis: this package is typechecked with no DOM lib, and a webview may deny storage outright.\n return (globalThis as { localStorage?: Storage }).localStorage\n } catch {\n return undefined\n }\n}\n\nfunction load(): Record<string, Draft> {\n if (memory) {\n return memory\n }\n memory = {}\n const raw = storage()?.getItem(KEY)\n if (raw) {\n try {\n const parsed = JSON.parse(raw) as Record<string, Draft>\n for (const [key, draft] of Object.entries(parsed)) {\n if (typeof draft?.text === 'string' && typeof draft.savedAt === 'number') {\n memory[key] = draft\n }\n }\n } catch {\n // A corrupt blob is not worth a broken composer; start over.\n }\n }\n return memory\n}\n\nfunction persist(drafts: Record<string, Draft>): void {\n const entries = Object.entries(drafts)\n if (entries.length > MAX_DRAFTS) {\n entries.sort((a, b) => b[1].savedAt - a[1].savedAt)\n for (const [key] of entries.slice(MAX_DRAFTS)) {\n delete drafts[key]\n }\n }\n try {\n storage()?.setItem(KEY, JSON.stringify(drafts))\n } catch {\n // Out of quota, or storage denied. The in-memory copy still carries the session switch.\n }\n}\n\n// NUL separates unambiguously: `identityKey` is JSON.stringify output, so no two pairs spell one key.\nexport function draftKey(client: WorkerDeckClient, sessionId: string): string {\n return `${client.identityKey}\\u0000${sessionId}`\n}\n\nexport function readDraft(key: string): string {\n return load()[key]?.text ?? ''\n}\n\nexport function writeDraft(key: string, text: string, now = Date.now()): void {\n const drafts = load()\n // An empty draft is the absence of one: keeping it would evict a real draft under the cap.\n if (text.trim() === '') {\n if (drafts[key] === undefined) {\n return\n }\n delete drafts[key]\n } else {\n drafts[key] = { text, savedAt: now }\n }\n persist(drafts)\n}\n\nexport function clearDrafts(): void {\n memory = {}\n try {\n storage()?.removeItem(KEY)\n } catch {}\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport type { WorkerDeckClient } from '@workerdeck/client'\nimport type { EngineCapabilities, ProfileEngine } from '@workerdeck/protocol'\n\nexport type StagedAttachment = {\n key: string\n name: string\n mediaType: string\n bytes: number\n previewUrl?: string\n status: 'uploading' | 'ready' | 'failed'\n id?: string\n error?: string\n}\n\nexport type AttachmentKind = 'image' | 'pdf' | 'text'\n\nconst TEXTUAL_TYPES = new Set([\n 'application/json',\n 'application/xml',\n 'application/yaml',\n 'application/x-yaml',\n 'application/toml',\n 'application/javascript',\n 'application/typescript',\n 'application/x-sh',\n 'application/sql',\n])\n\nconst MAX_IMAGE_EDGE = 1568\n\nexport function attachmentKind(mediaType: string): AttachmentKind | undefined {\n const type = mediaType.split(';')[0]!.trim().toLowerCase()\n if (type.startsWith('image/')) {\n return 'image'\n }\n if (type === 'application/pdf') {\n return 'pdf'\n }\n if (type.startsWith('text/')) {\n return 'text'\n }\n if (TEXTUAL_TYPES.has(type)) {\n return 'text'\n }\n return undefined\n}\n\nexport type UseAttachmentsOptions = {\n capabilities: EngineCapabilities\n engine?: ProfileEngine\n}\n\nexport type UseAttachmentsResult = {\n items: StagedAttachment[]\n readyIds: string[]\n uploading: boolean\n hasFailure: boolean\n accept: string\n disabled: boolean\n add: (files: Iterable<File>) => void\n retry: (key: string) => void\n remove: (key: string) => void\n clear: () => void\n error?: string\n dismissError: () => void\n}\n\nexport function useAttachments(\n client: WorkerDeckClient,\n sessionId: string | undefined,\n { capabilities, engine }: UseAttachmentsOptions,\n): UseAttachmentsResult {\n const [items, setItems] = useState<StagedAttachment[]>([])\n const [error, setError] = useState<string | undefined>()\n const counter = useRef(0)\n const fileByKey = useRef(new Map<string, File>())\n const previewUrls = useRef<string[]>([])\n previewUrls.current = items.flatMap((item) => (item.previewUrl ? [item.previewUrl] : []))\n const accepts = capabilities.attachments\n\n useEffect(\n () => () => {\n for (const url of previewUrls.current) {\n URL.revokeObjectURL(url)\n }\n },\n [],\n )\n\n const patch = useCallback((key: string, next: Partial<StagedAttachment>) => {\n setItems((current) => current.map((item) => (item.key === key ? { ...item, ...next } : item)))\n }, [])\n\n const upload = useCallback(\n (key: string, file: File) => {\n if (!sessionId) {\n return\n }\n patch(key, { status: 'uploading', error: undefined })\n void (async () => {\n try {\n const data = await prepare(file)\n const uploaded = await client.uploadAttachment(sessionId, {\n name: file.name,\n mediaType: data.mediaType,\n data: data.body,\n })\n patch(key, { status: 'ready', id: uploaded.id, bytes: uploaded.bytes ?? file.size })\n } catch (e) {\n patch(key, { status: 'failed', error: e instanceof Error ? e.message : 'Upload failed' })\n }\n })()\n },\n [client, patch, sessionId],\n )\n\n const add = useCallback(\n (files: Iterable<File>) => {\n const staged: StagedAttachment[] = []\n const pending: Array<{ key: string; file: File }> = []\n for (const file of files) {\n const mediaType = file.type || 'application/octet-stream'\n const kind = attachmentKind(mediaType)\n // An unclassifiable type still goes: the gateway's vocabulary is the authoritative one.\n if (kind && !accepts.includes(kind)) {\n setError(`The ${engine ?? 'claude'} engine does not take ${kind} attachments.`)\n continue\n }\n const key = `att-${++counter.current}`\n staged.push({\n key,\n name: file.name,\n mediaType,\n bytes: file.size,\n previewUrl: kind === 'image' ? URL.createObjectURL(file) : undefined,\n status: 'uploading',\n })\n pending.push({ key, file })\n }\n if (staged.length === 0) {\n return\n }\n setItems((current) => [...current, ...staged])\n fileByKey.current = new Map([...fileByKey.current, ...pending.map(({ key, file }) => [key, file] as const)])\n for (const { key, file } of pending) {\n upload(key, file)\n }\n },\n [accepts, engine, upload],\n )\n\n const forget = useCallback((keys: string[]) => {\n setItems((current) => {\n for (const item of current) {\n if (keys.includes(item.key) && item.previewUrl) {\n URL.revokeObjectURL(item.previewUrl)\n }\n }\n return current.filter((item) => !keys.includes(item.key))\n })\n for (const key of keys) {\n fileByKey.current.delete(key)\n }\n }, [])\n\n const remove = useCallback((key: string) => forget([key]), [forget])\n\n const clear = useCallback(() => {\n setItems((current) => {\n for (const item of current) {\n if (item.previewUrl) {\n URL.revokeObjectURL(item.previewUrl)\n }\n }\n return []\n })\n fileByKey.current.clear()\n }, [])\n\n const retry = useCallback(\n (key: string) => {\n const file = fileByKey.current.get(key)\n if (file) {\n upload(key, file)\n }\n },\n [upload],\n )\n\n return useMemo(\n () => ({\n items,\n readyIds: items.flatMap((item) => (item.id ? [item.id] : [])),\n uploading: items.some((item) => item.status === 'uploading'),\n hasFailure: items.some((item) => item.status === 'failed'),\n accept: acceptAttribute(accepts),\n disabled: accepts.length === 0 || !sessionId,\n add,\n retry,\n remove,\n clear,\n error,\n dismissError: () => setError(undefined),\n }),\n [items, accepts, sessionId, add, retry, remove, clear, error],\n )\n}\n\nfunction acceptAttribute(kinds: readonly AttachmentKind[]): string {\n if (kinds.length === 0) {\n return ''\n }\n const parts: string[] = []\n if (kinds.includes('image')) {\n parts.push('image/*')\n }\n if (kinds.includes('pdf')) {\n parts.push('application/pdf')\n }\n if (kinds.includes('text')) {\n parts.push('text/*', '.md', '.json', '.yaml', '.yml', '.toml')\n }\n // All three kinds is no narrowing at all, and an empty accept leaves the picker open.\n return kinds.length === 3 ? '' : parts.join(',')\n}\n\n// Reached through globalThis, not named directly: smoke/ typechecks this source with no DOM lib.\ntype ImageBitmapLike = { width: number; height: number; close(): void }\ntype CanvasLike = {\n width: number\n height: number\n getContext(contextId: '2d'): {\n drawImage(image: ImageBitmapLike, dx: number, dy: number, dw: number, dh: number): void\n } | null\n toBlob(callback: (blob: Blob | null) => void, type?: string, quality?: number): void\n}\nconst imaging = globalThis as unknown as {\n createImageBitmap?: (source: Blob) => Promise<ImageBitmapLike>\n document?: { createElement(tagName: 'canvas'): CanvasLike }\n}\n\nasync function prepare(file: File): Promise<{ body: Blob; mediaType: string }> {\n const mediaType = file.type || 'application/octet-stream'\n const { createImageBitmap, document } = imaging\n if (!createImageBitmap || !document || !mediaType.startsWith('image/')) {\n return { body: file, mediaType }\n }\n // A redraw of an animation would keep one frame of it.\n if (mediaType === 'image/gif') {\n return { body: file, mediaType }\n }\n try {\n const bitmap = await createImageBitmap(file)\n const longest = Math.max(bitmap.width, bitmap.height)\n if (longest <= MAX_IMAGE_EDGE) {\n bitmap.close()\n return { body: file, mediaType }\n }\n const scale = MAX_IMAGE_EDGE / longest\n const canvas = document.createElement('canvas')\n canvas.width = Math.round(bitmap.width * scale)\n canvas.height = Math.round(bitmap.height * scale)\n const context = canvas.getContext('2d')\n if (!context) {\n bitmap.close()\n return { body: file, mediaType }\n }\n context.drawImage(bitmap, 0, 0, canvas.width, canvas.height)\n bitmap.close()\n const blob = await new Promise<Blob | null>((resolve) => canvas.toBlob(resolve, 'image/jpeg', 0.85))\n return blob ? { body: blob, mediaType: 'image/jpeg' } : { body: file, mediaType }\n } catch {\n return { body: file, mediaType }\n }\n}\n","import { PEER_MENTION_SIGIL, PROMPT_SENTENCE_TAIL, isPeerMentionBody, peerMentionKey } from '@workerdeck/protocol'\n\nexport type PromptToken = {\n kind: 'file' | 'command' | 'skill' | 'session'\n start: number\n end: number\n text: string\n}\n\n// `$name` is codex's skill mention and `#Name` is another session on the gateway; in both cases only\n// a name this client knows is a token, so a dollar amount and a colour literal never badge. The\n// session list is *live*, so a mention drawn today may draw plain once that peer is renamed - the\n// characters never change, only the colour, which is why this does not break the rule that a\n// transcript must read on replay as it did live (that rule binds substituting a name for an id).\nexport type PromptTokenOptions = {\n skills?: readonly string[]\n // Folded slugs (`peerMentionKey(peerMentionSlug(title, id))`), not display titles.\n sessions?: readonly string[]\n}\n\n// No `/`, so a pasted absolute path is not a command; `:` is in for namespaced skills (`dev:wrapup`).\nconst COMMAND_BODY = /^[A-Za-z0-9\\-_.:]+$/\n\n// The same set the gateway peels with, so one boundary answers for every sigil.\nconst SENTENCE_TAIL = PROMPT_SENTENCE_TAIL\n\nexport function scanPromptTokens(text: string, options?: PromptTokenOptions): PromptToken[] {\n const tokens: PromptToken[] = []\n const skills = options?.skills?.length ? new Set(options.skills) : undefined\n const sessions = options?.sessions?.length ? new Set(options.sessions) : undefined\n const words = /\\S+/g\n let match: RegExpExecArray | null\n while ((match = words.exec(text)) !== null) {\n const word = match[0]\n const kind =\n word[0] === '@'\n ? 'file'\n : word[0] === '/'\n ? 'command'\n : word[0] === '$' && skills\n ? 'skill'\n : word[0] === PEER_MENTION_SIGIL && sessions\n ? 'session'\n : undefined\n if (!kind) {\n continue\n }\n let end = match.index + word.length\n while (end > match.index && SENTENCE_TAIL.has(text[end - 1]!)) {\n end--\n }\n const body = text.slice(match.index + 1, end)\n if (!body) {\n continue\n }\n if (kind === 'command' && !COMMAND_BODY.test(body)) {\n continue\n }\n if (kind === 'skill' && !skills!.has(body)) {\n continue\n }\n if (kind === 'session' && !(isPeerMentionBody(body) && sessions!.has(peerMentionKey(body)))) {\n continue\n }\n tokens.push({ kind, start: match.index, end, text: text.slice(match.index, end) })\n }\n return tokens\n}\n","import { useEffect, useRef, type RefObject } from 'react'\nimport { WorkerDeckError } from '@workerdeck/client'\n\n// Set in an effect, not at declaration: StrictMode remounts, and a once-initialised ref stays false.\nexport function useAliveRef(): RefObject<boolean> {\n const alive = useRef(true)\n useEffect(() => {\n alive.current = true\n return () => {\n alive.current = false\n }\n }, [])\n return alive\n}\n\nexport function isRouteUnsupported(e: unknown): boolean {\n return e instanceof WorkerDeckError && e.status === 404\n}\n","import type { HostDirEntry } from '@workerdeck/protocol'\n\nexport type HostDirState = {\n entries: HostDirEntry[]\n truncated?: boolean\n}\n\nexport type HostTreeRow = {\n entry: HostDirEntry\n depth: number\n expanded?: boolean\n loading?: boolean\n truncated?: boolean\n}\n\nexport function flattenHostTree(root: string, dirs: ReadonlyMap<string, HostDirState>, expanded: ReadonlySet<string>): HostTreeRow[] {\n const rows: HostTreeRow[] = []\n const rootState = dirs.get(root)\n if (!rootState) {\n return rows\n }\n // An explicit stack rather than recursion. Depth is bounded by how many directories the user has\n // expanded, not by tree size, so this is a small risk - but it is the user's clicks that set the\n // bound, and an expanded chain deep enough to exhaust the call stack should still just render.\n const stack: { entries: readonly HostDirEntry[]; index: number; depth: number }[] = [{ entries: rootState.entries, index: 0, depth: 0 }]\n while (stack.length > 0) {\n const frame = stack[stack.length - 1]\n const entry = frame.entries[frame.index]\n if (entry === undefined) {\n stack.pop()\n continue\n }\n frame.index += 1\n const depth = frame.depth\n if (entry.type !== 'dir') {\n rows.push({ entry, depth })\n continue\n }\n const isExpanded = expanded.has(entry.path)\n const childState = dirs.get(entry.path)\n rows.push({\n entry,\n depth,\n expanded: isExpanded,\n loading: isExpanded && !childState,\n truncated: isExpanded ? childState?.truncated : undefined,\n })\n if (isExpanded && childState) {\n stack.push({ entries: childState.entries, index: 0, depth: depth + 1 })\n }\n }\n return rows\n}\n\nexport function ancestorsWithin(root: string, path: string): string[] {\n const base = root.endsWith('/') ? root.slice(0, -1) : root\n if (path === base || !path.startsWith(`${base}/`)) {\n return []\n }\n const rest = path.slice(base.length + 1).split('/')\n const out: string[] = []\n let current = base\n for (const segment of rest.slice(0, -1)) {\n current = `${current}/${segment}`\n out.push(current)\n }\n return out\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport type { WorkerDeckClient } from '@workerdeck/client'\nimport { isRouteUnsupported, useAliveRef } from '../lib/async-guards.ts'\nimport type { HostFileMatch } from '@workerdeck/protocol'\nimport { ancestorsWithin, flattenHostTree, type HostDirState, type HostTreeRow } from '../lib/host-tree.ts'\n\nexport type UseHostFileSearchResult = {\n available: boolean\n search: (query: string, options?: { limit?: number; signal?: AbortSignal }) => Promise<HostFileMatch[]>\n}\n\nexport function useHostFileSearch(client: WorkerDeckClient, cwd: string | undefined): UseHostFileSearchResult {\n const [unsupported, setUnsupported] = useState(false)\n const lastCwd = useRef(cwd)\n useEffect(() => {\n if (lastCwd.current !== cwd) {\n lastCwd.current = cwd\n setUnsupported(false)\n }\n }, [cwd])\n\n const search = useCallback(\n async (query: string, options?: { limit?: number; signal?: AbortSignal }) => {\n if (!cwd || unsupported) {\n return []\n }\n try {\n const response = await client.findHostFiles(cwd, query, options?.limit ?? 8)\n return options?.signal?.aborted ? [] : response.matches\n } catch (e) {\n if (isRouteUnsupported(e)) {\n setUnsupported(true)\n }\n return []\n }\n },\n [client, cwd, unsupported],\n )\n\n return { available: !!cwd && !unsupported, search }\n}\n\nexport type UseHostFileRootsResult = {\n available: boolean\n canWrite: boolean\n}\n\nexport function useHostFileRoots(client: WorkerDeckClient): UseHostFileRootsResult {\n const [result, setResult] = useState<UseHostFileRootsResult>({\n available: false,\n canWrite: false,\n })\n useEffect(() => {\n let cancelled = false\n client\n .listHostRoots()\n .then((response) => {\n if (!cancelled) {\n setResult({ available: true, canWrite: response.canWrite })\n }\n })\n .catch(() => {\n if (!cancelled) {\n setResult({ available: false, canWrite: false })\n }\n })\n return () => {\n cancelled = true\n }\n }, [client])\n return result\n}\n\nexport type UseHostFileTreeResult = {\n available: boolean\n root: string | undefined\n rows: HostTreeRow[]\n loading: boolean\n error: string | undefined\n toggle: (path: string) => void\n reveal: (path: string) => void\n refresh: (path?: string) => void\n}\n\nexport function useHostFileTree(client: WorkerDeckClient, cwd: string | undefined): UseHostFileTreeResult {\n const [dirs, setDirs] = useState<Map<string, HostDirState>>(() => new Map())\n const [expanded, setExpanded] = useState<Set<string>>(() => new Set())\n const [unsupported, setUnsupported] = useState(false)\n const [error, setError] = useState<string | undefined>()\n\n const lastCwd = useRef(cwd)\n useEffect(() => {\n if (lastCwd.current === cwd) {\n return\n }\n lastCwd.current = cwd\n setDirs(new Map())\n setExpanded(new Set())\n setUnsupported(false)\n setError(undefined)\n }, [cwd])\n\n const alive = useAliveRef()\n\n const requested = useRef(new Set<string>())\n\n const list = useCallback(\n (target: string, { force = false } = {}) => {\n if (unsupported) {\n return\n }\n if (!force && requested.current.has(target)) {\n return\n }\n requested.current.add(target)\n client\n .listHostDir(target)\n .then((response) => {\n if (!alive.current) {\n return\n }\n setDirs((previous) => {\n const next = new Map(previous)\n // Keyed on the path asked for, never the canonical one answered: re-keying orphans the node that asked.\n next.set(target, { entries: response.entries, truncated: response.truncated })\n return next\n })\n })\n .catch((e: unknown) => {\n if (!alive.current) {\n return\n }\n requested.current.delete(target)\n if (isRouteUnsupported(e)) {\n setUnsupported(true)\n return\n }\n setError(e instanceof Error ? e.message : 'Could not read that directory')\n })\n },\n [client, unsupported],\n )\n\n useEffect(() => {\n if (cwd) {\n list(cwd)\n }\n }, [cwd, list])\n\n const toggle = useCallback(\n (path: string) => {\n setExpanded((previous) => {\n const next = new Set(previous)\n if (next.has(path)) {\n next.delete(path)\n } else {\n next.add(path)\n }\n return next\n })\n // Outside the updater, which React may run twice; `requested` makes this a no-op on the collapse.\n list(path)\n },\n [list],\n )\n\n const reveal = useCallback(\n (path: string) => {\n if (!cwd) {\n return\n }\n const ancestors = ancestorsWithin(cwd, path)\n if (ancestors.length === 0) {\n return\n }\n for (const dir of ancestors) {\n list(dir)\n }\n setExpanded((previous) => {\n const next = new Set(previous)\n for (const dir of ancestors) {\n next.add(dir)\n }\n return next\n })\n },\n [cwd, list],\n )\n\n const refresh = useCallback(\n (path?: string) => {\n const target = path ?? cwd\n if (!target) {\n return\n }\n setError(undefined)\n list(target, { force: true })\n },\n [cwd, list],\n )\n\n const rows = useMemo(() => (cwd ? flattenHostTree(cwd, dirs, expanded) : []), [cwd, dirs, expanded])\n\n return {\n available: !!cwd && !unsupported,\n root: cwd,\n rows,\n loading: !!cwd && !unsupported && !dirs.has(cwd) && !error,\n error,\n toggle,\n reveal,\n refresh,\n }\n}\n","import { useEffect, useMemo, useState } from 'react'\nimport type { WorkerDeckClient } from '@workerdeck/client'\nimport { peerMentionKey, peerMentionSlug, sessionLabel, type SessionInfo } from '@workerdeck/protocol'\nimport { isRouteUnsupported, useAliveRef } from '../lib/async-guards.ts'\n\nexport type PeerSessionOption = {\n id: string\n // What the composer writes after the `#`, and what the gateway folds to resolve it.\n slug: string\n label: string\n engine?: SessionInfo['engine']\n status: SessionInfo['status']\n cwd: string\n project?: string\n lastActivityAt?: number\n}\n\nexport type UsePeerSessionsResult = {\n available: boolean\n peers: PeerSessionOption[]\n // Folded slugs, for `scanPromptTokens`'s `sessions` allowlist.\n names: string[]\n}\n\nconst EMPTY: UsePeerSessionsResult = { available: false, peers: [], names: [] }\n\nconst IDLE_MS = 20_000\n\n// The other sessions this gateway will show, for the composer's `#` picker. Polled slowly on\n// purpose: a name is not a reading, and this list only has to be right when a menu opens. The\n// gateway resolves what was typed against the sender's own scope, so a stale row costs nothing\n// worse than a mention that stays plain text.\nexport function usePeerSessions(client: WorkerDeckClient, sessionId: string | undefined, enabled = true): UsePeerSessionsResult {\n const [sessions, setSessions] = useState<SessionInfo[] | undefined>(undefined)\n const [unsupported, setUnsupported] = useState(false)\n const alive = useAliveRef()\n\n useEffect(() => {\n if (!enabled || unsupported) {\n return\n }\n let timer: ReturnType<typeof setTimeout> | undefined\n const tick = () => {\n client\n .listSessions()\n .then((rows) => {\n if (!alive.current) {\n return\n }\n setSessions(rows)\n })\n .catch((e: unknown) => {\n if (alive.current && isRouteUnsupported(e)) {\n setUnsupported(true)\n }\n })\n .finally(() => {\n if (alive.current) {\n timer = setTimeout(tick, IDLE_MS)\n }\n })\n }\n tick()\n return () => {\n if (timer) {\n clearTimeout(timer)\n }\n }\n }, [client, enabled, unsupported])\n\n return useMemo(() => {\n if (!enabled || unsupported || !sessions) {\n return EMPTY\n }\n const peers = sessions\n .filter((info) => info.id !== sessionId)\n .sort((a, b) => (b.lastActivityAt ?? b.createdAt) - (a.lastActivityAt ?? a.createdAt))\n .map((info) => ({\n id: info.id,\n slug: peerMentionSlug(info.title, info.id),\n label: sessionLabel(info),\n engine: info.engine,\n status: info.status,\n cwd: info.cwd,\n project: info.project?.name,\n lastActivityAt: info.lastActivityAt,\n }))\n return { available: peers.length > 0, peers, names: peers.map((peer) => peerMentionKey(peer.slug)) }\n }, [enabled, sessionId, sessions, unsupported])\n}\n","import { useEffect, useState } from 'react'\nimport type { WorkerDeckClient } from '@workerdeck/client'\nimport type { SessionRow } from '@workerdeck/protocol'\n\nconst byHash = new Map<string, string>()\nconst inFlight = new Set<string>()\nconst failed = new Set<string>()\n\nexport type ClientForHost = (hostId: string) => WorkerDeckClient | undefined\n\nexport function useProjectIcons(rows: readonly SessionRow[], clientFor: ClientForHost): Record<string, string> {\n const [resolved, setResolved] = useState<Record<string, string>>(() => Object.fromEntries(byHash))\n\n useEffect(() => {\n let alive = true\n for (const row of rows) {\n const icon = row.info.project?.icon\n if (icon?.type !== 'image') {\n continue\n }\n const { hash } = icon\n if (byHash.has(hash) || inFlight.has(hash) || failed.has(hash)) {\n continue\n }\n const client = clientFor(row.hostId)\n // An unreachable gateway is not an iconless one: no failure recorded, so a later render retries.\n if (!client) {\n continue\n }\n inFlight.add(hash)\n void client\n .projectIcon(row.info.id)\n .then((blob) => {\n byHash.set(hash, URL.createObjectURL(blob))\n if (alive) {\n setResolved(Object.fromEntries(byHash))\n }\n })\n .catch(() => {\n failed.add(hash)\n })\n .finally(() => inFlight.delete(hash))\n }\n return () => {\n alive = false\n }\n }, [rows, clientFor])\n\n return resolved\n}\n","import { useCallback, useMemo } from 'react'\nimport type { WorkerDeckClient } from '@workerdeck/client'\nimport { draftKey, readDraft, writeDraft } from '../lib/draft-store.ts'\n\nexport type UseDraftResult = {\n // What was left unsent last time, read once so it can seed the composer on mount.\n initialText: string\n save: (text: string) => void\n clear: () => void\n}\n\n// Remember unsent composer text for a session. Purely local: it never reaches the gateway and never syncs between\n// clients, because a half-written prompt is not something anyone asked to publish.\nexport function useDraft(client: WorkerDeckClient, sessionId: string | undefined): UseDraftResult {\n const key = sessionId ? draftKey(client, sessionId) : undefined\n // Read once per key: re-reading on render would fight whatever is being typed.\n const initialText = useMemo(() => (key ? readDraft(key) : ''), [key])\n const save = useCallback(\n (text: string) => {\n if (key) {\n writeDraft(key, text)\n }\n },\n [key],\n )\n const clear = useCallback(() => {\n if (key) {\n writeDraft(key, '')\n }\n }, [key])\n return { initialText, save, clear }\n}\n","import { useCallback, useEffect, useState } from 'react'\nimport type { WorkerDeckClient } from '@workerdeck/client'\nimport { isRouteUnsupported, useAliveRef } from '../lib/async-guards.ts'\nimport { profileUsageCacheKey, readProfileUsageCache, writeProfileUsageCache } from '../lib/profile-usage-cache.ts'\nimport type { ProfileSpend, ProfileUsage } from '@workerdeck/protocol'\n\nexport type UseProfileUsageOptions = {\n intervalMs?: number\n enabled?: boolean\n}\n\nexport type UseProfileUsageResult = {\n usage: ProfileUsage | undefined\n spend: ProfileSpend | undefined\n refresh: () => void\n}\n\nexport function useProfileUsage(\n client: WorkerDeckClient,\n profile: string | undefined,\n options: UseProfileUsageOptions = {},\n): UseProfileUsageResult {\n const { intervalMs = 60_000, enabled = true } = options\n const cacheKey = profile ? profileUsageCacheKey(client, profile) : undefined\n const [usage, setUsage] = useState<ProfileUsage | undefined>(() => (cacheKey ? readProfileUsageCache(cacheKey) : undefined))\n const [spend, setSpend] = useState<ProfileSpend | undefined>(undefined)\n const [unsupported, setUnsupported] = useState(false)\n const [nonce, setNonce] = useState(0)\n const refresh = useCallback(() => setNonce((n) => n + 1), [])\n\n // A previous profile's reading is another account's plan, not a stale view of this one - so switch to what we last\n // knew about *this* profile rather than to nothing. Blanking here is what made a session switch fall back on the\n // newly-attached session's own replayed numbers, which is the usage-reverts report.\n useEffect(() => {\n setUsage(cacheKey ? readProfileUsageCache(cacheKey) : undefined)\n setSpend(undefined)\n }, [cacheKey])\n\n const alive = useAliveRef()\n\n useEffect(() => {\n if (!profile || !enabled || unsupported) {\n return\n }\n let cancelled = false\n const load = () => {\n // `document` through globalThis: the extras project typechecks this source with no DOM lib.\n if ((globalThis as { document?: { hidden?: boolean } }).document?.hidden) {\n return\n }\n client\n .listProfiles()\n .then((res) => {\n if (cancelled || !alive.current) {\n return\n }\n const found = res.profiles.find((p) => p.name === profile)\n const next = found?.usage\n if (cacheKey) {\n writeProfileUsageCache(cacheKey, next)\n }\n setUsage(next)\n setSpend(found?.spend)\n })\n .catch((e: unknown) => {\n if (cancelled || !alive.current) {\n return\n }\n if (isRouteUnsupported(e)) {\n setUnsupported(true)\n }\n })\n }\n load()\n const timer = setInterval(load, intervalMs)\n return () => {\n cancelled = true\n clearInterval(timer)\n }\n }, [client, profile, enabled, unsupported, intervalMs, nonce, cacheKey])\n\n return { usage, spend, refresh }\n}\n","import { useEffect, useState } from 'react'\nimport type { WorkerDeckClient } from '@workerdeck/client'\nimport type { SessionInfo } from '@workerdeck/protocol'\n\nexport type UseSessionInfoResult = {\n info: SessionInfo | undefined\n loading: boolean\n error: string | undefined\n}\n\nexport function useSessionInfo(client: WorkerDeckClient, sessionId: string | undefined): UseSessionInfoResult {\n const [info, setInfo] = useState<SessionInfo | undefined>()\n const [loading, setLoading] = useState(!!sessionId)\n const [error, setError] = useState<string | undefined>()\n\n useEffect(() => {\n if (!sessionId) {\n setInfo(undefined)\n setLoading(false)\n setError(undefined)\n return\n }\n let cancelled = false\n setLoading(true)\n setError(undefined)\n setInfo(undefined)\n client\n .getSession(sessionId)\n .then((next) => {\n if (cancelled) {\n return\n }\n setInfo(next)\n setLoading(false)\n })\n .catch((e: unknown) => {\n if (cancelled) {\n return\n }\n setError(e instanceof Error ? e.message : 'Session not found')\n setLoading(false)\n })\n return () => {\n cancelled = true\n }\n }, [client, sessionId])\n\n return { info, loading, error }\n}\n","export type OpenFile = {\n path: string\n name: string\n status: 'loading' | 'ready' | 'binary' | 'error'\n content?: string\n draft?: string\n bytes?: number\n hash?: string\n modifiedAt?: number\n error?: string\n saving?: boolean\n saveError?: string\n conflict?: boolean\n}\n\nexport function isDirty(file: OpenFile): boolean {\n return file.draft !== undefined && file.draft !== file.content\n}\n\nexport function currentText(file: OpenFile): string {\n return file.draft ?? file.content ?? ''\n}\n\nexport type OpenFilesState = {\n files: OpenFile[]\n activePath?: string\n}\n\nexport type OpenFilesAction =\n | { type: 'open'; path: string }\n | { type: 'close'; path: string }\n | { type: 'closeAll' }\n | { type: 'activate'; path: string }\n | {\n type: 'loaded'\n path: string\n content: string\n encoding: 'utf8' | 'base64'\n bytes: number\n hash: string\n modifiedAt: number\n }\n | { type: 'failed'; path: string; error: string }\n | { type: 'edit'; path: string; content: string }\n | { type: 'revert'; path: string }\n | { type: 'saveStart'; path: string }\n | { type: 'saved'; path: string; content: string; bytes: number; hash: string; modifiedAt: number }\n | { type: 'saveFailed'; path: string; error: string; conflict?: boolean }\n | { type: 'dismissConflict'; path: string }\n\nexport const initialOpenFilesState: OpenFilesState = { files: [] }\n\nexport function openFilesReducer(state: OpenFilesState, action: OpenFilesAction): OpenFilesState {\n switch (action.type) {\n case 'open': {\n if (state.files.some((f) => f.path === action.path)) {\n return state.activePath === action.path ? state : { ...state, activePath: action.path }\n }\n const file: OpenFile = { path: action.path, name: baseName(action.path), status: 'loading' }\n return { files: [...state.files, file], activePath: action.path }\n }\n\n case 'close': {\n const index = state.files.findIndex((f) => f.path === action.path)\n if (index === -1) {\n return state\n }\n const files = state.files.filter((f) => f.path !== action.path)\n if (state.activePath !== action.path) {\n return { ...state, files }\n }\n // The right-hand neighbour has slid into this index; a closed last tab has nothing there.\n const next = files[index] ?? files[index - 1]\n return { files, activePath: next?.path }\n }\n\n case 'closeAll': {\n return initialOpenFilesState\n }\n\n case 'activate': {\n if (!state.files.some((f) => f.path === action.path)) {\n return state\n }\n return state.activePath === action.path ? state : { ...state, activePath: action.path }\n }\n\n case 'loaded': {\n return patch(state, action.path, () => ({\n path: action.path,\n name: baseName(action.path),\n status: action.encoding === 'utf8' ? 'ready' : 'binary',\n content: action.encoding === 'utf8' ? action.content : undefined,\n bytes: action.bytes,\n hash: action.hash,\n modifiedAt: action.modifiedAt,\n }))\n }\n\n case 'failed': {\n return patch(state, action.path, (file) => ({ ...file, status: 'error', error: action.error }))\n }\n\n case 'edit': {\n return patch(state, action.path, (file) => (file.status === 'ready' ? { ...file, draft: action.content } : file))\n }\n\n case 'revert': {\n return patch(state, action.path, (file) => ({\n ...file,\n draft: undefined,\n saveError: undefined,\n conflict: false,\n }))\n }\n\n case 'saveStart': {\n return patch(state, action.path, (file) => ({\n ...file,\n saving: true,\n saveError: undefined,\n conflict: false,\n }))\n }\n\n case 'saved': {\n return patch(state, action.path, (file) => ({\n ...file,\n saving: false,\n saveError: undefined,\n conflict: false,\n content: action.content,\n bytes: action.bytes,\n hash: action.hash,\n modifiedAt: action.modifiedAt,\n draft: file.draft === action.content ? undefined : file.draft,\n }))\n }\n\n case 'saveFailed': {\n return patch(state, action.path, (file) => ({\n ...file,\n saving: false,\n saveError: action.error,\n conflict: action.conflict ?? false,\n }))\n }\n\n case 'dismissConflict': {\n return patch(state, action.path, (file) => ({\n ...file,\n conflict: false,\n saveError: undefined,\n }))\n }\n }\n}\n\nfunction patch(state: OpenFilesState, path: string, next: (file: OpenFile) => OpenFile): OpenFilesState {\n const index = state.files.findIndex((f) => f.path === path)\n if (index === -1) {\n return state\n }\n const current = state.files[index]!\n const updated = next(current)\n if (updated === current) {\n return state\n }\n const files = state.files.slice()\n files[index] = updated\n return { ...state, files }\n}\n\nfunction baseName(path: string): string {\n const trimmed = path.endsWith('/') ? path.slice(0, -1) : path\n return trimmed.slice(trimmed.lastIndexOf('/') + 1) || trimmed || path\n}\n","import { useCallback, useEffect, useMemo, useReducer, useRef } from 'react'\nimport { WorkerDeckError, type WorkerDeckClient } from '@workerdeck/client'\nimport { currentText, initialOpenFilesState, isDirty, openFilesReducer, type OpenFile, type OpenFilesState } from '../lib/open-files.ts'\n\nexport type UseOpenFilesResult = OpenFilesState & {\n active: OpenFile | undefined\n hasUnsaved: boolean\n open: (path: string) => void\n close: (path: string) => void\n closeAll: () => void\n activate: (path: string) => void\n edit: (path: string, content: string) => void\n save: (path: string) => Promise<void>\n revert: (path: string) => void\n reload: (path: string) => void\n overwrite: (path: string) => Promise<void>\n dismissConflict: (path: string) => void\n}\n\nexport function useOpenFiles(client: WorkerDeckClient): UseOpenFilesResult {\n const [state, dispatch] = useReducer(openFilesReducer, initialOpenFilesState)\n\n const requested = useRef(new Set<string>())\n const alive = useRef(true)\n useEffect(() => {\n alive.current = true\n return () => {\n alive.current = false\n }\n }, [])\n\n const latest = useRef(state)\n useEffect(() => {\n latest.current = state\n }, [state])\n\n const loading = state.files.filter((f) => f.status === 'loading')\n // Joined so the effect's identity is the set of pending reads, not the array the reducer rebuilds.\n const pending = loading.map((f) => f.path).join('\\n')\n\n const read = useCallback(\n (path: string) =>\n client.readHostFile(path).then((response) => {\n if (!alive.current) {\n return undefined\n }\n dispatch({\n type: 'loaded',\n // The tab is keyed on the path asked for, never the canonical one the gateway answers with.\n path,\n content: response.content,\n encoding: response.encoding,\n bytes: response.bytes,\n hash: response.hash,\n modifiedAt: response.modifiedAt,\n })\n return response\n }),\n [client],\n )\n\n useEffect(() => {\n for (const path of pending ? pending.split('\\n') : []) {\n if (requested.current.has(path)) {\n continue\n }\n requested.current.add(path)\n read(path).catch((e: unknown) => {\n if (!alive.current) {\n return\n }\n dispatch({\n type: 'failed',\n path,\n error: e instanceof Error ? e.message : 'Could not read that file',\n })\n })\n }\n }, [read, pending])\n\n const open = useCallback((path: string) => dispatch({ type: 'open', path }), [])\n const close = useCallback((path: string) => {\n requested.current.delete(path)\n dispatch({ type: 'close', path })\n }, [])\n const closeAll = useCallback(() => {\n requested.current.clear()\n dispatch({ type: 'closeAll' })\n }, [])\n const activate = useCallback((path: string) => dispatch({ type: 'activate', path }), [])\n const edit = useCallback((path: string, content: string) => dispatch({ type: 'edit', path, content }), [])\n const revert = useCallback((path: string) => dispatch({ type: 'revert', path }), [])\n const dismissConflict = useCallback((path: string) => dispatch({ type: 'dismissConflict', path }), [])\n\n const reload = useCallback(\n (path: string) => {\n requested.current.add(path)\n read(path).catch((e: unknown) => {\n if (!alive.current) {\n return\n }\n dispatch({\n type: 'failed',\n path,\n error: e instanceof Error ? e.message : 'Could not re-read that file',\n })\n })\n },\n [read],\n )\n\n const write = useCallback(\n async (path: string, text: string, expectedHash: string | undefined) => {\n try {\n const response = await client.writeHostFile({ path, content: text, expectedHash })\n if (!alive.current) {\n return\n }\n dispatch({\n type: 'saved',\n path,\n content: text,\n bytes: response.bytes,\n hash: response.hash,\n modifiedAt: response.modifiedAt,\n })\n } catch (e) {\n if (!alive.current) {\n return\n }\n const conflict = e instanceof WorkerDeckError && e.status === 409\n dispatch({\n type: 'saveFailed',\n path,\n conflict,\n error: conflict ? 'This file changed on disk since you opened it.' : e instanceof Error ? e.message : 'Could not save that file',\n })\n }\n },\n [client],\n )\n\n const save = useCallback(\n async (path: string) => {\n const file = latest.current.files.find((f) => f.path === path)\n if (!file || file.saving || !isDirty(file)) {\n return\n }\n dispatch({ type: 'saveStart', path })\n await write(path, currentText(file), file.hash)\n },\n [write],\n )\n\n const overwrite = useCallback(\n async (path: string) => {\n const file = latest.current.files.find((f) => f.path === path)\n if (!file || file.saving) {\n return\n }\n // Captured before the re-read, whose `loaded` clears the draft - the one thing \"take mine\" must not do.\n const mine = currentText(file)\n dispatch({ type: 'saveStart', path })\n try {\n const fresh = await client.readHostFile(path)\n if (!alive.current) {\n return\n }\n await write(path, mine, fresh.hash)\n } catch (e) {\n if (!alive.current) {\n return\n }\n dispatch({\n type: 'saveFailed',\n path,\n error: e instanceof Error ? e.message : 'Could not save that file',\n })\n }\n },\n [client, write],\n )\n\n const active = useMemo(() => state.files.find((f) => f.path === state.activePath), [state.files, state.activePath])\n const hasUnsaved = useMemo(() => state.files.some(isDirty), [state.files])\n\n return {\n ...state,\n active,\n hasUnsaved,\n open,\n close,\n closeAll,\n activate,\n edit,\n save,\n revert,\n reload,\n overwrite,\n dismissConflict,\n }\n}\n","import type { SessionHandle } from '@workerdeck/client'\nimport type { RunScriptResult, SandboxEngine, SandboxVfs } from '@workerdeck/sandbox'\nimport type { ToolCallRequestFrame } from '@workerdeck/protocol'\n\nexport type ToolHostExecution = {\n executionId: string\n toolName: string\n status: 'running' | 'settled' | 'failed' | 'canceled'\n reason?: string\n startedAt: number\n endedAt?: number\n}\n\nexport type ToolHostRunner = (request: {\n script: string\n vfs: SandboxVfs\n timeoutMs: number\n memoryLimitBytes: number\n signal: AbortSignal\n}) => Promise<RunScriptResult>\n\nexport type ClientToolResult = { value: unknown } | { error: string; reason?: string }\n\nexport type ClientToolHandler = (\n input: unknown,\n context: { executionId: string; signal: AbortSignal },\n) => ClientToolResult | Promise<ClientToolResult>\n\nexport type ToolCallHostOptions = {\n tools?: string[]\n clientTools?: Record<string, ClientToolHandler>\n timeoutMs?: number\n memoryLimitBytes?: number\n loadEngine?: () => Promise<SandboxEngine>\n // The guest deadline preempts the interpreter only on the thread it runs on; a Web Worker is the way off this one.\n execute?: ToolHostRunner\n fetchText?: (url: string) => Promise<string>\n onExecution?: (execution: ToolHostExecution) => void\n}\n\nexport function createToolCallHost(handle: SessionHandle, options: ToolCallHostOptions = {}): { dispose: () => void } {\n const inFlight = new Map<string, AbortController>()\n let enginePromise: Promise<SandboxEngine> | undefined\n let disposed = false\n\n const track = (execution: ToolHostExecution) => options.onExecution?.(execution)\n\n const refuse = (frame: ToolCallRequestFrame, reason: string, error: string, startedAt: number) => {\n handle.sendToolCallError(frame.executionId, reason, error)\n track({\n executionId: frame.executionId,\n toolName: frame.toolName,\n status: 'failed',\n reason,\n startedAt,\n endedAt: Date.now(),\n })\n }\n\n const runClientTool = async (frame: ToolCallRequestFrame, handler: ClientToolHandler): Promise<void> => {\n const startedAt = Date.now()\n const controller = new AbortController()\n inFlight.set(frame.executionId, controller)\n track({ executionId: frame.executionId, toolName: frame.toolName, status: 'running', startedAt })\n\n try {\n const result = await handler(frame.input, {\n executionId: frame.executionId,\n signal: controller.signal,\n })\n if (disposed || !inFlight.has(frame.executionId)) {\n return\n }\n if ('error' in result) {\n handle.sendToolCallError(frame.executionId, result.reason ?? 'client_error', result.error)\n track({\n executionId: frame.executionId,\n toolName: frame.toolName,\n status: 'failed',\n reason: result.reason ?? 'client_error',\n startedAt,\n endedAt: Date.now(),\n })\n } else {\n handle.sendToolCallResult(frame.executionId, { type: 'json', value: result.value })\n track({\n executionId: frame.executionId,\n toolName: frame.toolName,\n status: 'settled',\n startedAt,\n endedAt: Date.now(),\n })\n }\n } catch (error) {\n if (disposed || !inFlight.has(frame.executionId)) {\n return\n }\n refuse(frame, 'host_error', error instanceof Error ? error.message : String(error), startedAt)\n } finally {\n inFlight.delete(frame.executionId)\n }\n }\n\n const run = async (frame: ToolCallRequestFrame): Promise<void> => {\n const startedAt = Date.now()\n const clientHandler = options.clientTools?.[frame.toolName]\n if (clientHandler) {\n return runClientTool(frame, clientHandler)\n }\n const allowed = options.tools ?? ['eval_script']\n if (!allowed.includes(frame.toolName)) {\n refuse(frame, 'unsupported_tool', `this client does not execute '${frame.toolName}'`, startedAt)\n return\n }\n const script = (frame.input as { script?: unknown } | undefined)?.script\n if (typeof script !== 'string') {\n refuse(frame, 'invalid_input', 'expected a string `script` input', startedAt)\n return\n }\n\n const controller = new AbortController()\n inFlight.set(frame.executionId, controller)\n track({ executionId: frame.executionId, toolName: frame.toolName, status: 'running', startedAt })\n\n try {\n const sandbox = await import('@workerdeck/sandbox')\n const vfs = sandbox.createVfs(frame.vfsSeed)\n // Never above what the server asked for: it owns the deadline it gives up at.\n const timeoutMs = Math.min(frame.limits?.timeoutMs ?? Number.POSITIVE_INFINITY, options.timeoutMs ?? 5000)\n const memoryLimitBytes = Math.min(\n frame.limits?.memoryLimitBytes ?? Number.POSITIVE_INFINITY,\n options.memoryLimitBytes ?? 64 * 1024 * 1024,\n )\n\n const result = options.execute\n ? await options.execute({ script, vfs, timeoutMs, memoryLimitBytes, signal: controller.signal })\n : await (async () => {\n enginePromise ??= (options.loadEngine ?? defaultLoadEngine)()\n return sandbox.runScript(await enginePromise, {\n script,\n vfs,\n timeoutMs,\n memoryLimitBytes,\n signal: controller.signal,\n fetchText: options.fetchText,\n })\n })()\n\n if (disposed || !inFlight.has(frame.executionId)) {\n return\n }\n const logs = result.logs.map((l) => `[${l.level}] ${l.text}`)\n if (result.ok) {\n handle.sendToolCallResult(frame.executionId, { type: 'json', value: result.value }, logs)\n track({\n executionId: frame.executionId,\n toolName: frame.toolName,\n status: 'settled',\n startedAt,\n endedAt: Date.now(),\n })\n } else {\n handle.sendToolCallError(frame.executionId, result.reason, result.error, logs)\n track({\n executionId: frame.executionId,\n toolName: frame.toolName,\n status: 'failed',\n reason: result.reason,\n startedAt,\n endedAt: Date.now(),\n })\n }\n } catch (error) {\n if (disposed || !inFlight.has(frame.executionId)) {\n return\n }\n refuse(frame, 'host_error', error instanceof Error ? error.message : String(error), startedAt)\n } finally {\n inFlight.delete(frame.executionId)\n }\n }\n\n const offRequest = handle.on('toolCallRequest', (frame) => void run(frame))\n const offCancel = handle.on('toolCallCanceled', ({ executionId, reason }) => {\n const controller = inFlight.get(executionId)\n if (!controller) {\n return\n }\n controller.abort()\n inFlight.delete(executionId)\n track({\n executionId,\n toolName: '',\n status: 'canceled',\n reason,\n startedAt: Date.now(),\n endedAt: Date.now(),\n })\n })\n\n return {\n dispose: () => {\n disposed = true\n offRequest()\n offCancel()\n for (const controller of inFlight.values()) {\n controller.abort()\n }\n inFlight.clear()\n },\n }\n}\n\nasync function defaultLoadEngine(): Promise<SandboxEngine> {\n const [sandbox, variant] = await Promise.all([import('@workerdeck/sandbox'), import('@jitl/quickjs-singlefile-browser-release-asyncify')])\n return sandbox.loadEngine(variant as never)\n}\n","import { useEffect, useRef, useState } from 'react'\nimport type { SessionHandle } from '@workerdeck/client'\nimport { createToolCallHost, type ToolCallHostOptions, type ToolHostExecution } from '../lib/tool-host.ts'\n\nexport type UseToolCallHostOptions = ToolCallHostOptions & {\n enabled?: boolean\n historyLimit?: number\n}\n\nexport function useToolCallHost(\n handle: SessionHandle | undefined,\n options: UseToolCallHostOptions = {},\n): { executions: ToolHostExecution[] } {\n const [executions, setExecutions] = useState<ToolHostExecution[]>([])\n const optionsRef = useRef(options)\n optionsRef.current = options\n\n useEffect(() => {\n if (!handle || options.enabled === false) {\n return\n }\n const host = createToolCallHost(handle, {\n // Getters read the ref at call time, so inline objects and closures never resubscribe.\n get tools() {\n const base = optionsRef.current.tools\n const client = optionsRef.current.clientTools\n if (!client) {\n return base\n }\n const clientNames = Object.keys(client)\n return base ? [...new Set([...base, ...clientNames])] : clientNames\n },\n get clientTools() {\n return optionsRef.current.clientTools\n },\n get timeoutMs() {\n return optionsRef.current.timeoutMs\n },\n get memoryLimitBytes() {\n return optionsRef.current.memoryLimitBytes\n },\n get loadEngine() {\n return optionsRef.current.loadEngine\n },\n get execute() {\n return optionsRef.current.execute\n },\n get fetchText() {\n return optionsRef.current.fetchText\n },\n onExecution: (execution) => {\n optionsRef.current.onExecution?.(execution)\n const limit = optionsRef.current.historyLimit ?? 50\n setExecutions((prev) => [...prev.filter((e) => e.executionId !== execution.executionId), execution].slice(-limit))\n },\n })\n return () => host.dispose()\n }, [handle, options.enabled])\n\n return { executions }\n}\n","import type { TranscriptItem } from './transcript.ts'\n\nexport type RecapSummary = {\n turns: number\n replies: number\n tools: number\n toolNames: string[]\n files: number\n errors: number\n pending: number\n any: boolean\n}\n\nexport type RecapInput = {\n items: readonly TranscriptItem[]\n pendingApprovals?: readonly unknown[]\n}\n\n// The boundary is clamped, never rejected: a transcript can shrink (a `/clear`, a compaction).\nexport function summarizeSince(state: RecapInput, fromIndex: number): RecapSummary {\n const start = Math.max(0, Math.min(fromIndex, state.items.length))\n const fresh = state.items.slice(start)\n const toolCounts = new Map<string, number>()\n let turns = 0\n let replies = 0\n let tools = 0\n let files = 0\n let errors = 0\n\n for (const item of fresh) {\n switch (item.kind) {\n case 'turn_result': {\n turns += 1\n if (item.isError) {\n errors += 1\n }\n break\n }\n case 'assistant_text': {\n replies += 1\n break\n }\n case 'tool_call': {\n tools += 1\n toolCounts.set(item.name, (toolCounts.get(item.name) ?? 0) + 1)\n if (item.status === 'failed' || item.result?.isError) {\n errors += 1\n }\n break\n }\n case 'file_delivered': {\n files += 1\n break\n }\n case 'notice': {\n if (item.level === 'error') {\n errors += 1\n }\n break\n }\n default: {\n break\n }\n }\n }\n\n const toolNames = [...toolCounts.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).map(([name]) => name)\n const pending = state.pendingApprovals?.length ?? 0\n return {\n turns,\n replies,\n tools,\n toolNames,\n files,\n errors,\n pending,\n any: turns + replies + tools + files + errors + pending > 0,\n }\n}\n\nexport function recapLine(summary: RecapSummary): string | undefined {\n if (!summary.any) {\n return undefined\n }\n const parts: string[] = []\n if (summary.turns > 0) {\n parts.push(plural(summary.turns, 'turn'))\n } else if (summary.replies > 0) {\n parts.push(plural(summary.replies, 'reply', 'replies'))\n }\n if (summary.tools > 0) {\n const named = summary.toolNames.slice(0, 3).join(', ')\n const rest = summary.toolNames.length - 3\n parts.push(`${plural(summary.tools, 'tool call')}${named ? ` (${named}${rest > 0 ? `, +${rest}` : ''})` : ''}`)\n }\n if (summary.files > 0) {\n parts.push(plural(summary.files, 'file'))\n }\n if (summary.errors > 0) {\n parts.push(plural(summary.errors, 'error'))\n }\n if (summary.pending > 0) {\n parts.push(`${plural(summary.pending, 'approval')} waiting`)\n }\n return parts.join(' · ')\n}\n\nfunction plural(count: number, one: string, many = `${one}s`): string {\n return `${count} ${count === 1 ? one : many}`\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport type { SessionHandle } from '@workerdeck/client'\nimport type { ShellInfo } from '@workerdeck/protocol'\n\nexport type ShellTerminalSize = { cols: number; rows: number }\n\nexport type ShellTerminalStatus = 'idle' | 'attaching' | 'attached' | 'detached'\n\nexport type ShellAttachment = {\n shell: ShellInfo\n cols: number\n rows: number\n scrollback: string\n}\n\nexport type UseShellTerminalOptions = {\n onData: (data: string) => void\n onEnded?: (reason: string) => void\n onAttached?: (attachment: ShellAttachment) => void\n}\n\nexport type UseShellTerminalResult = {\n status: ShellTerminalStatus\n shell: ShellInfo | undefined\n reason: string | undefined\n attach: (size: ShellTerminalSize) => void\n write: (data: string) => void\n resize: (size: ShellTerminalSize) => void\n detach: () => void\n}\n\n// PTY bytes never enter React state, the transcript reducer or the transcript cache: they go\n// straight to the caller's renderer through a ref, so a noisy `npm run dev` re-renders nothing.\nexport function useShellTerminal(\n handle: SessionHandle | undefined,\n shellId: string | undefined,\n options: UseShellTerminalOptions,\n): UseShellTerminalResult {\n const [status, setStatus] = useState<ShellTerminalStatus>('idle')\n const [shell, setShell] = useState<ShellInfo | undefined>(undefined)\n const [reason, setReason] = useState<string | undefined>(undefined)\n const optionsRef = useRef(options)\n optionsRef.current = options\n const sizeRef = useRef<ShellTerminalSize>({ cols: 80, rows: 24 })\n const wantAttachRef = useRef(false)\n\n useEffect(() => {\n wantAttachRef.current = false\n setStatus('idle')\n setShell(undefined)\n setReason(undefined)\n }, [handle, shellId])\n\n useEffect(() => {\n if (!handle || shellId === undefined) {\n return\n }\n const offAttached = handle.on('shellAttached', (frame) => {\n if (frame.shellId !== shellId) {\n return\n }\n sizeRef.current = { cols: frame.cols, rows: frame.rows }\n setShell(frame.shell)\n setReason(undefined)\n setStatus('attached')\n const attachment: ShellAttachment = { shell: frame.shell, cols: frame.cols, rows: frame.rows, scrollback: frame.scrollback }\n if (optionsRef.current.onAttached) {\n optionsRef.current.onAttached(attachment)\n } else if (frame.scrollback) {\n optionsRef.current.onData(frame.scrollback)\n }\n })\n const offOutput = handle.on('shellOutput', (frame) => {\n if (frame.shellId === shellId) {\n optionsRef.current.onData(frame.data)\n }\n })\n const offDetached = handle.on('shellDetached', (frame) => {\n if (frame.shellId !== shellId) {\n return\n }\n wantAttachRef.current = false\n setReason(frame.reason)\n setStatus('detached')\n optionsRef.current.onEnded?.(frame.reason)\n })\n // A shell outlives the socket, so a reconnect re-attaches and the gateway replays the\n // scrollback into a reset screen rather than leaving a live pane frozen.\n const offConnection = handle.on('connectionChange', (connected) => {\n if (!wantAttachRef.current) {\n return\n }\n if (connected) {\n setStatus('attaching')\n handle.attachShell(shellId, sizeRef.current)\n } else {\n setStatus((current) => (current === 'attached' ? 'attaching' : current))\n }\n })\n return () => {\n offAttached()\n offOutput()\n offDetached()\n offConnection()\n if (wantAttachRef.current) {\n wantAttachRef.current = false\n handle.detachShell(shellId)\n }\n }\n }, [handle, shellId])\n\n const attach = useCallback(\n (size: ShellTerminalSize) => {\n if (!handle || shellId === undefined) {\n return\n }\n sizeRef.current = size\n wantAttachRef.current = true\n setReason(undefined)\n setStatus('attaching')\n handle.attachShell(shellId, size)\n },\n [handle, shellId],\n )\n\n const write = useCallback(\n (data: string) => {\n if (handle && shellId !== undefined) {\n handle.writeShell(shellId, data)\n }\n },\n [handle, shellId],\n )\n\n const resize = useCallback(\n (size: ShellTerminalSize) => {\n if (size.cols === sizeRef.current.cols && size.rows === sizeRef.current.rows) {\n return\n }\n sizeRef.current = size\n if (handle && shellId !== undefined && wantAttachRef.current) {\n handle.resizeShell(shellId, size)\n }\n },\n [handle, shellId],\n )\n\n const detach = useCallback(() => {\n if (handle && shellId !== undefined && wantAttachRef.current) {\n handle.detachShell(shellId)\n }\n wantAttachRef.current = false\n setStatus('idle')\n }, [handle, shellId])\n\n return useMemo(() => ({ status, shell, reason, attach, write, resize, detach }), [status, shell, reason, attach, write, resize, detach])\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@workerdeck/react",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.14.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Headless React layer for WorkerDeck: session hook + pure transcript and sessions-list reducers. No styling opinion - @workerdeck/ui is the styled layer on top.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -17,9 +17,9 @@
|
|
|
17
17
|
}
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@workerdeck/client": "2.
|
|
21
|
-
"@workerdeck/
|
|
22
|
-
"@workerdeck/
|
|
20
|
+
"@workerdeck/client": "2.14.0",
|
|
21
|
+
"@workerdeck/sandbox": "2.14.0",
|
|
22
|
+
"@workerdeck/protocol": "2.14.0"
|
|
23
23
|
},
|
|
24
24
|
"peerDependencies": {
|
|
25
25
|
"@jitl/quickjs-singlefile-browser-release-asyncify": "^0.31.0",
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
"tsdown": "^0.22.14",
|
|
42
42
|
"vitest": "^4.1.11",
|
|
43
43
|
"ws": "^8.21.3",
|
|
44
|
-
"@workerdeck/
|
|
45
|
-
"@workerdeck/
|
|
44
|
+
"@workerdeck/core": "2.14.0",
|
|
45
|
+
"@workerdeck/server": "2.14.0"
|
|
46
46
|
},
|
|
47
47
|
"author": "Tobias Strebitzer",
|
|
48
48
|
"repository": {
|