@workerdeck/react 2.15.0 → 3.1.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 +29 -3
- package/build/index.mjs +332 -173
- 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]);
|
|
@@ -740,6 +753,31 @@ function useClaudeSession(client, sessionId, options) {
|
|
|
740
753
|
return false;
|
|
741
754
|
}
|
|
742
755
|
}, [client, sessionId]);
|
|
756
|
+
const setShellAgentWrite = useCallback(async (shellId, enabled) => {
|
|
757
|
+
if (!sessionId) return false;
|
|
758
|
+
try {
|
|
759
|
+
const record = await client.setShellAgentWrite(sessionId, shellId, enabled);
|
|
760
|
+
dispatch({
|
|
761
|
+
type: "transcript_hydrate_shell",
|
|
762
|
+
shellId,
|
|
763
|
+
shell: record
|
|
764
|
+
});
|
|
765
|
+
return true;
|
|
766
|
+
} catch {
|
|
767
|
+
return false;
|
|
768
|
+
}
|
|
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
|
+
}), []);
|
|
743
781
|
return useMemo(() => ({
|
|
744
782
|
state,
|
|
745
783
|
connected,
|
|
@@ -751,20 +789,13 @@ function useClaudeSession(client, sessionId, options) {
|
|
|
751
789
|
models,
|
|
752
790
|
effectiveModel: state.model ?? state.defaultModel,
|
|
753
791
|
handle: handleState,
|
|
754
|
-
|
|
755
|
-
approve: (requestId, updatedInput) => handleRef.current?.approve(requestId, updatedInput),
|
|
756
|
-
deny: (requestId, message, interrupt) => handleRef.current?.deny(requestId, message, interrupt),
|
|
757
|
-
interrupt: () => handleRef.current?.interrupt(),
|
|
758
|
-
clearContext: () => handleRef.current?.clearContext(),
|
|
759
|
-
runShell: (command) => handleRef.current?.runShell(command),
|
|
760
|
-
setPermissionMode: (mode) => handleRef.current?.setPermissionMode(mode),
|
|
761
|
-
setModel: (model) => handleRef.current?.setModel(model),
|
|
762
|
-
closeSession: () => handleRef.current?.closeSession(),
|
|
792
|
+
...actions,
|
|
763
793
|
reconnectNow,
|
|
764
794
|
loadFullResult,
|
|
765
795
|
loadShellOutput,
|
|
766
796
|
verifyShell,
|
|
767
|
-
killShell
|
|
797
|
+
killShell,
|
|
798
|
+
setShellAgentWrite
|
|
768
799
|
}), [
|
|
769
800
|
state,
|
|
770
801
|
connected,
|
|
@@ -775,13 +806,18 @@ function useClaudeSession(client, sessionId, options) {
|
|
|
775
806
|
pricing,
|
|
776
807
|
models,
|
|
777
808
|
handleState,
|
|
809
|
+
actions,
|
|
778
810
|
reconnectNow,
|
|
779
811
|
loadFullResult,
|
|
780
812
|
loadShellOutput,
|
|
781
813
|
verifyShell,
|
|
782
|
-
killShell
|
|
814
|
+
killShell,
|
|
815
|
+
setShellAgentWrite
|
|
783
816
|
]);
|
|
784
817
|
}
|
|
818
|
+
function isNotFound(error) {
|
|
819
|
+
return error instanceof WorkerDeckError && error.status === 404;
|
|
820
|
+
}
|
|
785
821
|
function useProfileModelFallback(client, sessionId, state) {
|
|
786
822
|
const [catalog, setCatalog] = useState([]);
|
|
787
823
|
const profile = state.session?.profile;
|
|
@@ -825,7 +861,7 @@ function clearProfileUsageCache() {
|
|
|
825
861
|
const KEY = "workerdeck.drafts.v1";
|
|
826
862
|
const MAX_DRAFTS = 20;
|
|
827
863
|
let memory;
|
|
828
|
-
function storage() {
|
|
864
|
+
function storage$1() {
|
|
829
865
|
try {
|
|
830
866
|
return globalThis.localStorage;
|
|
831
867
|
} catch {
|
|
@@ -835,7 +871,7 @@ function storage() {
|
|
|
835
871
|
function load() {
|
|
836
872
|
if (memory) return memory;
|
|
837
873
|
memory = {};
|
|
838
|
-
const raw = storage()?.getItem(KEY);
|
|
874
|
+
const raw = storage$1()?.getItem(KEY);
|
|
839
875
|
if (raw) try {
|
|
840
876
|
const parsed = JSON.parse(raw);
|
|
841
877
|
for (const [key, draft] of Object.entries(parsed)) if (typeof draft?.text === "string" && typeof draft.savedAt === "number") memory[key] = draft;
|
|
@@ -849,7 +885,7 @@ function persist(drafts) {
|
|
|
849
885
|
for (const [key] of entries.slice(MAX_DRAFTS)) delete drafts[key];
|
|
850
886
|
}
|
|
851
887
|
try {
|
|
852
|
-
storage()?.setItem(KEY, JSON.stringify(drafts));
|
|
888
|
+
storage$1()?.setItem(KEY, JSON.stringify(drafts));
|
|
853
889
|
} catch {}
|
|
854
890
|
}
|
|
855
891
|
function draftKey(client, sessionId) {
|
|
@@ -872,7 +908,7 @@ function writeDraft(key, text, now = Date.now()) {
|
|
|
872
908
|
function clearDrafts() {
|
|
873
909
|
memory = {};
|
|
874
910
|
try {
|
|
875
|
-
storage()?.removeItem(KEY);
|
|
911
|
+
storage$1()?.removeItem(KEY);
|
|
876
912
|
} catch {}
|
|
877
913
|
}
|
|
878
914
|
//#endregion
|
|
@@ -935,7 +971,7 @@ function useAttachments(client, sessionId, { capabilities, engine }) {
|
|
|
935
971
|
} catch (e) {
|
|
936
972
|
patch(key, {
|
|
937
973
|
status: "failed",
|
|
938
|
-
error: e
|
|
974
|
+
error: errorMessage(e, "Upload failed")
|
|
939
975
|
});
|
|
940
976
|
}
|
|
941
977
|
})();
|
|
@@ -1124,6 +1160,58 @@ function useAliveRef() {
|
|
|
1124
1160
|
function isRouteUnsupported(e) {
|
|
1125
1161
|
return e instanceof WorkerDeckError && e.status === 404;
|
|
1126
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
|
+
}
|
|
1127
1215
|
//#endregion
|
|
1128
1216
|
//#region src/lib/host-tree.ts
|
|
1129
1217
|
function flattenHostTree(root, dirs, expanded) {
|
|
@@ -1271,7 +1359,7 @@ function useHostFileTree(client, cwd) {
|
|
|
1271
1359
|
setUnsupported(true);
|
|
1272
1360
|
return;
|
|
1273
1361
|
}
|
|
1274
|
-
setError(e
|
|
1362
|
+
setError(errorMessage(e, "Could not read that directory"));
|
|
1275
1363
|
});
|
|
1276
1364
|
}, [client, unsupported]);
|
|
1277
1365
|
useEffect(() => {
|
|
@@ -1321,7 +1409,7 @@ function useHostFileTree(client, cwd) {
|
|
|
1321
1409
|
}
|
|
1322
1410
|
//#endregion
|
|
1323
1411
|
//#region src/hooks/use-peer-sessions.ts
|
|
1324
|
-
const EMPTY = {
|
|
1412
|
+
const EMPTY$1 = {
|
|
1325
1413
|
available: false,
|
|
1326
1414
|
peers: [],
|
|
1327
1415
|
names: []
|
|
@@ -1354,7 +1442,7 @@ function usePeerSessions(client, sessionId, enabled = true) {
|
|
|
1354
1442
|
unsupported
|
|
1355
1443
|
]);
|
|
1356
1444
|
return useMemo(() => {
|
|
1357
|
-
if (!enabled || unsupported || !sessions) return EMPTY;
|
|
1445
|
+
if (!enabled || unsupported || !sessions) return EMPTY$1;
|
|
1358
1446
|
const peers = sessions.filter((info) => info.id !== sessionId).sort((a, b) => (b.lastActivityAt ?? b.createdAt) - (a.lastActivityAt ?? a.createdAt)).map((info) => ({
|
|
1359
1447
|
id: info.id,
|
|
1360
1448
|
slug: peerMentionSlug(info.title, info.id),
|
|
@@ -1408,6 +1496,111 @@ function useProjectIcons(rows, clientFor) {
|
|
|
1408
1496
|
return resolved;
|
|
1409
1497
|
}
|
|
1410
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
|
|
1411
1604
|
//#region src/hooks/use-draft.ts
|
|
1412
1605
|
function useDraft(client, sessionId) {
|
|
1413
1606
|
const key = sessionId ? draftKey(client, sessionId) : void 0;
|
|
@@ -1477,37 +1670,11 @@ function useProfileUsage(client, profile, options = {}) {
|
|
|
1477
1670
|
//#endregion
|
|
1478
1671
|
//#region src/hooks/use-session-info.ts
|
|
1479
1672
|
function useSessionInfo(client, sessionId) {
|
|
1480
|
-
const
|
|
1481
|
-
const [loading, setLoading] = useState(!!sessionId);
|
|
1482
|
-
const [error, setError] = useState();
|
|
1483
|
-
useEffect(() => {
|
|
1484
|
-
if (!sessionId) {
|
|
1485
|
-
setInfo(void 0);
|
|
1486
|
-
setLoading(false);
|
|
1487
|
-
setError(void 0);
|
|
1488
|
-
return;
|
|
1489
|
-
}
|
|
1490
|
-
let cancelled = false;
|
|
1491
|
-
setLoading(true);
|
|
1492
|
-
setError(void 0);
|
|
1493
|
-
setInfo(void 0);
|
|
1494
|
-
client.getSession(sessionId).then((next) => {
|
|
1495
|
-
if (cancelled) return;
|
|
1496
|
-
setInfo(next);
|
|
1497
|
-
setLoading(false);
|
|
1498
|
-
}).catch((e) => {
|
|
1499
|
-
if (cancelled) return;
|
|
1500
|
-
setError(e instanceof Error ? e.message : "Session not found");
|
|
1501
|
-
setLoading(false);
|
|
1502
|
-
});
|
|
1503
|
-
return () => {
|
|
1504
|
-
cancelled = true;
|
|
1505
|
-
};
|
|
1506
|
-
}, [client, sessionId]);
|
|
1673
|
+
const { data, error, loading } = useAsync(() => client.getSession(sessionId), [client, sessionId], { enabled: !!sessionId });
|
|
1507
1674
|
return {
|
|
1508
|
-
info,
|
|
1675
|
+
info: data,
|
|
1509
1676
|
loading,
|
|
1510
|
-
error
|
|
1677
|
+
error: error === void 0 ? void 0 : errorMessage(error, "Session not found")
|
|
1511
1678
|
};
|
|
1512
1679
|
}
|
|
1513
1680
|
//#endregion
|
|
@@ -1666,7 +1833,7 @@ function useOpenFiles(client) {
|
|
|
1666
1833
|
dispatch({
|
|
1667
1834
|
type: "failed",
|
|
1668
1835
|
path,
|
|
1669
|
-
error: e
|
|
1836
|
+
error: errorMessage(e, "Could not read that file")
|
|
1670
1837
|
});
|
|
1671
1838
|
});
|
|
1672
1839
|
}
|
|
@@ -1710,7 +1877,7 @@ function useOpenFiles(client) {
|
|
|
1710
1877
|
dispatch({
|
|
1711
1878
|
type: "failed",
|
|
1712
1879
|
path,
|
|
1713
|
-
error: e
|
|
1880
|
+
error: errorMessage(e, "Could not re-read that file")
|
|
1714
1881
|
});
|
|
1715
1882
|
});
|
|
1716
1883
|
}, [read]);
|
|
@@ -1737,7 +1904,7 @@ function useOpenFiles(client) {
|
|
|
1737
1904
|
type: "saveFailed",
|
|
1738
1905
|
path,
|
|
1739
1906
|
conflict,
|
|
1740
|
-
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")
|
|
1741
1908
|
});
|
|
1742
1909
|
}
|
|
1743
1910
|
}, [client]);
|
|
@@ -1767,7 +1934,7 @@ function useOpenFiles(client) {
|
|
|
1767
1934
|
dispatch({
|
|
1768
1935
|
type: "saveFailed",
|
|
1769
1936
|
path,
|
|
1770
|
-
error: e
|
|
1937
|
+
error: errorMessage(e, "Could not save that file")
|
|
1771
1938
|
});
|
|
1772
1939
|
}
|
|
1773
1940
|
}, [client, write]);
|
|
@@ -1796,19 +1963,33 @@ function createToolCallHost(handle, options = {}) {
|
|
|
1796
1963
|
let enginePromise;
|
|
1797
1964
|
let disposed = false;
|
|
1798
1965
|
const track = (execution) => options.onExecution?.(execution);
|
|
1799
|
-
const
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
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
|
+
}
|
|
1809
1991
|
};
|
|
1810
|
-
const
|
|
1811
|
-
const startedAt = Date.now();
|
|
1992
|
+
const execute = async (frame, startedAt, work) => {
|
|
1812
1993
|
const controller = new AbortController();
|
|
1813
1994
|
inFlight.set(frame.executionId, controller);
|
|
1814
1995
|
track({
|
|
@@ -1817,116 +1998,94 @@ function createToolCallHost(handle, options = {}) {
|
|
|
1817
1998
|
status: "running",
|
|
1818
1999
|
startedAt
|
|
1819
2000
|
});
|
|
2001
|
+
let outcome;
|
|
1820
2002
|
try {
|
|
1821
|
-
|
|
1822
|
-
executionId: frame.executionId,
|
|
1823
|
-
signal: controller.signal
|
|
1824
|
-
});
|
|
1825
|
-
if (disposed || !inFlight.has(frame.executionId)) return;
|
|
1826
|
-
if ("error" in result) {
|
|
1827
|
-
handle.sendToolCallError(frame.executionId, result.reason ?? "client_error", result.error);
|
|
1828
|
-
track({
|
|
1829
|
-
executionId: frame.executionId,
|
|
1830
|
-
toolName: frame.toolName,
|
|
1831
|
-
status: "failed",
|
|
1832
|
-
reason: result.reason ?? "client_error",
|
|
1833
|
-
startedAt,
|
|
1834
|
-
endedAt: Date.now()
|
|
1835
|
-
});
|
|
1836
|
-
} else {
|
|
1837
|
-
handle.sendToolCallResult(frame.executionId, {
|
|
1838
|
-
type: "json",
|
|
1839
|
-
value: result.value
|
|
1840
|
-
});
|
|
1841
|
-
track({
|
|
1842
|
-
executionId: frame.executionId,
|
|
1843
|
-
toolName: frame.toolName,
|
|
1844
|
-
status: "settled",
|
|
1845
|
-
startedAt,
|
|
1846
|
-
endedAt: Date.now()
|
|
1847
|
-
});
|
|
1848
|
-
}
|
|
2003
|
+
outcome = await work(controller.signal);
|
|
1849
2004
|
} catch (error) {
|
|
1850
|
-
|
|
1851
|
-
|
|
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);
|
|
1852
2013
|
} finally {
|
|
1853
2014
|
inFlight.delete(frame.executionId);
|
|
1854
2015
|
}
|
|
1855
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
|
+
});
|
|
1856
2067
|
const run = async (frame) => {
|
|
1857
2068
|
const startedAt = Date.now();
|
|
1858
2069
|
const clientHandler = options.clientTools?.[frame.toolName];
|
|
1859
|
-
if (clientHandler) return runClientTool(frame, clientHandler);
|
|
2070
|
+
if (clientHandler) return runClientTool(frame, clientHandler, startedAt);
|
|
1860
2071
|
if (!(options.tools ?? ["eval_script"]).includes(frame.toolName)) {
|
|
1861
|
-
|
|
2072
|
+
settle(frame, startedAt, {
|
|
2073
|
+
ok: false,
|
|
2074
|
+
reason: "unsupported_tool",
|
|
2075
|
+
error: `this client does not execute '${frame.toolName}'`
|
|
2076
|
+
});
|
|
1862
2077
|
return;
|
|
1863
2078
|
}
|
|
1864
2079
|
const script = frame.input?.script;
|
|
1865
2080
|
if (typeof script !== "string") {
|
|
1866
|
-
|
|
2081
|
+
settle(frame, startedAt, {
|
|
2082
|
+
ok: false,
|
|
2083
|
+
reason: "invalid_input",
|
|
2084
|
+
error: "expected a string `script` input"
|
|
2085
|
+
});
|
|
1867
2086
|
return;
|
|
1868
2087
|
}
|
|
1869
|
-
|
|
1870
|
-
inFlight.set(frame.executionId, controller);
|
|
1871
|
-
track({
|
|
1872
|
-
executionId: frame.executionId,
|
|
1873
|
-
toolName: frame.toolName,
|
|
1874
|
-
status: "running",
|
|
1875
|
-
startedAt
|
|
1876
|
-
});
|
|
1877
|
-
try {
|
|
1878
|
-
const sandbox = await import("@workerdeck/sandbox");
|
|
1879
|
-
const vfs = sandbox.createVfs(frame.vfsSeed);
|
|
1880
|
-
const timeoutMs = Math.min(frame.limits?.timeoutMs ?? Number.POSITIVE_INFINITY, options.timeoutMs ?? 5e3);
|
|
1881
|
-
const memoryLimitBytes = Math.min(frame.limits?.memoryLimitBytes ?? Number.POSITIVE_INFINITY, options.memoryLimitBytes ?? 67108864);
|
|
1882
|
-
const result = options.execute ? await options.execute({
|
|
1883
|
-
script,
|
|
1884
|
-
vfs,
|
|
1885
|
-
timeoutMs,
|
|
1886
|
-
memoryLimitBytes,
|
|
1887
|
-
signal: controller.signal
|
|
1888
|
-
}) : await (async () => {
|
|
1889
|
-
enginePromise ??= (options.loadEngine ?? defaultLoadEngine)();
|
|
1890
|
-
return sandbox.runScript(await enginePromise, {
|
|
1891
|
-
script,
|
|
1892
|
-
vfs,
|
|
1893
|
-
timeoutMs,
|
|
1894
|
-
memoryLimitBytes,
|
|
1895
|
-
signal: controller.signal,
|
|
1896
|
-
fetchText: options.fetchText
|
|
1897
|
-
});
|
|
1898
|
-
})();
|
|
1899
|
-
if (disposed || !inFlight.has(frame.executionId)) return;
|
|
1900
|
-
const logs = result.logs.map((l) => `[${l.level}] ${l.text}`);
|
|
1901
|
-
if (result.ok) {
|
|
1902
|
-
handle.sendToolCallResult(frame.executionId, {
|
|
1903
|
-
type: "json",
|
|
1904
|
-
value: result.value
|
|
1905
|
-
}, logs);
|
|
1906
|
-
track({
|
|
1907
|
-
executionId: frame.executionId,
|
|
1908
|
-
toolName: frame.toolName,
|
|
1909
|
-
status: "settled",
|
|
1910
|
-
startedAt,
|
|
1911
|
-
endedAt: Date.now()
|
|
1912
|
-
});
|
|
1913
|
-
} else {
|
|
1914
|
-
handle.sendToolCallError(frame.executionId, result.reason, result.error, logs);
|
|
1915
|
-
track({
|
|
1916
|
-
executionId: frame.executionId,
|
|
1917
|
-
toolName: frame.toolName,
|
|
1918
|
-
status: "failed",
|
|
1919
|
-
reason: result.reason,
|
|
1920
|
-
startedAt,
|
|
1921
|
-
endedAt: Date.now()
|
|
1922
|
-
});
|
|
1923
|
-
}
|
|
1924
|
-
} catch (error) {
|
|
1925
|
-
if (disposed || !inFlight.has(frame.executionId)) return;
|
|
1926
|
-
refuse(frame, "host_error", error instanceof Error ? error.message : String(error), startedAt);
|
|
1927
|
-
} finally {
|
|
1928
|
-
inFlight.delete(frame.executionId);
|
|
1929
|
-
}
|
|
2088
|
+
return runScript(frame, script, startedAt);
|
|
1930
2089
|
};
|
|
1931
2090
|
const offRequest = handle.on("toolCallRequest", (frame) => void run(frame));
|
|
1932
2091
|
const offCancel = handle.on("toolCallCanceled", ({ executionId, reason }) => {
|
|
@@ -2166,6 +2325,6 @@ function useShellTerminal(handle, shellId, options) {
|
|
|
2166
2325
|
]);
|
|
2167
2326
|
}
|
|
2168
2327
|
//#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 };
|
|
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 };
|
|
2170
2329
|
|
|
2171
2330
|
//# sourceMappingURL=index.mjs.map
|