@volter-ai-dev/supercode-ui 0.1.46 → 0.1.48
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 +3 -2
- package/activity.mjs +11 -5
- package/components.mjs +24 -14
- package/composer.mjs +14 -8
- package/controller.mjs +15 -8
- package/conversation.mjs +3 -1
- package/core.mjs +12 -5
- package/embed.mjs +19 -11
- package/index.d.ts +8 -1
- package/messenger.mjs +19 -11
- package/package.json +1 -1
- package/react/activity.mjs +11 -5
- package/react/components.mjs +24 -14
- package/react/composer.mjs +14 -8
- package/react/conversation.mjs +3 -1
- package/react/messenger.mjs +19 -11
- package/react/sessions.mjs +3 -2
- package/react/settings.mjs +3 -1
- package/sessions.mjs +3 -2
- package/settings.mjs +3 -1
- package/styles.css +10 -8
package/README.md
CHANGED
|
@@ -206,8 +206,9 @@ errors, and owned/attached identities without reimplementing transcript or capab
|
|
|
206
206
|
`projectSessionInventory` performs the corresponding title, latest-preview, activity, path, age,
|
|
207
207
|
sorting, and row projection for raw machine-wide descriptors; the trusted host supplies only its
|
|
208
208
|
opaque-key callback and retains the reversible locator map. Its `isWritable` capability callback
|
|
209
|
-
is fail-closed:
|
|
210
|
-
|
|
209
|
+
is fail-closed: unread badges remain neutral until the host proves a real send or terminal-control
|
|
210
|
+
path. Runtime activity remains independent, so a read-only channel can still truthfully show that
|
|
211
|
+
its external agent is working or needs input.
|
|
211
212
|
|
|
212
213
|
## Modularity contract
|
|
213
214
|
|
package/activity.mjs
CHANGED
|
@@ -32,9 +32,12 @@ var EMPTY_UI_STATE = Object.freeze({
|
|
|
32
32
|
canSend: false,
|
|
33
33
|
canSteer: false,
|
|
34
34
|
canResume: false,
|
|
35
|
+
supportsResume: false,
|
|
35
36
|
continuationModes: Object.freeze([]),
|
|
36
37
|
canBranch: false,
|
|
38
|
+
supportsBranch: false,
|
|
37
39
|
canAttach: false,
|
|
40
|
+
supportsAttach: false,
|
|
38
41
|
canDetach: false,
|
|
39
42
|
canOpenTerminal: false,
|
|
40
43
|
canExport: false,
|
|
@@ -712,9 +715,12 @@ function normalizeUiState(value) {
|
|
|
712
715
|
canSend: raw.canSend === true,
|
|
713
716
|
canSteer: raw.canSteer === true,
|
|
714
717
|
canResume,
|
|
718
|
+
supportsResume: raw.supportsResume === true,
|
|
715
719
|
continuationModes,
|
|
716
720
|
canBranch: raw.canBranch === true,
|
|
721
|
+
supportsBranch: raw.supportsBranch === true,
|
|
717
722
|
canAttach: raw.canAttach === true,
|
|
723
|
+
supportsAttach: raw.supportsAttach === true,
|
|
718
724
|
canDetach: raw.canDetach === true,
|
|
719
725
|
canOpenTerminal: raw.canOpenTerminal === true,
|
|
720
726
|
canExport: raw.canExport === true,
|
|
@@ -784,7 +790,6 @@ function sessionDisplayName(session) {
|
|
|
784
790
|
return title && title !== session.name ? title : session.name || "Untitled chat";
|
|
785
791
|
}
|
|
786
792
|
function sessionActivity(state, row) {
|
|
787
|
-
if (!row.writable) return "observed";
|
|
788
793
|
if (state.needsInput && row.active) return "needs-input";
|
|
789
794
|
if (state.busy && row.active) return "working";
|
|
790
795
|
if (row.runtimeStatus === "busy") return "working";
|
|
@@ -802,7 +807,6 @@ var ACTIVITY_PRIORITY = Object.freeze({
|
|
|
802
807
|
finished: 30,
|
|
803
808
|
running: 20,
|
|
804
809
|
recent: 10,
|
|
805
|
-
observed: 0,
|
|
806
810
|
idle: 0
|
|
807
811
|
});
|
|
808
812
|
function activityDetail(activity, preview, pill) {
|
|
@@ -813,13 +817,14 @@ function activityDetail(activity, preview, pill) {
|
|
|
813
817
|
if (activity === "finished") return "Finished";
|
|
814
818
|
if (activity === "unseen") return "New reply";
|
|
815
819
|
if (activity === "running") return "Session is running";
|
|
816
|
-
if (activity === "observed") return "Read-only channel";
|
|
817
820
|
return pill || "Agent chats";
|
|
818
821
|
}
|
|
819
822
|
function projectAgentActivity(value) {
|
|
820
823
|
const state = normalizeUiState(value);
|
|
821
824
|
const attentionByKey = new Map(state.attention.map((item) => [item.key, item]));
|
|
825
|
+
const sessionsByKey = new Map(state.sessions.map((row) => [row.key, row]));
|
|
822
826
|
const unreadCount = state.attention.reduce((total, item) => total + (item.unreadCount ?? 1), 0);
|
|
827
|
+
const unreadTone = state.attention.length > 0 && state.attention.every((item) => sessionsByKey.get(item.key)?.writable) ? "attention" : "neutral";
|
|
823
828
|
const ranked = state.sessions.map((row, index) => {
|
|
824
829
|
const activity2 = sessionActivity(state, row);
|
|
825
830
|
return {
|
|
@@ -843,7 +848,8 @@ function projectAgentActivity(value) {
|
|
|
843
848
|
title: selected ? sessionDisplayName(selected.row) : fallback ? sessionDisplayName(fallback) : "Agent chats",
|
|
844
849
|
detail: activityDetail(activity, preview, state.pill.label),
|
|
845
850
|
activity,
|
|
846
|
-
unreadCount
|
|
851
|
+
unreadCount,
|
|
852
|
+
unreadTone
|
|
847
853
|
};
|
|
848
854
|
}
|
|
849
855
|
function toolTarget(argumentsText) {
|
|
@@ -930,7 +936,7 @@ function AgentActivityLauncher({ state, onOpen, class: className = "", showSumma
|
|
|
930
936
|
const Logo = components.HarnessLogo ?? HarnessLogo;
|
|
931
937
|
const badge = value.unreadCount > 99 ? "99+" : String(value.unreadCount);
|
|
932
938
|
const label = [value.title, value.detail, value.unreadCount ? `${value.unreadCount} unread` : ""].filter(Boolean).join(" \xB7 ");
|
|
933
|
-
return /* @__PURE__ */ jsxs2("button", { className: `scui-launcher ${className}`, "data-activity": value.activity, type: "button", "aria-label": `Open ${label}`, onClick: () => onOpen?.(value), children: [
|
|
939
|
+
return /* @__PURE__ */ jsxs2("button", { className: `scui-launcher ${className}`, "data-activity": value.activity, "data-unread-tone": value.unreadTone, type: "button", "aria-label": `Open ${label}`, onClick: () => onOpen?.(value), children: [
|
|
934
940
|
/* @__PURE__ */ jsxs2("span", { className: "scui-launcher-logo", children: [
|
|
935
941
|
/* @__PURE__ */ jsx2(Logo, { id: value.harness || "supercode", activity: value.activity, size: 36 }),
|
|
936
942
|
value.unreadCount ? /* @__PURE__ */ jsx2("b", { "aria-hidden": "true", children: badge }) : null
|
package/components.mjs
CHANGED
|
@@ -35,9 +35,12 @@ var EMPTY_UI_STATE = Object.freeze({
|
|
|
35
35
|
canSend: false,
|
|
36
36
|
canSteer: false,
|
|
37
37
|
canResume: false,
|
|
38
|
+
supportsResume: false,
|
|
38
39
|
continuationModes: Object.freeze([]),
|
|
39
40
|
canBranch: false,
|
|
41
|
+
supportsBranch: false,
|
|
40
42
|
canAttach: false,
|
|
43
|
+
supportsAttach: false,
|
|
41
44
|
canDetach: false,
|
|
42
45
|
canOpenTerminal: false,
|
|
43
46
|
canExport: false,
|
|
@@ -724,9 +727,12 @@ function normalizeUiState(value) {
|
|
|
724
727
|
canSend: raw.canSend === true,
|
|
725
728
|
canSteer: raw.canSteer === true,
|
|
726
729
|
canResume,
|
|
730
|
+
supportsResume: raw.supportsResume === true,
|
|
727
731
|
continuationModes,
|
|
728
732
|
canBranch: raw.canBranch === true,
|
|
733
|
+
supportsBranch: raw.supportsBranch === true,
|
|
729
734
|
canAttach: raw.canAttach === true,
|
|
735
|
+
supportsAttach: raw.supportsAttach === true,
|
|
730
736
|
canDetach: raw.canDetach === true,
|
|
731
737
|
canOpenTerminal: raw.canOpenTerminal === true,
|
|
732
738
|
canExport: raw.canExport === true,
|
|
@@ -796,7 +802,6 @@ function sessionDisplayName(session) {
|
|
|
796
802
|
return title && title !== session.name ? title : session.name || "Untitled chat";
|
|
797
803
|
}
|
|
798
804
|
function sessionActivity(state, row) {
|
|
799
|
-
if (!row.writable) return "observed";
|
|
800
805
|
if (state.needsInput && row.active) return "needs-input";
|
|
801
806
|
if (state.busy && row.active) return "working";
|
|
802
807
|
if (row.runtimeStatus === "busy") return "working";
|
|
@@ -814,7 +819,6 @@ var ACTIVITY_PRIORITY = Object.freeze({
|
|
|
814
819
|
finished: 30,
|
|
815
820
|
running: 20,
|
|
816
821
|
recent: 10,
|
|
817
|
-
observed: 0,
|
|
818
822
|
idle: 0
|
|
819
823
|
});
|
|
820
824
|
function activityDetail(activity, preview, pill) {
|
|
@@ -825,13 +829,14 @@ function activityDetail(activity, preview, pill) {
|
|
|
825
829
|
if (activity === "finished") return "Finished";
|
|
826
830
|
if (activity === "unseen") return "New reply";
|
|
827
831
|
if (activity === "running") return "Session is running";
|
|
828
|
-
if (activity === "observed") return "Read-only channel";
|
|
829
832
|
return pill || "Agent chats";
|
|
830
833
|
}
|
|
831
834
|
function projectAgentActivity(value) {
|
|
832
835
|
const state = normalizeUiState(value);
|
|
833
836
|
const attentionByKey = new Map(state.attention.map((item) => [item.key, item]));
|
|
837
|
+
const sessionsByKey = new Map(state.sessions.map((row) => [row.key, row]));
|
|
834
838
|
const unreadCount = state.attention.reduce((total, item) => total + (item.unreadCount ?? 1), 0);
|
|
839
|
+
const unreadTone = state.attention.length > 0 && state.attention.every((item) => sessionsByKey.get(item.key)?.writable) ? "attention" : "neutral";
|
|
835
840
|
const ranked = state.sessions.map((row, index) => {
|
|
836
841
|
const activity2 = sessionActivity(state, row);
|
|
837
842
|
return {
|
|
@@ -855,7 +860,8 @@ function projectAgentActivity(value) {
|
|
|
855
860
|
title: selected ? sessionDisplayName(selected.row) : fallback ? sessionDisplayName(fallback) : "Agent chats",
|
|
856
861
|
detail: activityDetail(activity, preview, state.pill.label),
|
|
857
862
|
activity,
|
|
858
|
-
unreadCount
|
|
863
|
+
unreadCount,
|
|
864
|
+
unreadTone
|
|
859
865
|
};
|
|
860
866
|
}
|
|
861
867
|
function filterSessions(rows, query) {
|
|
@@ -1314,21 +1320,25 @@ function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
|
|
|
1314
1320
|
const attached = state.attached;
|
|
1315
1321
|
const row = attached?.key ? state.sessions.find((item) => item.key === attached.key) : null;
|
|
1316
1322
|
const activeElsewhere = row?.runtimeStatus === "running" || row?.runtimeStatus === "busy" || row?.runtimeStatus === "idle";
|
|
1317
|
-
const
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1323
|
+
const available = {
|
|
1324
|
+
resume: canContinueHere(state),
|
|
1325
|
+
join: state.canAttach,
|
|
1326
|
+
branch: state.canBranch
|
|
1327
|
+
};
|
|
1328
|
+
const continuation = available.join ? "join" : available.resume ? "resume" : available.branch ? "branch" : state.supportsAttach ? "join" : state.supportsResume ? "resume" : state.supportsBranch ? "branch" : null;
|
|
1329
|
+
if (!continuation) return /* @__PURE__ */ jsx3("div", { className: "scui-continuation", children: /* @__PURE__ */ jsxs3("span", { children: [
|
|
1321
1330
|
/* @__PURE__ */ jsx3("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
|
|
1322
1331
|
/* @__PURE__ */ jsx3("small", { children: "This session cannot be continued by an available harness." })
|
|
1323
1332
|
] }) });
|
|
1333
|
+
const enabled = available[continuation];
|
|
1324
1334
|
return /* @__PURE__ */ jsxs3("div", { className: "scui-continuation", children: [
|
|
1325
1335
|
/* @__PURE__ */ jsxs3("span", { children: [
|
|
1326
1336
|
/* @__PURE__ */ jsx3("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
|
|
1327
|
-
/* @__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." })
|
|
1337
|
+
/* @__PURE__ */ jsx3("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." })
|
|
1328
1338
|
] }),
|
|
1329
1339
|
/* @__PURE__ */ jsxs3("span", { className: "scui-continuation-actions", children: [
|
|
1330
|
-
|
|
1331
|
-
/* @__PURE__ */ jsx3("button", { type: "button", disabled: Boolean(state.operation), onClick: () => dispatchConfirmedIntent(adapter, join ? { action: "join" } : resume ? { action: "resume", mode: executionMode } : { action: "branch" }), children: join ? labels.joinLive : resume ? labels.continueHere : labels.forkHere })
|
|
1340
|
+
continuation === "resume" ? /* @__PURE__ */ jsx3(ExecutionModeSelect, { modes: continuationModes, value: executionMode, disabled: Boolean(state.operation) || !enabled, onChange: (mode) => setSelection({ key: state.attached?.key ?? null, mode }) }) : null,
|
|
1341
|
+
/* @__PURE__ */ jsx3("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 })
|
|
1332
1342
|
] })
|
|
1333
1343
|
] });
|
|
1334
1344
|
}
|
|
@@ -1643,7 +1653,7 @@ function AgentActivityLauncher({ state, onOpen, class: className = "", showSumma
|
|
|
1643
1653
|
const Logo = components.HarnessLogo ?? HarnessLogo;
|
|
1644
1654
|
const badge = value.unreadCount > 99 ? "99+" : String(value.unreadCount);
|
|
1645
1655
|
const label = [value.title, value.detail, value.unreadCount ? `${value.unreadCount} unread` : ""].filter(Boolean).join(" \xB7 ");
|
|
1646
|
-
return /* @__PURE__ */ jsxs5("button", { className: `scui-launcher ${className}`, "data-activity": value.activity, type: "button", "aria-label": `Open ${label}`, onClick: () => onOpen?.(value), children: [
|
|
1656
|
+
return /* @__PURE__ */ jsxs5("button", { className: `scui-launcher ${className}`, "data-activity": value.activity, "data-unread-tone": value.unreadTone, type: "button", "aria-label": `Open ${label}`, onClick: () => onOpen?.(value), children: [
|
|
1647
1657
|
/* @__PURE__ */ jsxs5("span", { className: "scui-launcher-logo", children: [
|
|
1648
1658
|
/* @__PURE__ */ jsx5(Logo, { id: value.harness || "supercode", activity: value.activity, size: 36 }),
|
|
1649
1659
|
value.unreadCount ? /* @__PURE__ */ jsx5("b", { "aria-hidden": "true", children: badge }) : null
|
|
@@ -2716,8 +2726,8 @@ function ChatHeader({ state, adapter, pendingStatus, actionPending, onBack, onNe
|
|
|
2716
2726
|
if (state.mode === "mirror" && !state.canSend) back.current?.focus({ preventScroll: true });
|
|
2717
2727
|
}, []);
|
|
2718
2728
|
return /* @__PURE__ */ jsxs9("header", { className: "scui-head scui-chat-head", children: [
|
|
2719
|
-
/* @__PURE__ */ jsx10("button", { ref: back, type: "button", "aria-label": "Back to chats", onClick: onBack, children: /* @__PURE__ */ jsx10(UiIcon, { name: "back", size:
|
|
2720
|
-
/* @__PURE__ */ jsx10(HarnessLogo, { id: harness, size:
|
|
2729
|
+
/* @__PURE__ */ jsx10("button", { ref: back, type: "button", "aria-label": "Back to chats", onClick: onBack, children: /* @__PURE__ */ jsx10(UiIcon, { name: "back", size: 17 }) }),
|
|
2730
|
+
/* @__PURE__ */ jsx10(HarnessLogo, { id: harness, size: 24 }),
|
|
2721
2731
|
/* @__PURE__ */ jsxs9("span", { className: "scui-head-copy", children: [
|
|
2722
2732
|
/* @__PURE__ */ jsx10("strong", { children: title }),
|
|
2723
2733
|
/* @__PURE__ */ jsxs9("small", { children: [
|
package/composer.mjs
CHANGED
|
@@ -35,9 +35,12 @@ var EMPTY_UI_STATE = Object.freeze({
|
|
|
35
35
|
canSend: false,
|
|
36
36
|
canSteer: false,
|
|
37
37
|
canResume: false,
|
|
38
|
+
supportsResume: false,
|
|
38
39
|
continuationModes: Object.freeze([]),
|
|
39
40
|
canBranch: false,
|
|
41
|
+
supportsBranch: false,
|
|
40
42
|
canAttach: false,
|
|
43
|
+
supportsAttach: false,
|
|
41
44
|
canDetach: false,
|
|
42
45
|
canOpenTerminal: false,
|
|
43
46
|
canExport: false,
|
|
@@ -77,7 +80,6 @@ var ACTIVITY_PRIORITY = Object.freeze({
|
|
|
77
80
|
finished: 30,
|
|
78
81
|
running: 20,
|
|
79
82
|
recent: 10,
|
|
80
|
-
observed: 0,
|
|
81
83
|
idle: 0
|
|
82
84
|
});
|
|
83
85
|
function canContinueHere(state) {
|
|
@@ -312,21 +314,25 @@ function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
|
|
|
312
314
|
const attached = state.attached;
|
|
313
315
|
const row = attached?.key ? state.sessions.find((item) => item.key === attached.key) : null;
|
|
314
316
|
const activeElsewhere = row?.runtimeStatus === "running" || row?.runtimeStatus === "busy" || row?.runtimeStatus === "idle";
|
|
315
|
-
const
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
317
|
+
const available = {
|
|
318
|
+
resume: canContinueHere(state),
|
|
319
|
+
join: state.canAttach,
|
|
320
|
+
branch: state.canBranch
|
|
321
|
+
};
|
|
322
|
+
const continuation = available.join ? "join" : available.resume ? "resume" : available.branch ? "branch" : state.supportsAttach ? "join" : state.supportsResume ? "resume" : state.supportsBranch ? "branch" : null;
|
|
323
|
+
if (!continuation) return /* @__PURE__ */ jsx3("div", { className: "scui-continuation", children: /* @__PURE__ */ jsxs3("span", { children: [
|
|
319
324
|
/* @__PURE__ */ jsx3("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
|
|
320
325
|
/* @__PURE__ */ jsx3("small", { children: "This session cannot be continued by an available harness." })
|
|
321
326
|
] }) });
|
|
327
|
+
const enabled = available[continuation];
|
|
322
328
|
return /* @__PURE__ */ jsxs3("div", { className: "scui-continuation", children: [
|
|
323
329
|
/* @__PURE__ */ jsxs3("span", { children: [
|
|
324
330
|
/* @__PURE__ */ jsx3("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
|
|
325
|
-
/* @__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." })
|
|
331
|
+
/* @__PURE__ */ jsx3("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." })
|
|
326
332
|
] }),
|
|
327
333
|
/* @__PURE__ */ jsxs3("span", { className: "scui-continuation-actions", children: [
|
|
328
|
-
|
|
329
|
-
/* @__PURE__ */ jsx3("button", { type: "button", disabled: Boolean(state.operation), onClick: () => dispatchConfirmedIntent(adapter, join ? { action: "join" } : resume ? { action: "resume", mode: executionMode } : { action: "branch" }), children: join ? labels.joinLive : resume ? labels.continueHere : labels.forkHere })
|
|
334
|
+
continuation === "resume" ? /* @__PURE__ */ jsx3(ExecutionModeSelect, { modes: continuationModes, value: executionMode, disabled: Boolean(state.operation) || !enabled, onChange: (mode) => setSelection({ key: state.attached?.key ?? null, mode }) }) : null,
|
|
335
|
+
/* @__PURE__ */ jsx3("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 })
|
|
330
336
|
] })
|
|
331
337
|
] });
|
|
332
338
|
}
|
package/controller.mjs
CHANGED
|
@@ -436,6 +436,10 @@ function projectClientSnapshotInternal(snapshot, options, imageRegistry) {
|
|
|
436
436
|
const now = Number.isFinite(options.now) ? options.now : Date.now();
|
|
437
437
|
const busy = ['running', 'interrupting', 'reconciling'].includes(snapshot.turn?.state);
|
|
438
438
|
const actions = snapshot.availableActions ?? {};
|
|
439
|
+
// Older clients did not expose operation-independent eligibility. Falling
|
|
440
|
+
// back preserves compatibility; current clients keep stable UI capability
|
|
441
|
+
// copy while an action temporarily makes every executable action false.
|
|
442
|
+
const eligibility = snapshot.actionEligibility ?? actions;
|
|
439
443
|
const maxSessions = positiveInteger(options.maxSessions, DEFAULT_MAX_SESSIONS);
|
|
440
444
|
const liveWindowMs = positiveInteger(options.liveWindowMs, DEFAULT_LIVE_WINDOW_MS);
|
|
441
445
|
const snapshotSessions = (snapshot.sessions ?? []).slice(0, maxSessions).map((session) => ({
|
|
@@ -475,9 +479,12 @@ function projectClientSnapshotInternal(snapshot, options, imageRegistry) {
|
|
|
475
479
|
canSend: actions.send === true,
|
|
476
480
|
canSteer: actions.steer === true,
|
|
477
481
|
canResume: actions.resume === true,
|
|
478
|
-
|
|
482
|
+
supportsResume: eligibility.resume === true,
|
|
483
|
+
continuationModes: options.continuationModes ?? (eligibility.resume === true ? ['headless'] : []),
|
|
479
484
|
canBranch: actions.branch === true,
|
|
485
|
+
supportsBranch: eligibility.branch === true,
|
|
480
486
|
canAttach: actions.attach === true,
|
|
487
|
+
supportsAttach: eligibility.attach === true,
|
|
481
488
|
canDetach: actions.detach === true,
|
|
482
489
|
canOpenTerminal: actions.openTerminal === true,
|
|
483
490
|
canExport: Boolean(options.exportBackTarget && snapshot.activeSessionKey),
|
|
@@ -517,13 +524,13 @@ function projectClientSnapshotInternal(snapshot, options, imageRegistry) {
|
|
|
517
524
|
protocol: harness.protocol,
|
|
518
525
|
repair: harness.repair ?? null,
|
|
519
526
|
capabilities: {
|
|
520
|
-
start: harness.
|
|
521
|
-
resume: harness.
|
|
522
|
-
attach: harness.
|
|
523
|
-
send: harness.
|
|
524
|
-
interrupt: harness.
|
|
525
|
-
steer: harness.
|
|
526
|
-
respond: harness.
|
|
527
|
+
start: (harness.effective_capabilities ?? harness.capabilities)?.start_session === true,
|
|
528
|
+
resume: (harness.effective_capabilities ?? harness.capabilities)?.resume_session === true,
|
|
529
|
+
attach: (harness.effective_capabilities ?? harness.capabilities)?.attach_existing_process === true,
|
|
530
|
+
send: (harness.effective_capabilities ?? harness.capabilities)?.send_input === true,
|
|
531
|
+
interrupt: (harness.effective_capabilities ?? harness.capabilities)?.interrupt === true,
|
|
532
|
+
steer: (harness.effective_capabilities ?? harness.capabilities)?.steer === true,
|
|
533
|
+
respond: (harness.effective_capabilities ?? harness.capabilities)?.respond_to_requests === true,
|
|
527
534
|
},
|
|
528
535
|
})),
|
|
529
536
|
history: {
|
package/conversation.mjs
CHANGED
|
@@ -36,9 +36,12 @@ var EMPTY_UI_STATE = Object.freeze({
|
|
|
36
36
|
canSend: false,
|
|
37
37
|
canSteer: false,
|
|
38
38
|
canResume: false,
|
|
39
|
+
supportsResume: false,
|
|
39
40
|
continuationModes: Object.freeze([]),
|
|
40
41
|
canBranch: false,
|
|
42
|
+
supportsBranch: false,
|
|
41
43
|
canAttach: false,
|
|
44
|
+
supportsAttach: false,
|
|
42
45
|
canDetach: false,
|
|
43
46
|
canOpenTerminal: false,
|
|
44
47
|
canExport: false,
|
|
@@ -439,7 +442,6 @@ var ACTIVITY_PRIORITY = Object.freeze({
|
|
|
439
442
|
finished: 30,
|
|
440
443
|
running: 20,
|
|
441
444
|
recent: 10,
|
|
442
|
-
observed: 0,
|
|
443
445
|
idle: 0
|
|
444
446
|
});
|
|
445
447
|
function groupConversation(entries) {
|
package/core.mjs
CHANGED
|
@@ -33,9 +33,12 @@ export const EMPTY_UI_STATE = Object.freeze({
|
|
|
33
33
|
canSend: false,
|
|
34
34
|
canSteer: false,
|
|
35
35
|
canResume: false,
|
|
36
|
+
supportsResume: false,
|
|
36
37
|
continuationModes: Object.freeze([]),
|
|
37
38
|
canBranch: false,
|
|
39
|
+
supportsBranch: false,
|
|
38
40
|
canAttach: false,
|
|
41
|
+
supportsAttach: false,
|
|
39
42
|
canDetach: false,
|
|
40
43
|
canOpenTerminal: false,
|
|
41
44
|
canExport: false,
|
|
@@ -776,9 +779,12 @@ export function normalizeUiState(value) {
|
|
|
776
779
|
canSend: raw.canSend === true,
|
|
777
780
|
canSteer: raw.canSteer === true,
|
|
778
781
|
canResume,
|
|
782
|
+
supportsResume: raw.supportsResume === true,
|
|
779
783
|
continuationModes,
|
|
780
784
|
canBranch: raw.canBranch === true,
|
|
785
|
+
supportsBranch: raw.supportsBranch === true,
|
|
781
786
|
canAttach: raw.canAttach === true,
|
|
787
|
+
supportsAttach: raw.supportsAttach === true,
|
|
782
788
|
canDetach: raw.canDetach === true,
|
|
783
789
|
canOpenTerminal: raw.canOpenTerminal === true,
|
|
784
790
|
canExport: raw.canExport === true,
|
|
@@ -859,9 +865,6 @@ export function sessionDisplayName(session) {
|
|
|
859
865
|
}
|
|
860
866
|
|
|
861
867
|
export function sessionActivity(state, row) {
|
|
862
|
-
// Runtime activity and interaction authority are deliberately independent. A process may be
|
|
863
|
-
// busy in another terminal, but presenting it as this surface's active agent is misleading.
|
|
864
|
-
if (!row.writable) return 'observed';
|
|
865
868
|
if (state.needsInput && row.active) return 'needs-input';
|
|
866
869
|
if (state.busy && row.active) return 'working';
|
|
867
870
|
// Unread/finished attention has its own badge. It must not suppress the
|
|
@@ -882,7 +885,6 @@ const ACTIVITY_PRIORITY = Object.freeze({
|
|
|
882
885
|
finished: 30,
|
|
883
886
|
running: 20,
|
|
884
887
|
recent: 10,
|
|
885
|
-
observed: 0,
|
|
886
888
|
idle: 0,
|
|
887
889
|
});
|
|
888
890
|
|
|
@@ -894,7 +896,6 @@ function activityDetail(activity, preview, pill) {
|
|
|
894
896
|
if (activity === 'finished') return 'Finished';
|
|
895
897
|
if (activity === 'unseen') return 'New reply';
|
|
896
898
|
if (activity === 'running') return 'Session is running';
|
|
897
|
-
if (activity === 'observed') return 'Read-only channel';
|
|
898
899
|
return pill || 'Agent chats';
|
|
899
900
|
}
|
|
900
901
|
|
|
@@ -902,7 +903,12 @@ function activityDetail(activity, preview, pill) {
|
|
|
902
903
|
export function projectAgentActivity(value) {
|
|
903
904
|
const state = normalizeUiState(value);
|
|
904
905
|
const attentionByKey = new Map(state.attention.map((item) => [item.key, item]));
|
|
906
|
+
const sessionsByKey = new Map(state.sessions.map((row) => [row.key, row]));
|
|
905
907
|
const unreadCount = state.attention.reduce((total, item) => total + (item.unreadCount ?? 1), 0);
|
|
908
|
+
const unreadTone = state.attention.length > 0
|
|
909
|
+
&& state.attention.every((item) => sessionsByKey.get(item.key)?.writable)
|
|
910
|
+
? 'attention'
|
|
911
|
+
: 'neutral';
|
|
906
912
|
const ranked = state.sessions.map((row, index) => {
|
|
907
913
|
const activity = sessionActivity(state, row);
|
|
908
914
|
return {
|
|
@@ -927,6 +933,7 @@ export function projectAgentActivity(value) {
|
|
|
927
933
|
detail: activityDetail(activity, preview, state.pill.label),
|
|
928
934
|
activity,
|
|
929
935
|
unreadCount,
|
|
936
|
+
unreadTone,
|
|
930
937
|
};
|
|
931
938
|
}
|
|
932
939
|
|
package/embed.mjs
CHANGED
|
@@ -38,9 +38,12 @@ var EMPTY_UI_STATE = Object.freeze({
|
|
|
38
38
|
canSend: false,
|
|
39
39
|
canSteer: false,
|
|
40
40
|
canResume: false,
|
|
41
|
+
supportsResume: false,
|
|
41
42
|
continuationModes: Object.freeze([]),
|
|
42
43
|
canBranch: false,
|
|
44
|
+
supportsBranch: false,
|
|
43
45
|
canAttach: false,
|
|
46
|
+
supportsAttach: false,
|
|
44
47
|
canDetach: false,
|
|
45
48
|
canOpenTerminal: false,
|
|
46
49
|
canExport: false,
|
|
@@ -727,9 +730,12 @@ function normalizeUiState(value) {
|
|
|
727
730
|
canSend: raw.canSend === true,
|
|
728
731
|
canSteer: raw.canSteer === true,
|
|
729
732
|
canResume,
|
|
733
|
+
supportsResume: raw.supportsResume === true,
|
|
730
734
|
continuationModes,
|
|
731
735
|
canBranch: raw.canBranch === true,
|
|
736
|
+
supportsBranch: raw.supportsBranch === true,
|
|
732
737
|
canAttach: raw.canAttach === true,
|
|
738
|
+
supportsAttach: raw.supportsAttach === true,
|
|
733
739
|
canDetach: raw.canDetach === true,
|
|
734
740
|
canOpenTerminal: raw.canOpenTerminal === true,
|
|
735
741
|
canExport: raw.canExport === true,
|
|
@@ -799,7 +805,6 @@ function sessionDisplayName(session) {
|
|
|
799
805
|
return title && title !== session.name ? title : session.name || "Untitled chat";
|
|
800
806
|
}
|
|
801
807
|
function sessionActivity(state, row) {
|
|
802
|
-
if (!row.writable) return "observed";
|
|
803
808
|
if (state.needsInput && row.active) return "needs-input";
|
|
804
809
|
if (state.busy && row.active) return "working";
|
|
805
810
|
if (row.runtimeStatus === "busy") return "working";
|
|
@@ -817,7 +822,6 @@ var ACTIVITY_PRIORITY = Object.freeze({
|
|
|
817
822
|
finished: 30,
|
|
818
823
|
running: 20,
|
|
819
824
|
recent: 10,
|
|
820
|
-
observed: 0,
|
|
821
825
|
idle: 0
|
|
822
826
|
});
|
|
823
827
|
function filterSessions(rows, query) {
|
|
@@ -1279,21 +1283,25 @@ function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
|
|
|
1279
1283
|
const attached = state.attached;
|
|
1280
1284
|
const row = attached?.key ? state.sessions.find((item) => item.key === attached.key) : null;
|
|
1281
1285
|
const activeElsewhere = row?.runtimeStatus === "running" || row?.runtimeStatus === "busy" || row?.runtimeStatus === "idle";
|
|
1282
|
-
const
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
+
const available = {
|
|
1287
|
+
resume: canContinueHere(state),
|
|
1288
|
+
join: state.canAttach,
|
|
1289
|
+
branch: state.canBranch
|
|
1290
|
+
};
|
|
1291
|
+
const continuation = available.join ? "join" : available.resume ? "resume" : available.branch ? "branch" : state.supportsAttach ? "join" : state.supportsResume ? "resume" : state.supportsBranch ? "branch" : null;
|
|
1292
|
+
if (!continuation) return /* @__PURE__ */ jsx3("div", { className: "scui-continuation", children: /* @__PURE__ */ jsxs3("span", { children: [
|
|
1286
1293
|
/* @__PURE__ */ jsx3("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
|
|
1287
1294
|
/* @__PURE__ */ jsx3("small", { children: "This session cannot be continued by an available harness." })
|
|
1288
1295
|
] }) });
|
|
1296
|
+
const enabled = available[continuation];
|
|
1289
1297
|
return /* @__PURE__ */ jsxs3("div", { className: "scui-continuation", children: [
|
|
1290
1298
|
/* @__PURE__ */ jsxs3("span", { children: [
|
|
1291
1299
|
/* @__PURE__ */ jsx3("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
|
|
1292
|
-
/* @__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." })
|
|
1300
|
+
/* @__PURE__ */ jsx3("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." })
|
|
1293
1301
|
] }),
|
|
1294
1302
|
/* @__PURE__ */ jsxs3("span", { className: "scui-continuation-actions", children: [
|
|
1295
|
-
|
|
1296
|
-
/* @__PURE__ */ jsx3("button", { type: "button", disabled: Boolean(state.operation), onClick: () => dispatchConfirmedIntent(adapter, join ? { action: "join" } : resume ? { action: "resume", mode: executionMode } : { action: "branch" }), children: join ? labels.joinLive : resume ? labels.continueHere : labels.forkHere })
|
|
1303
|
+
continuation === "resume" ? /* @__PURE__ */ jsx3(ExecutionModeSelect, { modes: continuationModes, value: executionMode, disabled: Boolean(state.operation) || !enabled, onChange: (mode) => setSelection({ key: state.attached?.key ?? null, mode }) }) : null,
|
|
1304
|
+
/* @__PURE__ */ jsx3("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 })
|
|
1297
1305
|
] })
|
|
1298
1306
|
] });
|
|
1299
1307
|
}
|
|
@@ -2635,8 +2643,8 @@ function ChatHeader({ state, adapter, pendingStatus, actionPending, onBack, onNe
|
|
|
2635
2643
|
if (state.mode === "mirror" && !state.canSend) back.current?.focus({ preventScroll: true });
|
|
2636
2644
|
}, []);
|
|
2637
2645
|
return /* @__PURE__ */ jsxs8("header", { className: "scui-head scui-chat-head", children: [
|
|
2638
|
-
/* @__PURE__ */ jsx9("button", { ref: back, type: "button", "aria-label": "Back to chats", onClick: onBack, children: /* @__PURE__ */ jsx9(UiIcon, { name: "back", size:
|
|
2639
|
-
/* @__PURE__ */ jsx9(HarnessLogo, { id: harness, size:
|
|
2646
|
+
/* @__PURE__ */ jsx9("button", { ref: back, type: "button", "aria-label": "Back to chats", onClick: onBack, children: /* @__PURE__ */ jsx9(UiIcon, { name: "back", size: 17 }) }),
|
|
2647
|
+
/* @__PURE__ */ jsx9(HarnessLogo, { id: harness, size: 24 }),
|
|
2640
2648
|
/* @__PURE__ */ jsxs8("span", { className: "scui-head-copy", children: [
|
|
2641
2649
|
/* @__PURE__ */ jsx9("strong", { children: title }),
|
|
2642
2650
|
/* @__PURE__ */ jsxs8("small", { children: [
|
package/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export type ControlStrategy = 'start' | 'resume' | 'attach' | 'branch' | 'reduce
|
|
|
8
8
|
export type ExecutionMode = 'headless' | 'terminal';
|
|
9
9
|
/** @deprecated Use ExecutionMode. */
|
|
10
10
|
export type ContinuationMode = ExecutionMode;
|
|
11
|
-
export type SessionActivity = 'idle' | '
|
|
11
|
+
export type SessionActivity = 'idle' | 'recent' | 'running' | 'working' | 'needs-input' | 'finished' | 'failed' | 'unseen';
|
|
12
12
|
|
|
13
13
|
export interface AgentActivityModel {
|
|
14
14
|
harness: HarnessId | '';
|
|
@@ -17,6 +17,7 @@ export interface AgentActivityModel {
|
|
|
17
17
|
detail: string;
|
|
18
18
|
activity: SessionActivity;
|
|
19
19
|
unreadCount: number;
|
|
20
|
+
unreadTone: 'attention' | 'neutral';
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
export interface HarnessOption {
|
|
@@ -266,10 +267,16 @@ export interface SupercodeUiState {
|
|
|
266
267
|
canSend: boolean;
|
|
267
268
|
canSteer: boolean;
|
|
268
269
|
canResume: boolean;
|
|
270
|
+
/** Stable continuation eligibility while another controller action is in flight. */
|
|
271
|
+
supportsResume: boolean;
|
|
269
272
|
/** Execution transports the current host can actually provide. */
|
|
270
273
|
continuationModes: ContinuationMode[];
|
|
271
274
|
canBranch: boolean;
|
|
275
|
+
/** Stable continuation eligibility while another controller action is in flight. */
|
|
276
|
+
supportsBranch: boolean;
|
|
272
277
|
canAttach: boolean;
|
|
278
|
+
/** Stable continuation eligibility while another controller action is in flight. */
|
|
279
|
+
supportsAttach: boolean;
|
|
273
280
|
canDetach: boolean;
|
|
274
281
|
canOpenTerminal: boolean;
|
|
275
282
|
canExport: boolean;
|
package/messenger.mjs
CHANGED
|
@@ -35,9 +35,12 @@ var EMPTY_UI_STATE = Object.freeze({
|
|
|
35
35
|
canSend: false,
|
|
36
36
|
canSteer: false,
|
|
37
37
|
canResume: false,
|
|
38
|
+
supportsResume: false,
|
|
38
39
|
continuationModes: Object.freeze([]),
|
|
39
40
|
canBranch: false,
|
|
41
|
+
supportsBranch: false,
|
|
40
42
|
canAttach: false,
|
|
43
|
+
supportsAttach: false,
|
|
41
44
|
canDetach: false,
|
|
42
45
|
canOpenTerminal: false,
|
|
43
46
|
canExport: false,
|
|
@@ -724,9 +727,12 @@ function normalizeUiState(value) {
|
|
|
724
727
|
canSend: raw.canSend === true,
|
|
725
728
|
canSteer: raw.canSteer === true,
|
|
726
729
|
canResume,
|
|
730
|
+
supportsResume: raw.supportsResume === true,
|
|
727
731
|
continuationModes,
|
|
728
732
|
canBranch: raw.canBranch === true,
|
|
733
|
+
supportsBranch: raw.supportsBranch === true,
|
|
729
734
|
canAttach: raw.canAttach === true,
|
|
735
|
+
supportsAttach: raw.supportsAttach === true,
|
|
730
736
|
canDetach: raw.canDetach === true,
|
|
731
737
|
canOpenTerminal: raw.canOpenTerminal === true,
|
|
732
738
|
canExport: raw.canExport === true,
|
|
@@ -796,7 +802,6 @@ function sessionDisplayName(session) {
|
|
|
796
802
|
return title && title !== session.name ? title : session.name || "Untitled chat";
|
|
797
803
|
}
|
|
798
804
|
function sessionActivity(state, row) {
|
|
799
|
-
if (!row.writable) return "observed";
|
|
800
805
|
if (state.needsInput && row.active) return "needs-input";
|
|
801
806
|
if (state.busy && row.active) return "working";
|
|
802
807
|
if (row.runtimeStatus === "busy") return "working";
|
|
@@ -814,7 +819,6 @@ var ACTIVITY_PRIORITY = Object.freeze({
|
|
|
814
819
|
finished: 30,
|
|
815
820
|
running: 20,
|
|
816
821
|
recent: 10,
|
|
817
|
-
observed: 0,
|
|
818
822
|
idle: 0
|
|
819
823
|
});
|
|
820
824
|
function filterSessions(rows, query) {
|
|
@@ -1276,21 +1280,25 @@ function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
|
|
|
1276
1280
|
const attached = state.attached;
|
|
1277
1281
|
const row = attached?.key ? state.sessions.find((item) => item.key === attached.key) : null;
|
|
1278
1282
|
const activeElsewhere = row?.runtimeStatus === "running" || row?.runtimeStatus === "busy" || row?.runtimeStatus === "idle";
|
|
1279
|
-
const
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
+
const available = {
|
|
1284
|
+
resume: canContinueHere(state),
|
|
1285
|
+
join: state.canAttach,
|
|
1286
|
+
branch: state.canBranch
|
|
1287
|
+
};
|
|
1288
|
+
const continuation = available.join ? "join" : available.resume ? "resume" : available.branch ? "branch" : state.supportsAttach ? "join" : state.supportsResume ? "resume" : state.supportsBranch ? "branch" : null;
|
|
1289
|
+
if (!continuation) return /* @__PURE__ */ jsx3("div", { className: "scui-continuation", children: /* @__PURE__ */ jsxs3("span", { children: [
|
|
1283
1290
|
/* @__PURE__ */ jsx3("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
|
|
1284
1291
|
/* @__PURE__ */ jsx3("small", { children: "This session cannot be continued by an available harness." })
|
|
1285
1292
|
] }) });
|
|
1293
|
+
const enabled = available[continuation];
|
|
1286
1294
|
return /* @__PURE__ */ jsxs3("div", { className: "scui-continuation", children: [
|
|
1287
1295
|
/* @__PURE__ */ jsxs3("span", { children: [
|
|
1288
1296
|
/* @__PURE__ */ jsx3("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
|
|
1289
|
-
/* @__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." })
|
|
1297
|
+
/* @__PURE__ */ jsx3("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." })
|
|
1290
1298
|
] }),
|
|
1291
1299
|
/* @__PURE__ */ jsxs3("span", { className: "scui-continuation-actions", children: [
|
|
1292
|
-
|
|
1293
|
-
/* @__PURE__ */ jsx3("button", { type: "button", disabled: Boolean(state.operation), onClick: () => dispatchConfirmedIntent(adapter, join ? { action: "join" } : resume ? { action: "resume", mode: executionMode } : { action: "branch" }), children: join ? labels.joinLive : resume ? labels.continueHere : labels.forkHere })
|
|
1300
|
+
continuation === "resume" ? /* @__PURE__ */ jsx3(ExecutionModeSelect, { modes: continuationModes, value: executionMode, disabled: Boolean(state.operation) || !enabled, onChange: (mode) => setSelection({ key: state.attached?.key ?? null, mode }) }) : null,
|
|
1301
|
+
/* @__PURE__ */ jsx3("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 })
|
|
1294
1302
|
] })
|
|
1295
1303
|
] });
|
|
1296
1304
|
}
|
|
@@ -2632,8 +2640,8 @@ function ChatHeader({ state, adapter, pendingStatus, actionPending, onBack, onNe
|
|
|
2632
2640
|
if (state.mode === "mirror" && !state.canSend) back.current?.focus({ preventScroll: true });
|
|
2633
2641
|
}, []);
|
|
2634
2642
|
return /* @__PURE__ */ jsxs8("header", { className: "scui-head scui-chat-head", children: [
|
|
2635
|
-
/* @__PURE__ */ jsx9("button", { ref: back, type: "button", "aria-label": "Back to chats", onClick: onBack, children: /* @__PURE__ */ jsx9(UiIcon, { name: "back", size:
|
|
2636
|
-
/* @__PURE__ */ jsx9(HarnessLogo, { id: harness, size:
|
|
2643
|
+
/* @__PURE__ */ jsx9("button", { ref: back, type: "button", "aria-label": "Back to chats", onClick: onBack, children: /* @__PURE__ */ jsx9(UiIcon, { name: "back", size: 17 }) }),
|
|
2644
|
+
/* @__PURE__ */ jsx9(HarnessLogo, { id: harness, size: 24 }),
|
|
2637
2645
|
/* @__PURE__ */ jsxs8("span", { className: "scui-head-copy", children: [
|
|
2638
2646
|
/* @__PURE__ */ jsx9("strong", { children: title }),
|
|
2639
2647
|
/* @__PURE__ */ jsxs8("small", { children: [
|
package/package.json
CHANGED
package/react/activity.mjs
CHANGED
|
@@ -32,9 +32,12 @@ var EMPTY_UI_STATE = Object.freeze({
|
|
|
32
32
|
canSend: false,
|
|
33
33
|
canSteer: false,
|
|
34
34
|
canResume: false,
|
|
35
|
+
supportsResume: false,
|
|
35
36
|
continuationModes: Object.freeze([]),
|
|
36
37
|
canBranch: false,
|
|
38
|
+
supportsBranch: false,
|
|
37
39
|
canAttach: false,
|
|
40
|
+
supportsAttach: false,
|
|
38
41
|
canDetach: false,
|
|
39
42
|
canOpenTerminal: false,
|
|
40
43
|
canExport: false,
|
|
@@ -712,9 +715,12 @@ function normalizeUiState(value) {
|
|
|
712
715
|
canSend: raw.canSend === true,
|
|
713
716
|
canSteer: raw.canSteer === true,
|
|
714
717
|
canResume,
|
|
718
|
+
supportsResume: raw.supportsResume === true,
|
|
715
719
|
continuationModes,
|
|
716
720
|
canBranch: raw.canBranch === true,
|
|
721
|
+
supportsBranch: raw.supportsBranch === true,
|
|
717
722
|
canAttach: raw.canAttach === true,
|
|
723
|
+
supportsAttach: raw.supportsAttach === true,
|
|
718
724
|
canDetach: raw.canDetach === true,
|
|
719
725
|
canOpenTerminal: raw.canOpenTerminal === true,
|
|
720
726
|
canExport: raw.canExport === true,
|
|
@@ -784,7 +790,6 @@ function sessionDisplayName(session) {
|
|
|
784
790
|
return title && title !== session.name ? title : session.name || "Untitled chat";
|
|
785
791
|
}
|
|
786
792
|
function sessionActivity(state, row) {
|
|
787
|
-
if (!row.writable) return "observed";
|
|
788
793
|
if (state.needsInput && row.active) return "needs-input";
|
|
789
794
|
if (state.busy && row.active) return "working";
|
|
790
795
|
if (row.runtimeStatus === "busy") return "working";
|
|
@@ -802,7 +807,6 @@ var ACTIVITY_PRIORITY = Object.freeze({
|
|
|
802
807
|
finished: 30,
|
|
803
808
|
running: 20,
|
|
804
809
|
recent: 10,
|
|
805
|
-
observed: 0,
|
|
806
810
|
idle: 0
|
|
807
811
|
});
|
|
808
812
|
function activityDetail(activity, preview, pill) {
|
|
@@ -813,13 +817,14 @@ function activityDetail(activity, preview, pill) {
|
|
|
813
817
|
if (activity === "finished") return "Finished";
|
|
814
818
|
if (activity === "unseen") return "New reply";
|
|
815
819
|
if (activity === "running") return "Session is running";
|
|
816
|
-
if (activity === "observed") return "Read-only channel";
|
|
817
820
|
return pill || "Agent chats";
|
|
818
821
|
}
|
|
819
822
|
function projectAgentActivity(value) {
|
|
820
823
|
const state = normalizeUiState(value);
|
|
821
824
|
const attentionByKey = new Map(state.attention.map((item) => [item.key, item]));
|
|
825
|
+
const sessionsByKey = new Map(state.sessions.map((row) => [row.key, row]));
|
|
822
826
|
const unreadCount = state.attention.reduce((total, item) => total + (item.unreadCount ?? 1), 0);
|
|
827
|
+
const unreadTone = state.attention.length > 0 && state.attention.every((item) => sessionsByKey.get(item.key)?.writable) ? "attention" : "neutral";
|
|
823
828
|
const ranked = state.sessions.map((row, index) => {
|
|
824
829
|
const activity2 = sessionActivity(state, row);
|
|
825
830
|
return {
|
|
@@ -843,7 +848,8 @@ function projectAgentActivity(value) {
|
|
|
843
848
|
title: selected ? sessionDisplayName(selected.row) : fallback ? sessionDisplayName(fallback) : "Agent chats",
|
|
844
849
|
detail: activityDetail(activity, preview, state.pill.label),
|
|
845
850
|
activity,
|
|
846
|
-
unreadCount
|
|
851
|
+
unreadCount,
|
|
852
|
+
unreadTone
|
|
847
853
|
};
|
|
848
854
|
}
|
|
849
855
|
function toolTarget(argumentsText) {
|
|
@@ -930,7 +936,7 @@ function AgentActivityLauncher({ state, onOpen, class: className = "", showSumma
|
|
|
930
936
|
const Logo = components.HarnessLogo ?? HarnessLogo;
|
|
931
937
|
const badge = value.unreadCount > 99 ? "99+" : String(value.unreadCount);
|
|
932
938
|
const label = [value.title, value.detail, value.unreadCount ? `${value.unreadCount} unread` : ""].filter(Boolean).join(" \xB7 ");
|
|
933
|
-
return /* @__PURE__ */ jsxs2("button", { className: `scui-launcher ${className}`, "data-activity": value.activity, type: "button", "aria-label": `Open ${label}`, onClick: () => onOpen?.(value), children: [
|
|
939
|
+
return /* @__PURE__ */ jsxs2("button", { className: `scui-launcher ${className}`, "data-activity": value.activity, "data-unread-tone": value.unreadTone, type: "button", "aria-label": `Open ${label}`, onClick: () => onOpen?.(value), children: [
|
|
934
940
|
/* @__PURE__ */ jsxs2("span", { className: "scui-launcher-logo", children: [
|
|
935
941
|
/* @__PURE__ */ jsx2(Logo, { id: value.harness || "supercode", activity: value.activity, size: 36 }),
|
|
936
942
|
value.unreadCount ? /* @__PURE__ */ jsx2("b", { "aria-hidden": "true", children: badge }) : null
|
package/react/components.mjs
CHANGED
|
@@ -35,9 +35,12 @@ var EMPTY_UI_STATE = Object.freeze({
|
|
|
35
35
|
canSend: false,
|
|
36
36
|
canSteer: false,
|
|
37
37
|
canResume: false,
|
|
38
|
+
supportsResume: false,
|
|
38
39
|
continuationModes: Object.freeze([]),
|
|
39
40
|
canBranch: false,
|
|
41
|
+
supportsBranch: false,
|
|
40
42
|
canAttach: false,
|
|
43
|
+
supportsAttach: false,
|
|
41
44
|
canDetach: false,
|
|
42
45
|
canOpenTerminal: false,
|
|
43
46
|
canExport: false,
|
|
@@ -724,9 +727,12 @@ function normalizeUiState(value) {
|
|
|
724
727
|
canSend: raw.canSend === true,
|
|
725
728
|
canSteer: raw.canSteer === true,
|
|
726
729
|
canResume,
|
|
730
|
+
supportsResume: raw.supportsResume === true,
|
|
727
731
|
continuationModes,
|
|
728
732
|
canBranch: raw.canBranch === true,
|
|
733
|
+
supportsBranch: raw.supportsBranch === true,
|
|
729
734
|
canAttach: raw.canAttach === true,
|
|
735
|
+
supportsAttach: raw.supportsAttach === true,
|
|
730
736
|
canDetach: raw.canDetach === true,
|
|
731
737
|
canOpenTerminal: raw.canOpenTerminal === true,
|
|
732
738
|
canExport: raw.canExport === true,
|
|
@@ -796,7 +802,6 @@ function sessionDisplayName(session) {
|
|
|
796
802
|
return title && title !== session.name ? title : session.name || "Untitled chat";
|
|
797
803
|
}
|
|
798
804
|
function sessionActivity(state, row) {
|
|
799
|
-
if (!row.writable) return "observed";
|
|
800
805
|
if (state.needsInput && row.active) return "needs-input";
|
|
801
806
|
if (state.busy && row.active) return "working";
|
|
802
807
|
if (row.runtimeStatus === "busy") return "working";
|
|
@@ -814,7 +819,6 @@ var ACTIVITY_PRIORITY = Object.freeze({
|
|
|
814
819
|
finished: 30,
|
|
815
820
|
running: 20,
|
|
816
821
|
recent: 10,
|
|
817
|
-
observed: 0,
|
|
818
822
|
idle: 0
|
|
819
823
|
});
|
|
820
824
|
function activityDetail(activity, preview, pill) {
|
|
@@ -825,13 +829,14 @@ function activityDetail(activity, preview, pill) {
|
|
|
825
829
|
if (activity === "finished") return "Finished";
|
|
826
830
|
if (activity === "unseen") return "New reply";
|
|
827
831
|
if (activity === "running") return "Session is running";
|
|
828
|
-
if (activity === "observed") return "Read-only channel";
|
|
829
832
|
return pill || "Agent chats";
|
|
830
833
|
}
|
|
831
834
|
function projectAgentActivity(value) {
|
|
832
835
|
const state = normalizeUiState(value);
|
|
833
836
|
const attentionByKey = new Map(state.attention.map((item) => [item.key, item]));
|
|
837
|
+
const sessionsByKey = new Map(state.sessions.map((row) => [row.key, row]));
|
|
834
838
|
const unreadCount = state.attention.reduce((total, item) => total + (item.unreadCount ?? 1), 0);
|
|
839
|
+
const unreadTone = state.attention.length > 0 && state.attention.every((item) => sessionsByKey.get(item.key)?.writable) ? "attention" : "neutral";
|
|
835
840
|
const ranked = state.sessions.map((row, index) => {
|
|
836
841
|
const activity2 = sessionActivity(state, row);
|
|
837
842
|
return {
|
|
@@ -855,7 +860,8 @@ function projectAgentActivity(value) {
|
|
|
855
860
|
title: selected ? sessionDisplayName(selected.row) : fallback ? sessionDisplayName(fallback) : "Agent chats",
|
|
856
861
|
detail: activityDetail(activity, preview, state.pill.label),
|
|
857
862
|
activity,
|
|
858
|
-
unreadCount
|
|
863
|
+
unreadCount,
|
|
864
|
+
unreadTone
|
|
859
865
|
};
|
|
860
866
|
}
|
|
861
867
|
function filterSessions(rows, query) {
|
|
@@ -1314,21 +1320,25 @@ function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
|
|
|
1314
1320
|
const attached = state.attached;
|
|
1315
1321
|
const row = attached?.key ? state.sessions.find((item) => item.key === attached.key) : null;
|
|
1316
1322
|
const activeElsewhere = row?.runtimeStatus === "running" || row?.runtimeStatus === "busy" || row?.runtimeStatus === "idle";
|
|
1317
|
-
const
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1323
|
+
const available = {
|
|
1324
|
+
resume: canContinueHere(state),
|
|
1325
|
+
join: state.canAttach,
|
|
1326
|
+
branch: state.canBranch
|
|
1327
|
+
};
|
|
1328
|
+
const continuation = available.join ? "join" : available.resume ? "resume" : available.branch ? "branch" : state.supportsAttach ? "join" : state.supportsResume ? "resume" : state.supportsBranch ? "branch" : null;
|
|
1329
|
+
if (!continuation) return /* @__PURE__ */ jsx3("div", { className: "scui-continuation", children: /* @__PURE__ */ jsxs3("span", { children: [
|
|
1321
1330
|
/* @__PURE__ */ jsx3("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
|
|
1322
1331
|
/* @__PURE__ */ jsx3("small", { children: "This session cannot be continued by an available harness." })
|
|
1323
1332
|
] }) });
|
|
1333
|
+
const enabled = available[continuation];
|
|
1324
1334
|
return /* @__PURE__ */ jsxs3("div", { className: "scui-continuation", children: [
|
|
1325
1335
|
/* @__PURE__ */ jsxs3("span", { children: [
|
|
1326
1336
|
/* @__PURE__ */ jsx3("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
|
|
1327
|
-
/* @__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." })
|
|
1337
|
+
/* @__PURE__ */ jsx3("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." })
|
|
1328
1338
|
] }),
|
|
1329
1339
|
/* @__PURE__ */ jsxs3("span", { className: "scui-continuation-actions", children: [
|
|
1330
|
-
|
|
1331
|
-
/* @__PURE__ */ jsx3("button", { type: "button", disabled: Boolean(state.operation), onClick: () => dispatchConfirmedIntent(adapter, join ? { action: "join" } : resume ? { action: "resume", mode: executionMode } : { action: "branch" }), children: join ? labels.joinLive : resume ? labels.continueHere : labels.forkHere })
|
|
1340
|
+
continuation === "resume" ? /* @__PURE__ */ jsx3(ExecutionModeSelect, { modes: continuationModes, value: executionMode, disabled: Boolean(state.operation) || !enabled, onChange: (mode) => setSelection({ key: state.attached?.key ?? null, mode }) }) : null,
|
|
1341
|
+
/* @__PURE__ */ jsx3("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 })
|
|
1332
1342
|
] })
|
|
1333
1343
|
] });
|
|
1334
1344
|
}
|
|
@@ -1643,7 +1653,7 @@ function AgentActivityLauncher({ state, onOpen, class: className = "", showSumma
|
|
|
1643
1653
|
const Logo = components.HarnessLogo ?? HarnessLogo;
|
|
1644
1654
|
const badge = value.unreadCount > 99 ? "99+" : String(value.unreadCount);
|
|
1645
1655
|
const label = [value.title, value.detail, value.unreadCount ? `${value.unreadCount} unread` : ""].filter(Boolean).join(" \xB7 ");
|
|
1646
|
-
return /* @__PURE__ */ jsxs5("button", { className: `scui-launcher ${className}`, "data-activity": value.activity, type: "button", "aria-label": `Open ${label}`, onClick: () => onOpen?.(value), children: [
|
|
1656
|
+
return /* @__PURE__ */ jsxs5("button", { className: `scui-launcher ${className}`, "data-activity": value.activity, "data-unread-tone": value.unreadTone, type: "button", "aria-label": `Open ${label}`, onClick: () => onOpen?.(value), children: [
|
|
1647
1657
|
/* @__PURE__ */ jsxs5("span", { className: "scui-launcher-logo", children: [
|
|
1648
1658
|
/* @__PURE__ */ jsx5(Logo, { id: value.harness || "supercode", activity: value.activity, size: 36 }),
|
|
1649
1659
|
value.unreadCount ? /* @__PURE__ */ jsx5("b", { "aria-hidden": "true", children: badge }) : null
|
|
@@ -2716,8 +2726,8 @@ function ChatHeader({ state, adapter, pendingStatus, actionPending, onBack, onNe
|
|
|
2716
2726
|
if (state.mode === "mirror" && !state.canSend) back.current?.focus({ preventScroll: true });
|
|
2717
2727
|
}, []);
|
|
2718
2728
|
return /* @__PURE__ */ jsxs9("header", { className: "scui-head scui-chat-head", children: [
|
|
2719
|
-
/* @__PURE__ */ jsx10("button", { ref: back, type: "button", "aria-label": "Back to chats", onClick: onBack, children: /* @__PURE__ */ jsx10(UiIcon, { name: "back", size:
|
|
2720
|
-
/* @__PURE__ */ jsx10(HarnessLogo, { id: harness, size:
|
|
2729
|
+
/* @__PURE__ */ jsx10("button", { ref: back, type: "button", "aria-label": "Back to chats", onClick: onBack, children: /* @__PURE__ */ jsx10(UiIcon, { name: "back", size: 17 }) }),
|
|
2730
|
+
/* @__PURE__ */ jsx10(HarnessLogo, { id: harness, size: 24 }),
|
|
2721
2731
|
/* @__PURE__ */ jsxs9("span", { className: "scui-head-copy", children: [
|
|
2722
2732
|
/* @__PURE__ */ jsx10("strong", { children: title }),
|
|
2723
2733
|
/* @__PURE__ */ jsxs9("small", { children: [
|
package/react/composer.mjs
CHANGED
|
@@ -35,9 +35,12 @@ var EMPTY_UI_STATE = Object.freeze({
|
|
|
35
35
|
canSend: false,
|
|
36
36
|
canSteer: false,
|
|
37
37
|
canResume: false,
|
|
38
|
+
supportsResume: false,
|
|
38
39
|
continuationModes: Object.freeze([]),
|
|
39
40
|
canBranch: false,
|
|
41
|
+
supportsBranch: false,
|
|
40
42
|
canAttach: false,
|
|
43
|
+
supportsAttach: false,
|
|
41
44
|
canDetach: false,
|
|
42
45
|
canOpenTerminal: false,
|
|
43
46
|
canExport: false,
|
|
@@ -77,7 +80,6 @@ var ACTIVITY_PRIORITY = Object.freeze({
|
|
|
77
80
|
finished: 30,
|
|
78
81
|
running: 20,
|
|
79
82
|
recent: 10,
|
|
80
|
-
observed: 0,
|
|
81
83
|
idle: 0
|
|
82
84
|
});
|
|
83
85
|
function canContinueHere(state) {
|
|
@@ -312,21 +314,25 @@ function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
|
|
|
312
314
|
const attached = state.attached;
|
|
313
315
|
const row = attached?.key ? state.sessions.find((item) => item.key === attached.key) : null;
|
|
314
316
|
const activeElsewhere = row?.runtimeStatus === "running" || row?.runtimeStatus === "busy" || row?.runtimeStatus === "idle";
|
|
315
|
-
const
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
317
|
+
const available = {
|
|
318
|
+
resume: canContinueHere(state),
|
|
319
|
+
join: state.canAttach,
|
|
320
|
+
branch: state.canBranch
|
|
321
|
+
};
|
|
322
|
+
const continuation = available.join ? "join" : available.resume ? "resume" : available.branch ? "branch" : state.supportsAttach ? "join" : state.supportsResume ? "resume" : state.supportsBranch ? "branch" : null;
|
|
323
|
+
if (!continuation) return /* @__PURE__ */ jsx3("div", { className: "scui-continuation", children: /* @__PURE__ */ jsxs3("span", { children: [
|
|
319
324
|
/* @__PURE__ */ jsx3("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
|
|
320
325
|
/* @__PURE__ */ jsx3("small", { children: "This session cannot be continued by an available harness." })
|
|
321
326
|
] }) });
|
|
327
|
+
const enabled = available[continuation];
|
|
322
328
|
return /* @__PURE__ */ jsxs3("div", { className: "scui-continuation", children: [
|
|
323
329
|
/* @__PURE__ */ jsxs3("span", { children: [
|
|
324
330
|
/* @__PURE__ */ jsx3("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
|
|
325
|
-
/* @__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." })
|
|
331
|
+
/* @__PURE__ */ jsx3("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." })
|
|
326
332
|
] }),
|
|
327
333
|
/* @__PURE__ */ jsxs3("span", { className: "scui-continuation-actions", children: [
|
|
328
|
-
|
|
329
|
-
/* @__PURE__ */ jsx3("button", { type: "button", disabled: Boolean(state.operation), onClick: () => dispatchConfirmedIntent(adapter, join ? { action: "join" } : resume ? { action: "resume", mode: executionMode } : { action: "branch" }), children: join ? labels.joinLive : resume ? labels.continueHere : labels.forkHere })
|
|
334
|
+
continuation === "resume" ? /* @__PURE__ */ jsx3(ExecutionModeSelect, { modes: continuationModes, value: executionMode, disabled: Boolean(state.operation) || !enabled, onChange: (mode) => setSelection({ key: state.attached?.key ?? null, mode }) }) : null,
|
|
335
|
+
/* @__PURE__ */ jsx3("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 })
|
|
330
336
|
] })
|
|
331
337
|
] });
|
|
332
338
|
}
|
package/react/conversation.mjs
CHANGED
|
@@ -36,9 +36,12 @@ var EMPTY_UI_STATE = Object.freeze({
|
|
|
36
36
|
canSend: false,
|
|
37
37
|
canSteer: false,
|
|
38
38
|
canResume: false,
|
|
39
|
+
supportsResume: false,
|
|
39
40
|
continuationModes: Object.freeze([]),
|
|
40
41
|
canBranch: false,
|
|
42
|
+
supportsBranch: false,
|
|
41
43
|
canAttach: false,
|
|
44
|
+
supportsAttach: false,
|
|
42
45
|
canDetach: false,
|
|
43
46
|
canOpenTerminal: false,
|
|
44
47
|
canExport: false,
|
|
@@ -439,7 +442,6 @@ var ACTIVITY_PRIORITY = Object.freeze({
|
|
|
439
442
|
finished: 30,
|
|
440
443
|
running: 20,
|
|
441
444
|
recent: 10,
|
|
442
|
-
observed: 0,
|
|
443
445
|
idle: 0
|
|
444
446
|
});
|
|
445
447
|
function groupConversation(entries) {
|
package/react/messenger.mjs
CHANGED
|
@@ -35,9 +35,12 @@ var EMPTY_UI_STATE = Object.freeze({
|
|
|
35
35
|
canSend: false,
|
|
36
36
|
canSteer: false,
|
|
37
37
|
canResume: false,
|
|
38
|
+
supportsResume: false,
|
|
38
39
|
continuationModes: Object.freeze([]),
|
|
39
40
|
canBranch: false,
|
|
41
|
+
supportsBranch: false,
|
|
40
42
|
canAttach: false,
|
|
43
|
+
supportsAttach: false,
|
|
41
44
|
canDetach: false,
|
|
42
45
|
canOpenTerminal: false,
|
|
43
46
|
canExport: false,
|
|
@@ -724,9 +727,12 @@ function normalizeUiState(value) {
|
|
|
724
727
|
canSend: raw.canSend === true,
|
|
725
728
|
canSteer: raw.canSteer === true,
|
|
726
729
|
canResume,
|
|
730
|
+
supportsResume: raw.supportsResume === true,
|
|
727
731
|
continuationModes,
|
|
728
732
|
canBranch: raw.canBranch === true,
|
|
733
|
+
supportsBranch: raw.supportsBranch === true,
|
|
729
734
|
canAttach: raw.canAttach === true,
|
|
735
|
+
supportsAttach: raw.supportsAttach === true,
|
|
730
736
|
canDetach: raw.canDetach === true,
|
|
731
737
|
canOpenTerminal: raw.canOpenTerminal === true,
|
|
732
738
|
canExport: raw.canExport === true,
|
|
@@ -796,7 +802,6 @@ function sessionDisplayName(session) {
|
|
|
796
802
|
return title && title !== session.name ? title : session.name || "Untitled chat";
|
|
797
803
|
}
|
|
798
804
|
function sessionActivity(state, row) {
|
|
799
|
-
if (!row.writable) return "observed";
|
|
800
805
|
if (state.needsInput && row.active) return "needs-input";
|
|
801
806
|
if (state.busy && row.active) return "working";
|
|
802
807
|
if (row.runtimeStatus === "busy") return "working";
|
|
@@ -814,7 +819,6 @@ var ACTIVITY_PRIORITY = Object.freeze({
|
|
|
814
819
|
finished: 30,
|
|
815
820
|
running: 20,
|
|
816
821
|
recent: 10,
|
|
817
|
-
observed: 0,
|
|
818
822
|
idle: 0
|
|
819
823
|
});
|
|
820
824
|
function filterSessions(rows, query) {
|
|
@@ -1276,21 +1280,25 @@ function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
|
|
|
1276
1280
|
const attached = state.attached;
|
|
1277
1281
|
const row = attached?.key ? state.sessions.find((item) => item.key === attached.key) : null;
|
|
1278
1282
|
const activeElsewhere = row?.runtimeStatus === "running" || row?.runtimeStatus === "busy" || row?.runtimeStatus === "idle";
|
|
1279
|
-
const
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
+
const available = {
|
|
1284
|
+
resume: canContinueHere(state),
|
|
1285
|
+
join: state.canAttach,
|
|
1286
|
+
branch: state.canBranch
|
|
1287
|
+
};
|
|
1288
|
+
const continuation = available.join ? "join" : available.resume ? "resume" : available.branch ? "branch" : state.supportsAttach ? "join" : state.supportsResume ? "resume" : state.supportsBranch ? "branch" : null;
|
|
1289
|
+
if (!continuation) return /* @__PURE__ */ jsx3("div", { className: "scui-continuation", children: /* @__PURE__ */ jsxs3("span", { children: [
|
|
1283
1290
|
/* @__PURE__ */ jsx3("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
|
|
1284
1291
|
/* @__PURE__ */ jsx3("small", { children: "This session cannot be continued by an available harness." })
|
|
1285
1292
|
] }) });
|
|
1293
|
+
const enabled = available[continuation];
|
|
1286
1294
|
return /* @__PURE__ */ jsxs3("div", { className: "scui-continuation", children: [
|
|
1287
1295
|
/* @__PURE__ */ jsxs3("span", { children: [
|
|
1288
1296
|
/* @__PURE__ */ jsx3("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
|
|
1289
|
-
/* @__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." })
|
|
1297
|
+
/* @__PURE__ */ jsx3("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." })
|
|
1290
1298
|
] }),
|
|
1291
1299
|
/* @__PURE__ */ jsxs3("span", { className: "scui-continuation-actions", children: [
|
|
1292
|
-
|
|
1293
|
-
/* @__PURE__ */ jsx3("button", { type: "button", disabled: Boolean(state.operation), onClick: () => dispatchConfirmedIntent(adapter, join ? { action: "join" } : resume ? { action: "resume", mode: executionMode } : { action: "branch" }), children: join ? labels.joinLive : resume ? labels.continueHere : labels.forkHere })
|
|
1300
|
+
continuation === "resume" ? /* @__PURE__ */ jsx3(ExecutionModeSelect, { modes: continuationModes, value: executionMode, disabled: Boolean(state.operation) || !enabled, onChange: (mode) => setSelection({ key: state.attached?.key ?? null, mode }) }) : null,
|
|
1301
|
+
/* @__PURE__ */ jsx3("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 })
|
|
1294
1302
|
] })
|
|
1295
1303
|
] });
|
|
1296
1304
|
}
|
|
@@ -2632,8 +2640,8 @@ function ChatHeader({ state, adapter, pendingStatus, actionPending, onBack, onNe
|
|
|
2632
2640
|
if (state.mode === "mirror" && !state.canSend) back.current?.focus({ preventScroll: true });
|
|
2633
2641
|
}, []);
|
|
2634
2642
|
return /* @__PURE__ */ jsxs8("header", { className: "scui-head scui-chat-head", children: [
|
|
2635
|
-
/* @__PURE__ */ jsx9("button", { ref: back, type: "button", "aria-label": "Back to chats", onClick: onBack, children: /* @__PURE__ */ jsx9(UiIcon, { name: "back", size:
|
|
2636
|
-
/* @__PURE__ */ jsx9(HarnessLogo, { id: harness, size:
|
|
2643
|
+
/* @__PURE__ */ jsx9("button", { ref: back, type: "button", "aria-label": "Back to chats", onClick: onBack, children: /* @__PURE__ */ jsx9(UiIcon, { name: "back", size: 17 }) }),
|
|
2644
|
+
/* @__PURE__ */ jsx9(HarnessLogo, { id: harness, size: 24 }),
|
|
2637
2645
|
/* @__PURE__ */ jsxs8("span", { className: "scui-head-copy", children: [
|
|
2638
2646
|
/* @__PURE__ */ jsx9("strong", { children: title }),
|
|
2639
2647
|
/* @__PURE__ */ jsxs8("small", { children: [
|
package/react/sessions.mjs
CHANGED
|
@@ -35,9 +35,12 @@ var EMPTY_UI_STATE = Object.freeze({
|
|
|
35
35
|
canSend: false,
|
|
36
36
|
canSteer: false,
|
|
37
37
|
canResume: false,
|
|
38
|
+
supportsResume: false,
|
|
38
39
|
continuationModes: Object.freeze([]),
|
|
39
40
|
canBranch: false,
|
|
41
|
+
supportsBranch: false,
|
|
40
42
|
canAttach: false,
|
|
43
|
+
supportsAttach: false,
|
|
41
44
|
canDetach: false,
|
|
42
45
|
canOpenTerminal: false,
|
|
43
46
|
canExport: false,
|
|
@@ -83,7 +86,6 @@ function sessionDisplayName(session) {
|
|
|
83
86
|
return title && title !== session.name ? title : session.name || "Untitled chat";
|
|
84
87
|
}
|
|
85
88
|
function sessionActivity(state, row) {
|
|
86
|
-
if (!row.writable) return "observed";
|
|
87
89
|
if (state.needsInput && row.active) return "needs-input";
|
|
88
90
|
if (state.busy && row.active) return "working";
|
|
89
91
|
if (row.runtimeStatus === "busy") return "working";
|
|
@@ -101,7 +103,6 @@ var ACTIVITY_PRIORITY = Object.freeze({
|
|
|
101
103
|
finished: 30,
|
|
102
104
|
running: 20,
|
|
103
105
|
recent: 10,
|
|
104
|
-
observed: 0,
|
|
105
106
|
idle: 0
|
|
106
107
|
});
|
|
107
108
|
function filterSessions(rows, query) {
|
package/react/settings.mjs
CHANGED
|
@@ -35,9 +35,12 @@ var EMPTY_UI_STATE = Object.freeze({
|
|
|
35
35
|
canSend: false,
|
|
36
36
|
canSteer: false,
|
|
37
37
|
canResume: false,
|
|
38
|
+
supportsResume: false,
|
|
38
39
|
continuationModes: Object.freeze([]),
|
|
39
40
|
canBranch: false,
|
|
41
|
+
supportsBranch: false,
|
|
40
42
|
canAttach: false,
|
|
43
|
+
supportsAttach: false,
|
|
41
44
|
canDetach: false,
|
|
42
45
|
canOpenTerminal: false,
|
|
43
46
|
canExport: false,
|
|
@@ -77,7 +80,6 @@ var ACTIVITY_PRIORITY = Object.freeze({
|
|
|
77
80
|
finished: 30,
|
|
78
81
|
running: 20,
|
|
79
82
|
recent: 10,
|
|
80
|
-
observed: 0,
|
|
81
83
|
idle: 0
|
|
82
84
|
});
|
|
83
85
|
|
package/sessions.mjs
CHANGED
|
@@ -35,9 +35,12 @@ var EMPTY_UI_STATE = Object.freeze({
|
|
|
35
35
|
canSend: false,
|
|
36
36
|
canSteer: false,
|
|
37
37
|
canResume: false,
|
|
38
|
+
supportsResume: false,
|
|
38
39
|
continuationModes: Object.freeze([]),
|
|
39
40
|
canBranch: false,
|
|
41
|
+
supportsBranch: false,
|
|
40
42
|
canAttach: false,
|
|
43
|
+
supportsAttach: false,
|
|
41
44
|
canDetach: false,
|
|
42
45
|
canOpenTerminal: false,
|
|
43
46
|
canExport: false,
|
|
@@ -83,7 +86,6 @@ function sessionDisplayName(session) {
|
|
|
83
86
|
return title && title !== session.name ? title : session.name || "Untitled chat";
|
|
84
87
|
}
|
|
85
88
|
function sessionActivity(state, row) {
|
|
86
|
-
if (!row.writable) return "observed";
|
|
87
89
|
if (state.needsInput && row.active) return "needs-input";
|
|
88
90
|
if (state.busy && row.active) return "working";
|
|
89
91
|
if (row.runtimeStatus === "busy") return "working";
|
|
@@ -101,7 +103,6 @@ var ACTIVITY_PRIORITY = Object.freeze({
|
|
|
101
103
|
finished: 30,
|
|
102
104
|
running: 20,
|
|
103
105
|
recent: 10,
|
|
104
|
-
observed: 0,
|
|
105
106
|
idle: 0
|
|
106
107
|
});
|
|
107
108
|
function filterSessions(rows, query) {
|
package/settings.mjs
CHANGED
|
@@ -35,9 +35,12 @@ var EMPTY_UI_STATE = Object.freeze({
|
|
|
35
35
|
canSend: false,
|
|
36
36
|
canSteer: false,
|
|
37
37
|
canResume: false,
|
|
38
|
+
supportsResume: false,
|
|
38
39
|
continuationModes: Object.freeze([]),
|
|
39
40
|
canBranch: false,
|
|
41
|
+
supportsBranch: false,
|
|
40
42
|
canAttach: false,
|
|
43
|
+
supportsAttach: false,
|
|
41
44
|
canDetach: false,
|
|
42
45
|
canOpenTerminal: false,
|
|
43
46
|
canExport: false,
|
|
@@ -77,7 +80,6 @@ var ACTIVITY_PRIORITY = Object.freeze({
|
|
|
77
80
|
finished: 30,
|
|
78
81
|
running: 20,
|
|
79
82
|
recent: 10,
|
|
80
|
-
observed: 0,
|
|
81
83
|
idle: 0
|
|
82
84
|
});
|
|
83
85
|
|
package/styles.css
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
--scui-warning: #b26a00;
|
|
14
14
|
--scui-danger: #b4232e;
|
|
15
15
|
--scui-radius: 10px;
|
|
16
|
+
--scui-head-height: 42px;
|
|
16
17
|
--scui-font: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
17
18
|
box-sizing: border-box;
|
|
18
19
|
display: flex;
|
|
@@ -53,11 +54,11 @@
|
|
|
53
54
|
.scui-sr-only { position:absolute; width:1px; height:1px; padding:0; overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0 }
|
|
54
55
|
|
|
55
56
|
.scui-list,.scui-chat { display:flex; flex:1; min-width:0; min-height:0; flex-direction:column }
|
|
56
|
-
.scui-head { display:flex; flex:none; align-items:center; gap:
|
|
57
|
+
.scui-head { display:flex; flex:none; align-items:center; gap:5px; min-height:var(--scui-head-height); padding:4px 6px 4px 8px; border-bottom:1px solid var(--scui-border); background:var(--scui-bg-raised) }
|
|
57
58
|
.scui-head > .scui-head-copy { display:grid; flex:1; min-width:0 }
|
|
58
|
-
.scui-head strong { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-size:
|
|
59
|
-
.scui-head small { overflow:hidden; color:var(--scui-muted); font-size:
|
|
60
|
-
.scui-head > button,.scui-menu-trigger { display:grid; place-items:center; width:
|
|
59
|
+
.scui-head strong { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-size:12px }
|
|
60
|
+
.scui-head small { overflow:hidden; color:var(--scui-muted); font-size:9.5px; text-overflow:ellipsis; white-space:nowrap }
|
|
61
|
+
.scui-head > button,.scui-menu-trigger { display:grid; place-items:center; width:28px; height:28px; padding:0; border:0; border-radius:7px; background:transparent; color:inherit; cursor:pointer; font-size:16px }
|
|
61
62
|
.scui-head > button:hover,.scui-menu-trigger:hover,.scui-menu-trigger[aria-expanded="true"] { background:var(--scui-fill) }
|
|
62
63
|
.scui-menu { position:relative }
|
|
63
64
|
.scui-menu-panel { position:absolute; z-index:20; top:36px; right:0; display:grid; width:250px; max-height:300px; padding:5px; overflow:auto; border:1px solid var(--scui-border-strong); border-radius:10px; background:var(--scui-bg); box-shadow:0 10px 28px rgba(0,0,0,.22) }
|
|
@@ -73,7 +74,6 @@
|
|
|
73
74
|
.scui-logo[data-harness="pi"] { color:#111; background:#efefeb }
|
|
74
75
|
.scui-logo[data-harness="supercode"] { background:#111923 }
|
|
75
76
|
.scui-logo > i { position:absolute; right:-5%; bottom:-5%; width:32%; height:32%; border:2px solid var(--scui-bg); border-radius:50%; background:var(--scui-muted) }
|
|
76
|
-
.scui-logo[data-activity="observed"] > i { background:var(--scui-muted) }
|
|
77
77
|
.scui-logo[data-activity="working"] > i,.scui-logo[data-activity="running"] > i { background:var(--scui-positive) }
|
|
78
78
|
.scui-logo[data-activity="needs-input"] > i { background:var(--scui-warning) }
|
|
79
79
|
.scui-logo[data-activity="failed"] > i { background:var(--scui-danger) }
|
|
@@ -81,6 +81,7 @@
|
|
|
81
81
|
|
|
82
82
|
.scui-launcher { --scui-bg:#fff; --scui-fg:#191918; --scui-muted:#5f5f5a; --scui-border:#deded9; --scui-positive:#22863a; --scui-warning:#b26a00; --scui-danger:#b4232e; display:inline-flex; min-width:44px; min-height:44px; align-items:center; gap:8px; padding:4px; overflow:visible; border:1px solid var(--scui-border); border-radius:999px; background:color-mix(in srgb,var(--scui-bg) 88%,transparent); color:var(--scui-fg); box-shadow:0 5px 18px rgba(0,0,0,.14); cursor:pointer; font:12px/1.25 var(--scui-font,Inter,ui-sans-serif,system-ui,sans-serif); backdrop-filter:blur(10px) }
|
|
83
83
|
.scui-launcher-logo { position:relative; display:grid; flex:none; place-items:center }.scui-launcher-logo > b { position:absolute; z-index:1; top:-6px; right:-8px; display:grid; min-width:18px; height:18px; padding:0 4px; place-items:center; border:2px solid var(--scui-bg); border-radius:999px; background:var(--scui-danger); color:#fff; font-size:9px; line-height:1 }
|
|
84
|
+
.scui-launcher[data-unread-tone="neutral"] .scui-launcher-logo > b { background:var(--scui-muted) }
|
|
84
85
|
.scui-launcher-copy { display:grid; min-width:0; max-width:220px; padding-right:8px; text-align:left }.scui-launcher-copy strong,.scui-launcher-copy small { overflow:hidden; text-overflow:ellipsis; white-space:nowrap }.scui-launcher-copy small { color:var(--scui-muted); font-size:10px }
|
|
85
86
|
.scui-launcher:hover { border-color:color-mix(in srgb,var(--scui-fg) 28%,var(--scui-border)); box-shadow:0 7px 22px rgba(0,0,0,.18) }.scui-launcher:focus-visible { outline:2px solid currentColor; outline-offset:2px }
|
|
86
87
|
@media (prefers-color-scheme:dark) { .scui-launcher { --scui-bg:#151515; --scui-fg:#f3f3ef; --scui-muted:#a3a39d; --scui-border:#353532; --scui-positive:#57c26e; --scui-warning:#e8a23a; --scui-danger:#ff747d } }
|
|
@@ -108,6 +109,7 @@
|
|
|
108
109
|
.scui-session-path { display:flex; min-width:0; overflow:hidden; color:var(--scui-muted); font-size:9.5px; white-space:nowrap }
|
|
109
110
|
.scui-session-path-leading { flex:0 1 auto; overflow:hidden; text-overflow:ellipsis }.scui-session-path-separator { flex:none }.scui-session-path-trailing { flex:none; max-width:58%; overflow:hidden; direction:rtl; text-align:left; text-overflow:ellipsis; unicode-bidi:plaintext }
|
|
110
111
|
.scui-session-preview small { flex:1; min-width:0; color:var(--scui-muted); font-size:10.5px }.scui-session-preview b { display:grid; flex:none; min-width:16px; height:16px; padding:0 4px; place-items:center; border-radius:8px; background:var(--scui-accent); color:var(--scui-bg); font-size:9px; line-height:16px }
|
|
112
|
+
.scui-session[data-writable="false"] .scui-session-preview b { background:var(--scui-muted) }
|
|
111
113
|
.scui-session-copy em { overflow:hidden; color:var(--scui-danger); font-size:10px; font-style:normal; text-overflow:ellipsis; white-space:nowrap }
|
|
112
114
|
.scui-load { display:block; margin:7px auto; padding:5px 10px; border:1px solid var(--scui-border); border-radius:8px; background:var(--scui-bg-raised); color:var(--scui-muted); cursor:pointer }.scui-load:disabled { opacity:.65; cursor:default }
|
|
113
115
|
|
|
@@ -206,7 +208,7 @@
|
|
|
206
208
|
.scui-harness-manage { margin-top:4px; padding-top:4px; border-top:1px solid var(--scui-border) }.scui-harness-manage > summary { padding:6px 7px; color:var(--scui-muted); cursor:pointer; font-size:9.5px }.scui-harness-manage > div { display:grid; gap:1px }.scui-harness-manage section { display:grid; grid-template-columns:auto minmax(0,1fr) auto; min-height:36px; align-items:center; gap:8px; padding:5px 7px }.scui-harness-manage section > span { display:grid; min-width:0 }.scui-harness-manage section strong,.scui-harness-manage section small { overflow:hidden; text-overflow:ellipsis; white-space:nowrap }.scui-harness-manage section strong { font-size:10.5px; font-weight:600 }.scui-harness-manage section small { color:var(--scui-muted); font-size:8.5px }.scui-harness-manage section > button { padding:4px 6px; border:1px solid var(--scui-border); border-radius:6px; background:transparent; color:var(--scui-muted); cursor:pointer; font-size:8.5px }.scui-harness-manage section > button:hover { border-color:var(--scui-border-strong); color:var(--scui-fg) }
|
|
207
209
|
.scui-readiness { margin:0 0 7px; border:1px solid var(--scui-border); border-radius:7px; background:var(--scui-bg) }.scui-readiness > summary { padding:6px 8px; color:var(--scui-muted); cursor:pointer; font-size:10px }.scui-readiness > div { display:grid; border-top:1px solid var(--scui-border) }.scui-readiness section { display:grid; grid-template-columns:auto minmax(0,1fr) auto; align-items:center; gap:7px; padding:7px 8px }.scui-readiness section + section { border-top:1px solid var(--scui-border) }.scui-readiness section > span { display:grid; min-width:0 }.scui-readiness section strong,.scui-readiness section small,.scui-readiness section em { overflow:hidden; text-overflow:ellipsis; white-space:nowrap }.scui-readiness section small { color:var(--scui-muted); font-size:9px }.scui-readiness section em { color:var(--scui-muted); font-size:8px; font-style:normal }.scui-readiness section button { padding:4px 6px; border:1px solid var(--scui-border); border-radius:6px; background:transparent; cursor:pointer; font-size:9px }
|
|
208
210
|
.scui-new { display:grid; justify-items:center; gap:5px; margin:auto; padding:20px; color:var(--scui-muted); text-align:center }.scui-new > span { color:var(--scui-accent); font-size:28px }.scui-new strong { color:var(--scui-fg) }
|
|
209
|
-
.scui-opening { position:absolute; z-index:30; inset:
|
|
211
|
+
.scui-opening { position:absolute; z-index:30; inset:var(--scui-head-height) 0 0; display:flex; align-items:center; justify-content:center; gap:10px; padding:20px; background:var(--scui-bg) }.scui-opening > span { display:grid }.scui-opening small { color:var(--scui-muted) }.scui-opening > i { width:16px; height:16px; border:2px solid var(--scui-border); border-top-color:var(--scui-accent); border-radius:50%; animation:scui-spin .8s linear infinite }
|
|
210
212
|
|
|
211
213
|
@keyframes scui-spin { to { transform:rotate(360deg) } }
|
|
212
214
|
@keyframes scui-breathe { 50% { transform:scale(.72); opacity:.5 } }
|
|
@@ -215,8 +217,8 @@
|
|
|
215
217
|
@keyframes scui-session-dots { 50% { transform:translateY(-1px); opacity:.55 } }
|
|
216
218
|
@media (prefers-reduced-motion:reduce) { .scui-root * { animation-duration:.001ms !important; animation-iteration-count:1 !important; transition:none !important } }
|
|
217
219
|
@media (pointer:coarse) {
|
|
218
|
-
.scui-
|
|
219
|
-
.scui-head {
|
|
220
|
+
:where(.scui-root) { --scui-head-height:44px }
|
|
221
|
+
.scui-head > button,.scui-menu-trigger { width:36px; height:36px }
|
|
220
222
|
.scui-menu-panel button,.scui-request-actions button,.scui-load { min-height:40px }
|
|
221
223
|
.scui-send,.scui-stop { width:40px; height:40px }
|
|
222
224
|
.scui-new-envelope-controls .scui-attach,.scui-harness-trigger { min-height:40px }
|