@volter-ai-dev/supercode-ui 0.1.17 → 0.1.20
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/README.md +6 -0
- package/components.mjs +503 -354
- package/composer.mjs +104 -33
- package/controller.mjs +7 -2
- package/conversation.mjs +74 -18
- package/core.mjs +64 -11
- package/embed.mjs +505 -356
- package/icon.mjs +1 -0
- package/index.d.ts +7 -4
- package/messenger.mjs +503 -354
- package/package.json +1 -1
- package/sessions.mjs +3 -2
- package/styles.css +4 -1
package/composer.mjs
CHANGED
|
@@ -82,6 +82,7 @@ function boundedSet(map, key, value) {
|
|
|
82
82
|
// src/icon.jsx
|
|
83
83
|
import { Fragment, jsx, jsxs } from "preact/jsx-runtime";
|
|
84
84
|
var ICONS = {
|
|
85
|
+
attach: () => /* @__PURE__ */ jsx("path", { d: "M6.25 9.75 10.6 5.4a2.1 2.1 0 0 1 2.97 2.97l-5.4 5.4a3.3 3.3 0 0 1-4.67-4.66l5.52-5.52" }),
|
|
85
86
|
back: () => /* @__PURE__ */ jsx("path", { d: "m11.5 4.5-4.5 4.5 4.5 4.5" }),
|
|
86
87
|
check: () => /* @__PURE__ */ jsx("path", { d: "m4 9 3.25 3.25L14 5.5" }),
|
|
87
88
|
chevron: () => /* @__PURE__ */ jsx("path", { d: "m7 4.5 4.5 4.5L7 13.5" }),
|
|
@@ -122,6 +123,44 @@ function UiIcon({ name, size = 16, class: className = "" }) {
|
|
|
122
123
|
return /* @__PURE__ */ jsx("svg", { class: `scui-icon ${className}`, style: { "--scui-icon-size": `${size}px` }, viewBox: "0 0 18 18", fill: "none", stroke: "currentColor", "stroke-width": "1.5", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx(Glyph, {}) });
|
|
123
124
|
}
|
|
124
125
|
|
|
126
|
+
// src/context.jsx
|
|
127
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "preact/jsx-runtime";
|
|
128
|
+
var MAX_CONTEXT_ITEMS = 32;
|
|
129
|
+
function normalizeContext(value) {
|
|
130
|
+
return (Array.isArray(value) ? value : value ? [value] : []).flatMap((item) => {
|
|
131
|
+
if (!item || typeof item.label !== "string" || typeof item.detail !== "string") return [];
|
|
132
|
+
const label = item.label.trim().slice(0, 200);
|
|
133
|
+
const detail = item.detail.slice(0, 2e4);
|
|
134
|
+
if (!label || !detail) return [];
|
|
135
|
+
return [{
|
|
136
|
+
...typeof item.id === "string" && item.id ? { id: item.id.slice(0, 2e3) } : {},
|
|
137
|
+
...typeof item.kind === "string" && item.kind ? { kind: item.kind.slice(0, 100) } : {},
|
|
138
|
+
label,
|
|
139
|
+
detail
|
|
140
|
+
}];
|
|
141
|
+
}).slice(0, MAX_CONTEXT_ITEMS);
|
|
142
|
+
}
|
|
143
|
+
function mergeContext(current, picked) {
|
|
144
|
+
const next = [...current];
|
|
145
|
+
const seen = new Set(current.map((item) => item.id ? `id:${item.id}` : `value:${item.kind ?? ""}\0${item.label}\0${item.detail}`));
|
|
146
|
+
for (const item of normalizeContext(picked)) {
|
|
147
|
+
const key = item.id ? `id:${item.id}` : `value:${item.kind ?? ""}\0${item.label}\0${item.detail}`;
|
|
148
|
+
if (seen.has(key)) continue;
|
|
149
|
+
seen.add(key);
|
|
150
|
+
next.push(item);
|
|
151
|
+
if (next.length === MAX_CONTEXT_ITEMS) break;
|
|
152
|
+
}
|
|
153
|
+
return next;
|
|
154
|
+
}
|
|
155
|
+
function ContextTray({ items, onRemove }) {
|
|
156
|
+
if (!items.length) return null;
|
|
157
|
+
return /* @__PURE__ */ jsx2("div", { class: "scui-compose-context", "aria-label": "Attached context", children: items.map((item, index) => /* @__PURE__ */ jsxs2("span", { children: [
|
|
158
|
+
/* @__PURE__ */ jsx2(UiIcon, { name: "attach", size: 12 }),
|
|
159
|
+
/* @__PURE__ */ jsx2("strong", { children: item.label }),
|
|
160
|
+
/* @__PURE__ */ jsx2("button", { type: "button", "aria-label": `Remove context ${item.label}`, onClick: () => onRemove(index), children: /* @__PURE__ */ jsx2(UiIcon, { name: "close", size: 12 }) })
|
|
161
|
+
] }, item.id ?? `${item.label}:${index}`)) });
|
|
162
|
+
}
|
|
163
|
+
|
|
125
164
|
// src/textarea.js
|
|
126
165
|
import { useLayoutEffect } from "preact/hooks";
|
|
127
166
|
function useAutosizeTextarea(ref, value) {
|
|
@@ -137,7 +176,7 @@ function useAutosizeTextarea(ref, value) {
|
|
|
137
176
|
}
|
|
138
177
|
|
|
139
178
|
// src/composer.jsx
|
|
140
|
-
import { jsx as
|
|
179
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "preact/jsx-runtime";
|
|
141
180
|
var composerMemory = /* @__PURE__ */ new Map();
|
|
142
181
|
function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
|
|
143
182
|
if (state.mode !== "mirror" || state.canSend) return null;
|
|
@@ -147,29 +186,32 @@ function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
|
|
|
147
186
|
const resume = canContinueHere(state);
|
|
148
187
|
const join = state.canAttach;
|
|
149
188
|
const branch = state.canBranch;
|
|
150
|
-
if (!resume && !join && !branch) return /* @__PURE__ */
|
|
151
|
-
/* @__PURE__ */
|
|
152
|
-
/* @__PURE__ */
|
|
189
|
+
if (!resume && !join && !branch) return /* @__PURE__ */ jsx3("div", { class: "scui-continuation", children: /* @__PURE__ */ jsxs3("span", { children: [
|
|
190
|
+
/* @__PURE__ */ jsx3("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
|
|
191
|
+
/* @__PURE__ */ jsx3("small", { children: "This session cannot be continued by an available harness." })
|
|
153
192
|
] }) });
|
|
154
|
-
return /* @__PURE__ */
|
|
155
|
-
/* @__PURE__ */
|
|
156
|
-
/* @__PURE__ */
|
|
157
|
-
/* @__PURE__ */
|
|
193
|
+
return /* @__PURE__ */ jsxs3("div", { class: "scui-continuation", children: [
|
|
194
|
+
/* @__PURE__ */ jsxs3("span", { children: [
|
|
195
|
+
/* @__PURE__ */ jsx3("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
|
|
196
|
+
/* @__PURE__ */ jsx3("small", { children: join ? "Join the proven live runtime without taking it over." : resume ? `Resume this ${harnessDisplayName(state.harness)} session here.` : "Start an independent continuation." })
|
|
158
197
|
] }),
|
|
159
|
-
/* @__PURE__ */
|
|
198
|
+
/* @__PURE__ */ jsx3("button", { type: "button", disabled: Boolean(state.operation), onClick: () => adapter.onIntent(join ? { action: "join" } : resume ? { action: "resume" } : { action: "branch" }), children: join ? labels.joinLive : resume ? labels.continueHere : labels.forkHere })
|
|
160
199
|
] });
|
|
161
200
|
}
|
|
162
201
|
function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`, pendingStatus = null, restoreDraft = null, onPending, onDraftRestored }) {
|
|
163
|
-
const remembered = composerMemory.get(memoryKey) ?? { draft: state.savedDraft, queue: [] };
|
|
202
|
+
const remembered = composerMemory.get(memoryKey) ?? { draft: state.savedDraft, context: [], queue: [] };
|
|
164
203
|
const [draft, setDraft] = useState(remembered.draft);
|
|
204
|
+
const [context, setContext] = useState(remembered.context);
|
|
165
205
|
const [queue, setQueue] = useState(remembered.queue);
|
|
166
206
|
const [dispatching, setDispatching] = useState(false);
|
|
207
|
+
const [picking, setPicking] = useState(false);
|
|
208
|
+
const [pickerError, setPickerError] = useState(null);
|
|
167
209
|
const textarea = useRef(null);
|
|
168
210
|
useAutosizeTextarea(textarea, draft);
|
|
169
|
-
const remember = (nextDraft, nextQueue) => boundedSet(composerMemory, memoryKey, { draft: nextDraft, queue: nextQueue });
|
|
211
|
+
const remember = (nextDraft, nextContext, nextQueue) => boundedSet(composerMemory, memoryKey, { draft: nextDraft, context: nextContext, queue: nextQueue });
|
|
170
212
|
const updateQueue = (update) => setQueue((items) => {
|
|
171
213
|
const next = update(items);
|
|
172
|
-
remember(draft, next);
|
|
214
|
+
remember(draft, context, next);
|
|
173
215
|
return next;
|
|
174
216
|
});
|
|
175
217
|
const queueBlocked = state.busy || pendingStatus !== null || dispatching;
|
|
@@ -179,9 +221,9 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
|
|
|
179
221
|
const [next, ...rest] = queue;
|
|
180
222
|
setDispatching(true);
|
|
181
223
|
setQueue(rest);
|
|
182
|
-
remember(draft, rest);
|
|
183
|
-
onPending?.(next);
|
|
184
|
-
adapter.onIntent({ action: "send", text: next });
|
|
224
|
+
remember(draft, context, rest);
|
|
225
|
+
onPending?.(next.text, next.context);
|
|
226
|
+
adapter.onIntent({ action: "send", text: next.text, ...next.context.length ? { context: next.context } : {} });
|
|
185
227
|
}
|
|
186
228
|
}, [adapter, draft, memoryKey, onPending, queue, queueBlocked, state.canSend]);
|
|
187
229
|
useEffect(() => {
|
|
@@ -193,7 +235,9 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
|
|
|
193
235
|
useEffect(() => {
|
|
194
236
|
if (!restoreDraft) return;
|
|
195
237
|
setDraft(restoreDraft.text);
|
|
196
|
-
|
|
238
|
+
const restoredContext = normalizeContext(restoreDraft.context);
|
|
239
|
+
setContext(restoredContext);
|
|
240
|
+
remember(restoreDraft.text, restoredContext, queue);
|
|
197
241
|
textarea.current?.focus({ preventScroll: true });
|
|
198
242
|
onDraftRestored?.(restoreDraft.id);
|
|
199
243
|
}, [onDraftRestored, restoreDraft?.id]);
|
|
@@ -201,43 +245,70 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
|
|
|
201
245
|
const timer = setTimeout(() => adapter.onIntent({ action: "draft", text: draft }), 250);
|
|
202
246
|
return () => clearTimeout(timer);
|
|
203
247
|
}, [adapter, draft]);
|
|
248
|
+
const pickContext = () => {
|
|
249
|
+
if (!adapter.pickContext || state.mode !== "control" || picking || context.length >= MAX_CONTEXT_ITEMS) return;
|
|
250
|
+
setPicking(true);
|
|
251
|
+
setPickerError(null);
|
|
252
|
+
Promise.resolve().then(() => adapter.pickContext()).then((picked) => {
|
|
253
|
+
setContext((current) => {
|
|
254
|
+
const next = mergeContext(current, picked);
|
|
255
|
+
remember(draft, next, queue);
|
|
256
|
+
return next;
|
|
257
|
+
});
|
|
258
|
+
}, (error) => setPickerError(error instanceof Error ? error.message : "Could not attach context.")).finally(() => setPicking(false));
|
|
259
|
+
};
|
|
204
260
|
const send = () => {
|
|
205
261
|
const text = draft.trim();
|
|
206
262
|
if (!text) return;
|
|
207
|
-
|
|
263
|
+
const message = { text, context };
|
|
264
|
+
if (queuesNewMessage) updateQueue((items) => [...items, message]);
|
|
208
265
|
else if (state.canSend) {
|
|
209
266
|
if (onPending) setDispatching(true);
|
|
210
|
-
onPending?.(text);
|
|
211
|
-
adapter.onIntent({ action: "send", text });
|
|
267
|
+
onPending?.(text, context);
|
|
268
|
+
adapter.onIntent({ action: "send", text, ...context.length ? { context } : {} });
|
|
212
269
|
} else return;
|
|
213
270
|
setDraft("");
|
|
214
|
-
|
|
271
|
+
setContext([]);
|
|
272
|
+
remember("", [], queuesNewMessage ? [...queue, message] : queue);
|
|
215
273
|
};
|
|
216
|
-
return /* @__PURE__ */
|
|
217
|
-
queue.length ? /* @__PURE__ */
|
|
218
|
-
/* @__PURE__ */
|
|
274
|
+
return /* @__PURE__ */ jsxs3("div", { class: "scui-compose", children: [
|
|
275
|
+
queue.length ? /* @__PURE__ */ jsxs3("div", { class: "scui-queue", children: [
|
|
276
|
+
/* @__PURE__ */ jsxs3("strong", { children: [
|
|
219
277
|
queue.length,
|
|
220
278
|
" queued"
|
|
221
279
|
] }),
|
|
222
|
-
queue.map((item, index) => /* @__PURE__ */
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
280
|
+
queue.map((item, index) => /* @__PURE__ */ jsxs3("span", { children: [
|
|
281
|
+
/* @__PURE__ */ jsxs3("span", { children: [
|
|
282
|
+
item.text,
|
|
283
|
+
item.context.length ? /* @__PURE__ */ jsxs3("small", { children: [
|
|
284
|
+
item.context.length,
|
|
285
|
+
" attached"
|
|
286
|
+
] }) : null
|
|
287
|
+
] }),
|
|
288
|
+
/* @__PURE__ */ jsx3("button", { type: "button", "aria-label": `Remove queued message ${index + 1}`, onClick: () => updateQueue((items) => items.filter((_, itemIndex) => itemIndex !== index)), children: /* @__PURE__ */ jsx3(UiIcon, { name: "close", size: 13 }) })
|
|
289
|
+
] }, `${index}:${item.text}`))
|
|
226
290
|
] }) : null,
|
|
227
|
-
/* @__PURE__ */
|
|
228
|
-
|
|
291
|
+
/* @__PURE__ */ jsx3(ContextTray, { items: context, onRemove: (index) => setContext((items) => {
|
|
292
|
+
const next = items.filter((_, itemIndex) => itemIndex !== index);
|
|
293
|
+
remember(draft, next, queue);
|
|
294
|
+
return next;
|
|
295
|
+
}) }),
|
|
296
|
+
pickerError ? /* @__PURE__ */ jsx3("small", { class: "scui-context-error", role: "alert", children: pickerError }) : null,
|
|
297
|
+
/* @__PURE__ */ jsxs3("div", { class: "scui-envelope", children: [
|
|
298
|
+
adapter.pickContext && state.mode === "control" ? /* @__PURE__ */ jsx3("button", { class: "scui-attach", type: "button", "aria-label": "Attach context", disabled: picking || context.length >= MAX_CONTEXT_ITEMS, onClick: pickContext, children: picking ? /* @__PURE__ */ jsx3("i", { class: "scui-control-spinner" }) : /* @__PURE__ */ jsx3(UiIcon, { name: "attach", size: 17 }) }) : null,
|
|
299
|
+
/* @__PURE__ */ jsx3("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" : queueBlocked ? "Queue a follow-up\u2026" : labels.askAgent, value: draft, disabled: state.mode !== "control" && !state.canSend, onInput: (event) => {
|
|
229
300
|
const value = event.currentTarget.value;
|
|
230
301
|
setDraft(value);
|
|
231
|
-
remember(value, queue);
|
|
302
|
+
remember(value, context, queue);
|
|
232
303
|
}, onKeyDown: (event) => {
|
|
233
304
|
if (isSendKey(event)) {
|
|
234
305
|
event.preventDefault();
|
|
235
306
|
send();
|
|
236
307
|
}
|
|
237
308
|
} }),
|
|
238
|
-
/* @__PURE__ */
|
|
239
|
-
state.busy ? /* @__PURE__ */
|
|
240
|
-
/* @__PURE__ */
|
|
309
|
+
/* @__PURE__ */ jsxs3("span", { children: [
|
|
310
|
+
state.busy ? /* @__PURE__ */ jsx3("button", { class: "scui-stop", type: "button", "aria-label": "Stop agent", disabled: !state.canInterrupt, onClick: () => adapter.onIntent({ action: "interrupt" }), children: /* @__PURE__ */ jsx3(UiIcon, { name: "stop", size: 15 }) }) : null,
|
|
311
|
+
/* @__PURE__ */ jsx3("button", { class: "scui-send", type: "button", "aria-label": queuesNewMessage ? "Queue message" : "Send message", disabled: !draft.trim() || !queuesNewMessage && !state.canSend, onClick: send, children: /* @__PURE__ */ jsx3(UiIcon, { name: queuesNewMessage ? "plus" : "send", size: 17 }) })
|
|
241
312
|
] })
|
|
242
313
|
] })
|
|
243
314
|
] });
|
package/controller.mjs
CHANGED
|
@@ -141,6 +141,11 @@ function projectConversationEntry(entry, maxEntryChars) {
|
|
|
141
141
|
};
|
|
142
142
|
projected.presentation = createToolPresentation({
|
|
143
143
|
...projected,
|
|
144
|
+
// Presentation is a small semantic projection, so derive it before the raw native
|
|
145
|
+
// envelope is bounded for transport. Large Agent prompts and patches routinely exceed the
|
|
146
|
+
// widget cap; parsing the truncated JSON made their useful description/path disappear.
|
|
147
|
+
arguments: (entry.arguments ?? '').trim(),
|
|
148
|
+
resultText: (entry.resultText ?? '').trim(),
|
|
144
149
|
resultContent: entry.resultContent,
|
|
145
150
|
metadata: entry.metadata,
|
|
146
151
|
});
|
|
@@ -371,10 +376,10 @@ async function dispatchStandard(controller, intent, options) {
|
|
|
371
376
|
const active = snapshot.activeSessionKey;
|
|
372
377
|
if (intent.action === 'mounted') return;
|
|
373
378
|
if (intent.action === 'attach') return controller.dispatch({ type: 'observe', sessionKey: intent.key });
|
|
374
|
-
if (intent.action === 'send') return controller.dispatch({ type: 'send', text: intent.text });
|
|
379
|
+
if (intent.action === 'send') return controller.dispatch({ type: 'send', text: intent.text, ...(intent.context?.length ? { context: intent.context } : {}) });
|
|
375
380
|
if (intent.action === 'new') {
|
|
376
381
|
await controller.dispatch({ type: 'start', harness: intent.harness });
|
|
377
|
-
return controller.dispatch({ type: 'send', text: intent.text });
|
|
382
|
+
return controller.dispatch({ type: 'send', text: intent.text, ...(intent.context?.length ? { context: intent.context } : {}) });
|
|
378
383
|
}
|
|
379
384
|
if (intent.action === 'resume' && active) return controller.dispatch({ type: 'resume', sessionKey: active });
|
|
380
385
|
if (intent.action === 'join' && active) return controller.dispatch({ type: 'attach', sessionKey: active });
|
package/conversation.mjs
CHANGED
|
@@ -102,6 +102,12 @@ function sourceString(source, keys) {
|
|
|
102
102
|
const match = new RegExp(`(?:^|[,{\\s])["']?(?:${names})["']?\\s*:\\s*("(?:\\\\.|[^"\\\\])*"|'(?:\\\\.|[^'\\\\])*'|\`(?:\\\\.|[^\`\\\\])*\`)`).exec(source);
|
|
103
103
|
return decodedLiteral(match?.[1]);
|
|
104
104
|
}
|
|
105
|
+
function assignedString(source, keys) {
|
|
106
|
+
if (!source) return "";
|
|
107
|
+
const names = keys.join("|");
|
|
108
|
+
const match = new RegExp(`\\b(?:${names})\\s*=\\s*("(?:\\\\.|[^"\\\\])*"|'(?:\\\\.|[^'\\\\])*'|\`(?:\\\\.|[^\`\\\\])*\`)`).exec(source);
|
|
109
|
+
return decodedLiteral(match?.[1]);
|
|
110
|
+
}
|
|
105
111
|
function callArgumentSource(source, open) {
|
|
106
112
|
let depth = 1;
|
|
107
113
|
let quote = "";
|
|
@@ -243,6 +249,13 @@ function planItems(args) {
|
|
|
243
249
|
return [{ label: boundedString(label, 300), status: firstString(value, ["status"]) }];
|
|
244
250
|
}).slice(0, 12);
|
|
245
251
|
}
|
|
252
|
+
function agentItems(name, resultText) {
|
|
253
|
+
if (!/list.?agents/i.test(name)) return [];
|
|
254
|
+
return (resultText ?? "").split("\n").flatMap((line) => {
|
|
255
|
+
const parts = line.trim().split(/\s+·\s+/).filter(Boolean);
|
|
256
|
+
return parts.length > 1 ? [{ label: boundedString(parts[0], 120), status: boundedString(parts.slice(1).join(" \xB7 "), 180) }] : [];
|
|
257
|
+
}).slice(0, 12);
|
|
258
|
+
}
|
|
246
259
|
function editPreview(args, resultText, source) {
|
|
247
260
|
const direct = firstString(args, ["patch", "diff"]);
|
|
248
261
|
if (direct) return direct;
|
|
@@ -260,7 +273,19 @@ function editPreview(args, resultText, source) {
|
|
|
260
273
|
}
|
|
261
274
|
function toolResultEnvelope(resultText) {
|
|
262
275
|
const match = /^Script (?:completed|failed)\r?\nWall time ([0-9.]+) seconds\r?\nOutput:\r?\n([\s\S]*)$/.exec(resultText ?? "");
|
|
263
|
-
if (!match)
|
|
276
|
+
if (!match) {
|
|
277
|
+
try {
|
|
278
|
+
const value = JSON.parse(resultText ?? "");
|
|
279
|
+
const object = record(value);
|
|
280
|
+
return {
|
|
281
|
+
preview: typeof value === "string" ? value : firstString(object, ["output", "message", "text", "summary", "result"]) || resultText || "",
|
|
282
|
+
value: object,
|
|
283
|
+
durationMs: null
|
|
284
|
+
};
|
|
285
|
+
} catch {
|
|
286
|
+
return { preview: resultText ?? "", value: null, durationMs: null };
|
|
287
|
+
}
|
|
288
|
+
}
|
|
264
289
|
const durationMs = Number(match[1]) * 1e3;
|
|
265
290
|
try {
|
|
266
291
|
const value = record(JSON.parse(match[2]));
|
|
@@ -273,6 +298,15 @@ function toolResultEnvelope(resultText) {
|
|
|
273
298
|
return { preview: match[2], value: null, durationMs: Number.isFinite(durationMs) ? durationMs : null };
|
|
274
299
|
}
|
|
275
300
|
}
|
|
301
|
+
function semanticAgentPreview(name, status, outcome) {
|
|
302
|
+
const normalized = name.toLocaleLowerCase();
|
|
303
|
+
if (status === "error") return outcome.preview;
|
|
304
|
+
if (/^(?:agent|task)$|spawn.?agent/.test(normalized) && outcome.preview) return "Agent is working in the background.";
|
|
305
|
+
if (/send.?message|followup.?task/.test(normalized) && outcome.preview) {
|
|
306
|
+
return /resumed from transcript|resumedAgentId/i.test(outcome.preview) ? "Agent resumed in the background." : "Message delivered.";
|
|
307
|
+
}
|
|
308
|
+
return outcome.preview;
|
|
309
|
+
}
|
|
276
310
|
function verificationCommand(command) {
|
|
277
311
|
let shell = "";
|
|
278
312
|
let quote = "";
|
|
@@ -305,12 +339,13 @@ function verificationCommand(command) {
|
|
|
305
339
|
function classifyTool(name, command) {
|
|
306
340
|
const normalized = name.toLocaleLowerCase();
|
|
307
341
|
if (/write_stdin|^wait$/.test(normalized)) return "command";
|
|
308
|
-
if (/update.?plan|todo|checklist|taskcreate|taskupdate/.test(normalized)) return "plan";
|
|
342
|
+
if (/update.?plan|todo|checklist|taskcreate|taskupdate|create.?goal|update.?goal/.test(normalized)) return "plan";
|
|
309
343
|
if (/search.?replace|edit|write|patch|replace|create_file|apply_patch/.test(normalized)) return "edit";
|
|
310
344
|
if (/read|view|open_file|list_dir/.test(normalized)) return "read";
|
|
345
|
+
if (/web.?search|web.?fetch|fetch.?url/.test(normalized)) return "web";
|
|
311
346
|
if (/search|find|grep|glob|toolsearch/.test(normalized)) return "search";
|
|
312
347
|
if (/browser|web|fetch|url/.test(normalized)) return "web";
|
|
313
|
-
if (/agent|subagent|
|
|
348
|
+
if (/agent|subagent|send.?message|delegate|followup.?task|taskstop|taskoutput|^task$/.test(normalized)) return "agent";
|
|
314
349
|
if (/test|typecheck|lint|build/.test(normalized)) return "test";
|
|
315
350
|
if (/terminal|bash|shell|command|exec|write_stdin|^wait$/.test(normalized)) return verificationCommand(command) ? "test" : "command";
|
|
316
351
|
return "other";
|
|
@@ -319,9 +354,17 @@ function toolAction(status, category, name, tools) {
|
|
|
319
354
|
const position = status === "pending" ? 0 : status === "error" ? 2 : 1;
|
|
320
355
|
if (tools.length > 1) return [`Running ${tools.length} actions`, `Ran ${tools.length} actions`, `${tools.length} actions failed`][position];
|
|
321
356
|
const normalized = name.toLocaleLowerCase();
|
|
322
|
-
if (/
|
|
323
|
-
if (/kill_command_or_subagent/.test(normalized)) return ["Stopping", "Stopped", "Stop failed"][position];
|
|
357
|
+
if (/send.?message|followup.?task/.test(normalized)) return ["Messaging agent", "Messaged agent", "Agent message failed"][position];
|
|
358
|
+
if (/taskstop|interrupt.?agent|kill_command_or_subagent/.test(normalized)) return ["Stopping agent", "Stopped agent", "Stop failed"][position];
|
|
359
|
+
if (/list.?agents|taskoutput|wait.?agent/.test(normalized)) return ["Checking agents", "Checked agents", "Agent check failed"][position];
|
|
324
360
|
if (/get_command_or_subagent_output|write_stdin|^wait$/.test(normalized)) return ["Waiting for", "Checked", "Check failed"][position];
|
|
361
|
+
if (/web.?search/.test(normalized)) return ["Searching web", "Searched web", "Web search failed"][position];
|
|
362
|
+
if (/web.?fetch|fetch.?url/.test(normalized)) return ["Fetching page", "Fetched page", "Page fetch failed"][position];
|
|
363
|
+
if (/^skill$|use.?skill|load.?skill/.test(normalized)) return ["Loading skill", "Loaded skill", "Skill load failed"][position];
|
|
364
|
+
if (/taskcreate/.test(normalized)) return ["Adding task", "Added task", "Task creation failed"][position];
|
|
365
|
+
if (/taskupdate/.test(normalized)) return ["Updating task", "Updated task", "Task update failed"][position];
|
|
366
|
+
if (/create.?goal/.test(normalized)) return ["Creating goal", "Created goal", "Goal creation failed"][position];
|
|
367
|
+
if (/update.?goal/.test(normalized)) return ["Updating goal", "Updated goal", "Goal update failed"][position];
|
|
325
368
|
const actions = {
|
|
326
369
|
read: ["Reading", "Read", "Read failed"],
|
|
327
370
|
search: ["Searching", "Searched", "Search failed"],
|
|
@@ -338,18 +381,21 @@ function createToolPresentation(entry) {
|
|
|
338
381
|
const envelope = toolEnvelope(entry);
|
|
339
382
|
const args = envelope.args;
|
|
340
383
|
const outcome = toolResultEnvelope(entry.resultText);
|
|
384
|
+
const patchSource = assignedString(envelope.source, ["patch"]) || envelope.source;
|
|
341
385
|
const command = firstString(args, ["command", "cmd"]) || sourceString(envelope.callSource, ["command", "cmd"]);
|
|
342
386
|
const category = classifyTool(envelope.name, command || envelope.source || entry.arguments || "");
|
|
343
|
-
const path = firstString(args, ["file_path", "target_file", "target_directory", "path"]) || sourceString(envelope.callSource, ["file_path", "target_file", "target_directory", "path"]) || patchPath(
|
|
387
|
+
const path = firstString(args, ["file_path", "target_file", "target_directory", "path"]) || sourceString(envelope.callSource, ["file_path", "target_file", "target_directory", "path"]) || patchPath(patchSource);
|
|
344
388
|
const query = firstString(args, ["query", "pattern"]) || sourceString(envelope.callSource, ["query", "pattern", "q"]);
|
|
345
389
|
const url = firstString(args, ["url"]) || sourceString(envelope.callSource, ["url", "ref_id"]);
|
|
346
|
-
const subject = firstString(args, ["subject", "description", "summary", "task", "prompt"]) || sourceString(envelope.callSource, ["subject", "description", "summary", "task", "prompt"]);
|
|
390
|
+
const subject = firstString(args, ["subject", "description", "summary", "task", "objective", "prompt"]) || sourceString(envelope.callSource, ["subject", "description", "summary", "task", "objective", "prompt"]);
|
|
391
|
+
const agentTarget = category === "agent" ? firstString(record(outcome.value), ["command", "name"]) || firstString(args, ["target", "task_name", "taskId", "task_id", "agentId", "agent_id", "resume", "team_name"]) || sourceString(envelope.callSource, ["target", "task_name", "taskId", "task_id", "agentId", "agent_id", "resume", "team_name"]) : "";
|
|
392
|
+
const skillTarget = /^skill$|use.?skill|load.?skill/i.test(envelope.name) ? firstString(args, ["skill", "name"]) || sourceString(envelope.callSource, ["skill", "name"]) : "";
|
|
347
393
|
const background = /get_command_or_subagent_output|kill_command_or_subagent/i.test(envelope.name) ? "background task" : /write_stdin|^wait$/i.test(envelope.name) ? "background command" : "";
|
|
348
|
-
const items = planItems(args);
|
|
394
|
+
const items = category === "agent" ? agentItems(envelope.name, outcome.preview) : planItems(args);
|
|
349
395
|
const taskId = firstString(args, ["taskId", "task_id"]);
|
|
350
396
|
const planTarget = category === "plan" ? items.length ? `${items.length} ${items.length === 1 ? "item" : "items"}` : taskId ? `task ${taskId}` : "" : "";
|
|
351
|
-
const target = path || command || query || url || subject || background || planTarget || (envelope.tools.length > 1 ? `${envelope.tools.length} coordinated actions` : toolTarget(entry.arguments));
|
|
352
|
-
const previewSource = category === "edit" ? editPreview(args, outcome.preview, envelope.
|
|
397
|
+
const target = path || command || query || url || subject || agentTarget || skillTarget || background || planTarget || (envelope.tools.length > 1 ? `${envelope.tools.length} coordinated actions` : toolTarget(entry.arguments));
|
|
398
|
+
const previewSource = category === "edit" ? editPreview(args, outcome.preview, patchSource) : category === "agent" ? semanticAgentPreview(envelope.name, entry.status ?? "completed", outcome) : outcome.preview;
|
|
353
399
|
const result = record(entry.resultContent);
|
|
354
400
|
const metadata = record(entry.metadata);
|
|
355
401
|
const resultMetadata = record(result?.metadata);
|
|
@@ -529,6 +575,7 @@ function boundedSet(map, key, value) {
|
|
|
529
575
|
// src/icon.jsx
|
|
530
576
|
import { Fragment, jsx as jsx2, jsxs } from "preact/jsx-runtime";
|
|
531
577
|
var ICONS = {
|
|
578
|
+
attach: () => /* @__PURE__ */ jsx2("path", { d: "M6.25 9.75 10.6 5.4a2.1 2.1 0 0 1 2.97 2.97l-5.4 5.4a3.3 3.3 0 0 1-4.67-4.66l5.52-5.52" }),
|
|
532
579
|
back: () => /* @__PURE__ */ jsx2("path", { d: "m11.5 4.5-4.5 4.5 4.5 4.5" }),
|
|
533
580
|
check: () => /* @__PURE__ */ jsx2("path", { d: "m4 9 3.25 3.25L14 5.5" }),
|
|
534
581
|
chevron: () => /* @__PURE__ */ jsx2("path", { d: "m7 4.5 4.5 4.5L7 13.5" }),
|
|
@@ -799,7 +846,10 @@ function ToolPreview({ presentation, entry }) {
|
|
|
799
846
|
presentation.url ? /* @__PURE__ */ jsx3("code", { children: presentation.url }) : null,
|
|
800
847
|
presentation.preview ? /* @__PURE__ */ jsx3("p", { children: stripAnsi(presentation.preview) }) : /* @__PURE__ */ jsx3("small", { children: pending ? "Waiting for the page" : "No page summary returned" })
|
|
801
848
|
] });
|
|
802
|
-
if (presentation.detail === "agent") return /* @__PURE__ */ jsx3("section", { class: "scui-agent-preview", children: presentation.
|
|
849
|
+
if (presentation.detail === "agent") return /* @__PURE__ */ jsx3("section", { class: "scui-agent-preview", children: presentation.items?.length ? /* @__PURE__ */ jsx3("ol", { class: "scui-agent-roster", children: presentation.items.map((item, index) => /* @__PURE__ */ jsxs2("li", { children: [
|
|
850
|
+
/* @__PURE__ */ jsx3("strong", { children: item.label }),
|
|
851
|
+
/* @__PURE__ */ jsx3("small", { children: item.status })
|
|
852
|
+
] }, `${item.label}:${index}`)) }) : presentation.preview ? /* @__PURE__ */ jsx3("pre", { children: stripAnsi(presentation.preview) }) : /* @__PURE__ */ jsx3("small", { children: pending ? "Agent is working" : "No textual handoff returned" }) });
|
|
803
853
|
if (presentation.detail === "plan") return /* @__PURE__ */ jsx3("ol", { class: "scui-plan-preview", children: presentation.items?.map((item, index) => /* @__PURE__ */ jsxs2("li", { "data-status": item.status, children: [
|
|
804
854
|
/* @__PURE__ */ jsx3("i", { "aria-hidden": "true" }),
|
|
805
855
|
/* @__PURE__ */ jsx3("span", { children: item.label })
|
|
@@ -1017,18 +1067,23 @@ function Conversation({ state, adapter, components = {}, slots = {}, memoryKey =
|
|
|
1017
1067
|
const element = scroller.current;
|
|
1018
1068
|
if (!element) return;
|
|
1019
1069
|
const anchor = earlierAnchor.current;
|
|
1020
|
-
if (anchor
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1070
|
+
if (anchor) {
|
|
1071
|
+
if (state.operation === "loadEarlier") anchor.seenOperation = true;
|
|
1072
|
+
const prepended = state.transcript.length > anchor.entries && state.transcript[0]?.id !== anchor.firstId;
|
|
1073
|
+
if (prepended) {
|
|
1074
|
+
element.scrollTop = anchor.top + (element.scrollHeight - anchor.height);
|
|
1075
|
+
earlierAnchor.current = null;
|
|
1076
|
+
remember({ top: element.scrollTop, atBottom: false });
|
|
1077
|
+
return;
|
|
1078
|
+
}
|
|
1079
|
+
if (state.error || anchor.seenOperation && state.operation !== "loadEarlier") earlierAnchor.current = null;
|
|
1025
1080
|
}
|
|
1026
1081
|
if (!restored.current) {
|
|
1027
1082
|
restored.current = true;
|
|
1028
1083
|
if (remembered.top !== null && !remembered.atBottom) element.scrollTop = remembered.top;
|
|
1029
1084
|
else pin();
|
|
1030
1085
|
} else if (atBottom) pin();
|
|
1031
|
-
}, [memoryKey, state.transcript, state.busy, state.operation, pendingMessage?.text, pendingMessage?.status]);
|
|
1086
|
+
}, [memoryKey, state.transcript, state.busy, state.operation, state.error, pendingMessage?.text, pendingMessage?.status]);
|
|
1032
1087
|
return /* @__PURE__ */ jsxs2("div", { class: "scui-conversation-wrap", children: [
|
|
1033
1088
|
/* @__PURE__ */ jsx3(ConversationAnnouncements, { state }),
|
|
1034
1089
|
/* @__PURE__ */ jsx3("div", { class: "scui-conversation", ref: scroller, tabIndex: 0, "aria-label": "Conversation", onScroll: (event) => {
|
|
@@ -1042,7 +1097,7 @@ function Conversation({ state, adapter, components = {}, slots = {}, memoryKey =
|
|
|
1042
1097
|
/* @__PURE__ */ jsx3(SessionDetails, { semantics: state.semantics }),
|
|
1043
1098
|
state.history.hasEarlier ? /* @__PURE__ */ jsx3("button", { class: "scui-load", type: "button", disabled: Boolean(state.operation), onClick: () => {
|
|
1044
1099
|
const element = scroller.current;
|
|
1045
|
-
if (element) earlierAnchor.current = { height: element.scrollHeight, top: element.scrollTop, entries: state.transcript.length };
|
|
1100
|
+
if (element) earlierAnchor.current = { height: element.scrollHeight, top: element.scrollTop, entries: state.transcript.length, firstId: state.transcript[0]?.id, seenOperation: false };
|
|
1046
1101
|
setAtBottom(false);
|
|
1047
1102
|
adapter.onIntent({ action: "loadEarlier" });
|
|
1048
1103
|
}, children: "Load earlier messages" }) : null,
|
|
@@ -1054,6 +1109,7 @@ function Conversation({ state, adapter, components = {}, slots = {}, memoryKey =
|
|
|
1054
1109
|
] }, block.id)),
|
|
1055
1110
|
pendingMessage ? /* @__PURE__ */ jsxs2("article", { class: "scui-message scui-pending", "data-role": "user", "data-status": pendingMessage.status, "aria-label": "Your pending message", children: [
|
|
1056
1111
|
/* @__PURE__ */ jsx3(Markdown, { value: pendingMessage.text, copyText: adapter?.copyText }),
|
|
1112
|
+
/* @__PURE__ */ jsx3(ContextDisclosure, { context: pendingMessage.context }),
|
|
1057
1113
|
/* @__PURE__ */ jsxs2("footer", { children: [
|
|
1058
1114
|
/* @__PURE__ */ jsx3("small", { children: pendingMessage.status === "failed" ? "Not sent" : "Sending\u2026" }),
|
|
1059
1115
|
pendingMessage.status === "failed" ? /* @__PURE__ */ jsxs2("span", { children: [
|
package/core.mjs
CHANGED
|
@@ -131,6 +131,13 @@ function sourceString(source, keys) {
|
|
|
131
131
|
return decodedLiteral(match?.[1]);
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
function assignedString(source, keys) {
|
|
135
|
+
if (!source) return '';
|
|
136
|
+
const names = keys.join('|');
|
|
137
|
+
const match = new RegExp(`\\b(?:${names})\\s*=\\s*(\"(?:\\\\.|[^\"\\\\])*\"|'(?:\\\\.|[^'\\\\])*'|\`(?:\\\\.|[^\`\\\\])*\`)`).exec(source);
|
|
138
|
+
return decodedLiteral(match?.[1]);
|
|
139
|
+
}
|
|
140
|
+
|
|
134
141
|
function callArgumentSource(source, open) {
|
|
135
142
|
let depth = 1;
|
|
136
143
|
let quote = '';
|
|
@@ -243,6 +250,14 @@ function planItems(args) {
|
|
|
243
250
|
}).slice(0, 12);
|
|
244
251
|
}
|
|
245
252
|
|
|
253
|
+
function agentItems(name, resultText) {
|
|
254
|
+
if (!/list.?agents/i.test(name)) return [];
|
|
255
|
+
return (resultText ?? '').split('\n').flatMap((line) => {
|
|
256
|
+
const parts = line.trim().split(/\s+·\s+/).filter(Boolean);
|
|
257
|
+
return parts.length > 1 ? [{ label: boundedString(parts[0], 120), status: boundedString(parts.slice(1).join(' · '), 180) }] : [];
|
|
258
|
+
}).slice(0, 12);
|
|
259
|
+
}
|
|
260
|
+
|
|
246
261
|
function editPreview(args, resultText, source) {
|
|
247
262
|
const direct = firstString(args, ['patch', 'diff']);
|
|
248
263
|
if (direct) return direct;
|
|
@@ -261,7 +276,19 @@ function editPreview(args, resultText, source) {
|
|
|
261
276
|
|
|
262
277
|
function toolResultEnvelope(resultText) {
|
|
263
278
|
const match = /^Script (?:completed|failed)\r?\nWall time ([0-9.]+) seconds\r?\nOutput:\r?\n([\s\S]*)$/.exec(resultText ?? '');
|
|
264
|
-
if (!match)
|
|
279
|
+
if (!match) {
|
|
280
|
+
try {
|
|
281
|
+
const value = JSON.parse(resultText ?? '');
|
|
282
|
+
const object = record(value);
|
|
283
|
+
return {
|
|
284
|
+
preview: typeof value === 'string' ? value : firstString(object, ['output', 'message', 'text', 'summary', 'result']) || resultText || '',
|
|
285
|
+
value: object,
|
|
286
|
+
durationMs: null,
|
|
287
|
+
};
|
|
288
|
+
} catch {
|
|
289
|
+
return { preview: resultText ?? '', value: null, durationMs: null };
|
|
290
|
+
}
|
|
291
|
+
}
|
|
265
292
|
const durationMs = Number(match[1]) * 1_000;
|
|
266
293
|
try {
|
|
267
294
|
const value = record(JSON.parse(match[2]));
|
|
@@ -275,6 +302,16 @@ function toolResultEnvelope(resultText) {
|
|
|
275
302
|
}
|
|
276
303
|
}
|
|
277
304
|
|
|
305
|
+
function semanticAgentPreview(name, status, outcome) {
|
|
306
|
+
const normalized = name.toLocaleLowerCase();
|
|
307
|
+
if (status === 'error') return outcome.preview;
|
|
308
|
+
if (/^(?:agent|task)$|spawn.?agent/.test(normalized) && outcome.preview) return 'Agent is working in the background.';
|
|
309
|
+
if (/send.?message|followup.?task/.test(normalized) && outcome.preview) {
|
|
310
|
+
return /resumed from transcript|resumedAgentId/i.test(outcome.preview) ? 'Agent resumed in the background.' : 'Message delivered.';
|
|
311
|
+
}
|
|
312
|
+
return outcome.preview;
|
|
313
|
+
}
|
|
314
|
+
|
|
278
315
|
function verificationCommand(command) {
|
|
279
316
|
let shell = '';
|
|
280
317
|
let quote = '';
|
|
@@ -292,12 +329,13 @@ function verificationCommand(command) {
|
|
|
292
329
|
function classifyTool(name, command) {
|
|
293
330
|
const normalized = name.toLocaleLowerCase();
|
|
294
331
|
if (/write_stdin|^wait$/.test(normalized)) return 'command';
|
|
295
|
-
if (/update.?plan|todo|checklist|taskcreate|taskupdate/.test(normalized)) return 'plan';
|
|
332
|
+
if (/update.?plan|todo|checklist|taskcreate|taskupdate|create.?goal|update.?goal/.test(normalized)) return 'plan';
|
|
296
333
|
if (/search.?replace|edit|write|patch|replace|create_file|apply_patch/.test(normalized)) return 'edit';
|
|
297
334
|
if (/read|view|open_file|list_dir/.test(normalized)) return 'read';
|
|
335
|
+
if (/web.?search|web.?fetch|fetch.?url/.test(normalized)) return 'web';
|
|
298
336
|
if (/search|find|grep|glob|toolsearch/.test(normalized)) return 'search';
|
|
299
337
|
if (/browser|web|fetch|url/.test(normalized)) return 'web';
|
|
300
|
-
if (/agent|subagent|
|
|
338
|
+
if (/agent|subagent|send.?message|delegate|followup.?task|taskstop|taskoutput|^task$/.test(normalized)) return 'agent';
|
|
301
339
|
if (/test|typecheck|lint|build/.test(normalized)) return 'test';
|
|
302
340
|
if (/terminal|bash|shell|command|exec|write_stdin|^wait$/.test(normalized)) return verificationCommand(command) ? 'test' : 'command';
|
|
303
341
|
return 'other';
|
|
@@ -307,9 +345,17 @@ function toolAction(status, category, name, tools) {
|
|
|
307
345
|
const position = status === 'pending' ? 0 : status === 'error' ? 2 : 1;
|
|
308
346
|
if (tools.length > 1) return [`Running ${tools.length} actions`, `Ran ${tools.length} actions`, `${tools.length} actions failed`][position];
|
|
309
347
|
const normalized = name.toLocaleLowerCase();
|
|
310
|
-
if (/
|
|
311
|
-
if (/kill_command_or_subagent/.test(normalized)) return ['Stopping', 'Stopped', 'Stop failed'][position];
|
|
348
|
+
if (/send.?message|followup.?task/.test(normalized)) return ['Messaging agent', 'Messaged agent', 'Agent message failed'][position];
|
|
349
|
+
if (/taskstop|interrupt.?agent|kill_command_or_subagent/.test(normalized)) return ['Stopping agent', 'Stopped agent', 'Stop failed'][position];
|
|
350
|
+
if (/list.?agents|taskoutput|wait.?agent/.test(normalized)) return ['Checking agents', 'Checked agents', 'Agent check failed'][position];
|
|
312
351
|
if (/get_command_or_subagent_output|write_stdin|^wait$/.test(normalized)) return ['Waiting for', 'Checked', 'Check failed'][position];
|
|
352
|
+
if (/web.?search/.test(normalized)) return ['Searching web', 'Searched web', 'Web search failed'][position];
|
|
353
|
+
if (/web.?fetch|fetch.?url/.test(normalized)) return ['Fetching page', 'Fetched page', 'Page fetch failed'][position];
|
|
354
|
+
if (/^skill$|use.?skill|load.?skill/.test(normalized)) return ['Loading skill', 'Loaded skill', 'Skill load failed'][position];
|
|
355
|
+
if (/taskcreate/.test(normalized)) return ['Adding task', 'Added task', 'Task creation failed'][position];
|
|
356
|
+
if (/taskupdate/.test(normalized)) return ['Updating task', 'Updated task', 'Task update failed'][position];
|
|
357
|
+
if (/create.?goal/.test(normalized)) return ['Creating goal', 'Created goal', 'Goal creation failed'][position];
|
|
358
|
+
if (/update.?goal/.test(normalized)) return ['Updating goal', 'Updated goal', 'Goal update failed'][position];
|
|
313
359
|
const actions = {
|
|
314
360
|
read: ['Reading', 'Read', 'Read failed'],
|
|
315
361
|
search: ['Searching', 'Searched', 'Search failed'],
|
|
@@ -327,18 +373,25 @@ export function createToolPresentation(entry) {
|
|
|
327
373
|
const envelope = toolEnvelope(entry);
|
|
328
374
|
const args = envelope.args;
|
|
329
375
|
const outcome = toolResultEnvelope(entry.resultText);
|
|
376
|
+
const patchSource = assignedString(envelope.source, ['patch']) || envelope.source;
|
|
330
377
|
const command = firstString(args, ['command', 'cmd']) || sourceString(envelope.callSource, ['command', 'cmd']);
|
|
331
378
|
const category = classifyTool(envelope.name, command || envelope.source || entry.arguments || '');
|
|
332
|
-
const path = firstString(args, ['file_path', 'target_file', 'target_directory', 'path']) || sourceString(envelope.callSource, ['file_path', 'target_file', 'target_directory', 'path']) || patchPath(
|
|
379
|
+
const path = firstString(args, ['file_path', 'target_file', 'target_directory', 'path']) || sourceString(envelope.callSource, ['file_path', 'target_file', 'target_directory', 'path']) || patchPath(patchSource);
|
|
333
380
|
const query = firstString(args, ['query', 'pattern']) || sourceString(envelope.callSource, ['query', 'pattern', 'q']);
|
|
334
381
|
const url = firstString(args, ['url']) || sourceString(envelope.callSource, ['url', 'ref_id']);
|
|
335
|
-
const subject = firstString(args, ['subject', 'description', 'summary', 'task', 'prompt']) || sourceString(envelope.callSource, ['subject', 'description', 'summary', 'task', 'prompt']);
|
|
382
|
+
const subject = firstString(args, ['subject', 'description', 'summary', 'task', 'objective', 'prompt']) || sourceString(envelope.callSource, ['subject', 'description', 'summary', 'task', 'objective', 'prompt']);
|
|
383
|
+
const agentTarget = category === 'agent'
|
|
384
|
+
? firstString(record(outcome.value), ['command', 'name']) || firstString(args, ['target', 'task_name', 'taskId', 'task_id', 'agentId', 'agent_id', 'resume', 'team_name']) || sourceString(envelope.callSource, ['target', 'task_name', 'taskId', 'task_id', 'agentId', 'agent_id', 'resume', 'team_name'])
|
|
385
|
+
: '';
|
|
386
|
+
const skillTarget = /^skill$|use.?skill|load.?skill/i.test(envelope.name)
|
|
387
|
+
? firstString(args, ['skill', 'name']) || sourceString(envelope.callSource, ['skill', 'name'])
|
|
388
|
+
: '';
|
|
336
389
|
const background = /get_command_or_subagent_output|kill_command_or_subagent/i.test(envelope.name) ? 'background task' : /write_stdin|^wait$/i.test(envelope.name) ? 'background command' : '';
|
|
337
|
-
const items = planItems(args);
|
|
390
|
+
const items = category === 'agent' ? agentItems(envelope.name, outcome.preview) : planItems(args);
|
|
338
391
|
const taskId = firstString(args, ['taskId', 'task_id']);
|
|
339
392
|
const planTarget = category === 'plan' ? items.length ? `${items.length} ${items.length === 1 ? 'item' : 'items'}` : taskId ? `task ${taskId}` : '' : '';
|
|
340
|
-
const target = path || command || query || url || subject || background || planTarget || (envelope.tools.length > 1 ? `${envelope.tools.length} coordinated actions` : toolTarget(entry.arguments));
|
|
341
|
-
const previewSource = category === 'edit' ? editPreview(args, outcome.preview, envelope.
|
|
393
|
+
const target = path || command || query || url || subject || agentTarget || skillTarget || background || planTarget || (envelope.tools.length > 1 ? `${envelope.tools.length} coordinated actions` : toolTarget(entry.arguments));
|
|
394
|
+
const previewSource = category === 'edit' ? editPreview(args, outcome.preview, patchSource) : category === 'agent' ? semanticAgentPreview(envelope.name, entry.status ?? 'completed', outcome) : outcome.preview;
|
|
342
395
|
const result = record(entry.resultContent);
|
|
343
396
|
const metadata = record(entry.metadata);
|
|
344
397
|
const resultMetadata = record(result?.metadata);
|
|
@@ -668,7 +721,7 @@ export function sessionActivity(state, row) {
|
|
|
668
721
|
export function filterSessions(rows, query) {
|
|
669
722
|
const needle = query.trim().toLocaleLowerCase();
|
|
670
723
|
if (!needle) return [...rows];
|
|
671
|
-
return rows.filter((row) => [row.name, row.title, row.cwd, row.harness, harnessDisplayName(row.harness)].some((value) => value.toLocaleLowerCase().includes(needle)));
|
|
724
|
+
return rows.filter((row) => [row.name, row.title, row.preview, row.cwd, row.harness, harnessDisplayName(row.harness)].some((value) => typeof value === 'string' && value.toLocaleLowerCase().includes(needle)));
|
|
672
725
|
}
|
|
673
726
|
|
|
674
727
|
export function groupConversation(entries) {
|