@workerdeck/react 3.0.1 → 3.2.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 +28 -3
- package/build/index.mjs +314 -171
- package/build/index.mjs.map +1 -1
- package/package.json +6 -6
package/build/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { useCallback, useEffect, useMemo, useReducer, useRef, useState } from "react";
|
|
2
|
-
import { DEFAULT_PRICING, ENGINE_CAPABILITIES, PEER_MENTION_SIGIL, PROMPT_SENTENCE_TAIL, PROTOCOL_VERSION, isPeerMentionBody, mergePricing, mergeUsage, orderUsageWindows, peerMentionKey, peerMentionSlug, sessionLabel } from "@workerdeck/protocol";
|
|
1
|
+
import { useCallback, useEffect, useMemo, useReducer, useRef, useState, useSyncExternalStore } from "react";
|
|
3
2
|
import { WorkerDeckError } from "@workerdeck/client";
|
|
3
|
+
import { DEFAULT_PRICING, ENGINE_CAPABILITIES, PEER_MENTION_SIGIL, PROMPT_SENTENCE_TAIL, PROTOCOL_VERSION, errorMessage, isPeerMentionBody, mergePricing, mergeUsage, orderUsageWindows, peerMentionKey, peerMentionSlug, sessionLabel } from "@workerdeck/protocol";
|
|
4
4
|
//#region src/lib/transcript.ts
|
|
5
5
|
const initialTranscriptState = {
|
|
6
6
|
status: "starting",
|
|
@@ -94,13 +94,22 @@ function slashCommandText(text) {
|
|
|
94
94
|
const args = COMMAND_ARGS.exec(text)?.[1]?.trim();
|
|
95
95
|
return args ? `${name} ${args}` : name;
|
|
96
96
|
}
|
|
97
|
-
function
|
|
98
|
-
|
|
97
|
+
function findLastIndexOf(items, kind, id) {
|
|
98
|
+
for (let index = items.length - 1; index >= 0; index--) {
|
|
99
|
+
const item = items[index];
|
|
100
|
+
if (item?.id === id && item.kind === kind) return index;
|
|
101
|
+
}
|
|
102
|
+
return -1;
|
|
103
|
+
}
|
|
104
|
+
function replaceAt(items, index, item) {
|
|
99
105
|
if (index === -1) return [...items, item];
|
|
100
106
|
const next = [...items];
|
|
101
107
|
next[index] = item;
|
|
102
108
|
return next;
|
|
103
109
|
}
|
|
110
|
+
function upsert(items, item) {
|
|
111
|
+
return replaceAt(items, items.findIndex((existing) => existing.id === item.id && existing.kind === item.kind), item);
|
|
112
|
+
}
|
|
104
113
|
function seedFromSessionInfo(state, info) {
|
|
105
114
|
const engine = info.engine ?? state.engine;
|
|
106
115
|
return {
|
|
@@ -372,21 +381,23 @@ function applyEvent(state, event) {
|
|
|
372
381
|
if (delta.type !== "content_block_delta") return base;
|
|
373
382
|
if (delta.delta?.type === "text_delta") {
|
|
374
383
|
const id = streamingTextId(event.parentToolUseId);
|
|
384
|
+
const index = findLastIndexOf(base.items, "assistant_text", id);
|
|
375
385
|
const item = {
|
|
376
386
|
kind: "assistant_text",
|
|
377
387
|
id,
|
|
378
|
-
text: (
|
|
388
|
+
text: ((index === -1 ? void 0 : base.items[index])?.text ?? "") + (delta.delta.text ?? ""),
|
|
379
389
|
streaming: true,
|
|
380
390
|
parentToolUseId: event.parentToolUseId
|
|
381
391
|
};
|
|
382
392
|
return {
|
|
383
393
|
...base,
|
|
384
|
-
items:
|
|
394
|
+
items: replaceAt(base.items, index, item)
|
|
385
395
|
};
|
|
386
396
|
}
|
|
387
397
|
if (delta.delta?.type === "thinking_delta") {
|
|
388
398
|
const id = streamingThinkingId(event.parentToolUseId);
|
|
389
|
-
const
|
|
399
|
+
const index = findLastIndexOf(base.items, "thinking", id);
|
|
400
|
+
const text = ((index === -1 ? void 0 : base.items[index])?.text ?? "") + (delta.delta.thinking ?? "");
|
|
390
401
|
if (text.trim() === "") return base;
|
|
391
402
|
const item = {
|
|
392
403
|
kind: "thinking",
|
|
@@ -396,7 +407,7 @@ function applyEvent(state, event) {
|
|
|
396
407
|
};
|
|
397
408
|
return {
|
|
398
409
|
...base,
|
|
399
|
-
items:
|
|
410
|
+
items: replaceAt(base.items, index, item)
|
|
400
411
|
};
|
|
401
412
|
}
|
|
402
413
|
return base;
|
|
@@ -697,8 +708,8 @@ function useClaudeSession(client, sessionId, options) {
|
|
|
697
708
|
text
|
|
698
709
|
});
|
|
699
710
|
return true;
|
|
700
|
-
} catch {
|
|
701
|
-
dispatch({
|
|
711
|
+
} catch (error) {
|
|
712
|
+
if (isNotFound(error)) dispatch({
|
|
702
713
|
type: "transcript_hydrate_shell",
|
|
703
714
|
shellId,
|
|
704
715
|
shell: void 0
|
|
@@ -707,8 +718,9 @@ function useClaudeSession(client, sessionId, options) {
|
|
|
707
718
|
}
|
|
708
719
|
}, [client, sessionId]);
|
|
709
720
|
const verifyShell = useCallback(async (shellId) => {
|
|
710
|
-
|
|
711
|
-
|
|
721
|
+
const verified = verifiedRef.current;
|
|
722
|
+
if (!sessionId || verified.has(shellId)) return false;
|
|
723
|
+
verified.add(shellId);
|
|
712
724
|
try {
|
|
713
725
|
const record = await client.getShell(sessionId, shellId);
|
|
714
726
|
dispatch({
|
|
@@ -717,12 +729,13 @@ function useClaudeSession(client, sessionId, options) {
|
|
|
717
729
|
shell: record
|
|
718
730
|
});
|
|
719
731
|
return true;
|
|
720
|
-
} catch {
|
|
721
|
-
dispatch({
|
|
732
|
+
} catch (error) {
|
|
733
|
+
if (isNotFound(error)) dispatch({
|
|
722
734
|
type: "transcript_hydrate_shell",
|
|
723
735
|
shellId,
|
|
724
736
|
shell: void 0
|
|
725
737
|
});
|
|
738
|
+
else verified.delete(shellId);
|
|
726
739
|
return false;
|
|
727
740
|
}
|
|
728
741
|
}, [client, sessionId]);
|
|
@@ -754,6 +767,17 @@ function useClaudeSession(client, sessionId, options) {
|
|
|
754
767
|
return false;
|
|
755
768
|
}
|
|
756
769
|
}, [client, sessionId]);
|
|
770
|
+
const actions = useMemo(() => ({
|
|
771
|
+
send: (text, attachmentIds) => handleRef.current?.send(text, attachmentIds),
|
|
772
|
+
approve: (requestId, updatedInput) => handleRef.current?.approve(requestId, updatedInput),
|
|
773
|
+
deny: (requestId, message, interrupt) => handleRef.current?.deny(requestId, message, interrupt),
|
|
774
|
+
interrupt: () => handleRef.current?.interrupt(),
|
|
775
|
+
clearContext: () => handleRef.current?.clearContext(),
|
|
776
|
+
runShell: (command) => handleRef.current?.runShell(command),
|
|
777
|
+
setPermissionMode: (mode) => handleRef.current?.setPermissionMode(mode),
|
|
778
|
+
setModel: (model) => handleRef.current?.setModel(model),
|
|
779
|
+
closeSession: () => handleRef.current?.closeSession()
|
|
780
|
+
}), []);
|
|
757
781
|
return useMemo(() => ({
|
|
758
782
|
state,
|
|
759
783
|
connected,
|
|
@@ -765,15 +789,7 @@ function useClaudeSession(client, sessionId, options) {
|
|
|
765
789
|
models,
|
|
766
790
|
effectiveModel: state.model ?? state.defaultModel,
|
|
767
791
|
handle: handleState,
|
|
768
|
-
|
|
769
|
-
approve: (requestId, updatedInput) => handleRef.current?.approve(requestId, updatedInput),
|
|
770
|
-
deny: (requestId, message, interrupt) => handleRef.current?.deny(requestId, message, interrupt),
|
|
771
|
-
interrupt: () => handleRef.current?.interrupt(),
|
|
772
|
-
clearContext: () => handleRef.current?.clearContext(),
|
|
773
|
-
runShell: (command) => handleRef.current?.runShell(command),
|
|
774
|
-
setPermissionMode: (mode) => handleRef.current?.setPermissionMode(mode),
|
|
775
|
-
setModel: (model) => handleRef.current?.setModel(model),
|
|
776
|
-
closeSession: () => handleRef.current?.closeSession(),
|
|
792
|
+
...actions,
|
|
777
793
|
reconnectNow,
|
|
778
794
|
loadFullResult,
|
|
779
795
|
loadShellOutput,
|
|
@@ -790,6 +806,7 @@ function useClaudeSession(client, sessionId, options) {
|
|
|
790
806
|
pricing,
|
|
791
807
|
models,
|
|
792
808
|
handleState,
|
|
809
|
+
actions,
|
|
793
810
|
reconnectNow,
|
|
794
811
|
loadFullResult,
|
|
795
812
|
loadShellOutput,
|
|
@@ -798,6 +815,9 @@ function useClaudeSession(client, sessionId, options) {
|
|
|
798
815
|
setShellAgentWrite
|
|
799
816
|
]);
|
|
800
817
|
}
|
|
818
|
+
function isNotFound(error) {
|
|
819
|
+
return error instanceof WorkerDeckError && error.status === 404;
|
|
820
|
+
}
|
|
801
821
|
function useProfileModelFallback(client, sessionId, state) {
|
|
802
822
|
const [catalog, setCatalog] = useState([]);
|
|
803
823
|
const profile = state.session?.profile;
|
|
@@ -841,7 +861,7 @@ function clearProfileUsageCache() {
|
|
|
841
861
|
const KEY = "workerdeck.drafts.v1";
|
|
842
862
|
const MAX_DRAFTS = 20;
|
|
843
863
|
let memory;
|
|
844
|
-
function storage() {
|
|
864
|
+
function storage$1() {
|
|
845
865
|
try {
|
|
846
866
|
return globalThis.localStorage;
|
|
847
867
|
} catch {
|
|
@@ -851,7 +871,7 @@ function storage() {
|
|
|
851
871
|
function load() {
|
|
852
872
|
if (memory) return memory;
|
|
853
873
|
memory = {};
|
|
854
|
-
const raw = storage()?.getItem(KEY);
|
|
874
|
+
const raw = storage$1()?.getItem(KEY);
|
|
855
875
|
if (raw) try {
|
|
856
876
|
const parsed = JSON.parse(raw);
|
|
857
877
|
for (const [key, draft] of Object.entries(parsed)) if (typeof draft?.text === "string" && typeof draft.savedAt === "number") memory[key] = draft;
|
|
@@ -865,7 +885,7 @@ function persist(drafts) {
|
|
|
865
885
|
for (const [key] of entries.slice(MAX_DRAFTS)) delete drafts[key];
|
|
866
886
|
}
|
|
867
887
|
try {
|
|
868
|
-
storage()?.setItem(KEY, JSON.stringify(drafts));
|
|
888
|
+
storage$1()?.setItem(KEY, JSON.stringify(drafts));
|
|
869
889
|
} catch {}
|
|
870
890
|
}
|
|
871
891
|
function draftKey(client, sessionId) {
|
|
@@ -888,7 +908,7 @@ function writeDraft(key, text, now = Date.now()) {
|
|
|
888
908
|
function clearDrafts() {
|
|
889
909
|
memory = {};
|
|
890
910
|
try {
|
|
891
|
-
storage()?.removeItem(KEY);
|
|
911
|
+
storage$1()?.removeItem(KEY);
|
|
892
912
|
} catch {}
|
|
893
913
|
}
|
|
894
914
|
//#endregion
|
|
@@ -951,7 +971,7 @@ function useAttachments(client, sessionId, { capabilities, engine }) {
|
|
|
951
971
|
} catch (e) {
|
|
952
972
|
patch(key, {
|
|
953
973
|
status: "failed",
|
|
954
|
-
error: e
|
|
974
|
+
error: errorMessage(e, "Upload failed")
|
|
955
975
|
});
|
|
956
976
|
}
|
|
957
977
|
})();
|
|
@@ -1140,6 +1160,58 @@ function useAliveRef() {
|
|
|
1140
1160
|
function isRouteUnsupported(e) {
|
|
1141
1161
|
return e instanceof WorkerDeckError && e.status === 404;
|
|
1142
1162
|
}
|
|
1163
|
+
function useAsync(load, deps, { enabled = true, pollMs } = {}) {
|
|
1164
|
+
const [data, setData] = useState();
|
|
1165
|
+
const [error, setError] = useState();
|
|
1166
|
+
const [loading, setLoading] = useState(enabled);
|
|
1167
|
+
const generation = useRef(0);
|
|
1168
|
+
const loadRef = useRef(load);
|
|
1169
|
+
loadRef.current = load;
|
|
1170
|
+
const run = useCallback(async () => {
|
|
1171
|
+
const id = ++generation.current;
|
|
1172
|
+
setLoading(true);
|
|
1173
|
+
try {
|
|
1174
|
+
const next = await loadRef.current();
|
|
1175
|
+
if (id === generation.current) {
|
|
1176
|
+
setData(() => next);
|
|
1177
|
+
setError(void 0);
|
|
1178
|
+
}
|
|
1179
|
+
} catch (e) {
|
|
1180
|
+
if (id === generation.current) setError(e);
|
|
1181
|
+
} finally {
|
|
1182
|
+
if (id === generation.current) setLoading(false);
|
|
1183
|
+
}
|
|
1184
|
+
}, []);
|
|
1185
|
+
useEffect(() => {
|
|
1186
|
+
setData(void 0);
|
|
1187
|
+
setError(void 0);
|
|
1188
|
+
}, deps);
|
|
1189
|
+
useEffect(() => {
|
|
1190
|
+
if (!enabled) {
|
|
1191
|
+
generation.current++;
|
|
1192
|
+
setLoading(false);
|
|
1193
|
+
return;
|
|
1194
|
+
}
|
|
1195
|
+
run();
|
|
1196
|
+
const timer = pollMs ? setInterval(() => void run(), pollMs) : void 0;
|
|
1197
|
+
return () => {
|
|
1198
|
+
generation.current++;
|
|
1199
|
+
clearInterval(timer);
|
|
1200
|
+
};
|
|
1201
|
+
}, [
|
|
1202
|
+
enabled,
|
|
1203
|
+
pollMs,
|
|
1204
|
+
run,
|
|
1205
|
+
...deps
|
|
1206
|
+
]);
|
|
1207
|
+
return {
|
|
1208
|
+
data,
|
|
1209
|
+
error,
|
|
1210
|
+
loading,
|
|
1211
|
+
reload: run,
|
|
1212
|
+
setData
|
|
1213
|
+
};
|
|
1214
|
+
}
|
|
1143
1215
|
//#endregion
|
|
1144
1216
|
//#region src/lib/host-tree.ts
|
|
1145
1217
|
function flattenHostTree(root, dirs, expanded) {
|
|
@@ -1287,7 +1359,7 @@ function useHostFileTree(client, cwd) {
|
|
|
1287
1359
|
setUnsupported(true);
|
|
1288
1360
|
return;
|
|
1289
1361
|
}
|
|
1290
|
-
setError(e
|
|
1362
|
+
setError(errorMessage(e, "Could not read that directory"));
|
|
1291
1363
|
});
|
|
1292
1364
|
}, [client, unsupported]);
|
|
1293
1365
|
useEffect(() => {
|
|
@@ -1337,7 +1409,7 @@ function useHostFileTree(client, cwd) {
|
|
|
1337
1409
|
}
|
|
1338
1410
|
//#endregion
|
|
1339
1411
|
//#region src/hooks/use-peer-sessions.ts
|
|
1340
|
-
const EMPTY = {
|
|
1412
|
+
const EMPTY$1 = {
|
|
1341
1413
|
available: false,
|
|
1342
1414
|
peers: [],
|
|
1343
1415
|
names: []
|
|
@@ -1370,7 +1442,7 @@ function usePeerSessions(client, sessionId, enabled = true) {
|
|
|
1370
1442
|
unsupported
|
|
1371
1443
|
]);
|
|
1372
1444
|
return useMemo(() => {
|
|
1373
|
-
if (!enabled || unsupported || !sessions) return EMPTY;
|
|
1445
|
+
if (!enabled || unsupported || !sessions) return EMPTY$1;
|
|
1374
1446
|
const peers = sessions.filter((info) => info.id !== sessionId).sort((a, b) => (b.lastActivityAt ?? b.createdAt) - (a.lastActivityAt ?? a.createdAt)).map((info) => ({
|
|
1375
1447
|
id: info.id,
|
|
1376
1448
|
slug: peerMentionSlug(info.title, info.id),
|
|
@@ -1424,6 +1496,111 @@ function useProjectIcons(rows, clientFor) {
|
|
|
1424
1496
|
return resolved;
|
|
1425
1497
|
}
|
|
1426
1498
|
//#endregion
|
|
1499
|
+
//#region src/lib/bookmark-store.ts
|
|
1500
|
+
const BOOKMARKS_STORAGE_KEY = "workerdeck.bookmarks.v1";
|
|
1501
|
+
const EMPTY = Object.freeze([]);
|
|
1502
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
1503
|
+
let loaded;
|
|
1504
|
+
let detachStorageEvent;
|
|
1505
|
+
function storage() {
|
|
1506
|
+
try {
|
|
1507
|
+
return globalThis.localStorage ?? void 0;
|
|
1508
|
+
} catch {
|
|
1509
|
+
return;
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
function storageEvents() {
|
|
1513
|
+
const target = globalThis.window;
|
|
1514
|
+
return typeof target?.addEventListener === "function" ? target : void 0;
|
|
1515
|
+
}
|
|
1516
|
+
function readStored() {
|
|
1517
|
+
try {
|
|
1518
|
+
const raw = storage()?.getItem(BOOKMARKS_STORAGE_KEY);
|
|
1519
|
+
if (raw == null) return {};
|
|
1520
|
+
const parsed = JSON.parse(raw);
|
|
1521
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return {};
|
|
1522
|
+
const map = {};
|
|
1523
|
+
for (const [key, value] of Object.entries(parsed)) if (Array.isArray(value)) map[key] = value.filter((id) => typeof id === "string");
|
|
1524
|
+
return map;
|
|
1525
|
+
} catch {
|
|
1526
|
+
return;
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
function sameIds(a, b) {
|
|
1530
|
+
return a.length === b.length && a.every((id, index) => id === b[index]);
|
|
1531
|
+
}
|
|
1532
|
+
function adopt(next) {
|
|
1533
|
+
const previous = loaded ?? {};
|
|
1534
|
+
const merged = {};
|
|
1535
|
+
for (const [key, ids] of Object.entries(next)) {
|
|
1536
|
+
const held = previous[key];
|
|
1537
|
+
merged[key] = held && sameIds(held, ids) ? held : ids;
|
|
1538
|
+
}
|
|
1539
|
+
loaded = merged;
|
|
1540
|
+
}
|
|
1541
|
+
function current() {
|
|
1542
|
+
if (loaded === void 0) adopt(readStored() ?? {});
|
|
1543
|
+
return loaded ?? {};
|
|
1544
|
+
}
|
|
1545
|
+
function notify() {
|
|
1546
|
+
for (const listener of listeners) listener();
|
|
1547
|
+
}
|
|
1548
|
+
function bookmarksFor(sessionKey) {
|
|
1549
|
+
return current()[sessionKey] ?? EMPTY;
|
|
1550
|
+
}
|
|
1551
|
+
function toggleBookmark(sessionKey, itemId) {
|
|
1552
|
+
const base = readStored() ?? current();
|
|
1553
|
+
const held = base[sessionKey] ?? EMPTY;
|
|
1554
|
+
const ids = held.includes(itemId) ? held.filter((id) => id !== itemId) : [...held, itemId];
|
|
1555
|
+
const next = {
|
|
1556
|
+
...base,
|
|
1557
|
+
[sessionKey]: ids
|
|
1558
|
+
};
|
|
1559
|
+
if (ids.length === 0) delete next[sessionKey];
|
|
1560
|
+
try {
|
|
1561
|
+
storage()?.setItem(BOOKMARKS_STORAGE_KEY, JSON.stringify(next));
|
|
1562
|
+
} catch {}
|
|
1563
|
+
adopt(next);
|
|
1564
|
+
notify();
|
|
1565
|
+
}
|
|
1566
|
+
function onStorage(event) {
|
|
1567
|
+
if (event.key !== null && event.key !== "workerdeck.bookmarks.v1") return;
|
|
1568
|
+
const stored = readStored();
|
|
1569
|
+
if (stored) {
|
|
1570
|
+
adopt(stored);
|
|
1571
|
+
notify();
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
function subscribeBookmarks(listener) {
|
|
1575
|
+
listeners.add(listener);
|
|
1576
|
+
const target = storageEvents();
|
|
1577
|
+
if (listeners.size === 1 && target) {
|
|
1578
|
+
target.addEventListener("storage", onStorage);
|
|
1579
|
+
detachStorageEvent = () => target.removeEventListener("storage", onStorage);
|
|
1580
|
+
}
|
|
1581
|
+
return () => {
|
|
1582
|
+
listeners.delete(listener);
|
|
1583
|
+
if (listeners.size === 0) {
|
|
1584
|
+
detachStorageEvent?.();
|
|
1585
|
+
detachStorageEvent = void 0;
|
|
1586
|
+
}
|
|
1587
|
+
};
|
|
1588
|
+
}
|
|
1589
|
+
//#endregion
|
|
1590
|
+
//#region src/hooks/use-bookmarks.ts
|
|
1591
|
+
const NONE = Object.freeze([]);
|
|
1592
|
+
function useBookmarks(sessionKey) {
|
|
1593
|
+
const read = useCallback(() => sessionKey ? bookmarksFor(sessionKey) : NONE, [sessionKey]);
|
|
1594
|
+
const bookmarks = useSyncExternalStore(subscribeBookmarks, read, () => NONE);
|
|
1595
|
+
const toggle = useCallback((itemId) => {
|
|
1596
|
+
if (sessionKey) toggleBookmark(sessionKey, itemId);
|
|
1597
|
+
}, [sessionKey]);
|
|
1598
|
+
return useMemo(() => ({
|
|
1599
|
+
bookmarks,
|
|
1600
|
+
toggle
|
|
1601
|
+
}), [bookmarks, toggle]);
|
|
1602
|
+
}
|
|
1603
|
+
//#endregion
|
|
1427
1604
|
//#region src/hooks/use-draft.ts
|
|
1428
1605
|
function useDraft(client, sessionId) {
|
|
1429
1606
|
const key = sessionId ? draftKey(client, sessionId) : void 0;
|
|
@@ -1493,37 +1670,11 @@ function useProfileUsage(client, profile, options = {}) {
|
|
|
1493
1670
|
//#endregion
|
|
1494
1671
|
//#region src/hooks/use-session-info.ts
|
|
1495
1672
|
function useSessionInfo(client, sessionId) {
|
|
1496
|
-
const
|
|
1497
|
-
const [loading, setLoading] = useState(!!sessionId);
|
|
1498
|
-
const [error, setError] = useState();
|
|
1499
|
-
useEffect(() => {
|
|
1500
|
-
if (!sessionId) {
|
|
1501
|
-
setInfo(void 0);
|
|
1502
|
-
setLoading(false);
|
|
1503
|
-
setError(void 0);
|
|
1504
|
-
return;
|
|
1505
|
-
}
|
|
1506
|
-
let cancelled = false;
|
|
1507
|
-
setLoading(true);
|
|
1508
|
-
setError(void 0);
|
|
1509
|
-
setInfo(void 0);
|
|
1510
|
-
client.getSession(sessionId).then((next) => {
|
|
1511
|
-
if (cancelled) return;
|
|
1512
|
-
setInfo(next);
|
|
1513
|
-
setLoading(false);
|
|
1514
|
-
}).catch((e) => {
|
|
1515
|
-
if (cancelled) return;
|
|
1516
|
-
setError(e instanceof Error ? e.message : "Session not found");
|
|
1517
|
-
setLoading(false);
|
|
1518
|
-
});
|
|
1519
|
-
return () => {
|
|
1520
|
-
cancelled = true;
|
|
1521
|
-
};
|
|
1522
|
-
}, [client, sessionId]);
|
|
1673
|
+
const { data, error, loading } = useAsync(() => client.getSession(sessionId), [client, sessionId], { enabled: !!sessionId });
|
|
1523
1674
|
return {
|
|
1524
|
-
info,
|
|
1675
|
+
info: data,
|
|
1525
1676
|
loading,
|
|
1526
|
-
error
|
|
1677
|
+
error: error === void 0 ? void 0 : errorMessage(error, "Session not found")
|
|
1527
1678
|
};
|
|
1528
1679
|
}
|
|
1529
1680
|
//#endregion
|
|
@@ -1682,7 +1833,7 @@ function useOpenFiles(client) {
|
|
|
1682
1833
|
dispatch({
|
|
1683
1834
|
type: "failed",
|
|
1684
1835
|
path,
|
|
1685
|
-
error: e
|
|
1836
|
+
error: errorMessage(e, "Could not read that file")
|
|
1686
1837
|
});
|
|
1687
1838
|
});
|
|
1688
1839
|
}
|
|
@@ -1726,7 +1877,7 @@ function useOpenFiles(client) {
|
|
|
1726
1877
|
dispatch({
|
|
1727
1878
|
type: "failed",
|
|
1728
1879
|
path,
|
|
1729
|
-
error: e
|
|
1880
|
+
error: errorMessage(e, "Could not re-read that file")
|
|
1730
1881
|
});
|
|
1731
1882
|
});
|
|
1732
1883
|
}, [read]);
|
|
@@ -1753,7 +1904,7 @@ function useOpenFiles(client) {
|
|
|
1753
1904
|
type: "saveFailed",
|
|
1754
1905
|
path,
|
|
1755
1906
|
conflict,
|
|
1756
|
-
error: conflict ? "This file changed on disk since you opened it." : e
|
|
1907
|
+
error: conflict ? "This file changed on disk since you opened it." : errorMessage(e, "Could not save that file")
|
|
1757
1908
|
});
|
|
1758
1909
|
}
|
|
1759
1910
|
}, [client]);
|
|
@@ -1783,7 +1934,7 @@ function useOpenFiles(client) {
|
|
|
1783
1934
|
dispatch({
|
|
1784
1935
|
type: "saveFailed",
|
|
1785
1936
|
path,
|
|
1786
|
-
error: e
|
|
1937
|
+
error: errorMessage(e, "Could not save that file")
|
|
1787
1938
|
});
|
|
1788
1939
|
}
|
|
1789
1940
|
}, [client, write]);
|
|
@@ -1812,19 +1963,33 @@ function createToolCallHost(handle, options = {}) {
|
|
|
1812
1963
|
let enginePromise;
|
|
1813
1964
|
let disposed = false;
|
|
1814
1965
|
const track = (execution) => options.onExecution?.(execution);
|
|
1815
|
-
const
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1966
|
+
const settle = (frame, startedAt, outcome) => {
|
|
1967
|
+
const { executionId, toolName } = frame;
|
|
1968
|
+
if (outcome.ok) {
|
|
1969
|
+
handle.sendToolCallResult(executionId, {
|
|
1970
|
+
type: "json",
|
|
1971
|
+
value: outcome.value
|
|
1972
|
+
}, outcome.logs);
|
|
1973
|
+
track({
|
|
1974
|
+
executionId,
|
|
1975
|
+
toolName,
|
|
1976
|
+
status: "settled",
|
|
1977
|
+
startedAt,
|
|
1978
|
+
endedAt: Date.now()
|
|
1979
|
+
});
|
|
1980
|
+
} else {
|
|
1981
|
+
handle.sendToolCallError(executionId, outcome.reason, outcome.error, outcome.logs);
|
|
1982
|
+
track({
|
|
1983
|
+
executionId,
|
|
1984
|
+
toolName,
|
|
1985
|
+
status: "failed",
|
|
1986
|
+
reason: outcome.reason,
|
|
1987
|
+
startedAt,
|
|
1988
|
+
endedAt: Date.now()
|
|
1989
|
+
});
|
|
1990
|
+
}
|
|
1825
1991
|
};
|
|
1826
|
-
const
|
|
1827
|
-
const startedAt = Date.now();
|
|
1992
|
+
const execute = async (frame, startedAt, work) => {
|
|
1828
1993
|
const controller = new AbortController();
|
|
1829
1994
|
inFlight.set(frame.executionId, controller);
|
|
1830
1995
|
track({
|
|
@@ -1833,116 +1998,94 @@ function createToolCallHost(handle, options = {}) {
|
|
|
1833
1998
|
status: "running",
|
|
1834
1999
|
startedAt
|
|
1835
2000
|
});
|
|
2001
|
+
let outcome;
|
|
1836
2002
|
try {
|
|
1837
|
-
|
|
1838
|
-
executionId: frame.executionId,
|
|
1839
|
-
signal: controller.signal
|
|
1840
|
-
});
|
|
1841
|
-
if (disposed || !inFlight.has(frame.executionId)) return;
|
|
1842
|
-
if ("error" in result) {
|
|
1843
|
-
handle.sendToolCallError(frame.executionId, result.reason ?? "client_error", result.error);
|
|
1844
|
-
track({
|
|
1845
|
-
executionId: frame.executionId,
|
|
1846
|
-
toolName: frame.toolName,
|
|
1847
|
-
status: "failed",
|
|
1848
|
-
reason: result.reason ?? "client_error",
|
|
1849
|
-
startedAt,
|
|
1850
|
-
endedAt: Date.now()
|
|
1851
|
-
});
|
|
1852
|
-
} else {
|
|
1853
|
-
handle.sendToolCallResult(frame.executionId, {
|
|
1854
|
-
type: "json",
|
|
1855
|
-
value: result.value
|
|
1856
|
-
});
|
|
1857
|
-
track({
|
|
1858
|
-
executionId: frame.executionId,
|
|
1859
|
-
toolName: frame.toolName,
|
|
1860
|
-
status: "settled",
|
|
1861
|
-
startedAt,
|
|
1862
|
-
endedAt: Date.now()
|
|
1863
|
-
});
|
|
1864
|
-
}
|
|
2003
|
+
outcome = await work(controller.signal);
|
|
1865
2004
|
} catch (error) {
|
|
1866
|
-
|
|
1867
|
-
|
|
2005
|
+
outcome = {
|
|
2006
|
+
ok: false,
|
|
2007
|
+
reason: "host_error",
|
|
2008
|
+
error: errorMessage(error)
|
|
2009
|
+
};
|
|
2010
|
+
}
|
|
2011
|
+
try {
|
|
2012
|
+
if (!disposed && inFlight.has(frame.executionId)) settle(frame, startedAt, outcome);
|
|
1868
2013
|
} finally {
|
|
1869
2014
|
inFlight.delete(frame.executionId);
|
|
1870
2015
|
}
|
|
1871
2016
|
};
|
|
2017
|
+
const runClientTool = (frame, handler, startedAt) => execute(frame, startedAt, async (signal) => {
|
|
2018
|
+
const result = await handler(frame.input, {
|
|
2019
|
+
executionId: frame.executionId,
|
|
2020
|
+
signal
|
|
2021
|
+
});
|
|
2022
|
+
return "error" in result ? {
|
|
2023
|
+
ok: false,
|
|
2024
|
+
reason: result.reason ?? "client_error",
|
|
2025
|
+
error: result.error
|
|
2026
|
+
} : {
|
|
2027
|
+
ok: true,
|
|
2028
|
+
value: result.value
|
|
2029
|
+
};
|
|
2030
|
+
});
|
|
2031
|
+
const runScript = (frame, script, startedAt) => execute(frame, startedAt, async (signal) => {
|
|
2032
|
+
const sandbox = await import("@workerdeck/sandbox");
|
|
2033
|
+
const vfs = sandbox.createVfs(frame.vfsSeed);
|
|
2034
|
+
const timeoutMs = Math.min(frame.limits?.timeoutMs ?? Number.POSITIVE_INFINITY, options.timeoutMs ?? 5e3);
|
|
2035
|
+
const memoryLimitBytes = Math.min(frame.limits?.memoryLimitBytes ?? Number.POSITIVE_INFINITY, options.memoryLimitBytes ?? 67108864);
|
|
2036
|
+
let result;
|
|
2037
|
+
if (options.execute) result = await options.execute({
|
|
2038
|
+
script,
|
|
2039
|
+
vfs,
|
|
2040
|
+
timeoutMs,
|
|
2041
|
+
memoryLimitBytes,
|
|
2042
|
+
signal
|
|
2043
|
+
});
|
|
2044
|
+
else {
|
|
2045
|
+
enginePromise ??= (options.loadEngine ?? defaultLoadEngine)();
|
|
2046
|
+
result = await sandbox.runScript(await enginePromise, {
|
|
2047
|
+
script,
|
|
2048
|
+
vfs,
|
|
2049
|
+
timeoutMs,
|
|
2050
|
+
memoryLimitBytes,
|
|
2051
|
+
signal,
|
|
2052
|
+
fetchText: options.fetchText
|
|
2053
|
+
});
|
|
2054
|
+
}
|
|
2055
|
+
const logs = result.logs.map((l) => `[${l.level}] ${l.text}`);
|
|
2056
|
+
return result.ok ? {
|
|
2057
|
+
ok: true,
|
|
2058
|
+
value: result.value,
|
|
2059
|
+
logs
|
|
2060
|
+
} : {
|
|
2061
|
+
ok: false,
|
|
2062
|
+
reason: result.reason,
|
|
2063
|
+
error: result.error,
|
|
2064
|
+
logs
|
|
2065
|
+
};
|
|
2066
|
+
});
|
|
1872
2067
|
const run = async (frame) => {
|
|
1873
2068
|
const startedAt = Date.now();
|
|
1874
2069
|
const clientHandler = options.clientTools?.[frame.toolName];
|
|
1875
|
-
if (clientHandler) return runClientTool(frame, clientHandler);
|
|
2070
|
+
if (clientHandler) return runClientTool(frame, clientHandler, startedAt);
|
|
1876
2071
|
if (!(options.tools ?? ["eval_script"]).includes(frame.toolName)) {
|
|
1877
|
-
|
|
2072
|
+
settle(frame, startedAt, {
|
|
2073
|
+
ok: false,
|
|
2074
|
+
reason: "unsupported_tool",
|
|
2075
|
+
error: `this client does not execute '${frame.toolName}'`
|
|
2076
|
+
});
|
|
1878
2077
|
return;
|
|
1879
2078
|
}
|
|
1880
2079
|
const script = frame.input?.script;
|
|
1881
2080
|
if (typeof script !== "string") {
|
|
1882
|
-
|
|
2081
|
+
settle(frame, startedAt, {
|
|
2082
|
+
ok: false,
|
|
2083
|
+
reason: "invalid_input",
|
|
2084
|
+
error: "expected a string `script` input"
|
|
2085
|
+
});
|
|
1883
2086
|
return;
|
|
1884
2087
|
}
|
|
1885
|
-
|
|
1886
|
-
inFlight.set(frame.executionId, controller);
|
|
1887
|
-
track({
|
|
1888
|
-
executionId: frame.executionId,
|
|
1889
|
-
toolName: frame.toolName,
|
|
1890
|
-
status: "running",
|
|
1891
|
-
startedAt
|
|
1892
|
-
});
|
|
1893
|
-
try {
|
|
1894
|
-
const sandbox = await import("@workerdeck/sandbox");
|
|
1895
|
-
const vfs = sandbox.createVfs(frame.vfsSeed);
|
|
1896
|
-
const timeoutMs = Math.min(frame.limits?.timeoutMs ?? Number.POSITIVE_INFINITY, options.timeoutMs ?? 5e3);
|
|
1897
|
-
const memoryLimitBytes = Math.min(frame.limits?.memoryLimitBytes ?? Number.POSITIVE_INFINITY, options.memoryLimitBytes ?? 67108864);
|
|
1898
|
-
const result = options.execute ? await options.execute({
|
|
1899
|
-
script,
|
|
1900
|
-
vfs,
|
|
1901
|
-
timeoutMs,
|
|
1902
|
-
memoryLimitBytes,
|
|
1903
|
-
signal: controller.signal
|
|
1904
|
-
}) : await (async () => {
|
|
1905
|
-
enginePromise ??= (options.loadEngine ?? defaultLoadEngine)();
|
|
1906
|
-
return sandbox.runScript(await enginePromise, {
|
|
1907
|
-
script,
|
|
1908
|
-
vfs,
|
|
1909
|
-
timeoutMs,
|
|
1910
|
-
memoryLimitBytes,
|
|
1911
|
-
signal: controller.signal,
|
|
1912
|
-
fetchText: options.fetchText
|
|
1913
|
-
});
|
|
1914
|
-
})();
|
|
1915
|
-
if (disposed || !inFlight.has(frame.executionId)) return;
|
|
1916
|
-
const logs = result.logs.map((l) => `[${l.level}] ${l.text}`);
|
|
1917
|
-
if (result.ok) {
|
|
1918
|
-
handle.sendToolCallResult(frame.executionId, {
|
|
1919
|
-
type: "json",
|
|
1920
|
-
value: result.value
|
|
1921
|
-
}, logs);
|
|
1922
|
-
track({
|
|
1923
|
-
executionId: frame.executionId,
|
|
1924
|
-
toolName: frame.toolName,
|
|
1925
|
-
status: "settled",
|
|
1926
|
-
startedAt,
|
|
1927
|
-
endedAt: Date.now()
|
|
1928
|
-
});
|
|
1929
|
-
} else {
|
|
1930
|
-
handle.sendToolCallError(frame.executionId, result.reason, result.error, logs);
|
|
1931
|
-
track({
|
|
1932
|
-
executionId: frame.executionId,
|
|
1933
|
-
toolName: frame.toolName,
|
|
1934
|
-
status: "failed",
|
|
1935
|
-
reason: result.reason,
|
|
1936
|
-
startedAt,
|
|
1937
|
-
endedAt: Date.now()
|
|
1938
|
-
});
|
|
1939
|
-
}
|
|
1940
|
-
} catch (error) {
|
|
1941
|
-
if (disposed || !inFlight.has(frame.executionId)) return;
|
|
1942
|
-
refuse(frame, "host_error", error instanceof Error ? error.message : String(error), startedAt);
|
|
1943
|
-
} finally {
|
|
1944
|
-
inFlight.delete(frame.executionId);
|
|
1945
|
-
}
|
|
2088
|
+
return runScript(frame, script, startedAt);
|
|
1946
2089
|
};
|
|
1947
2090
|
const offRequest = handle.on("toolCallRequest", (frame) => void run(frame));
|
|
1948
2091
|
const offCancel = handle.on("toolCallCanceled", ({ executionId, reason }) => {
|
|
@@ -2182,6 +2325,6 @@ function useShellTerminal(handle, shellId, options) {
|
|
|
2182
2325
|
]);
|
|
2183
2326
|
}
|
|
2184
2327
|
//#endregion
|
|
2185
|
-
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 };
|
|
2328
|
+
export { BOOKMARKS_STORAGE_KEY, 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, useAsync, useAttachments, useBookmarks, useClaudeSession, useDraft, useHostFileRoots, useHostFileSearch, useHostFileTree, useOpenFiles, usePeerSessions, useProfileUsage, useProjectIcons, useSessionInfo, useShellTerminal, useToolCallHost };
|
|
2186
2329
|
|
|
2187
2330
|
//# sourceMappingURL=index.mjs.map
|