@volter-ai-dev/supercode-ui 0.1.54 → 0.1.55

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/composer.mjs CHANGED
@@ -65,6 +65,7 @@ var EMPTY_UI_STATE = Object.freeze({
65
65
  savedDraft: "",
66
66
  attention: Object.freeze([]),
67
67
  sessions: Object.freeze([]),
68
+ subagentInspector: null,
68
69
  attached: null,
69
70
  owned: null,
70
71
  attachError: null
@@ -102,6 +103,12 @@ function boundedSet(map, key, value) {
102
103
  // src/icon.jsx
103
104
  import { Fragment, jsx, jsxs } from "preact/jsx-runtime";
104
105
  var ICONS = {
106
+ agents: () => /* @__PURE__ */ jsxs(Fragment, { children: [
107
+ /* @__PURE__ */ jsx("circle", { cx: "6", cy: "6.5", r: "2" }),
108
+ /* @__PURE__ */ jsx("path", { d: "M2.75 13c.45-2 1.55-3 3.25-3s2.8 1 3.25 3" }),
109
+ /* @__PURE__ */ jsx("circle", { cx: "12.25", cy: "7", r: "1.5" }),
110
+ /* @__PURE__ */ jsx("path", { d: "M10.5 10.75c1.95-.65 3.45.1 4 2.25" })
111
+ ] }),
105
112
  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" }),
106
113
  back: () => /* @__PURE__ */ jsx("path", { d: "m11.5 4.5-4.5 4.5 4.5 4.5" }),
107
114
  check: () => /* @__PURE__ */ jsx("path", { d: "m4 9 3.25 3.25L14 5.5" }),
package/controller.d.ts CHANGED
@@ -81,6 +81,14 @@ export function projectSessionInventory(
81
81
  descriptors: readonly SessionDescriptor[],
82
82
  options: SessionInventoryProjectionOptions,
83
83
  ): ProjectedSessionRowModel[];
84
+ export function projectSubagentInventory(
85
+ descriptors: readonly SessionDescriptor[],
86
+ options: SessionInventoryProjectionOptions,
87
+ ): ProjectedSessionRowModel[];
88
+ export function projectSubagentTranscript(
89
+ session: import('@volter-ai-dev/supercode-harness-sdk').NormalizedSession,
90
+ options?: Pick<ClientProjectionOptions, 'maxEntries' | 'maxScanEntries' | 'maxEntryChars'> & { prefix?: string },
91
+ ): import('./index.js').TranscriptEntryModel[];
84
92
 
85
93
  export interface ResolvableTranscriptImage {
86
94
  id?: string;
package/controller.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { conversationPreviewText } from '@volter-ai-dev/supercode-client';
1
+ import { conversationPreviewText, projectConversation as projectNormalizedConversation } from '@volter-ai-dev/supercode-client';
2
2
  import { createToolPresentation, normalizeUiState, relativeAge } from './core.mjs';
3
3
 
4
4
  const HARNESS_LABELS = {
@@ -128,12 +128,59 @@ export function projectSessionInventory(descriptors, options) {
128
128
  writable: options.isWritable?.(descriptor) === true,
129
129
  live: updatedAt !== null && now - updatedAt <= liveWindowMs,
130
130
  runtimeStatus: sessionDescriptorRuntimeStatus(descriptor),
131
+ ...(Number.isSafeInteger(descriptor.child_session_count) && descriptor.child_session_count > 0
132
+ ? { subagentCount: descriptor.child_session_count }
133
+ : {}),
131
134
  });
132
135
  if (rows.length >= maxSessions) break;
133
136
  }
134
137
  return rows;
135
138
  }
136
139
 
140
+ function descriptorSessionActivity(descriptor) {
141
+ if (descriptor?.activity?.turn === 'needs_input') return 'needs-input';
142
+ if (descriptor?.activity?.turn === 'working') return 'working';
143
+ if (descriptor?.activity?.presence === 'running' || descriptor?.activity?.presence === 'shutting_down') return 'running';
144
+ if (descriptor?.activity?.turn === 'idle') return 'recent';
145
+ if (descriptor?.live_status === 'busy') return 'working';
146
+ if (descriptor?.live_status === 'running') return 'running';
147
+ if (descriptor?.live_status === 'idle') return 'recent';
148
+ return 'idle';
149
+ }
150
+
151
+ const SUBAGENT_ACTIVITY_PRIORITY = Object.freeze({
152
+ 'needs-input': 4,
153
+ failed: 3,
154
+ working: 2,
155
+ running: 1,
156
+ recent: 1,
157
+ idle: 0,
158
+ });
159
+
160
+ /** Project an explicitly requested native session family into read-only child rows. */
161
+ export function projectSubagentInventory(descriptors, options) {
162
+ const rows = projectSessionInventory(
163
+ (descriptors ?? []).filter((descriptor) => descriptor?.parent_session_id),
164
+ { ...options, preserveOrder: true, isWritable: () => false },
165
+ ).map((row) => {
166
+ const descriptor = descriptors.find((candidate) => options.keyFor(candidate) === row.key);
167
+ return { ...row, activity: descriptorSessionActivity(descriptor) };
168
+ });
169
+ return rows.sort((left, right) =>
170
+ (SUBAGENT_ACTIVITY_PRIORITY[right.activity] ?? 0) - (SUBAGENT_ACTIVITY_PRIORITY[left.activity] ?? 0)
171
+ || (right.updatedAt ?? 0) - (left.updatedAt ?? 0)
172
+ || left.title.localeCompare(right.title));
173
+ }
174
+
175
+ /** Project one directly loaded child session without requiring a controller takeover. */
176
+ export function projectSubagentTranscript(session, options = {}) {
177
+ return projectConversation(
178
+ projectNormalizedConversation(session, { prefix: options.prefix ?? session?.session_id ?? 'subagent' }),
179
+ options,
180
+ null,
181
+ );
182
+ }
183
+
137
184
  function payloadText(payload) {
138
185
  if (typeof payload === 'string') return payload;
139
186
  try {
package/conversation.mjs CHANGED
@@ -66,6 +66,7 @@ var EMPTY_UI_STATE = Object.freeze({
66
66
  savedDraft: "",
67
67
  attention: Object.freeze([]),
68
68
  sessions: Object.freeze([]),
69
+ subagentInspector: null,
69
70
  attached: null,
70
71
  owned: null,
71
72
  attachError: null
@@ -595,6 +596,12 @@ function boundedSet(map, key, value) {
595
596
  // src/icon.jsx
596
597
  import { Fragment, jsx as jsx2, jsxs } from "preact/jsx-runtime";
597
598
  var ICONS = {
599
+ agents: () => /* @__PURE__ */ jsxs(Fragment, { children: [
600
+ /* @__PURE__ */ jsx2("circle", { cx: "6", cy: "6.5", r: "2" }),
601
+ /* @__PURE__ */ jsx2("path", { d: "M2.75 13c.45-2 1.55-3 3.25-3s2.8 1 3.25 3" }),
602
+ /* @__PURE__ */ jsx2("circle", { cx: "12.25", cy: "7", r: "1.5" }),
603
+ /* @__PURE__ */ jsx2("path", { d: "M10.5 10.75c1.95-.65 3.45.1 4 2.25" })
604
+ ] }),
598
605
  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" }),
599
606
  back: () => /* @__PURE__ */ jsx2("path", { d: "m11.5 4.5-4.5 4.5 4.5 4.5" }),
600
607
  check: () => /* @__PURE__ */ jsx2("path", { d: "m4 9 3.25 3.25L14 5.5" }),
package/core.mjs CHANGED
@@ -63,6 +63,7 @@ export const EMPTY_UI_STATE = Object.freeze({
63
63
  savedDraft: '',
64
64
  attention: Object.freeze([]),
65
65
  sessions: Object.freeze([]),
66
+ subagentInspector: null,
66
67
  attached: null,
67
68
  owned: null,
68
69
  attachError: null,
@@ -568,10 +569,26 @@ function readSessions(value) {
568
569
  writable: row.writable === true,
569
570
  live: row.live === true,
570
571
  runtimeStatus: row.runtimeStatus === 'running' || row.runtimeStatus === 'busy' || row.runtimeStatus === 'idle' ? row.runtimeStatus : null,
572
+ ...(Number.isSafeInteger(row.subagentCount) && row.subagentCount > 0 ? { subagentCount: row.subagentCount } : {}),
573
+ activity: ACTIVITY_PRIORITY[row.activity] !== undefined ? row.activity : undefined,
571
574
  }];
572
575
  });
573
576
  }
574
577
 
578
+ function readSubagentInspector(value) {
579
+ const inspector = record(value);
580
+ if (!inspector || typeof inspector.parentKey !== 'string' || !inspector.parentKey) return null;
581
+ return {
582
+ parentKey: inspector.parentKey,
583
+ parentTitle: boundedString(string(inspector.parentTitle), 500),
584
+ status: ['loading', 'ready', 'error'].includes(inspector.status) ? inspector.status : 'loading',
585
+ items: readSessions(inspector.items).slice(0, 100),
586
+ selectedKey: typeof inspector.selectedKey === 'string' && inspector.selectedKey ? inspector.selectedKey : null,
587
+ transcript: readTranscript(inspector.transcript).slice(-120),
588
+ error: typeof inspector.error === 'string' ? boundedString(inspector.error) : null,
589
+ };
590
+ }
591
+
575
592
  function readAttached(value) {
576
593
  const item = record(value);
577
594
  if (!item || typeof item.harness !== 'string') return null;
@@ -849,6 +866,7 @@ export function normalizeUiState(value) {
849
866
  : [];
850
867
  }) : [],
851
868
  sessions: readSessions(raw.sessions),
869
+ subagentInspector: readSubagentInspector(raw.subagentInspector),
852
870
  attached: readAttached(raw.attached),
853
871
  owned: readAttached(raw.owned),
854
872
  attachError: attachError && typeof attachError.key === 'string' && typeof attachError.message === 'string' ? { key: attachError.key, message: attachError.message } : null,
@@ -865,6 +883,7 @@ export function sessionDisplayName(session) {
865
883
  }
866
884
 
867
885
  export function sessionActivity(state, row) {
886
+ if (row.activity && ACTIVITY_PRIORITY[row.activity] !== undefined) return row.activity;
868
887
  if (state.needsInput && row.active) return 'needs-input';
869
888
  if (state.busy && row.active) return 'working';
870
889
  // Unread/finished attention has its own badge. It must not suppress the
@@ -1080,13 +1099,20 @@ export function parseSupercodeUiIntent(value) {
1080
1099
  const intent = intentRecord(value);
1081
1100
  if (!intent || typeof intent.action !== 'string') return null;
1082
1101
  const exact = (...keys) => intentKeys(intent, ['action', ...keys]);
1083
- const actionOnly = ['mounted', 'loadSessions', 'loadEarlier', 'join', 'detach', 'terminal', 'interrupt', 'refresh', 'release'];
1102
+ const actionOnly = ['mounted', 'loadSessions', 'loadEarlier', 'closeSubagents', 'join', 'detach', 'terminal', 'interrupt', 'refresh', 'release'];
1084
1103
  if (actionOnly.includes(intent.action)) return exact() ? { action: intent.action } : null;
1085
- if (intent.action === 'attach' || intent.action === 'ack') {
1104
+ if (intent.action === 'attach' || intent.action === 'ack' || intent.action === 'openSubagents') {
1086
1105
  return exact('key') && typeof intent.key === 'string' && intent.key.trim() && intent.key.length <= 4_000
1087
1106
  ? { action: intent.action, key: intent.key.trim() }
1088
1107
  : null;
1089
1108
  }
1109
+ if (intent.action === 'openSubagent') {
1110
+ return exact('parentKey', 'key')
1111
+ && typeof intent.parentKey === 'string' && intent.parentKey.trim() && intent.parentKey.length <= 4_000
1112
+ && typeof intent.key === 'string' && intent.key.trim() && intent.key.length <= 4_000
1113
+ ? { action: 'openSubagent', parentKey: intent.parentKey.trim(), key: intent.key.trim() }
1114
+ : null;
1115
+ }
1090
1116
  if (intent.action === 'draft') {
1091
1117
  return exact('text') && typeof intent.text === 'string' && intent.text.length <= 50_000
1092
1118
  ? { action: 'draft', text: intent.text }