@volter-ai-dev/supercode-ui 0.1.24 → 0.1.26
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 -1
- package/components.mjs +43 -7
- package/core.mjs +1 -1
- package/embed.mjs +21 -7
- package/index.d.ts +3 -0
- package/logo.d.ts +1 -1
- package/logo.mjs +22 -0
- package/messenger.mjs +21 -7
- package/package.json +1 -1
- package/sessions.mjs +20 -6
- package/styles.css +6 -5
package/README.md
CHANGED
|
@@ -59,7 +59,7 @@ import {
|
|
|
59
59
|
Conversation,
|
|
60
60
|
SessionList,
|
|
61
61
|
} from '@volter-ai-dev/supercode-ui/preact';
|
|
62
|
-
import { HarnessLogo } from '@volter-ai-dev/supercode-ui/preact/logo';
|
|
62
|
+
import { HarnessLogo, harnessLogoDataUrl } from '@volter-ai-dev/supercode-ui/preact/logo';
|
|
63
63
|
import { groupConversation } from '@volter-ai-dev/supercode-ui/core';
|
|
64
64
|
```
|
|
65
65
|
|
|
@@ -70,6 +70,8 @@ formatters, and intent constructors live at `supercode-ui/core` and have no DOM
|
|
|
70
70
|
For genuine partial delivery, the `preact/logo`, `preact/icon`, `preact/conversation`, `preact/sessions`,
|
|
71
71
|
`preact/composer`, and `preact/messenger` subpaths are independently tree-shaken artifacts; taking
|
|
72
72
|
the logo does not pull in Markdown, the messenger, or session-list code.
|
|
73
|
+
`harnessLogoDataUrl(id)` gives non-Preact launchers the same self-contained canonical SVG; it
|
|
74
|
+
returns `null` for an unknown harness rather than inventing a fallback identity.
|
|
73
75
|
|
|
74
76
|
## Bind directly to the headless controller
|
|
75
77
|
|
package/components.mjs
CHANGED
|
@@ -667,7 +667,7 @@ function normalizeUiState(value) {
|
|
|
667
667
|
savedDraft: string(raw.savedDraft),
|
|
668
668
|
attention: Array.isArray(raw.attention) ? raw.attention.flatMap((candidate) => {
|
|
669
669
|
const item = record(candidate);
|
|
670
|
-
return item && typeof item.key === "string" && ["unseen", "finished", "failed"].includes(item.kind) ? [{ key: item.key, kind: item.kind, ...typeof item.preview === "string" ? { preview: item.preview } : {}, ...Number.isSafeInteger(item.afterMessages) && item.afterMessages >= 0 ? { afterMessages: item.afterMessages } : {} }] : [];
|
|
670
|
+
return item && typeof item.key === "string" && ["unseen", "finished", "failed"].includes(item.kind) ? [{ key: item.key, kind: item.kind, ...typeof item.preview === "string" ? { preview: item.preview } : {}, ...Number.isSafeInteger(item.afterMessages) && item.afterMessages >= 0 ? { afterMessages: item.afterMessages } : {}, ...Number.isSafeInteger(item.unreadCount) && item.unreadCount > 0 ? { unreadCount: item.unreadCount } : {} }] : [];
|
|
671
671
|
}) : [],
|
|
672
672
|
sessions: readSessions(raw.sessions),
|
|
673
673
|
attached: readAttached(raw.attached),
|
|
@@ -1952,6 +1952,27 @@ var LOGOS = {
|
|
|
1952
1952
|
function hasHarnessLogo(id) {
|
|
1953
1953
|
return Object.hasOwn(LOGOS, id);
|
|
1954
1954
|
}
|
|
1955
|
+
var LOGO_CHROME = {
|
|
1956
|
+
codex: { background: "#f7f7f5", color: "#111" },
|
|
1957
|
+
gemini: { background: "#f7f7f5", color: "#6e79dc" },
|
|
1958
|
+
goose: { background: "#f7f7f5", color: "#101010" },
|
|
1959
|
+
pi: { background: "#efefeb", color: "#111" },
|
|
1960
|
+
supercode: { background: "#111923", color: "#f7f7f5" }
|
|
1961
|
+
};
|
|
1962
|
+
function escapeSvgAttribute(value) {
|
|
1963
|
+
return String(value).replaceAll("&", "&").replaceAll('"', """).replaceAll("<", "<").replaceAll(">", ">");
|
|
1964
|
+
}
|
|
1965
|
+
function harnessLogoDataUrl(id) {
|
|
1966
|
+
const logo = LOGOS[id];
|
|
1967
|
+
if (!logo) return null;
|
|
1968
|
+
const chrome = LOGO_CHROME[id] ?? { background: "#111", color: id === "claude-code" ? "#d97757" : "#f7f7f5" };
|
|
1969
|
+
const glyph = logo.paths.map(([tag, attributes]) => {
|
|
1970
|
+
const serialized = Object.entries(attributes).map(([name, value]) => `${name}="${escapeSvgAttribute(value)}"`).join(" ");
|
|
1971
|
+
return `<${tag} ${serialized}/>`;
|
|
1972
|
+
}).join("");
|
|
1973
|
+
const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"><circle cx="20" cy="20" r="19" fill="${chrome.background}" stroke="#383a42"/><svg x="7" y="7" width="26" height="26" viewBox="${logo.viewBox}" color="${chrome.color}" fill="currentColor" preserveAspectRatio="xMidYMid meet">${glyph}</svg></svg>`;
|
|
1974
|
+
return `data:image/svg+xml,${encodeURIComponent(svg)}`;
|
|
1975
|
+
}
|
|
1955
1976
|
function HarnessLogo({ id, activity, size = 28, onMissingLogo }) {
|
|
1956
1977
|
const logo = LOGOS[id];
|
|
1957
1978
|
useEffect5(() => {
|
|
@@ -1971,19 +1992,33 @@ import { useEffect as useEffect7, useId as useId2, useMemo as useMemo2, useRef a
|
|
|
1971
1992
|
import { useEffect as useEffect6, useLayoutEffect as useLayoutEffect3, useRef as useRef5, useState as useState4 } from "preact/hooks";
|
|
1972
1993
|
import { jsx as jsx7, jsxs as jsxs6 } from "preact/jsx-runtime";
|
|
1973
1994
|
var sessionListMemory = /* @__PURE__ */ new Map();
|
|
1995
|
+
function compactSessionPath(value, maxCharacters = 34) {
|
|
1996
|
+
const segments = String(value ?? "").replaceAll("\\", "/").split("/").filter((segment) => segment && segment !== "~");
|
|
1997
|
+
const complete = segments.join("/");
|
|
1998
|
+
if (complete.length <= maxCharacters) return complete;
|
|
1999
|
+
if (segments.length < 2) return `${complete.slice(0, maxCharacters - 1)}\u2026`;
|
|
2000
|
+
return `${segments[0]}/\u2026/${segments.at(-1)}`;
|
|
2001
|
+
}
|
|
1974
2002
|
function SessionRow({ row, state, onOpen }) {
|
|
1975
2003
|
const activity = sessionActivity(state, row);
|
|
1976
|
-
const
|
|
2004
|
+
const attention = state.attention.find((item) => item.key === row.key);
|
|
1977
2005
|
const title = sessionDisplayName(row);
|
|
1978
|
-
const
|
|
1979
|
-
|
|
2006
|
+
const path = compactSessionPath(row.cwd);
|
|
2007
|
+
const preview = row.preview || attention?.preview || "";
|
|
2008
|
+
const unreadCount = attention?.unreadCount ?? 0;
|
|
2009
|
+
const unreadLabel = unreadCount > 99 ? "99+" : String(unreadCount);
|
|
2010
|
+
return /* @__PURE__ */ jsxs6("button", { class: "scui-session", "data-active": row.active, "data-activity": activity, "data-session-key": row.key, type: "button", "aria-label": `${title} \xB7 ${harnessDisplayName(row.harness)}${path ? ` \xB7 ${path}` : ""}${preview ? ` \xB7 ${preview}` : ""}${unreadCount ? ` \xB7 ${unreadCount} unread` : ""}${row.age ? ` \xB7 ${row.age}` : ""}`, "aria-current": row.active ? "true" : void 0, onClick: () => onOpen(row), children: [
|
|
1980
2011
|
/* @__PURE__ */ jsx7(HarnessLogo, { id: row.harness, activity, size: 34 }),
|
|
1981
2012
|
/* @__PURE__ */ jsxs6("span", { class: "scui-session-copy", children: [
|
|
1982
|
-
/* @__PURE__ */ jsxs6("span", { children: [
|
|
2013
|
+
/* @__PURE__ */ jsxs6("span", { class: "scui-session-title", children: [
|
|
1983
2014
|
/* @__PURE__ */ jsx7("strong", { children: title }),
|
|
1984
|
-
/* @__PURE__ */ jsx7("
|
|
2015
|
+
row.age ? /* @__PURE__ */ jsx7("time", { children: row.age }) : null
|
|
1985
2016
|
] }),
|
|
1986
|
-
|
|
2017
|
+
path ? /* @__PURE__ */ jsx7("small", { class: "scui-session-path", title: row.cwd, children: path }) : null,
|
|
2018
|
+
preview || unreadCount ? /* @__PURE__ */ jsxs6("span", { class: "scui-session-preview", children: [
|
|
2019
|
+
preview ? /* @__PURE__ */ jsx7("small", { children: preview }) : null,
|
|
2020
|
+
unreadCount ? /* @__PURE__ */ jsx7("b", { "aria-label": `${unreadCount} unread messages`, children: unreadLabel }) : null
|
|
2021
|
+
] }) : null,
|
|
1987
2022
|
state.attachError?.key === row.key ? /* @__PURE__ */ jsx7("em", { children: state.attachError.message }) : null
|
|
1988
2023
|
] })
|
|
1989
2024
|
] });
|
|
@@ -2535,5 +2570,6 @@ export {
|
|
|
2535
2570
|
ToolRow,
|
|
2536
2571
|
TranscriptEntry,
|
|
2537
2572
|
UiIcon,
|
|
2573
|
+
harnessLogoDataUrl,
|
|
2538
2574
|
hasHarnessLogo
|
|
2539
2575
|
};
|
package/core.mjs
CHANGED
|
@@ -704,7 +704,7 @@ export function normalizeUiState(value) {
|
|
|
704
704
|
attention: Array.isArray(raw.attention) ? raw.attention.flatMap((candidate) => {
|
|
705
705
|
const item = record(candidate);
|
|
706
706
|
return item && typeof item.key === 'string' && ['unseen', 'finished', 'failed'].includes(item.kind)
|
|
707
|
-
? [{ key: item.key, kind: item.kind, ...(typeof item.preview === 'string' ? { preview: item.preview } : {}), ...(Number.isSafeInteger(item.afterMessages) && item.afterMessages >= 0 ? { afterMessages: item.afterMessages } : {}) }]
|
|
707
|
+
? [{ key: item.key, kind: item.kind, ...(typeof item.preview === 'string' ? { preview: item.preview } : {}), ...(Number.isSafeInteger(item.afterMessages) && item.afterMessages >= 0 ? { afterMessages: item.afterMessages } : {}), ...(Number.isSafeInteger(item.unreadCount) && item.unreadCount > 0 ? { unreadCount: item.unreadCount } : {}) }]
|
|
708
708
|
: [];
|
|
709
709
|
}) : [],
|
|
710
710
|
sessions: readSessions(raw.sessions),
|
package/embed.mjs
CHANGED
|
@@ -670,7 +670,7 @@ function normalizeUiState(value) {
|
|
|
670
670
|
savedDraft: string(raw.savedDraft),
|
|
671
671
|
attention: Array.isArray(raw.attention) ? raw.attention.flatMap((candidate) => {
|
|
672
672
|
const item = record(candidate);
|
|
673
|
-
return item && typeof item.key === "string" && ["unseen", "finished", "failed"].includes(item.kind) ? [{ key: item.key, kind: item.kind, ...typeof item.preview === "string" ? { preview: item.preview } : {}, ...Number.isSafeInteger(item.afterMessages) && item.afterMessages >= 0 ? { afterMessages: item.afterMessages } : {} }] : [];
|
|
673
|
+
return item && typeof item.key === "string" && ["unseen", "finished", "failed"].includes(item.kind) ? [{ key: item.key, kind: item.kind, ...typeof item.preview === "string" ? { preview: item.preview } : {}, ...Number.isSafeInteger(item.afterMessages) && item.afterMessages >= 0 ? { afterMessages: item.afterMessages } : {}, ...Number.isSafeInteger(item.unreadCount) && item.unreadCount > 0 ? { unreadCount: item.unreadCount } : {} }] : [];
|
|
674
674
|
}) : [],
|
|
675
675
|
sessions: readSessions(raw.sessions),
|
|
676
676
|
attached: readAttached(raw.attached),
|
|
@@ -1971,19 +1971,33 @@ function HarnessLogo({ id, activity, size = 28, onMissingLogo }) {
|
|
|
1971
1971
|
import { useEffect as useEffect6, useLayoutEffect as useLayoutEffect3, useRef as useRef5, useState as useState4 } from "preact/hooks";
|
|
1972
1972
|
import { jsx as jsx7, jsxs as jsxs6 } from "preact/jsx-runtime";
|
|
1973
1973
|
var sessionListMemory = /* @__PURE__ */ new Map();
|
|
1974
|
+
function compactSessionPath(value, maxCharacters = 34) {
|
|
1975
|
+
const segments = String(value ?? "").replaceAll("\\", "/").split("/").filter((segment) => segment && segment !== "~");
|
|
1976
|
+
const complete = segments.join("/");
|
|
1977
|
+
if (complete.length <= maxCharacters) return complete;
|
|
1978
|
+
if (segments.length < 2) return `${complete.slice(0, maxCharacters - 1)}\u2026`;
|
|
1979
|
+
return `${segments[0]}/\u2026/${segments.at(-1)}`;
|
|
1980
|
+
}
|
|
1974
1981
|
function SessionRow({ row, state, onOpen }) {
|
|
1975
1982
|
const activity = sessionActivity(state, row);
|
|
1976
|
-
const
|
|
1983
|
+
const attention = state.attention.find((item) => item.key === row.key);
|
|
1977
1984
|
const title = sessionDisplayName(row);
|
|
1978
|
-
const
|
|
1979
|
-
|
|
1985
|
+
const path = compactSessionPath(row.cwd);
|
|
1986
|
+
const preview = row.preview || attention?.preview || "";
|
|
1987
|
+
const unreadCount = attention?.unreadCount ?? 0;
|
|
1988
|
+
const unreadLabel = unreadCount > 99 ? "99+" : String(unreadCount);
|
|
1989
|
+
return /* @__PURE__ */ jsxs6("button", { class: "scui-session", "data-active": row.active, "data-activity": activity, "data-session-key": row.key, type: "button", "aria-label": `${title} \xB7 ${harnessDisplayName(row.harness)}${path ? ` \xB7 ${path}` : ""}${preview ? ` \xB7 ${preview}` : ""}${unreadCount ? ` \xB7 ${unreadCount} unread` : ""}${row.age ? ` \xB7 ${row.age}` : ""}`, "aria-current": row.active ? "true" : void 0, onClick: () => onOpen(row), children: [
|
|
1980
1990
|
/* @__PURE__ */ jsx7(HarnessLogo, { id: row.harness, activity, size: 34 }),
|
|
1981
1991
|
/* @__PURE__ */ jsxs6("span", { class: "scui-session-copy", children: [
|
|
1982
|
-
/* @__PURE__ */ jsxs6("span", { children: [
|
|
1992
|
+
/* @__PURE__ */ jsxs6("span", { class: "scui-session-title", children: [
|
|
1983
1993
|
/* @__PURE__ */ jsx7("strong", { children: title }),
|
|
1984
|
-
/* @__PURE__ */ jsx7("
|
|
1994
|
+
row.age ? /* @__PURE__ */ jsx7("time", { children: row.age }) : null
|
|
1985
1995
|
] }),
|
|
1986
|
-
|
|
1996
|
+
path ? /* @__PURE__ */ jsx7("small", { class: "scui-session-path", title: row.cwd, children: path }) : null,
|
|
1997
|
+
preview || unreadCount ? /* @__PURE__ */ jsxs6("span", { class: "scui-session-preview", children: [
|
|
1998
|
+
preview ? /* @__PURE__ */ jsx7("small", { children: preview }) : null,
|
|
1999
|
+
unreadCount ? /* @__PURE__ */ jsx7("b", { "aria-label": `${unreadCount} unread messages`, children: unreadLabel }) : null
|
|
2000
|
+
] }) : null,
|
|
1987
2001
|
state.attachError?.key === row.key ? /* @__PURE__ */ jsx7("em", { children: state.attachError.message }) : null
|
|
1988
2002
|
] })
|
|
1989
2003
|
] });
|
package/index.d.ts
CHANGED
|
@@ -164,6 +164,8 @@ export interface SessionAttention {
|
|
|
164
164
|
preview?: string;
|
|
165
165
|
/** The canonical message count when this conversation was last seen. */
|
|
166
166
|
afterMessages?: number;
|
|
167
|
+
/** Human-visible replies observed since this conversation was last read. */
|
|
168
|
+
unreadCount?: number;
|
|
167
169
|
}
|
|
168
170
|
|
|
169
171
|
export interface SupercodeUiState {
|
|
@@ -363,6 +365,7 @@ export function HarnessLogo(props: { id: HarnessId; activity?: SessionActivity;
|
|
|
363
365
|
export type UiIconName = 'attach' | 'back' | 'check' | 'chevron' | 'close' | 'copy' | 'down' | 'menu' | 'plus' | 'search' | 'send' | 'stop';
|
|
364
366
|
export function UiIcon(props: { name: UiIconName; size?: number; class?: string }): VNode | null;
|
|
365
367
|
export function hasHarnessLogo(id: string): boolean;
|
|
368
|
+
export function harnessLogoDataUrl(id: string): string | null;
|
|
366
369
|
export function ImageViewer(props: { items: TranscriptImage[]; index: number; adapter?: Pick<UiAdapter, 'copyText' | 'resolveImage'>; onChange(index: number): void; onClose(): void }): VNode | null;
|
|
367
370
|
export function MessageImages(props: { items?: TranscriptImage[]; adapter?: Pick<UiAdapter, 'copyText' | 'resolveImage'> }): VNode | null;
|
|
368
371
|
export function LoadingStatus(props: { state: SupercodeUiState; compact?: boolean }): VNode;
|
package/logo.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export type { HarnessId, SessionActivity } from './index.js';
|
|
2
|
-
export { HarnessLogo, hasHarnessLogo } from './index.js';
|
|
2
|
+
export { HarnessLogo, harnessLogoDataUrl, hasHarnessLogo } from './index.js';
|
package/logo.mjs
CHANGED
|
@@ -48,6 +48,27 @@ var LOGOS = {
|
|
|
48
48
|
function hasHarnessLogo(id) {
|
|
49
49
|
return Object.hasOwn(LOGOS, id);
|
|
50
50
|
}
|
|
51
|
+
var LOGO_CHROME = {
|
|
52
|
+
codex: { background: "#f7f7f5", color: "#111" },
|
|
53
|
+
gemini: { background: "#f7f7f5", color: "#6e79dc" },
|
|
54
|
+
goose: { background: "#f7f7f5", color: "#101010" },
|
|
55
|
+
pi: { background: "#efefeb", color: "#111" },
|
|
56
|
+
supercode: { background: "#111923", color: "#f7f7f5" }
|
|
57
|
+
};
|
|
58
|
+
function escapeSvgAttribute(value) {
|
|
59
|
+
return String(value).replaceAll("&", "&").replaceAll('"', """).replaceAll("<", "<").replaceAll(">", ">");
|
|
60
|
+
}
|
|
61
|
+
function harnessLogoDataUrl(id) {
|
|
62
|
+
const logo = LOGOS[id];
|
|
63
|
+
if (!logo) return null;
|
|
64
|
+
const chrome = LOGO_CHROME[id] ?? { background: "#111", color: id === "claude-code" ? "#d97757" : "#f7f7f5" };
|
|
65
|
+
const glyph = logo.paths.map(([tag, attributes]) => {
|
|
66
|
+
const serialized = Object.entries(attributes).map(([name, value]) => `${name}="${escapeSvgAttribute(value)}"`).join(" ");
|
|
67
|
+
return `<${tag} ${serialized}/>`;
|
|
68
|
+
}).join("");
|
|
69
|
+
const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"><circle cx="20" cy="20" r="19" fill="${chrome.background}" stroke="#383a42"/><svg x="7" y="7" width="26" height="26" viewBox="${logo.viewBox}" color="${chrome.color}" fill="currentColor" preserveAspectRatio="xMidYMid meet">${glyph}</svg></svg>`;
|
|
70
|
+
return `data:image/svg+xml,${encodeURIComponent(svg)}`;
|
|
71
|
+
}
|
|
51
72
|
function HarnessLogo({ id, activity, size = 28, onMissingLogo }) {
|
|
52
73
|
const logo = LOGOS[id];
|
|
53
74
|
useEffect(() => {
|
|
@@ -61,5 +82,6 @@ function HarnessLogo({ id, activity, size = 28, onMissingLogo }) {
|
|
|
61
82
|
}
|
|
62
83
|
export {
|
|
63
84
|
HarnessLogo,
|
|
85
|
+
harnessLogoDataUrl,
|
|
64
86
|
hasHarnessLogo
|
|
65
87
|
};
|
package/messenger.mjs
CHANGED
|
@@ -667,7 +667,7 @@ function normalizeUiState(value) {
|
|
|
667
667
|
savedDraft: string(raw.savedDraft),
|
|
668
668
|
attention: Array.isArray(raw.attention) ? raw.attention.flatMap((candidate) => {
|
|
669
669
|
const item = record(candidate);
|
|
670
|
-
return item && typeof item.key === "string" && ["unseen", "finished", "failed"].includes(item.kind) ? [{ key: item.key, kind: item.kind, ...typeof item.preview === "string" ? { preview: item.preview } : {}, ...Number.isSafeInteger(item.afterMessages) && item.afterMessages >= 0 ? { afterMessages: item.afterMessages } : {} }] : [];
|
|
670
|
+
return item && typeof item.key === "string" && ["unseen", "finished", "failed"].includes(item.kind) ? [{ key: item.key, kind: item.kind, ...typeof item.preview === "string" ? { preview: item.preview } : {}, ...Number.isSafeInteger(item.afterMessages) && item.afterMessages >= 0 ? { afterMessages: item.afterMessages } : {}, ...Number.isSafeInteger(item.unreadCount) && item.unreadCount > 0 ? { unreadCount: item.unreadCount } : {} }] : [];
|
|
671
671
|
}) : [],
|
|
672
672
|
sessions: readSessions(raw.sessions),
|
|
673
673
|
attached: readAttached(raw.attached),
|
|
@@ -1968,19 +1968,33 @@ function HarnessLogo({ id, activity, size = 28, onMissingLogo }) {
|
|
|
1968
1968
|
import { useEffect as useEffect6, useLayoutEffect as useLayoutEffect3, useRef as useRef5, useState as useState4 } from "preact/hooks";
|
|
1969
1969
|
import { jsx as jsx7, jsxs as jsxs6 } from "preact/jsx-runtime";
|
|
1970
1970
|
var sessionListMemory = /* @__PURE__ */ new Map();
|
|
1971
|
+
function compactSessionPath(value, maxCharacters = 34) {
|
|
1972
|
+
const segments = String(value ?? "").replaceAll("\\", "/").split("/").filter((segment) => segment && segment !== "~");
|
|
1973
|
+
const complete = segments.join("/");
|
|
1974
|
+
if (complete.length <= maxCharacters) return complete;
|
|
1975
|
+
if (segments.length < 2) return `${complete.slice(0, maxCharacters - 1)}\u2026`;
|
|
1976
|
+
return `${segments[0]}/\u2026/${segments.at(-1)}`;
|
|
1977
|
+
}
|
|
1971
1978
|
function SessionRow({ row, state, onOpen }) {
|
|
1972
1979
|
const activity = sessionActivity(state, row);
|
|
1973
|
-
const
|
|
1980
|
+
const attention = state.attention.find((item) => item.key === row.key);
|
|
1974
1981
|
const title = sessionDisplayName(row);
|
|
1975
|
-
const
|
|
1976
|
-
|
|
1982
|
+
const path = compactSessionPath(row.cwd);
|
|
1983
|
+
const preview = row.preview || attention?.preview || "";
|
|
1984
|
+
const unreadCount = attention?.unreadCount ?? 0;
|
|
1985
|
+
const unreadLabel = unreadCount > 99 ? "99+" : String(unreadCount);
|
|
1986
|
+
return /* @__PURE__ */ jsxs6("button", { class: "scui-session", "data-active": row.active, "data-activity": activity, "data-session-key": row.key, type: "button", "aria-label": `${title} \xB7 ${harnessDisplayName(row.harness)}${path ? ` \xB7 ${path}` : ""}${preview ? ` \xB7 ${preview}` : ""}${unreadCount ? ` \xB7 ${unreadCount} unread` : ""}${row.age ? ` \xB7 ${row.age}` : ""}`, "aria-current": row.active ? "true" : void 0, onClick: () => onOpen(row), children: [
|
|
1977
1987
|
/* @__PURE__ */ jsx7(HarnessLogo, { id: row.harness, activity, size: 34 }),
|
|
1978
1988
|
/* @__PURE__ */ jsxs6("span", { class: "scui-session-copy", children: [
|
|
1979
|
-
/* @__PURE__ */ jsxs6("span", { children: [
|
|
1989
|
+
/* @__PURE__ */ jsxs6("span", { class: "scui-session-title", children: [
|
|
1980
1990
|
/* @__PURE__ */ jsx7("strong", { children: title }),
|
|
1981
|
-
/* @__PURE__ */ jsx7("
|
|
1991
|
+
row.age ? /* @__PURE__ */ jsx7("time", { children: row.age }) : null
|
|
1982
1992
|
] }),
|
|
1983
|
-
|
|
1993
|
+
path ? /* @__PURE__ */ jsx7("small", { class: "scui-session-path", title: row.cwd, children: path }) : null,
|
|
1994
|
+
preview || unreadCount ? /* @__PURE__ */ jsxs6("span", { class: "scui-session-preview", children: [
|
|
1995
|
+
preview ? /* @__PURE__ */ jsx7("small", { children: preview }) : null,
|
|
1996
|
+
unreadCount ? /* @__PURE__ */ jsx7("b", { "aria-label": `${unreadCount} unread messages`, children: unreadLabel }) : null
|
|
1997
|
+
] }) : null,
|
|
1984
1998
|
state.attachError?.key === row.key ? /* @__PURE__ */ jsx7("em", { children: state.attachError.message }) : null
|
|
1985
1999
|
] })
|
|
1986
2000
|
] });
|
package/package.json
CHANGED
package/sessions.mjs
CHANGED
|
@@ -279,19 +279,33 @@ function HarnessLogo({ id, activity, size = 28, onMissingLogo }) {
|
|
|
279
279
|
// src/sessions.jsx
|
|
280
280
|
import { jsx as jsx6, jsxs as jsxs5 } from "preact/jsx-runtime";
|
|
281
281
|
var sessionListMemory = /* @__PURE__ */ new Map();
|
|
282
|
+
function compactSessionPath(value, maxCharacters = 34) {
|
|
283
|
+
const segments = String(value ?? "").replaceAll("\\", "/").split("/").filter((segment) => segment && segment !== "~");
|
|
284
|
+
const complete = segments.join("/");
|
|
285
|
+
if (complete.length <= maxCharacters) return complete;
|
|
286
|
+
if (segments.length < 2) return `${complete.slice(0, maxCharacters - 1)}\u2026`;
|
|
287
|
+
return `${segments[0]}/\u2026/${segments.at(-1)}`;
|
|
288
|
+
}
|
|
282
289
|
function SessionRow({ row, state, onOpen }) {
|
|
283
290
|
const activity = sessionActivity(state, row);
|
|
284
|
-
const
|
|
291
|
+
const attention = state.attention.find((item) => item.key === row.key);
|
|
285
292
|
const title = sessionDisplayName(row);
|
|
286
|
-
const
|
|
287
|
-
|
|
293
|
+
const path = compactSessionPath(row.cwd);
|
|
294
|
+
const preview = row.preview || attention?.preview || "";
|
|
295
|
+
const unreadCount = attention?.unreadCount ?? 0;
|
|
296
|
+
const unreadLabel = unreadCount > 99 ? "99+" : String(unreadCount);
|
|
297
|
+
return /* @__PURE__ */ jsxs5("button", { class: "scui-session", "data-active": row.active, "data-activity": activity, "data-session-key": row.key, type: "button", "aria-label": `${title} \xB7 ${harnessDisplayName(row.harness)}${path ? ` \xB7 ${path}` : ""}${preview ? ` \xB7 ${preview}` : ""}${unreadCount ? ` \xB7 ${unreadCount} unread` : ""}${row.age ? ` \xB7 ${row.age}` : ""}`, "aria-current": row.active ? "true" : void 0, onClick: () => onOpen(row), children: [
|
|
288
298
|
/* @__PURE__ */ jsx6(HarnessLogo, { id: row.harness, activity, size: 34 }),
|
|
289
299
|
/* @__PURE__ */ jsxs5("span", { class: "scui-session-copy", children: [
|
|
290
|
-
/* @__PURE__ */ jsxs5("span", { children: [
|
|
300
|
+
/* @__PURE__ */ jsxs5("span", { class: "scui-session-title", children: [
|
|
291
301
|
/* @__PURE__ */ jsx6("strong", { children: title }),
|
|
292
|
-
/* @__PURE__ */ jsx6("
|
|
302
|
+
row.age ? /* @__PURE__ */ jsx6("time", { children: row.age }) : null
|
|
293
303
|
] }),
|
|
294
|
-
|
|
304
|
+
path ? /* @__PURE__ */ jsx6("small", { class: "scui-session-path", title: row.cwd, children: path }) : null,
|
|
305
|
+
preview || unreadCount ? /* @__PURE__ */ jsxs5("span", { class: "scui-session-preview", children: [
|
|
306
|
+
preview ? /* @__PURE__ */ jsx6("small", { children: preview }) : null,
|
|
307
|
+
unreadCount ? /* @__PURE__ */ jsx6("b", { "aria-label": `${unreadCount} unread messages`, children: unreadLabel }) : null
|
|
308
|
+
] }) : null,
|
|
295
309
|
state.attachError?.key === row.key ? /* @__PURE__ */ jsx6("em", { children: state.attachError.message }) : null
|
|
296
310
|
] })
|
|
297
311
|
] });
|
package/styles.css
CHANGED
|
@@ -92,13 +92,14 @@
|
|
|
92
92
|
.scui-search { display:flex; flex:none; align-items:center; gap:7px; margin:8px; padding:6px 8px; border:1px solid var(--scui-border); border-radius:8px; background:var(--scui-bg-raised); color:var(--scui-muted) }
|
|
93
93
|
.scui-search input { flex:1; min-width:0; border:0; outline:0; background:transparent; color:var(--scui-fg) }
|
|
94
94
|
.scui-session-rows { flex:1; min-height:0; overflow:auto; padding:0 6px 8px }
|
|
95
|
-
.scui-session { display:flex; align-items:
|
|
95
|
+
.scui-session { display:flex; align-items:flex-start; gap:9px; width:100%; padding:8px; border:0; border-radius:7px; background:transparent; text-align:left; cursor:pointer }
|
|
96
96
|
.scui-session:hover,.scui-session[data-active="true"] { background:var(--scui-fill) }
|
|
97
|
-
.scui-session-copy { display:grid; flex:1; min-width:0; gap:
|
|
97
|
+
.scui-session-copy { display:grid; flex:1; min-width:0; gap:1px }
|
|
98
98
|
.scui-session-copy > span { display:flex; align-items:baseline; gap:7px; min-width:0 }
|
|
99
|
-
.scui-session-copy strong,.scui-session-copy span > small { overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
|
|
100
|
-
.scui-session-copy strong { flex:1; font-size:12.5px }.scui-session-
|
|
101
|
-
.scui-session-
|
|
99
|
+
.scui-session-copy strong,.scui-session-copy span > small,.scui-session-path { overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
|
|
100
|
+
.scui-session-copy strong { flex:1; font-size:12.5px }.scui-session-title time { flex:none; color:var(--scui-muted); font-size:10px }
|
|
101
|
+
.scui-session-path { min-width:0; color:var(--scui-muted); font-size:9.5px }
|
|
102
|
+
.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 }
|
|
102
103
|
.scui-session-copy em { overflow:hidden; color:var(--scui-danger); font-size:10px; font-style:normal; text-overflow:ellipsis; white-space:nowrap }
|
|
103
104
|
.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 }
|
|
104
105
|
|