@volter-ai-dev/supercode-ui 0.1.1 → 0.1.3

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/conversation.mjs CHANGED
@@ -1,11 +1,12 @@
1
- // src/components.jsx
2
- import MarkdownIt from "markdown-it";
3
- import { useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "preact/hooks";
1
+ // src/conversation.jsx
2
+ import { useEffect, useId, useLayoutEffect, useRef, useState } from "preact/hooks";
4
3
 
5
4
  // core.mjs
6
5
  var HARNESS_NAMES = Object.freeze({
7
6
  "claude-code": "Claude Code",
8
7
  codex: "Codex",
8
+ gemini: "Gemini CLI",
9
+ goose: "Goose",
9
10
  opencode: "OpenCode",
10
11
  pi: "Pi",
11
12
  grok: "Grok"
@@ -109,8 +110,10 @@ function activitySummary(entries) {
109
110
  return `Activity \xB7 ${Object.entries(labels).flatMap(([key, label]) => counts.has(key) ? [`${counts.get(key)} ${label}`] : []).join(" \xB7 ")}`;
110
111
  }
111
112
 
112
- // src/components.jsx
113
- import { jsx, jsxs } from "preact/jsx-runtime";
113
+ // src/markdown.jsx
114
+ import MarkdownIt from "markdown-it";
115
+ import { useMemo } from "preact/hooks";
116
+ import { jsx } from "preact/jsx-runtime";
114
117
  var markdown = new MarkdownIt({ html: false, linkify: true, breaks: false });
115
118
  var defaultLinkOpen = markdown.renderer.rules.link_open;
116
119
  markdown.renderer.rules.link_open = (tokens, index, options, env, self) => {
@@ -122,6 +125,17 @@ function Markdown({ value }) {
122
125
  const html = useMemo(() => markdown.render(value), [value]);
123
126
  return /* @__PURE__ */ jsx("div", { class: "scui-markdown", dangerouslySetInnerHTML: { __html: html } });
124
127
  }
128
+
129
+ // src/memory.js
130
+ var MEMORY_LIMIT = 100;
131
+ function boundedSet(map, key, value) {
132
+ map.delete(key);
133
+ map.set(key, value);
134
+ while (map.size > MEMORY_LIMIT) map.delete(map.keys().next().value);
135
+ }
136
+
137
+ // src/conversation.jsx
138
+ import { jsx as jsx2, jsxs } from "preact/jsx-runtime";
125
139
  function LoadingStatus({ state, compact = false }) {
126
140
  const copy = {
127
141
  connecting: ["Connecting to coding agents", "Checking installed harnesses and capabilities.", 0],
@@ -130,12 +144,12 @@ function LoadingStatus({ state, compact = false }) {
130
144
  ready: ["Ready", "Coding sessions are up to date.", 3]
131
145
  }[state.startup];
132
146
  return /* @__PURE__ */ jsxs("div", { class: `scui-loading${compact ? " scui-loading-compact" : ""}`, role: "status", "aria-busy": state.startup !== "ready", children: [
133
- /* @__PURE__ */ jsx("span", { class: "scui-orbit", "aria-hidden": "true", children: /* @__PURE__ */ jsx("i", {}) }),
147
+ /* @__PURE__ */ jsx2("span", { class: "scui-orbit", "aria-hidden": "true", children: /* @__PURE__ */ jsx2("i", {}) }),
134
148
  /* @__PURE__ */ jsxs("span", { class: "scui-loading-copy", children: [
135
- /* @__PURE__ */ jsx("strong", { children: copy[0] }),
136
- /* @__PURE__ */ jsx("small", { children: copy[1] })
149
+ /* @__PURE__ */ jsx2("strong", { children: copy[0] }),
150
+ /* @__PURE__ */ jsx2("small", { children: copy[1] })
137
151
  ] }),
138
- /* @__PURE__ */ jsx("span", { class: "scui-progress", "aria-hidden": "true", children: [1, 2, 3].map((step) => /* @__PURE__ */ jsx("i", { "data-progress": step <= copy[2] ? "done" : step === copy[2] + 1 ? "current" : "waiting" }, step)) })
152
+ /* @__PURE__ */ jsx2("span", { class: "scui-progress", "aria-hidden": "true", children: [1, 2, 3].map((step) => /* @__PURE__ */ jsx2("i", { "data-progress": step <= copy[2] ? "done" : step === copy[2] + 1 ? "current" : "waiting" }, step)) })
139
153
  ] });
140
154
  }
141
155
  function RequestCard({ entry, adapter, canRespond }) {
@@ -148,11 +162,11 @@ function RequestCard({ entry, adapter, canRespond }) {
148
162
  ] });
149
163
  }
150
164
  return /* @__PURE__ */ jsxs("section", { class: "scui-request", "aria-label": `${request.requestKind} needs input`, children: [
151
- /* @__PURE__ */ jsx("strong", { children: "Agent needs input" }),
152
- /* @__PURE__ */ jsx(Markdown, { value: request.payloadText || entry.text }),
165
+ /* @__PURE__ */ jsx2("strong", { children: "Agent needs input" }),
166
+ /* @__PURE__ */ jsx2(Markdown, { value: request.payloadText || entry.text }),
153
167
  /* @__PURE__ */ jsxs("div", { class: "scui-request-actions", children: [
154
- request.options.map((option) => /* @__PURE__ */ jsx("button", { type: "button", disabled: !canRespond, onClick: () => adapter.onIntent({ action: "respond", requestId: request.requestId, optionId: option.optionId }), children: option.name }, option.optionId)),
155
- request.cancellable ? /* @__PURE__ */ jsx("button", { type: "button", disabled: !canRespond, onClick: () => adapter.onIntent({ action: "respond", requestId: request.requestId, optionId: null }), children: "Cancel" }) : null
168
+ request.options.map((option) => /* @__PURE__ */ jsx2("button", { type: "button", disabled: !canRespond, onClick: () => adapter.onIntent({ action: "respond", requestId: request.requestId, optionId: option.optionId }), children: option.name }, option.optionId)),
169
+ request.cancellable ? /* @__PURE__ */ jsx2("button", { type: "button", disabled: !canRespond, onClick: () => adapter.onIntent({ action: "respond", requestId: request.requestId, optionId: null }), children: "Cancel" }) : null
156
170
  ] })
157
171
  ] });
158
172
  }
@@ -163,25 +177,25 @@ function ContextDisclosure({ context }) {
163
177
  "Context \xB7 ",
164
178
  context.length
165
179
  ] }),
166
- /* @__PURE__ */ jsx("div", { children: context.map((item, index) => /* @__PURE__ */ jsxs("p", { children: [
167
- /* @__PURE__ */ jsx("strong", { children: item.label }),
168
- /* @__PURE__ */ jsx("span", { children: item.detail })
180
+ /* @__PURE__ */ jsx2("div", { children: context.map((item, index) => /* @__PURE__ */ jsxs("p", { children: [
181
+ /* @__PURE__ */ jsx2("strong", { children: item.label }),
182
+ /* @__PURE__ */ jsx2("span", { children: item.detail })
169
183
  ] }, item.id ?? index)) })
170
184
  ] });
171
185
  }
172
186
  function TranscriptEntry({ entry, state, adapter }) {
173
- if (entry.role === "request") return /* @__PURE__ */ jsx(RequestCard, { entry, adapter, canRespond: state.canRespond });
187
+ if (entry.role === "request") return /* @__PURE__ */ jsx2(RequestCard, { entry, adapter, canRespond: state.canRespond });
174
188
  if (entry.role === "reasoning") {
175
189
  return /* @__PURE__ */ jsxs("details", { class: "scui-reasoning", open: entry.streaming, children: [
176
- /* @__PURE__ */ jsx("summary", { children: entry.streaming ? "Reasoning\u2026" : "Reasoning" }),
177
- /* @__PURE__ */ jsx(Markdown, { value: entry.text })
190
+ /* @__PURE__ */ jsx2("summary", { children: entry.streaming ? "Reasoning\u2026" : "Reasoning" }),
191
+ /* @__PURE__ */ jsx2(Markdown, { value: entry.text })
178
192
  ] });
179
193
  }
180
- if (entry.role === "notice" || entry.role === "system") return /* @__PURE__ */ jsx("div", { class: "scui-notice", "data-code": entry.code, children: entry.text });
194
+ if (entry.role === "notice" || entry.role === "system") return /* @__PURE__ */ jsx2("div", { class: "scui-notice", "data-code": entry.code, children: entry.text });
181
195
  return /* @__PURE__ */ jsxs("article", { class: "scui-message", "data-role": entry.role, children: [
182
- /* @__PURE__ */ jsx(Markdown, { value: entry.text }),
183
- /* @__PURE__ */ jsx(ContextDisclosure, { context: entry.context }),
184
- entry.truncated ? /* @__PURE__ */ jsx("small", { class: "scui-truncated", children: "Entry truncated by host \xB7 load native session for the complete value" }) : null
196
+ /* @__PURE__ */ jsx2(Markdown, { value: entry.text }),
197
+ /* @__PURE__ */ jsx2(ContextDisclosure, { context: entry.context }),
198
+ entry.truncated ? /* @__PURE__ */ jsx2("small", { class: "scui-truncated", children: "Entry truncated by host \xB7 load native session for the complete value" }) : null
185
199
  ] });
186
200
  }
187
201
  function ToolRow({ entry, workspace }) {
@@ -192,20 +206,20 @@ function ToolRow({ entry, workspace }) {
192
206
  const category = toolCategory(entry);
193
207
  return /* @__PURE__ */ jsxs("div", { class: "scui-tool", "data-status": entry.status ?? "completed", "data-category": category, children: [
194
208
  /* @__PURE__ */ jsxs("button", { type: "button", class: "scui-tool-head", disabled: !hasDetail, "aria-expanded": hasDetail ? open : void 0, "aria-controls": hasDetail ? detailId : void 0, onClick: () => hasDetail && setOpen((value) => !value), children: [
195
- /* @__PURE__ */ jsx("span", { class: "scui-tool-glyph", "aria-hidden": "true", children: { read: "\u25A4", search: "\u2315", edit: "\u270E", command: ">_", test: "\u25C7", web: "\u25CE", agent: "\u2659", other: "\u25C6" }[category] }),
196
- /* @__PURE__ */ jsx("strong", { children: entry.label?.split(/__|\//).at(-1)?.replaceAll("_", " ") || "Tool" }),
197
- target ? /* @__PURE__ */ jsx("span", { class: "scui-tool-target", title: toolTarget(entry.arguments), children: target }) : null,
198
- /* @__PURE__ */ jsx("span", { class: "scui-spacer" }),
199
- /* @__PURE__ */ jsx("span", { "aria-label": entry.status ?? "completed", children: entry.status === "pending" ? "\u25CC" : entry.status === "error" ? "\xD7" : "\u2713" })
209
+ /* @__PURE__ */ jsx2("span", { class: "scui-tool-glyph", "aria-hidden": "true", children: { read: "\u25A4", search: "\u2315", edit: "\u270E", command: ">_", test: "\u25C7", web: "\u25CE", agent: "\u2659", other: "\u25C6" }[category] }),
210
+ /* @__PURE__ */ jsx2("strong", { children: entry.label?.split(/__|\//).at(-1)?.replaceAll("_", " ") || "Tool" }),
211
+ target ? /* @__PURE__ */ jsx2("span", { class: "scui-tool-target", title: toolTarget(entry.arguments), children: target }) : null,
212
+ /* @__PURE__ */ jsx2("span", { class: "scui-spacer" }),
213
+ /* @__PURE__ */ jsx2("span", { "aria-label": entry.status ?? "completed", children: entry.status === "pending" ? "\u25CC" : entry.status === "error" ? "\xD7" : "\u2713" })
200
214
  ] }),
201
215
  hasDetail && open ? /* @__PURE__ */ jsxs("div", { id: detailId, class: "scui-tool-detail", children: [
202
216
  entry.arguments ? /* @__PURE__ */ jsxs("pre", { children: [
203
- /* @__PURE__ */ jsx("b", { children: "Input" }),
217
+ /* @__PURE__ */ jsx2("b", { children: "Input" }),
204
218
  "\n",
205
219
  entry.arguments
206
220
  ] }) : null,
207
221
  entry.resultText ? /* @__PURE__ */ jsxs("pre", { "data-error": entry.status === "error", children: [
208
- /* @__PURE__ */ jsx("b", { children: "Output" }),
222
+ /* @__PURE__ */ jsx2("b", { children: "Output" }),
209
223
  "\n",
210
224
  entry.resultText,
211
225
  entry.truncated ? "\n[truncated]" : ""
@@ -222,16 +236,16 @@ function ActivityGroup({ entries, state }) {
222
236
  }, [active]);
223
237
  return /* @__PURE__ */ jsxs("section", { class: "scui-activity", children: [
224
238
  /* @__PURE__ */ jsxs("button", { class: "scui-activity-head", type: "button", "aria-expanded": open, "aria-controls": id, onClick: () => setOpen((value) => !value), children: [
225
- /* @__PURE__ */ jsx("span", { class: "scui-fold", "data-open": open, children: "\u203A" }),
226
- /* @__PURE__ */ jsx("strong", { children: activitySummary(entries) }),
227
- /* @__PURE__ */ jsx("span", { class: "scui-spacer" }),
239
+ /* @__PURE__ */ jsx2("span", { class: "scui-fold", "data-open": open, children: "\u203A" }),
240
+ /* @__PURE__ */ jsx2("strong", { children: activitySummary(entries) }),
241
+ /* @__PURE__ */ jsx2("span", { class: "scui-spacer" }),
228
242
  /* @__PURE__ */ jsxs("small", { children: [
229
243
  entries.filter((entry) => entry.status === "completed").length,
230
244
  "/",
231
245
  entries.length
232
246
  ] })
233
247
  ] }),
234
- open ? /* @__PURE__ */ jsx("div", { id, children: entries.map((entry) => /* @__PURE__ */ jsx(ToolRow, { entry, workspace: state.workspace }, entry.id)) }) : null
248
+ open ? /* @__PURE__ */ jsx2("div", { id, children: entries.map((entry) => /* @__PURE__ */ jsx2(ToolRow, { entry, workspace: state.workspace }, entry.id)) }) : null
235
249
  ] });
236
250
  }
237
251
  function TaskPlan({ plan }) {
@@ -239,43 +253,43 @@ function TaskPlan({ plan }) {
239
253
  const complete = plan.items.filter((item) => item.status === "completed" || item.status === "cancelled").length;
240
254
  return /* @__PURE__ */ jsxs("details", { class: "scui-plan", children: [
241
255
  /* @__PURE__ */ jsxs("summary", { children: [
242
- /* @__PURE__ */ jsx("span", { children: "Plan" }),
256
+ /* @__PURE__ */ jsx2("span", { children: "Plan" }),
243
257
  /* @__PURE__ */ jsxs("small", { children: [
244
258
  complete,
245
259
  "/",
246
260
  plan.items.length
247
261
  ] })
248
262
  ] }),
249
- /* @__PURE__ */ jsx("ol", { children: plan.items.map((item) => /* @__PURE__ */ jsxs("li", { "data-status": item.status, children: [
250
- /* @__PURE__ */ jsx("i", { "aria-hidden": "true" }),
263
+ /* @__PURE__ */ jsx2("ol", { tabIndex: 0, "aria-label": "Task plan steps", children: plan.items.map((item) => /* @__PURE__ */ jsxs("li", { "data-status": item.status, children: [
264
+ /* @__PURE__ */ jsx2("i", { "aria-hidden": "true" }),
251
265
  " ",
252
- /* @__PURE__ */ jsx("span", { children: item.title })
266
+ /* @__PURE__ */ jsx2("span", { children: item.title })
253
267
  ] }, item.id)) })
254
268
  ] });
255
269
  }
256
270
  function SessionDetails({ semantics }) {
257
271
  if (!semantics.fidelity && !semantics.residueCount && !semantics.parseErrors && !semantics.subagents.length) return null;
258
272
  return /* @__PURE__ */ jsxs("details", { class: "scui-details", children: [
259
- /* @__PURE__ */ jsx("summary", { children: "Session details" }),
273
+ /* @__PURE__ */ jsx2("summary", { children: "Session details" }),
260
274
  /* @__PURE__ */ jsxs("div", { children: [
261
275
  semantics.fidelity ? /* @__PURE__ */ jsxs("p", { children: [
262
- /* @__PURE__ */ jsx("strong", { children: "Fidelity" }),
263
- /* @__PURE__ */ jsx("span", { children: semantics.fidelity.replaceAll("_", " ") })
276
+ /* @__PURE__ */ jsx2("strong", { children: "Fidelity" }),
277
+ /* @__PURE__ */ jsx2("span", { children: semantics.fidelity.replaceAll("_", " ") })
264
278
  ] }) : null,
265
279
  /* @__PURE__ */ jsxs("p", { children: [
266
- /* @__PURE__ */ jsx("strong", { children: "Native records" }),
267
- /* @__PURE__ */ jsx("span", { children: semantics.rawRecords })
280
+ /* @__PURE__ */ jsx2("strong", { children: "Native records" }),
281
+ /* @__PURE__ */ jsx2("span", { children: semantics.rawRecords })
268
282
  ] }),
269
283
  semantics.residueCount ? /* @__PURE__ */ jsxs("p", { children: [
270
- /* @__PURE__ */ jsx("strong", { children: "Residue" }),
284
+ /* @__PURE__ */ jsx2("strong", { children: "Residue" }),
271
285
  /* @__PURE__ */ jsxs("span", { children: [
272
286
  semantics.residueCount,
273
287
  " retained"
274
288
  ] })
275
289
  ] }) : null,
276
290
  semantics.parseErrors ? /* @__PURE__ */ jsxs("p", { children: [
277
- /* @__PURE__ */ jsx("strong", { children: "Parse diagnostics" }),
278
- /* @__PURE__ */ jsx("span", { children: semantics.parseErrors })
291
+ /* @__PURE__ */ jsx2("strong", { children: "Parse diagnostics" }),
292
+ /* @__PURE__ */ jsx2("span", { children: semantics.parseErrors })
279
293
  ] }) : null,
280
294
  semantics.subagents.map((agent) => /* @__PURE__ */ jsxs("p", { children: [
281
295
  /* @__PURE__ */ jsxs("strong", { children: [
@@ -304,11 +318,12 @@ function Conversation({ state, adapter, components = {}, slots = {}, memoryKey =
304
318
  const Before = slots.beforeConversation;
305
319
  const After = slots.afterConversation;
306
320
  const Empty = slots.emptyConversation;
321
+ const remember = (value) => boundedSet(conversationMemory, memoryKey, value);
307
322
  const pin = () => {
308
323
  if (!scroller.current) return;
309
324
  scroller.current.scrollTop = scroller.current.scrollHeight;
310
325
  setAtBottom(true);
311
- conversationMemory.set(memoryKey, { top: scroller.current.scrollTop, atBottom: true });
326
+ remember({ top: scroller.current.scrollTop, atBottom: true });
312
327
  };
313
328
  useLayoutEffect(() => {
314
329
  const element = scroller.current;
@@ -317,7 +332,7 @@ function Conversation({ state, adapter, components = {}, slots = {}, memoryKey =
317
332
  if (anchor && state.transcript.length > anchor.entries) {
318
333
  element.scrollTop = anchor.top + (element.scrollHeight - anchor.height);
319
334
  earlierAnchor.current = null;
320
- conversationMemory.set(memoryKey, { top: element.scrollTop, atBottom: false });
335
+ remember({ top: element.scrollTop, atBottom: false });
321
336
  return;
322
337
  }
323
338
  if (!restored.current) {
@@ -327,41 +342,41 @@ function Conversation({ state, adapter, components = {}, slots = {}, memoryKey =
327
342
  } else if (atBottom) pin();
328
343
  }, [memoryKey, state.transcript.length, state.busy]);
329
344
  return /* @__PURE__ */ jsxs("div", { class: "scui-conversation-wrap", children: [
330
- /* @__PURE__ */ jsx("div", { class: "scui-conversation", ref: scroller, tabIndex: 0, "aria-label": "Conversation", onScroll: (event) => {
345
+ /* @__PURE__ */ jsx2("div", { class: "scui-conversation", ref: scroller, tabIndex: 0, "aria-label": "Conversation", onScroll: (event) => {
331
346
  const element = event.currentTarget;
332
347
  const bottom = element.scrollHeight - element.scrollTop - element.clientHeight <= 64;
333
348
  setAtBottom(bottom);
334
- conversationMemory.set(memoryKey, { top: element.scrollTop, atBottom: bottom });
349
+ remember({ top: element.scrollTop, atBottom: bottom });
335
350
  }, children: /* @__PURE__ */ jsxs("div", { children: [
336
- Before ? /* @__PURE__ */ jsx(Before, { state, adapter, value: null }) : null,
337
- /* @__PURE__ */ jsx(TaskPlan, { plan: state.taskPlan }),
338
- /* @__PURE__ */ jsx(SessionDetails, { semantics: state.semantics }),
339
- state.history.hasEarlier ? /* @__PURE__ */ jsx("button", { class: "scui-load", type: "button", disabled: Boolean(state.operation), onClick: () => {
351
+ Before ? /* @__PURE__ */ jsx2(Before, { state, adapter, value: null }) : null,
352
+ /* @__PURE__ */ jsx2(TaskPlan, { plan: state.taskPlan }),
353
+ /* @__PURE__ */ jsx2(SessionDetails, { semantics: state.semantics }),
354
+ state.history.hasEarlier ? /* @__PURE__ */ jsx2("button", { class: "scui-load", type: "button", disabled: Boolean(state.operation), onClick: () => {
340
355
  const element = scroller.current;
341
356
  if (element) earlierAnchor.current = { height: element.scrollHeight, top: element.scrollTop, entries: state.transcript.length };
342
357
  setAtBottom(false);
343
358
  adapter.onIntent({ action: "loadEarlier" });
344
359
  }, children: "Load earlier messages" }) : null,
345
- !blocks.length && state.startup !== "ready" ? /* @__PURE__ */ jsx(LoadingStatus, { state }) : null,
346
- !blocks.length && state.startup === "ready" ? Empty ? /* @__PURE__ */ jsx(Empty, { state, adapter, value: null }) : /* @__PURE__ */ jsx("div", { class: "scui-empty", children: state.error ?? (state.harness ? `${harnessDisplayName(state.harness)} is listening. Say something.` : "No transcript yet.") }) : null,
347
- blocks.map((block) => block.kind === "activity" ? /* @__PURE__ */ jsx(Group, { value: block.entries, entries: block.entries, state, adapter }, block.id) : /* @__PURE__ */ jsx(Entry, { value: block.entry, entry: block.entry, state, adapter }, block.id)),
360
+ !blocks.length && state.startup !== "ready" ? /* @__PURE__ */ jsx2(LoadingStatus, { state }) : null,
361
+ !blocks.length && state.startup === "ready" ? Empty ? /* @__PURE__ */ jsx2(Empty, { state, adapter, value: null }) : /* @__PURE__ */ jsx2("div", { class: "scui-empty", children: state.error ?? (state.harness ? `${harnessDisplayName(state.harness)} is listening. Say something.` : "No transcript yet.") }) : null,
362
+ blocks.map((block) => block.kind === "activity" ? /* @__PURE__ */ jsx2(Group, { value: block.entries, entries: block.entries, state, adapter }, block.id) : /* @__PURE__ */ jsx2(Entry, { value: block.entry, entry: block.entry, state, adapter }, block.id)),
348
363
  pending ? /* @__PURE__ */ jsxs("article", { class: "scui-message scui-pending", "data-role": "user", children: [
349
- /* @__PURE__ */ jsx(Markdown, { value: pending }),
350
- /* @__PURE__ */ jsx("small", { children: state.error && !state.busy ? "Not sent" : "Sending\u2026" })
364
+ /* @__PURE__ */ jsx2(Markdown, { value: pending }),
365
+ /* @__PURE__ */ jsx2("small", { children: state.error && !state.busy ? "Not sent" : "Sending\u2026" })
351
366
  ] }) : null,
352
367
  state.busy ? /* @__PURE__ */ jsxs("div", { class: "scui-working", role: "status", children: [
353
- /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u2726" }),
354
- /* @__PURE__ */ jsx("i", {}),
355
- /* @__PURE__ */ jsx("i", {}),
356
- /* @__PURE__ */ jsx("i", {}),
368
+ /* @__PURE__ */ jsx2("span", { "aria-hidden": "true", children: "\u2726" }),
369
+ /* @__PURE__ */ jsx2("i", {}),
370
+ /* @__PURE__ */ jsx2("i", {}),
371
+ /* @__PURE__ */ jsx2("i", {}),
357
372
  /* @__PURE__ */ jsxs("small", { children: [
358
373
  harnessDisplayName(state.harness),
359
374
  " is working"
360
375
  ] })
361
376
  ] }) : null,
362
- After ? /* @__PURE__ */ jsx(After, { state, adapter, value: null }) : null
377
+ After ? /* @__PURE__ */ jsx2(After, { state, adapter, value: null }) : null
363
378
  ] }) }),
364
- !atBottom ? /* @__PURE__ */ jsx("button", { class: "scui-latest", type: "button", onClick: pin, children: "\u2193 Latest" }) : null
379
+ !atBottom ? /* @__PURE__ */ jsx2("button", { class: "scui-latest", type: "button", onClick: pin, children: "\u2193 Latest" }) : null
365
380
  ] });
366
381
  }
367
382
  export {
package/core.d.ts ADDED
@@ -0,0 +1,41 @@
1
+ export type {
2
+ AttachedSessionModel,
3
+ ControlStrategy,
4
+ HarnessId,
5
+ HarnessOption,
6
+ MessengerLabels,
7
+ ReductionReceiptModel,
8
+ RequestOption,
9
+ SessionActivity,
10
+ SessionAttention,
11
+ SessionMode,
12
+ SessionRowModel,
13
+ SessionSemanticsModel,
14
+ StartupPhase,
15
+ SupercodeUiIntent,
16
+ SupercodeUiState,
17
+ TaskPlanItem,
18
+ TaskPlanModel,
19
+ TranscriptContext,
20
+ TranscriptEntryModel,
21
+ TranscriptRequest,
22
+ UiTone,
23
+ } from './index.js';
24
+ export {
25
+ DEFAULT_LABELS,
26
+ EMPTY_UI_STATE,
27
+ activitySummary,
28
+ canContinueHere,
29
+ compactToolTarget,
30
+ filterSessions,
31
+ groupConversation,
32
+ harnessDisplayName,
33
+ isSendKey,
34
+ normalizeUiState,
35
+ operationLabel,
36
+ sessionActivity,
37
+ sessionDisplayName,
38
+ terminalCommand,
39
+ toolCategory,
40
+ toolTarget,
41
+ } from './index.js';
package/core.mjs CHANGED
@@ -1,6 +1,8 @@
1
1
  const HARNESS_NAMES = Object.freeze({
2
2
  'claude-code': 'Claude Code',
3
3
  codex: 'Codex',
4
+ gemini: 'Gemini CLI',
5
+ goose: 'Goose',
4
6
  opencode: 'OpenCode',
5
7
  pi: 'Pi',
6
8
  grok: 'Grok',
@@ -58,7 +60,7 @@ export const EMPTY_UI_STATE = Object.freeze({
58
60
 
59
61
  const ROLES = new Set(['system', 'user', 'assistant', 'tool', 'reasoning', 'request', 'notice']);
60
62
  const MODES = new Set(['none', 'control', 'mirror']);
61
- const STRATEGIES = new Set(['start', 'resume', 'attach', 'branch']);
63
+ const STRATEGIES = new Set(['start', 'resume', 'attach', 'branch', 'reduce']);
62
64
  const STARTUP = new Set(['connecting', 'starting', 'discovering', 'ready']);
63
65
  const FIDELITY = new Set(['byte_lossless', 'value_lossless', 'semantic']);
64
66
 
@@ -196,6 +198,72 @@ function readSemantics(value) {
196
198
  };
197
199
  }
198
200
 
201
+ function readTerminalHandoff(value) {
202
+ const handoff = record(value);
203
+ if (
204
+ !handoff ||
205
+ typeof handoff.program !== 'string' ||
206
+ !handoff.program.trim() ||
207
+ !Array.isArray(handoff.arguments) ||
208
+ !handoff.arguments.every((argument) => typeof argument === 'string') ||
209
+ typeof handoff.cwd !== 'string'
210
+ ) return null;
211
+ return { program: handoff.program, arguments: [...handoff.arguments], cwd: handoff.cwd };
212
+ }
213
+
214
+ function readExportReceipt(value) {
215
+ const receipt = record(value);
216
+ if (
217
+ !receipt ||
218
+ typeof receipt.targetHarness !== 'string' ||
219
+ !['byte_lossless', 'value_lossless'].includes(receipt.fidelity) ||
220
+ typeof receipt.path !== 'string' ||
221
+ !receipt.path.trim() ||
222
+ !Number.isInteger(receipt.files) ||
223
+ receipt.files < 1 ||
224
+ !Number.isInteger(receipt.residueCount) ||
225
+ receipt.residueCount < 0
226
+ ) return null;
227
+ return {
228
+ targetHarness: receipt.targetHarness,
229
+ fidelity: receipt.fidelity,
230
+ path: receipt.path,
231
+ files: receipt.files,
232
+ residueCount: receipt.residueCount,
233
+ };
234
+ }
235
+
236
+ function readReductionReceipt(value) {
237
+ const receipt = record(value);
238
+ if (
239
+ !receipt ||
240
+ typeof receipt.sourceTokens !== 'number' ||
241
+ !Number.isFinite(receipt.sourceTokens) ||
242
+ typeof receipt.reducedTokens !== 'number' ||
243
+ !Number.isFinite(receipt.reducedTokens) ||
244
+ receipt.sourceTokens <= receipt.reducedTokens ||
245
+ receipt.reducedTokens < 0 ||
246
+ typeof receipt.ratio !== 'number' ||
247
+ !Number.isFinite(receipt.ratio) ||
248
+ receipt.ratio <= 1 ||
249
+ typeof receipt.sidecarId !== 'string' ||
250
+ !receipt.sidecarId.trim() ||
251
+ receipt.verified !== true ||
252
+ receipt.reversible !== true ||
253
+ typeof receipt.targetHarness !== 'string' ||
254
+ !receipt.targetHarness.trim()
255
+ ) return null;
256
+ return {
257
+ sourceTokens: receipt.sourceTokens,
258
+ reducedTokens: receipt.reducedTokens,
259
+ ratio: receipt.ratio,
260
+ sidecarId: receipt.sidecarId,
261
+ verified: true,
262
+ reversible: true,
263
+ targetHarness: receipt.targetHarness,
264
+ };
265
+ }
266
+
199
267
  export function normalizeUiState(value) {
200
268
  const raw = record(value) ?? {};
201
269
  const pill = record(raw.pill);
@@ -225,10 +293,10 @@ export function normalizeUiState(value) {
225
293
  workspace: string(raw.workspace),
226
294
  taskPlan: readTaskPlan(raw.taskPlan),
227
295
  semantics: readSemantics(raw.semantics),
228
- terminalHandoff: record(raw.terminalHandoff),
296
+ terminalHandoff: readTerminalHandoff(raw.terminalHandoff),
229
297
  exportBackTarget: typeof raw.exportBackTarget === 'string' ? raw.exportBackTarget : null,
230
- exportReceipt: record(raw.exportReceipt),
231
- reductionReceipt: record(raw.reductionReceipt),
298
+ exportReceipt: readExportReceipt(raw.exportReceipt),
299
+ reductionReceipt: readReductionReceipt(raw.reductionReceipt),
232
300
  error: typeof raw.error === 'string' ? raw.error : null,
233
301
  recoverable: raw.recoverable === true,
234
302
  harnesses: Array.isArray(raw.harnesses) ? raw.harnesses.flatMap((candidate) => {
package/embed.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export type { MessengerProps, MountedMessenger, SupercodeUiState } from './index.js';
2
+ export { mountSupercodeMessenger } from './index.js';