@volter-ai-dev/supercode-ui 0.1.70 → 0.1.72

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/README.md +61 -1
  2. package/activity.mjs +5 -1235
  3. package/chunks/chunk-2FG7VKIW.mjs +201 -0
  4. package/chunks/chunk-4XUMCWPC.mjs +29 -0
  5. package/chunks/chunk-E65I2I2L.mjs +120 -0
  6. package/chunks/chunk-IL5T2AST.mjs +842 -0
  7. package/chunks/chunk-LOP6XOON.mjs +671 -0
  8. package/chunks/chunk-LS6JBXNT.mjs +1237 -0
  9. package/chunks/chunk-SJ3YTA6Z.mjs +316 -0
  10. package/chunks/chunk-TKTOVDXB.mjs +139 -0
  11. package/chunks/chunk-V3UM7H7W.mjs +328 -0
  12. package/chunks/chunk-WRK5TBX3.mjs +224 -0
  13. package/chunks/chunk-ZLYHUYE2.mjs +62 -0
  14. package/components.d.ts +3 -0
  15. package/components.mjs +59 -3766
  16. package/composer.mjs +8 -580
  17. package/conversation.mjs +16 -1373
  18. package/embed.mjs +15 -3681
  19. package/icon.mjs +3 -58
  20. package/index.d.ts +25 -0
  21. package/logo.mjs +5 -87
  22. package/messenger.d.ts +3 -0
  23. package/messenger.mjs +21 -3677
  24. package/package.json +22 -3
  25. package/react/activity.mjs +5 -1235
  26. package/react/chunks/chunk-7ES5FSLG.mjs +316 -0
  27. package/react/chunks/chunk-LS6JBXNT.mjs +1237 -0
  28. package/react/chunks/chunk-LYRIQE5M.mjs +29 -0
  29. package/react/chunks/chunk-NJC6S2AW.mjs +201 -0
  30. package/react/chunks/chunk-OINC7LV7.mjs +62 -0
  31. package/react/chunks/chunk-QL6QEYPK.mjs +842 -0
  32. package/react/chunks/chunk-UGL6AB2K.mjs +120 -0
  33. package/react/chunks/chunk-UKHDCPME.mjs +328 -0
  34. package/react/chunks/chunk-UKMTRNJN.mjs +671 -0
  35. package/react/chunks/chunk-VFOVJ4S3.mjs +139 -0
  36. package/react/chunks/chunk-YK7SJ6EH.mjs +224 -0
  37. package/react/components.mjs +59 -3766
  38. package/react/composer.mjs +8 -580
  39. package/react/conversation.mjs +16 -1373
  40. package/react/icon.mjs +3 -58
  41. package/react/index.d.ts +25 -0
  42. package/react/logo.mjs +5 -87
  43. package/react/messenger.d.ts +3 -0
  44. package/react/messenger.mjs +21 -3677
  45. package/react/sessions.mjs +9 -519
  46. package/react/settings.mjs +9 -425
  47. package/react/subagents.mjs +8 -1546
  48. package/react/supervision-components.mjs +1354 -0
  49. package/react/supervision.d.ts +36 -0
  50. package/sessions.mjs +9 -519
  51. package/settings.mjs +9 -425
  52. package/source-inventory.d.ts +240 -0
  53. package/source-inventory.mjs +367 -0
  54. package/styles.css +104 -0
  55. package/subagents.mjs +8 -1546
  56. package/supervision-components.d.ts +36 -0
  57. package/supervision-components.mjs +1354 -0
  58. package/supervision.d.ts +242 -0
  59. package/supervision.mjs +349 -0
@@ -0,0 +1,316 @@
1
+ import {
2
+ ContextCandidates,
3
+ ContextTray,
4
+ ImageTray,
5
+ MAX_CONTEXT_ITEMS,
6
+ MAX_IMAGE_ITEMS,
7
+ boundedSet,
8
+ imageAttachmentsFromFiles,
9
+ mergeContext,
10
+ mergeImages,
11
+ normalizeContext,
12
+ normalizeImages,
13
+ partitionAttachments,
14
+ uiMemory
15
+ } from "./chunk-UKHDCPME.mjs";
16
+ import {
17
+ DEFAULT_LABELS,
18
+ canContinueHere,
19
+ harnessDisplayName,
20
+ isSendKey
21
+ } from "./chunk-LS6JBXNT.mjs";
22
+ import {
23
+ UiIcon
24
+ } from "./chunk-OINC7LV7.mjs";
25
+
26
+ // src/composer.jsx
27
+ import { useEffect, useRef, useState } from "react";
28
+
29
+ // src/intent.js
30
+ var CONFIRMABLE_ACTIONS = /* @__PURE__ */ new Set(["resume", "join", "branch", "reduce", "export", "take_over"]);
31
+ async function dispatchConfirmedIntent(adapter, intent) {
32
+ if (CONFIRMABLE_ACTIONS.has(intent.action) && adapter.confirmIntent) {
33
+ const confirmed = await adapter.confirmIntent(intent);
34
+ if (!confirmed) return;
35
+ }
36
+ return adapter.onIntent(intent);
37
+ }
38
+
39
+ // src/textarea.js
40
+ import { useLayoutEffect } from "react";
41
+ function useAutosizeTextarea(ref, value) {
42
+ useLayoutEffect(() => {
43
+ const element = ref.current;
44
+ if (!element) return;
45
+ element.style.height = "auto";
46
+ const maxHeight = Number.parseFloat(getComputedStyle(element).maxHeight) || 150;
47
+ const height = Math.min(element.scrollHeight, maxHeight);
48
+ element.style.height = `${height}px`;
49
+ element.style.overflowY = element.scrollHeight > maxHeight ? "auto" : "hidden";
50
+ }, [ref, value]);
51
+ }
52
+
53
+ // src/composer.jsx
54
+ import { jsx, jsxs } from "react/jsx-runtime";
55
+ var composerMemory = uiMemory();
56
+ function ExecutionModeSelect({ modes = [], value, onChange, disabled = false, label = "Run in" }) {
57
+ if (modes.length < 2) return null;
58
+ return /* @__PURE__ */ jsxs("label", { className: "scui-execution-mode", title: disabled ? void 0 : `${label}: ${value}`, children: [
59
+ /* @__PURE__ */ jsx("span", { children: label }),
60
+ /* @__PURE__ */ jsx("select", { "aria-label": label, value, disabled, onChange: (event) => onChange?.(event.currentTarget.value), children: modes.map((mode) => /* @__PURE__ */ jsx("option", { value: mode, children: mode === "terminal" ? "Terminal" : "Headless" }, mode)) })
61
+ ] });
62
+ }
63
+ function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
64
+ const continuationModes = state.continuationModes?.length ? state.continuationModes : ["headless"];
65
+ const [selection, setSelection] = useState({ key: null, mode: null });
66
+ const requestedMode = selection.key === state.attached?.key ? selection.mode : null;
67
+ const executionMode = continuationModes.includes(requestedMode) ? requestedMode : continuationModes.includes("terminal") ? "terminal" : continuationModes[0];
68
+ if (state.mode !== "mirror" || state.canSend) return null;
69
+ const attached = state.attached;
70
+ const row = attached?.key ? state.sessions.find((item) => item.key === attached.key) : null;
71
+ const activeElsewhere = row?.runtimeStatus === "running" || row?.runtimeStatus === "busy" || row?.runtimeStatus === "idle";
72
+ const available = {
73
+ resume: canContinueHere(state),
74
+ join: state.canAttach,
75
+ branch: state.canBranch
76
+ };
77
+ const continuation = state.supportsAttach ? "join" : state.supportsResume ? "resume" : state.supportsBranch ? "branch" : available.join ? "join" : available.resume ? "resume" : available.branch ? "branch" : null;
78
+ if (!continuation) return /* @__PURE__ */ jsx("div", { className: "scui-continuation", children: /* @__PURE__ */ jsxs("span", { children: [
79
+ /* @__PURE__ */ jsx("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
80
+ /* @__PURE__ */ jsx("small", { children: "This session cannot be continued by an available harness." })
81
+ ] }) });
82
+ const enabled = available[continuation];
83
+ return /* @__PURE__ */ jsxs("div", { className: "scui-continuation", children: [
84
+ /* @__PURE__ */ jsxs("span", { children: [
85
+ /* @__PURE__ */ jsx("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
86
+ /* @__PURE__ */ jsx("small", { children: continuation === "join" ? "Join the proven live runtime without taking it over." : continuation === "resume" ? `Resume this ${harnessDisplayName(state.harness)} session here.` : "Start an independent continuation." })
87
+ ] }),
88
+ /* @__PURE__ */ jsxs("span", { className: "scui-continuation-actions", children: [
89
+ continuation === "resume" ? /* @__PURE__ */ jsx(ExecutionModeSelect, { modes: continuationModes, value: executionMode, disabled: Boolean(state.operation) || !enabled, onChange: (mode) => setSelection({ key: state.attached?.key ?? null, mode }) }) : null,
90
+ /* @__PURE__ */ jsx("button", { type: "button", disabled: Boolean(state.operation) || !enabled, onClick: () => dispatchConfirmedIntent(adapter, continuation === "join" ? { action: "join" } : continuation === "resume" ? { action: "resume", mode: executionMode } : { action: "branch" }), children: continuation === "join" ? labels.joinLive : continuation === "resume" ? labels.continueHere : labels.forkHere })
91
+ ] })
92
+ ] });
93
+ }
94
+ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`, pendingStatus = null, restoreDraft = null, command = null, contextCandidates = [], components = {}, onPending, onDraftRestored }) {
95
+ const remembered = composerMemory.get(memoryKey) ?? { draft: state.savedDraft, context: [], images: [], queue: [] };
96
+ const [draft, setDraft] = useState(remembered.draft);
97
+ const [context, setContext] = useState(remembered.context ?? []);
98
+ const [images, setImages] = useState(remembered.images ?? []);
99
+ const [queue, setQueue] = useState((remembered.queue ?? []).map((item) => ({ ...item, context: item.context ?? [], images: item.images ?? [] })));
100
+ const [dispatching, setDispatching] = useState(false);
101
+ const [steering, setSteering] = useState(false);
102
+ const [picking, setPicking] = useState(false);
103
+ const [dragging, setDragging] = useState(false);
104
+ const [pickerError, setPickerError] = useState(null);
105
+ const textarea = useRef(null);
106
+ const lastCommand = useRef(null);
107
+ useAutosizeTextarea(textarea, draft);
108
+ const remember = (nextDraft, nextContext, nextImages, nextQueue) => boundedSet(composerMemory, memoryKey, { draft: nextDraft, context: nextContext, images: nextImages, queue: nextQueue });
109
+ useEffect(() => {
110
+ remember(draft, context, images, queue);
111
+ }, [draft, context, images, memoryKey, queue]);
112
+ const updateQueue = (update) => setQueue((items) => {
113
+ const next = update(items);
114
+ remember(draft, context, images, next);
115
+ return next;
116
+ });
117
+ const queueBlocked = state.busy || pendingStatus !== null || dispatching || steering;
118
+ const queuesNewMessage = state.busy || pendingStatus === "sending" || pendingStatus === "failed" || dispatching || steering;
119
+ const steerAvailable = state.busy && state.canSteer && !steering && pendingStatus === null;
120
+ const canSteerDraft = steerAvailable && Boolean(draft.trim()) && context.length === 0 && images.length === 0;
121
+ useEffect(() => {
122
+ if (!queueBlocked && state.canSend && queue.length) {
123
+ const [next, ...rest] = queue;
124
+ setDispatching(true);
125
+ setQueue(rest);
126
+ remember(draft, context, images, rest);
127
+ onPending?.(next.text, next.context, next.images);
128
+ adapter.onIntent({ action: "send", text: next.text, ...next.context.length ? { context: next.context } : {}, ...next.images.length ? { images: next.images } : {} });
129
+ }
130
+ }, [adapter, draft, memoryKey, onPending, queue, queueBlocked, state.canSend]);
131
+ useEffect(() => {
132
+ if (pendingStatus !== null || state.busy) setDispatching(false);
133
+ }, [pendingStatus, state.busy]);
134
+ useEffect(() => {
135
+ textarea.current?.focus({ preventScroll: true });
136
+ }, [memoryKey]);
137
+ useEffect(() => {
138
+ if (!restoreDraft) return;
139
+ setDraft(restoreDraft.text);
140
+ const restoredContext = normalizeContext(restoreDraft.context);
141
+ const restoredImages = normalizeImages(restoreDraft.images);
142
+ setContext(restoredContext);
143
+ setImages(restoredImages);
144
+ remember(restoreDraft.text, restoredContext, restoredImages, queue);
145
+ textarea.current?.focus({ preventScroll: true });
146
+ onDraftRestored?.(restoreDraft.id);
147
+ }, [onDraftRestored, restoreDraft?.id]);
148
+ useEffect(() => {
149
+ if (!command || command.id === lastCommand.current) return;
150
+ lastCommand.current = command.id;
151
+ if (command.action === "attach") {
152
+ try {
153
+ const attachments = partitionAttachments(command.attachments);
154
+ if (context.length + attachments.context.length > MAX_CONTEXT_ITEMS) throw new Error(`Attach at most ${MAX_CONTEXT_ITEMS} text items.`);
155
+ if (images.length + attachments.images.length > MAX_IMAGE_ITEMS) throw new Error(`Attach at most ${MAX_IMAGE_ITEMS} images.`);
156
+ const nextContext = mergeContext(context, attachments.context);
157
+ const nextImages = mergeImages(images, attachments.images);
158
+ setContext(nextContext);
159
+ setImages(nextImages);
160
+ setPickerError(null);
161
+ remember(draft, nextContext, nextImages, queue);
162
+ } catch (error) {
163
+ setPickerError(error instanceof Error ? error.message : "Could not attach context.");
164
+ }
165
+ }
166
+ textarea.current?.focus({ preventScroll: true });
167
+ }, [command?.id]);
168
+ useEffect(() => {
169
+ const timer = setTimeout(() => adapter.onIntent({ action: "draft", text: draft }), 250);
170
+ return () => clearTimeout(timer);
171
+ }, [adapter, draft]);
172
+ const pickContext = () => {
173
+ if (!adapter.pickContext || state.mode !== "control" || picking || context.length >= MAX_CONTEXT_ITEMS && images.length >= MAX_IMAGE_ITEMS) return;
174
+ setPicking(true);
175
+ setPickerError(null);
176
+ Promise.resolve().then(() => adapter.pickContext()).then((picked) => {
177
+ const attachments = partitionAttachments(picked);
178
+ if (context.length + attachments.context.length > MAX_CONTEXT_ITEMS) throw new Error(`Attach at most ${MAX_CONTEXT_ITEMS} text items.`);
179
+ if (images.length + attachments.images.length > MAX_IMAGE_ITEMS) throw new Error(`Attach at most ${MAX_IMAGE_ITEMS} images.`);
180
+ setContext((current) => {
181
+ const next = mergeContext(current, attachments.context);
182
+ remember(draft, next, images, queue);
183
+ return next;
184
+ });
185
+ setImages((current) => {
186
+ const next = mergeImages(current, attachments.images);
187
+ remember(draft, context, next, queue);
188
+ return next;
189
+ });
190
+ }).catch((error) => setPickerError(error instanceof Error ? error.message : "Could not attach context.")).finally(() => setPicking(false));
191
+ };
192
+ const attachCandidate = (picked) => {
193
+ const attachments = partitionAttachments(picked);
194
+ const nextContext = mergeContext(context, attachments.context);
195
+ const nextImages = mergeImages(images, attachments.images);
196
+ setContext(nextContext);
197
+ setImages(nextImages);
198
+ remember(draft, nextContext, nextImages, queue);
199
+ };
200
+ const addImageFiles = (value, source) => {
201
+ const allFiles = Array.from(value ?? []);
202
+ if (!allFiles.length) return false;
203
+ const files = allFiles.filter((file) => file.type.startsWith("image/"));
204
+ if (files.length !== allFiles.length) {
205
+ setPickerError("Drop or paste PNG, JPEG, GIF, or WebP images.");
206
+ return true;
207
+ }
208
+ if (images.length + files.length > MAX_IMAGE_ITEMS) {
209
+ setPickerError(`Attach at most ${MAX_IMAGE_ITEMS} images.`);
210
+ return true;
211
+ }
212
+ setPicking(true);
213
+ setPickerError(null);
214
+ imageAttachmentsFromFiles(files).then((picked) => setImages((current) => {
215
+ const next = mergeImages(current, picked);
216
+ remember(draft, context, next, queue);
217
+ return next;
218
+ }), (error) => setPickerError(error instanceof Error ? error.message : `Could not ${source} image.`)).finally(() => setPicking(false));
219
+ return true;
220
+ };
221
+ const pasteImages = (event) => {
222
+ if (addImageFiles(event.clipboardData?.files, "paste")) event.preventDefault();
223
+ };
224
+ const dropImages = (event) => {
225
+ setDragging(false);
226
+ if (addImageFiles(event.dataTransfer?.files, "drop")) event.preventDefault();
227
+ };
228
+ const send = (forceQueue = false) => {
229
+ const text = draft.trim();
230
+ if (!text && !images.length) return;
231
+ if (canSteerDraft && !forceQueue) {
232
+ setSteering(true);
233
+ Promise.resolve(adapter.onIntent({ action: "steer", text })).then(() => {
234
+ setDraft("");
235
+ remember("", context, images, queue);
236
+ }, (error) => setPickerError(error instanceof Error ? error.message : "Could not steer the active turn.")).finally(() => setSteering(false));
237
+ return;
238
+ }
239
+ const message = { text, context, images };
240
+ if (queuesNewMessage) updateQueue((items) => [...items, message]);
241
+ else if (state.canSend) {
242
+ if (onPending) setDispatching(true);
243
+ onPending?.(text, context, images);
244
+ adapter.onIntent({ action: "send", text, ...context.length ? { context } : {}, ...images.length ? { images } : {} });
245
+ } else return;
246
+ setDraft("");
247
+ setContext([]);
248
+ setImages([]);
249
+ remember("", [], [], queuesNewMessage ? [...queue, message] : queue);
250
+ };
251
+ return /* @__PURE__ */ jsxs("div", { className: "scui-compose", children: [
252
+ queue.length ? /* @__PURE__ */ jsxs("div", { className: "scui-queue", children: [
253
+ /* @__PURE__ */ jsxs("strong", { children: [
254
+ queue.length,
255
+ " queued"
256
+ ] }),
257
+ queue.map((item, index) => /* @__PURE__ */ jsxs("span", { children: [
258
+ /* @__PURE__ */ jsxs("span", { children: [
259
+ item.text || "Image attachment",
260
+ item.context.length + item.images.length ? /* @__PURE__ */ jsxs("small", { children: [
261
+ item.context.length + item.images.length,
262
+ " attached"
263
+ ] }) : null
264
+ ] }),
265
+ /* @__PURE__ */ jsx("button", { type: "button", "aria-label": `Remove queued message ${index + 1}`, onClick: () => updateQueue((items) => items.filter((_, itemIndex) => itemIndex !== index)), children: /* @__PURE__ */ jsx(UiIcon, { name: "close", size: 13 }) })
266
+ ] }, `${index}:${item.text}`))
267
+ ] }) : null,
268
+ /* @__PURE__ */ jsx(ContextCandidates, { items: contextCandidates, context, images, state, adapter, onAttach: attachCandidate, component: components.ContextCandidate }),
269
+ /* @__PURE__ */ jsx(ImageTray, { items: images, onRemove: (index) => setImages((items) => {
270
+ const next = items.filter((_, itemIndex) => itemIndex !== index);
271
+ remember(draft, context, next, queue);
272
+ return next;
273
+ }) }),
274
+ /* @__PURE__ */ jsx(ContextTray, { items: context, onRemove: (index) => setContext((items) => {
275
+ const next = items.filter((_, itemIndex) => itemIndex !== index);
276
+ remember(draft, next, images, queue);
277
+ return next;
278
+ }) }),
279
+ pickerError ? /* @__PURE__ */ jsx("small", { className: "scui-context-error", role: "alert", children: pickerError }) : null,
280
+ /* @__PURE__ */ jsxs("div", { className: `scui-envelope${dragging ? " scui-drop-target" : ""}`, onDragEnter: (event) => {
281
+ if (Array.from(event.dataTransfer?.types ?? []).includes("Files")) {
282
+ event.preventDefault();
283
+ setDragging(true);
284
+ }
285
+ }, onDragOver: (event) => {
286
+ if (Array.from(event.dataTransfer?.types ?? []).includes("Files")) event.preventDefault();
287
+ }, onDragLeave: (event) => {
288
+ if (!event.currentTarget.contains(event.relatedTarget)) setDragging(false);
289
+ }, onDrop: dropImages, children: [
290
+ adapter.pickContext && state.mode === "control" ? /* @__PURE__ */ jsx("button", { className: "scui-attach", type: "button", "aria-label": labels.attachContext ?? DEFAULT_LABELS.attachContext, disabled: picking || context.length >= MAX_CONTEXT_ITEMS && images.length >= MAX_IMAGE_ITEMS, onClick: pickContext, children: picking ? /* @__PURE__ */ jsx("i", { className: "scui-control-spinner" }) : /* @__PURE__ */ jsx(UiIcon, { name: "attach", size: 17 }) }) : null,
291
+ /* @__PURE__ */ jsx("textarea", { ref: textarea, rows: 1, "aria-label": `Message ${harnessDisplayName(state.harness) || "agent"}`, placeholder: state.startup !== "ready" ? "Connecting\u2026" : pendingStatus === "failed" ? "Retry or edit the unsent message\u2026" : pendingStatus === "editing" ? "Edit and resend\u2026" : steerAvailable && context.length === 0 && images.length === 0 ? "Redirect the current turn\u2026" : queueBlocked ? "Queue a follow-up\u2026" : labels.askAgent, value: draft, disabled: state.mode !== "control" && !state.canSend, onPaste: pasteImages, onInput: (event) => {
292
+ const value = event.currentTarget.value;
293
+ setDraft(value);
294
+ remember(value, context, images, queue);
295
+ }, onKeyDown: (event) => {
296
+ if (isSendKey(event)) {
297
+ event.preventDefault();
298
+ send();
299
+ }
300
+ } }),
301
+ /* @__PURE__ */ jsxs("span", { children: [
302
+ state.busy ? /* @__PURE__ */ jsx("button", { className: "scui-stop", type: "button", "aria-label": "Stop agent", disabled: !state.canInterrupt, onClick: () => adapter.onIntent({ action: "interrupt" }), children: /* @__PURE__ */ jsx(UiIcon, { name: "stop", size: 15 }) }) : null,
303
+ canSteerDraft ? /* @__PURE__ */ jsx("button", { className: "scui-queue-send", type: "button", "aria-label": "Queue follow-up instead", onClick: () => send(true), children: /* @__PURE__ */ jsx(UiIcon, { name: "plus", size: 15 }) }) : null,
304
+ /* @__PURE__ */ jsx("button", { className: "scui-send", type: "button", "aria-label": canSteerDraft ? "Steer current turn" : queuesNewMessage ? "Queue message" : "Send message", disabled: steering || !draft.trim() && !images.length || !queuesNewMessage && !state.canSend, onClick: () => send(), children: steering ? /* @__PURE__ */ jsx("i", { className: "scui-control-spinner" }) : /* @__PURE__ */ jsx(UiIcon, { name: canSteerDraft ? "send" : queuesNewMessage ? "plus" : "send", size: 17 }) })
305
+ ] })
306
+ ] })
307
+ ] });
308
+ }
309
+
310
+ export {
311
+ dispatchConfirmedIntent,
312
+ useAutosizeTextarea,
313
+ ExecutionModeSelect,
314
+ ContinuationBar,
315
+ Composer
316
+ };