@volter-ai-dev/supercode-ui 0.1.41 → 0.1.42
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 -3
- package/components.d.ts +1 -0
- package/components.mjs +84 -15
- package/embed.mjs +83 -15
- package/index.d.ts +11 -0
- package/messenger.mjs +83 -15
- package/package.json +1 -1
- package/react/components.mjs +84 -15
- package/react/index.d.ts +4 -0
- package/react/messenger.mjs +83 -15
- package/react/settings.d.ts +2 -2
- package/react/settings.mjs +74 -0
- package/settings.d.ts +2 -2
- package/settings.mjs +74 -0
- package/styles.css +6 -1
package/README.md
CHANGED
|
@@ -60,14 +60,14 @@ import {
|
|
|
60
60
|
SessionList,
|
|
61
61
|
} from '@volter-ai-dev/supercode-ui/preact';
|
|
62
62
|
import { HarnessLogo, harnessLogoDataUrl } from '@volter-ai-dev/supercode-ui/preact/logo';
|
|
63
|
-
import { HarnessAdvisory, HarnessSettingsPanel } from '@volter-ai-dev/supercode-ui/preact/settings';
|
|
63
|
+
import { HarnessAdvisory, HarnessPicker, HarnessSettingsPanel } from '@volter-ai-dev/supercode-ui/preact/settings';
|
|
64
64
|
import { groupConversation } from '@volter-ai-dev/supercode-ui/core';
|
|
65
65
|
```
|
|
66
66
|
|
|
67
67
|
The public components are `SupercodeMessenger`, `AgentActivityLauncher`, `Conversation`, `TranscriptEntry`,
|
|
68
68
|
`ActivityGroup`, `RequestCard`, `SessionList`, `SessionRow`, `Composer`, `ContinuationBar`,
|
|
69
|
-
`ContextCandidate`, `ContextCandidates`, `LoadingStatus`, `TaskPlan`, `SessionDetails`, `HarnessLogo`, `HarnessAdvisory`,
|
|
70
|
-
`HarnessSettingsPanel`. Pure state readers, selectors,
|
|
69
|
+
`ContextCandidate`, `ContextCandidates`, `LoadingStatus`, `TaskPlan`, `SessionDetails`, `HarnessLogo`, `HarnessAdvisory`,
|
|
70
|
+
`HarnessPicker`, and `HarnessSettingsPanel`. Pure state readers, selectors,
|
|
71
71
|
formatters, and intent constructors live at `supercode-ui/core` and have no DOM or Preact imports.
|
|
72
72
|
For genuine partial delivery, the `preact/logo`, `preact/icon`, `preact/conversation`, `preact/sessions`,
|
|
73
73
|
`preact/composer`, `preact/settings`, and `preact/messenger` subpaths are independently tree-shaken artifacts; taking
|
package/components.d.ts
CHANGED
package/components.mjs
CHANGED
|
@@ -2477,6 +2477,79 @@ function HarnessReadiness({ harnesses, adapter }) {
|
|
|
2477
2477
|
] }, item.id)) })
|
|
2478
2478
|
] });
|
|
2479
2479
|
}
|
|
2480
|
+
function HarnessPicker({ harnesses, value, disabled = false, adapter, onChange, logo: Logo = HarnessLogo }) {
|
|
2481
|
+
const [open, setOpen] = useState5(false);
|
|
2482
|
+
const menuId = useId2();
|
|
2483
|
+
const root = useRef6(null);
|
|
2484
|
+
const trigger = useRef6(null);
|
|
2485
|
+
const panel = useRef6(null);
|
|
2486
|
+
const available = harnesses.filter((item) => item.startable);
|
|
2487
|
+
const unavailable = harnesses.filter((item) => !item.startable);
|
|
2488
|
+
const selected = available.find((item) => item.id === value) ?? available[0] ?? null;
|
|
2489
|
+
const close = () => {
|
|
2490
|
+
setOpen(false);
|
|
2491
|
+
trigger.current?.focus({ preventScroll: true });
|
|
2492
|
+
};
|
|
2493
|
+
useEffect7(() => {
|
|
2494
|
+
if (!open) return;
|
|
2495
|
+
panel.current?.querySelector('[aria-selected="true"], [role="option"]')?.focus({ preventScroll: true });
|
|
2496
|
+
const dismiss = (event) => {
|
|
2497
|
+
if (event.type === "keydown" && event.key === "Escape") {
|
|
2498
|
+
event.preventDefault();
|
|
2499
|
+
close();
|
|
2500
|
+
} else if (event.type === "pointerdown" && !root.current?.contains(event.target)) {
|
|
2501
|
+
setOpen(false);
|
|
2502
|
+
}
|
|
2503
|
+
};
|
|
2504
|
+
document.addEventListener("keydown", dismiss);
|
|
2505
|
+
document.addEventListener("pointerdown", dismiss, true);
|
|
2506
|
+
return () => {
|
|
2507
|
+
document.removeEventListener("keydown", dismiss);
|
|
2508
|
+
document.removeEventListener("pointerdown", dismiss, true);
|
|
2509
|
+
};
|
|
2510
|
+
}, [open]);
|
|
2511
|
+
const navigate = (event) => {
|
|
2512
|
+
if (!["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) return;
|
|
2513
|
+
const items = [...panel.current.querySelectorAll('[role="option"]')];
|
|
2514
|
+
if (!items.length) return;
|
|
2515
|
+
event.preventDefault();
|
|
2516
|
+
const current = items.indexOf(document.activeElement);
|
|
2517
|
+
const index = event.key === "Home" ? 0 : event.key === "End" ? items.length - 1 : event.key === "ArrowDown" ? (current + 1) % items.length : (current <= 0 ? items.length : current) - 1;
|
|
2518
|
+
items[index].focus({ preventScroll: true });
|
|
2519
|
+
};
|
|
2520
|
+
const select = (id) => {
|
|
2521
|
+
onChange(id);
|
|
2522
|
+
close();
|
|
2523
|
+
};
|
|
2524
|
+
return /* @__PURE__ */ jsxs8("div", { className: "scui-harness-menu", ref: root, onBlur: (event) => {
|
|
2525
|
+
if (event.relatedTarget && !event.currentTarget.contains(event.relatedTarget)) setOpen(false);
|
|
2526
|
+
}, children: [
|
|
2527
|
+
/* @__PURE__ */ jsxs8("button", { ref: trigger, className: "scui-harness-trigger", type: "button", disabled: disabled || !selected, "aria-label": selected ? `Coding harness: ${selected.label}` : "No coding harness available", "aria-haspopup": "dialog", "aria-expanded": open, "aria-controls": open ? menuId : void 0, onClick: () => setOpen((current) => !current), children: [
|
|
2528
|
+
selected ? /* @__PURE__ */ jsx9(Logo, { id: selected.id, size: 20 }) : null,
|
|
2529
|
+
/* @__PURE__ */ jsx9("strong", { children: selected?.label ?? "No harness available" }),
|
|
2530
|
+
/* @__PURE__ */ jsx9(UiIcon, { name: "chevron", size: 13 })
|
|
2531
|
+
] }),
|
|
2532
|
+
open ? /* @__PURE__ */ jsxs8("div", { ref: panel, id: menuId, className: "scui-harness-popover", role: "dialog", "aria-label": "Choose coding harness", onKeyDown: navigate, children: [
|
|
2533
|
+
/* @__PURE__ */ jsx9("strong", { className: "scui-harness-popover-title", children: "Choose coding harness" }),
|
|
2534
|
+
/* @__PURE__ */ jsx9("div", { className: "scui-harness-options", role: "listbox", "aria-label": "Available coding harnesses", children: available.map((item) => /* @__PURE__ */ jsxs8("button", { type: "button", role: "option", "aria-selected": item.id === selected?.id, onClick: () => select(item.id), children: [
|
|
2535
|
+
/* @__PURE__ */ jsx9(Logo, { id: item.id, size: 24 }),
|
|
2536
|
+
/* @__PURE__ */ jsx9("strong", { children: item.label }),
|
|
2537
|
+
/* @__PURE__ */ jsx9("span", { children: item.id === selected?.id ? /* @__PURE__ */ jsx9(UiIcon, { name: "check", size: 15 }) : null })
|
|
2538
|
+
] }, item.id)) }),
|
|
2539
|
+
unavailable.length ? /* @__PURE__ */ jsxs8("details", { className: "scui-harness-manage", children: [
|
|
2540
|
+
/* @__PURE__ */ jsx9("summary", { children: "Manage additional harnesses" }),
|
|
2541
|
+
/* @__PURE__ */ jsx9("div", { children: unavailable.map((item) => /* @__PURE__ */ jsxs8("section", { children: [
|
|
2542
|
+
/* @__PURE__ */ jsx9(Logo, { id: item.id, size: 24 }),
|
|
2543
|
+
/* @__PURE__ */ jsxs8("span", { children: [
|
|
2544
|
+
/* @__PURE__ */ jsx9("strong", { children: item.label }),
|
|
2545
|
+
/* @__PURE__ */ jsx9("small", { children: item.reason || (item.auth === "required" ? "Authentication required" : "Unavailable") })
|
|
2546
|
+
] }),
|
|
2547
|
+
item.repair ? /* @__PURE__ */ jsx9("button", { type: "button", onClick: () => adapter?.copyText?.(item.repair), children: "Copy fix" }) : null
|
|
2548
|
+
] }, item.id)) })
|
|
2549
|
+
] }) : null
|
|
2550
|
+
] }) : null
|
|
2551
|
+
] });
|
|
2552
|
+
}
|
|
2480
2553
|
|
|
2481
2554
|
// src/messenger.jsx
|
|
2482
2555
|
import { jsx as jsx10, jsxs as jsxs9 } from "preact/jsx-runtime";
|
|
@@ -2770,6 +2843,7 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2770
2843
|
const startSequence = useRef7(0);
|
|
2771
2844
|
const textarea = useRef7(null);
|
|
2772
2845
|
const selectedHarness = startable.find((item) => item.id === harness) ?? null;
|
|
2846
|
+
const Picker = components.HarnessPicker ?? HarnessPicker;
|
|
2773
2847
|
const Readiness = components.HarnessReadiness ?? HarnessReadiness;
|
|
2774
2848
|
const launchModes = selectedHarness?.launchModes?.length ? selectedHarness.launchModes : ["headless"];
|
|
2775
2849
|
const rememberedMode = modes[harness];
|
|
@@ -2907,18 +2981,6 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2907
2981
|
/* @__PURE__ */ jsx10("small", { children: "Choose a coding harness and send the first message." })
|
|
2908
2982
|
] }),
|
|
2909
2983
|
/* @__PURE__ */ jsxs9("div", { className: "scui-compose", children: [
|
|
2910
|
-
/* @__PURE__ */ jsxs9("label", { className: "scui-harness-picker", children: [
|
|
2911
|
-
/* @__PURE__ */ jsx10(HarnessLogo, { id: harness, size: 24 }),
|
|
2912
|
-
/* @__PURE__ */ jsx10("span", { children: "Coding harness" }),
|
|
2913
|
-
/* @__PURE__ */ jsx10("select", { value: harness, disabled: Boolean(starting), onChange: (event) => {
|
|
2914
|
-
const value = event.currentTarget.value;
|
|
2915
|
-
setHarness(value);
|
|
2916
|
-
remember({ harness: value });
|
|
2917
|
-
}, children: state.harnesses.map((item) => /* @__PURE__ */ jsxs9("option", { value: item.id, disabled: !item.startable, children: [
|
|
2918
|
-
item.label,
|
|
2919
|
-
item.startable ? "" : " \xB7 unavailable"
|
|
2920
|
-
] }, item.id)) })
|
|
2921
|
-
] }),
|
|
2922
2984
|
/* @__PURE__ */ jsx10(Readiness, { harnesses: state.harnesses, state, adapter }),
|
|
2923
2985
|
launchModes.length > 1 ? /* @__PURE__ */ jsxs9("fieldset", { className: "scui-launch-modes", disabled: Boolean(starting), children: [
|
|
2924
2986
|
/* @__PURE__ */ jsx10("legend", { children: "Run as" }),
|
|
@@ -2947,7 +3009,7 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2947
3009
|
return next;
|
|
2948
3010
|
}) }),
|
|
2949
3011
|
terminalAttachments ? /* @__PURE__ */ jsx10("small", { className: "scui-context-error", role: "alert", children: "Terminal starts currently accept text only. Remove attachments or choose Chat." }) : pickerError ? /* @__PURE__ */ jsx10("small", { className: "scui-context-error", role: "alert", children: pickerError }) : null,
|
|
2950
|
-
/* @__PURE__ */ jsxs9("div", { className: `scui-envelope${dragging ? " scui-drop-target" : ""}`, onDragEnter: (event) => {
|
|
3012
|
+
/* @__PURE__ */ jsxs9("div", { className: `scui-envelope scui-new-envelope${dragging ? " scui-drop-target" : ""}`, onDragEnter: (event) => {
|
|
2951
3013
|
if (Array.from(event.dataTransfer?.types ?? []).includes("Files")) {
|
|
2952
3014
|
event.preventDefault();
|
|
2953
3015
|
setDragging(true);
|
|
@@ -2957,7 +3019,6 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2957
3019
|
}, onDragLeave: (event) => {
|
|
2958
3020
|
if (!event.currentTarget.contains(event.relatedTarget)) setDragging(false);
|
|
2959
3021
|
}, onDrop: dropImages, children: [
|
|
2960
|
-
adapter.pickContext ? /* @__PURE__ */ jsx10("button", { className: "scui-attach", type: "button", "aria-label": "Attach files or images", disabled: mode === "terminal" || picking || context.length >= MAX_CONTEXT_ITEMS && images.length >= MAX_IMAGE_ITEMS || Boolean(starting), onClick: pickContext, children: picking ? /* @__PURE__ */ jsx10("i", { className: "scui-control-spinner" }) : /* @__PURE__ */ jsx10(UiIcon, { name: "attach", size: 17 }) }) : null,
|
|
2961
3022
|
/* @__PURE__ */ jsx10("textarea", { ref: textarea, rows: 3, "aria-label": "Message coding agent", placeholder: startable.length ? "What should the agent do?" : "No coding harness is available", value: draft, disabled: !startable.length || Boolean(starting), onPaste: pasteImages, onInput: (event) => {
|
|
2962
3023
|
const value = event.currentTarget.value;
|
|
2963
3024
|
setDraft(value);
|
|
@@ -2968,7 +3029,14 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2968
3029
|
send();
|
|
2969
3030
|
}
|
|
2970
3031
|
} }),
|
|
2971
|
-
/* @__PURE__ */
|
|
3032
|
+
/* @__PURE__ */ jsxs9("footer", { className: "scui-new-envelope-controls", children: [
|
|
3033
|
+
adapter.pickContext ? /* @__PURE__ */ jsx10("button", { className: "scui-attach", type: "button", "aria-label": "Attach files or images", disabled: mode === "terminal" || picking || context.length >= MAX_CONTEXT_ITEMS && images.length >= MAX_IMAGE_ITEMS || Boolean(starting), onClick: pickContext, children: picking ? /* @__PURE__ */ jsx10("i", { className: "scui-control-spinner" }) : /* @__PURE__ */ jsx10(UiIcon, { name: "attach", size: 17 }) }) : null,
|
|
3034
|
+
/* @__PURE__ */ jsx10(Picker, { harnesses: state.harnesses, value: harness, disabled: Boolean(starting), adapter, logo: components.HarnessLogo, onChange: (value) => {
|
|
3035
|
+
setHarness(value);
|
|
3036
|
+
remember({ harness: value });
|
|
3037
|
+
} }),
|
|
3038
|
+
/* @__PURE__ */ jsx10("span", { children: /* @__PURE__ */ jsx10("button", { type: "button", className: "scui-send", "aria-label": mode === "terminal" ? "Start terminal session" : "Start chat", disabled: !draft.trim() && !images.length || !harness || Boolean(starting) || terminalAttachments || mode === "terminal" && !draft.trim(), onClick: send, children: starting ? /* @__PURE__ */ jsx10("i", { className: "scui-control-spinner" }) : /* @__PURE__ */ jsx10(UiIcon, { name: "send", size: 17 }) }) })
|
|
3039
|
+
] })
|
|
2972
3040
|
] })
|
|
2973
3041
|
] })
|
|
2974
3042
|
] });
|
|
@@ -3078,6 +3146,7 @@ export {
|
|
|
3078
3146
|
Conversation,
|
|
3079
3147
|
HarnessAdvisory,
|
|
3080
3148
|
HarnessLogo,
|
|
3149
|
+
HarnessPicker,
|
|
3081
3150
|
HarnessReadiness,
|
|
3082
3151
|
HarnessSettingsPanel,
|
|
3083
3152
|
ImageViewer,
|
package/embed.mjs
CHANGED
|
@@ -2397,6 +2397,79 @@ function HarnessReadiness({ harnesses, adapter }) {
|
|
|
2397
2397
|
] }, item.id)) })
|
|
2398
2398
|
] });
|
|
2399
2399
|
}
|
|
2400
|
+
function HarnessPicker({ harnesses, value, disabled = false, adapter, onChange, logo: Logo = HarnessLogo }) {
|
|
2401
|
+
const [open, setOpen] = useState5(false);
|
|
2402
|
+
const menuId = useId2();
|
|
2403
|
+
const root = useRef6(null);
|
|
2404
|
+
const trigger = useRef6(null);
|
|
2405
|
+
const panel = useRef6(null);
|
|
2406
|
+
const available = harnesses.filter((item) => item.startable);
|
|
2407
|
+
const unavailable = harnesses.filter((item) => !item.startable);
|
|
2408
|
+
const selected = available.find((item) => item.id === value) ?? available[0] ?? null;
|
|
2409
|
+
const close = () => {
|
|
2410
|
+
setOpen(false);
|
|
2411
|
+
trigger.current?.focus({ preventScroll: true });
|
|
2412
|
+
};
|
|
2413
|
+
useEffect7(() => {
|
|
2414
|
+
if (!open) return;
|
|
2415
|
+
panel.current?.querySelector('[aria-selected="true"], [role="option"]')?.focus({ preventScroll: true });
|
|
2416
|
+
const dismiss = (event) => {
|
|
2417
|
+
if (event.type === "keydown" && event.key === "Escape") {
|
|
2418
|
+
event.preventDefault();
|
|
2419
|
+
close();
|
|
2420
|
+
} else if (event.type === "pointerdown" && !root.current?.contains(event.target)) {
|
|
2421
|
+
setOpen(false);
|
|
2422
|
+
}
|
|
2423
|
+
};
|
|
2424
|
+
document.addEventListener("keydown", dismiss);
|
|
2425
|
+
document.addEventListener("pointerdown", dismiss, true);
|
|
2426
|
+
return () => {
|
|
2427
|
+
document.removeEventListener("keydown", dismiss);
|
|
2428
|
+
document.removeEventListener("pointerdown", dismiss, true);
|
|
2429
|
+
};
|
|
2430
|
+
}, [open]);
|
|
2431
|
+
const navigate = (event) => {
|
|
2432
|
+
if (!["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) return;
|
|
2433
|
+
const items = [...panel.current.querySelectorAll('[role="option"]')];
|
|
2434
|
+
if (!items.length) return;
|
|
2435
|
+
event.preventDefault();
|
|
2436
|
+
const current = items.indexOf(document.activeElement);
|
|
2437
|
+
const index = event.key === "Home" ? 0 : event.key === "End" ? items.length - 1 : event.key === "ArrowDown" ? (current + 1) % items.length : (current <= 0 ? items.length : current) - 1;
|
|
2438
|
+
items[index].focus({ preventScroll: true });
|
|
2439
|
+
};
|
|
2440
|
+
const select = (id) => {
|
|
2441
|
+
onChange(id);
|
|
2442
|
+
close();
|
|
2443
|
+
};
|
|
2444
|
+
return /* @__PURE__ */ jsxs7("div", { className: "scui-harness-menu", ref: root, onBlur: (event) => {
|
|
2445
|
+
if (event.relatedTarget && !event.currentTarget.contains(event.relatedTarget)) setOpen(false);
|
|
2446
|
+
}, children: [
|
|
2447
|
+
/* @__PURE__ */ jsxs7("button", { ref: trigger, className: "scui-harness-trigger", type: "button", disabled: disabled || !selected, "aria-label": selected ? `Coding harness: ${selected.label}` : "No coding harness available", "aria-haspopup": "dialog", "aria-expanded": open, "aria-controls": open ? menuId : void 0, onClick: () => setOpen((current) => !current), children: [
|
|
2448
|
+
selected ? /* @__PURE__ */ jsx8(Logo, { id: selected.id, size: 20 }) : null,
|
|
2449
|
+
/* @__PURE__ */ jsx8("strong", { children: selected?.label ?? "No harness available" }),
|
|
2450
|
+
/* @__PURE__ */ jsx8(UiIcon, { name: "chevron", size: 13 })
|
|
2451
|
+
] }),
|
|
2452
|
+
open ? /* @__PURE__ */ jsxs7("div", { ref: panel, id: menuId, className: "scui-harness-popover", role: "dialog", "aria-label": "Choose coding harness", onKeyDown: navigate, children: [
|
|
2453
|
+
/* @__PURE__ */ jsx8("strong", { className: "scui-harness-popover-title", children: "Choose coding harness" }),
|
|
2454
|
+
/* @__PURE__ */ jsx8("div", { className: "scui-harness-options", role: "listbox", "aria-label": "Available coding harnesses", children: available.map((item) => /* @__PURE__ */ jsxs7("button", { type: "button", role: "option", "aria-selected": item.id === selected?.id, onClick: () => select(item.id), children: [
|
|
2455
|
+
/* @__PURE__ */ jsx8(Logo, { id: item.id, size: 24 }),
|
|
2456
|
+
/* @__PURE__ */ jsx8("strong", { children: item.label }),
|
|
2457
|
+
/* @__PURE__ */ jsx8("span", { children: item.id === selected?.id ? /* @__PURE__ */ jsx8(UiIcon, { name: "check", size: 15 }) : null })
|
|
2458
|
+
] }, item.id)) }),
|
|
2459
|
+
unavailable.length ? /* @__PURE__ */ jsxs7("details", { className: "scui-harness-manage", children: [
|
|
2460
|
+
/* @__PURE__ */ jsx8("summary", { children: "Manage additional harnesses" }),
|
|
2461
|
+
/* @__PURE__ */ jsx8("div", { children: unavailable.map((item) => /* @__PURE__ */ jsxs7("section", { children: [
|
|
2462
|
+
/* @__PURE__ */ jsx8(Logo, { id: item.id, size: 24 }),
|
|
2463
|
+
/* @__PURE__ */ jsxs7("span", { children: [
|
|
2464
|
+
/* @__PURE__ */ jsx8("strong", { children: item.label }),
|
|
2465
|
+
/* @__PURE__ */ jsx8("small", { children: item.reason || (item.auth === "required" ? "Authentication required" : "Unavailable") })
|
|
2466
|
+
] }),
|
|
2467
|
+
item.repair ? /* @__PURE__ */ jsx8("button", { type: "button", onClick: () => adapter?.copyText?.(item.repair), children: "Copy fix" }) : null
|
|
2468
|
+
] }, item.id)) })
|
|
2469
|
+
] }) : null
|
|
2470
|
+
] }) : null
|
|
2471
|
+
] });
|
|
2472
|
+
}
|
|
2400
2473
|
|
|
2401
2474
|
// src/messenger.jsx
|
|
2402
2475
|
import { jsx as jsx9, jsxs as jsxs8 } from "preact/jsx-runtime";
|
|
@@ -2690,6 +2763,7 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2690
2763
|
const startSequence = useRef7(0);
|
|
2691
2764
|
const textarea = useRef7(null);
|
|
2692
2765
|
const selectedHarness = startable.find((item) => item.id === harness) ?? null;
|
|
2766
|
+
const Picker = components.HarnessPicker ?? HarnessPicker;
|
|
2693
2767
|
const Readiness = components.HarnessReadiness ?? HarnessReadiness;
|
|
2694
2768
|
const launchModes = selectedHarness?.launchModes?.length ? selectedHarness.launchModes : ["headless"];
|
|
2695
2769
|
const rememberedMode = modes[harness];
|
|
@@ -2827,18 +2901,6 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2827
2901
|
/* @__PURE__ */ jsx9("small", { children: "Choose a coding harness and send the first message." })
|
|
2828
2902
|
] }),
|
|
2829
2903
|
/* @__PURE__ */ jsxs8("div", { className: "scui-compose", children: [
|
|
2830
|
-
/* @__PURE__ */ jsxs8("label", { className: "scui-harness-picker", children: [
|
|
2831
|
-
/* @__PURE__ */ jsx9(HarnessLogo, { id: harness, size: 24 }),
|
|
2832
|
-
/* @__PURE__ */ jsx9("span", { children: "Coding harness" }),
|
|
2833
|
-
/* @__PURE__ */ jsx9("select", { value: harness, disabled: Boolean(starting), onChange: (event) => {
|
|
2834
|
-
const value = event.currentTarget.value;
|
|
2835
|
-
setHarness(value);
|
|
2836
|
-
remember({ harness: value });
|
|
2837
|
-
}, children: state.harnesses.map((item) => /* @__PURE__ */ jsxs8("option", { value: item.id, disabled: !item.startable, children: [
|
|
2838
|
-
item.label,
|
|
2839
|
-
item.startable ? "" : " \xB7 unavailable"
|
|
2840
|
-
] }, item.id)) })
|
|
2841
|
-
] }),
|
|
2842
2904
|
/* @__PURE__ */ jsx9(Readiness, { harnesses: state.harnesses, state, adapter }),
|
|
2843
2905
|
launchModes.length > 1 ? /* @__PURE__ */ jsxs8("fieldset", { className: "scui-launch-modes", disabled: Boolean(starting), children: [
|
|
2844
2906
|
/* @__PURE__ */ jsx9("legend", { children: "Run as" }),
|
|
@@ -2867,7 +2929,7 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2867
2929
|
return next;
|
|
2868
2930
|
}) }),
|
|
2869
2931
|
terminalAttachments ? /* @__PURE__ */ jsx9("small", { className: "scui-context-error", role: "alert", children: "Terminal starts currently accept text only. Remove attachments or choose Chat." }) : pickerError ? /* @__PURE__ */ jsx9("small", { className: "scui-context-error", role: "alert", children: pickerError }) : null,
|
|
2870
|
-
/* @__PURE__ */ jsxs8("div", { className: `scui-envelope${dragging ? " scui-drop-target" : ""}`, onDragEnter: (event) => {
|
|
2932
|
+
/* @__PURE__ */ jsxs8("div", { className: `scui-envelope scui-new-envelope${dragging ? " scui-drop-target" : ""}`, onDragEnter: (event) => {
|
|
2871
2933
|
if (Array.from(event.dataTransfer?.types ?? []).includes("Files")) {
|
|
2872
2934
|
event.preventDefault();
|
|
2873
2935
|
setDragging(true);
|
|
@@ -2877,7 +2939,6 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2877
2939
|
}, onDragLeave: (event) => {
|
|
2878
2940
|
if (!event.currentTarget.contains(event.relatedTarget)) setDragging(false);
|
|
2879
2941
|
}, onDrop: dropImages, children: [
|
|
2880
|
-
adapter.pickContext ? /* @__PURE__ */ jsx9("button", { className: "scui-attach", type: "button", "aria-label": "Attach files or images", disabled: mode === "terminal" || picking || context.length >= MAX_CONTEXT_ITEMS && images.length >= MAX_IMAGE_ITEMS || Boolean(starting), onClick: pickContext, children: picking ? /* @__PURE__ */ jsx9("i", { className: "scui-control-spinner" }) : /* @__PURE__ */ jsx9(UiIcon, { name: "attach", size: 17 }) }) : null,
|
|
2881
2942
|
/* @__PURE__ */ jsx9("textarea", { ref: textarea, rows: 3, "aria-label": "Message coding agent", placeholder: startable.length ? "What should the agent do?" : "No coding harness is available", value: draft, disabled: !startable.length || Boolean(starting), onPaste: pasteImages, onInput: (event) => {
|
|
2882
2943
|
const value = event.currentTarget.value;
|
|
2883
2944
|
setDraft(value);
|
|
@@ -2888,7 +2949,14 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2888
2949
|
send();
|
|
2889
2950
|
}
|
|
2890
2951
|
} }),
|
|
2891
|
-
/* @__PURE__ */
|
|
2952
|
+
/* @__PURE__ */ jsxs8("footer", { className: "scui-new-envelope-controls", children: [
|
|
2953
|
+
adapter.pickContext ? /* @__PURE__ */ jsx9("button", { className: "scui-attach", type: "button", "aria-label": "Attach files or images", disabled: mode === "terminal" || picking || context.length >= MAX_CONTEXT_ITEMS && images.length >= MAX_IMAGE_ITEMS || Boolean(starting), onClick: pickContext, children: picking ? /* @__PURE__ */ jsx9("i", { className: "scui-control-spinner" }) : /* @__PURE__ */ jsx9(UiIcon, { name: "attach", size: 17 }) }) : null,
|
|
2954
|
+
/* @__PURE__ */ jsx9(Picker, { harnesses: state.harnesses, value: harness, disabled: Boolean(starting), adapter, logo: components.HarnessLogo, onChange: (value) => {
|
|
2955
|
+
setHarness(value);
|
|
2956
|
+
remember({ harness: value });
|
|
2957
|
+
} }),
|
|
2958
|
+
/* @__PURE__ */ jsx9("span", { children: /* @__PURE__ */ jsx9("button", { type: "button", className: "scui-send", "aria-label": mode === "terminal" ? "Start terminal session" : "Start chat", disabled: !draft.trim() && !images.length || !harness || Boolean(starting) || terminalAttachments || mode === "terminal" && !draft.trim(), onClick: send, children: starting ? /* @__PURE__ */ jsx9("i", { className: "scui-control-spinner" }) : /* @__PURE__ */ jsx9(UiIcon, { name: "send", size: 17 }) }) })
|
|
2959
|
+
] })
|
|
2892
2960
|
] })
|
|
2893
2961
|
] })
|
|
2894
2962
|
] });
|
package/index.d.ts
CHANGED
|
@@ -433,6 +433,15 @@ export interface HarnessSettingsPanelProps {
|
|
|
433
433
|
onClose(): void;
|
|
434
434
|
}
|
|
435
435
|
|
|
436
|
+
export interface HarnessPickerProps {
|
|
437
|
+
harnesses: HarnessOption[];
|
|
438
|
+
value: HarnessId;
|
|
439
|
+
disabled?: boolean;
|
|
440
|
+
adapter?: Pick<UiAdapter, 'copyText'>;
|
|
441
|
+
onChange(harness: HarnessId): void;
|
|
442
|
+
logo?: ComponentType<{ id: HarnessId; activity?: SessionActivity; size?: number }>;
|
|
443
|
+
}
|
|
444
|
+
|
|
436
445
|
export interface MessengerComponents {
|
|
437
446
|
SessionRow?: ComponentType<SessionRowProps>;
|
|
438
447
|
TranscriptEntry?: ComponentType<TranscriptEntryProps>;
|
|
@@ -441,6 +450,7 @@ export interface MessengerComponents {
|
|
|
441
450
|
HarnessLogo?: ComponentType<{ id: HarnessId; activity?: SessionActivity; size?: number }>;
|
|
442
451
|
HarnessAdvisory?: ComponentType<HarnessAdvisoryProps>;
|
|
443
452
|
HarnessSettingsPanel?: ComponentType<HarnessSettingsPanelProps>;
|
|
453
|
+
HarnessPicker?: ComponentType<HarnessPickerProps>;
|
|
444
454
|
ContextCandidate?: ComponentType<ContextCandidateProps>;
|
|
445
455
|
HarnessReadiness?: ComponentType<{ harnesses: HarnessOption[]; state: SupercodeUiState; adapter: UiAdapter }>;
|
|
446
456
|
}
|
|
@@ -532,6 +542,7 @@ export function ToolRow(props: ToolRowProps): VNode;
|
|
|
532
542
|
export function TaskPlan(props: { plan: TaskPlanModel }): VNode | null;
|
|
533
543
|
export function HarnessAdvisory(props: HarnessAdvisoryProps): VNode | null;
|
|
534
544
|
export function HarnessSettingsPanel(props: HarnessSettingsPanelProps): VNode;
|
|
545
|
+
export function HarnessPicker(props: HarnessPickerProps): VNode;
|
|
535
546
|
export function HarnessReadiness(props: { harnesses: HarnessOption[]; state: SupercodeUiState; adapter: UiAdapter }): VNode | null;
|
|
536
547
|
export function SessionDetails(props: { semantics: SessionSemanticsModel }): VNode | null;
|
|
537
548
|
export function Conversation(props: { state: SupercodeUiState; adapter: UiAdapter; components?: MessengerComponents; slots?: MessengerSlots; memoryKey?: string; pending?: string | PendingMessageModel | null; unreadAfterMessages?: number | null }): VNode;
|
package/messenger.mjs
CHANGED
|
@@ -2394,6 +2394,79 @@ function HarnessReadiness({ harnesses, adapter }) {
|
|
|
2394
2394
|
] }, item.id)) })
|
|
2395
2395
|
] });
|
|
2396
2396
|
}
|
|
2397
|
+
function HarnessPicker({ harnesses, value, disabled = false, adapter, onChange, logo: Logo = HarnessLogo }) {
|
|
2398
|
+
const [open, setOpen] = useState5(false);
|
|
2399
|
+
const menuId = useId2();
|
|
2400
|
+
const root = useRef6(null);
|
|
2401
|
+
const trigger = useRef6(null);
|
|
2402
|
+
const panel = useRef6(null);
|
|
2403
|
+
const available = harnesses.filter((item) => item.startable);
|
|
2404
|
+
const unavailable = harnesses.filter((item) => !item.startable);
|
|
2405
|
+
const selected = available.find((item) => item.id === value) ?? available[0] ?? null;
|
|
2406
|
+
const close = () => {
|
|
2407
|
+
setOpen(false);
|
|
2408
|
+
trigger.current?.focus({ preventScroll: true });
|
|
2409
|
+
};
|
|
2410
|
+
useEffect7(() => {
|
|
2411
|
+
if (!open) return;
|
|
2412
|
+
panel.current?.querySelector('[aria-selected="true"], [role="option"]')?.focus({ preventScroll: true });
|
|
2413
|
+
const dismiss = (event) => {
|
|
2414
|
+
if (event.type === "keydown" && event.key === "Escape") {
|
|
2415
|
+
event.preventDefault();
|
|
2416
|
+
close();
|
|
2417
|
+
} else if (event.type === "pointerdown" && !root.current?.contains(event.target)) {
|
|
2418
|
+
setOpen(false);
|
|
2419
|
+
}
|
|
2420
|
+
};
|
|
2421
|
+
document.addEventListener("keydown", dismiss);
|
|
2422
|
+
document.addEventListener("pointerdown", dismiss, true);
|
|
2423
|
+
return () => {
|
|
2424
|
+
document.removeEventListener("keydown", dismiss);
|
|
2425
|
+
document.removeEventListener("pointerdown", dismiss, true);
|
|
2426
|
+
};
|
|
2427
|
+
}, [open]);
|
|
2428
|
+
const navigate = (event) => {
|
|
2429
|
+
if (!["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) return;
|
|
2430
|
+
const items = [...panel.current.querySelectorAll('[role="option"]')];
|
|
2431
|
+
if (!items.length) return;
|
|
2432
|
+
event.preventDefault();
|
|
2433
|
+
const current = items.indexOf(document.activeElement);
|
|
2434
|
+
const index = event.key === "Home" ? 0 : event.key === "End" ? items.length - 1 : event.key === "ArrowDown" ? (current + 1) % items.length : (current <= 0 ? items.length : current) - 1;
|
|
2435
|
+
items[index].focus({ preventScroll: true });
|
|
2436
|
+
};
|
|
2437
|
+
const select = (id) => {
|
|
2438
|
+
onChange(id);
|
|
2439
|
+
close();
|
|
2440
|
+
};
|
|
2441
|
+
return /* @__PURE__ */ jsxs7("div", { className: "scui-harness-menu", ref: root, onBlur: (event) => {
|
|
2442
|
+
if (event.relatedTarget && !event.currentTarget.contains(event.relatedTarget)) setOpen(false);
|
|
2443
|
+
}, children: [
|
|
2444
|
+
/* @__PURE__ */ jsxs7("button", { ref: trigger, className: "scui-harness-trigger", type: "button", disabled: disabled || !selected, "aria-label": selected ? `Coding harness: ${selected.label}` : "No coding harness available", "aria-haspopup": "dialog", "aria-expanded": open, "aria-controls": open ? menuId : void 0, onClick: () => setOpen((current) => !current), children: [
|
|
2445
|
+
selected ? /* @__PURE__ */ jsx8(Logo, { id: selected.id, size: 20 }) : null,
|
|
2446
|
+
/* @__PURE__ */ jsx8("strong", { children: selected?.label ?? "No harness available" }),
|
|
2447
|
+
/* @__PURE__ */ jsx8(UiIcon, { name: "chevron", size: 13 })
|
|
2448
|
+
] }),
|
|
2449
|
+
open ? /* @__PURE__ */ jsxs7("div", { ref: panel, id: menuId, className: "scui-harness-popover", role: "dialog", "aria-label": "Choose coding harness", onKeyDown: navigate, children: [
|
|
2450
|
+
/* @__PURE__ */ jsx8("strong", { className: "scui-harness-popover-title", children: "Choose coding harness" }),
|
|
2451
|
+
/* @__PURE__ */ jsx8("div", { className: "scui-harness-options", role: "listbox", "aria-label": "Available coding harnesses", children: available.map((item) => /* @__PURE__ */ jsxs7("button", { type: "button", role: "option", "aria-selected": item.id === selected?.id, onClick: () => select(item.id), children: [
|
|
2452
|
+
/* @__PURE__ */ jsx8(Logo, { id: item.id, size: 24 }),
|
|
2453
|
+
/* @__PURE__ */ jsx8("strong", { children: item.label }),
|
|
2454
|
+
/* @__PURE__ */ jsx8("span", { children: item.id === selected?.id ? /* @__PURE__ */ jsx8(UiIcon, { name: "check", size: 15 }) : null })
|
|
2455
|
+
] }, item.id)) }),
|
|
2456
|
+
unavailable.length ? /* @__PURE__ */ jsxs7("details", { className: "scui-harness-manage", children: [
|
|
2457
|
+
/* @__PURE__ */ jsx8("summary", { children: "Manage additional harnesses" }),
|
|
2458
|
+
/* @__PURE__ */ jsx8("div", { children: unavailable.map((item) => /* @__PURE__ */ jsxs7("section", { children: [
|
|
2459
|
+
/* @__PURE__ */ jsx8(Logo, { id: item.id, size: 24 }),
|
|
2460
|
+
/* @__PURE__ */ jsxs7("span", { children: [
|
|
2461
|
+
/* @__PURE__ */ jsx8("strong", { children: item.label }),
|
|
2462
|
+
/* @__PURE__ */ jsx8("small", { children: item.reason || (item.auth === "required" ? "Authentication required" : "Unavailable") })
|
|
2463
|
+
] }),
|
|
2464
|
+
item.repair ? /* @__PURE__ */ jsx8("button", { type: "button", onClick: () => adapter?.copyText?.(item.repair), children: "Copy fix" }) : null
|
|
2465
|
+
] }, item.id)) })
|
|
2466
|
+
] }) : null
|
|
2467
|
+
] }) : null
|
|
2468
|
+
] });
|
|
2469
|
+
}
|
|
2397
2470
|
|
|
2398
2471
|
// src/messenger.jsx
|
|
2399
2472
|
import { jsx as jsx9, jsxs as jsxs8 } from "preact/jsx-runtime";
|
|
@@ -2687,6 +2760,7 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2687
2760
|
const startSequence = useRef7(0);
|
|
2688
2761
|
const textarea = useRef7(null);
|
|
2689
2762
|
const selectedHarness = startable.find((item) => item.id === harness) ?? null;
|
|
2763
|
+
const Picker = components.HarnessPicker ?? HarnessPicker;
|
|
2690
2764
|
const Readiness = components.HarnessReadiness ?? HarnessReadiness;
|
|
2691
2765
|
const launchModes = selectedHarness?.launchModes?.length ? selectedHarness.launchModes : ["headless"];
|
|
2692
2766
|
const rememberedMode = modes[harness];
|
|
@@ -2824,18 +2898,6 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2824
2898
|
/* @__PURE__ */ jsx9("small", { children: "Choose a coding harness and send the first message." })
|
|
2825
2899
|
] }),
|
|
2826
2900
|
/* @__PURE__ */ jsxs8("div", { className: "scui-compose", children: [
|
|
2827
|
-
/* @__PURE__ */ jsxs8("label", { className: "scui-harness-picker", children: [
|
|
2828
|
-
/* @__PURE__ */ jsx9(HarnessLogo, { id: harness, size: 24 }),
|
|
2829
|
-
/* @__PURE__ */ jsx9("span", { children: "Coding harness" }),
|
|
2830
|
-
/* @__PURE__ */ jsx9("select", { value: harness, disabled: Boolean(starting), onChange: (event) => {
|
|
2831
|
-
const value = event.currentTarget.value;
|
|
2832
|
-
setHarness(value);
|
|
2833
|
-
remember({ harness: value });
|
|
2834
|
-
}, children: state.harnesses.map((item) => /* @__PURE__ */ jsxs8("option", { value: item.id, disabled: !item.startable, children: [
|
|
2835
|
-
item.label,
|
|
2836
|
-
item.startable ? "" : " \xB7 unavailable"
|
|
2837
|
-
] }, item.id)) })
|
|
2838
|
-
] }),
|
|
2839
2901
|
/* @__PURE__ */ jsx9(Readiness, { harnesses: state.harnesses, state, adapter }),
|
|
2840
2902
|
launchModes.length > 1 ? /* @__PURE__ */ jsxs8("fieldset", { className: "scui-launch-modes", disabled: Boolean(starting), children: [
|
|
2841
2903
|
/* @__PURE__ */ jsx9("legend", { children: "Run as" }),
|
|
@@ -2864,7 +2926,7 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2864
2926
|
return next;
|
|
2865
2927
|
}) }),
|
|
2866
2928
|
terminalAttachments ? /* @__PURE__ */ jsx9("small", { className: "scui-context-error", role: "alert", children: "Terminal starts currently accept text only. Remove attachments or choose Chat." }) : pickerError ? /* @__PURE__ */ jsx9("small", { className: "scui-context-error", role: "alert", children: pickerError }) : null,
|
|
2867
|
-
/* @__PURE__ */ jsxs8("div", { className: `scui-envelope${dragging ? " scui-drop-target" : ""}`, onDragEnter: (event) => {
|
|
2929
|
+
/* @__PURE__ */ jsxs8("div", { className: `scui-envelope scui-new-envelope${dragging ? " scui-drop-target" : ""}`, onDragEnter: (event) => {
|
|
2868
2930
|
if (Array.from(event.dataTransfer?.types ?? []).includes("Files")) {
|
|
2869
2931
|
event.preventDefault();
|
|
2870
2932
|
setDragging(true);
|
|
@@ -2874,7 +2936,6 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2874
2936
|
}, onDragLeave: (event) => {
|
|
2875
2937
|
if (!event.currentTarget.contains(event.relatedTarget)) setDragging(false);
|
|
2876
2938
|
}, onDrop: dropImages, children: [
|
|
2877
|
-
adapter.pickContext ? /* @__PURE__ */ jsx9("button", { className: "scui-attach", type: "button", "aria-label": "Attach files or images", disabled: mode === "terminal" || picking || context.length >= MAX_CONTEXT_ITEMS && images.length >= MAX_IMAGE_ITEMS || Boolean(starting), onClick: pickContext, children: picking ? /* @__PURE__ */ jsx9("i", { className: "scui-control-spinner" }) : /* @__PURE__ */ jsx9(UiIcon, { name: "attach", size: 17 }) }) : null,
|
|
2878
2939
|
/* @__PURE__ */ jsx9("textarea", { ref: textarea, rows: 3, "aria-label": "Message coding agent", placeholder: startable.length ? "What should the agent do?" : "No coding harness is available", value: draft, disabled: !startable.length || Boolean(starting), onPaste: pasteImages, onInput: (event) => {
|
|
2879
2940
|
const value = event.currentTarget.value;
|
|
2880
2941
|
setDraft(value);
|
|
@@ -2885,7 +2946,14 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2885
2946
|
send();
|
|
2886
2947
|
}
|
|
2887
2948
|
} }),
|
|
2888
|
-
/* @__PURE__ */
|
|
2949
|
+
/* @__PURE__ */ jsxs8("footer", { className: "scui-new-envelope-controls", children: [
|
|
2950
|
+
adapter.pickContext ? /* @__PURE__ */ jsx9("button", { className: "scui-attach", type: "button", "aria-label": "Attach files or images", disabled: mode === "terminal" || picking || context.length >= MAX_CONTEXT_ITEMS && images.length >= MAX_IMAGE_ITEMS || Boolean(starting), onClick: pickContext, children: picking ? /* @__PURE__ */ jsx9("i", { className: "scui-control-spinner" }) : /* @__PURE__ */ jsx9(UiIcon, { name: "attach", size: 17 }) }) : null,
|
|
2951
|
+
/* @__PURE__ */ jsx9(Picker, { harnesses: state.harnesses, value: harness, disabled: Boolean(starting), adapter, logo: components.HarnessLogo, onChange: (value) => {
|
|
2952
|
+
setHarness(value);
|
|
2953
|
+
remember({ harness: value });
|
|
2954
|
+
} }),
|
|
2955
|
+
/* @__PURE__ */ jsx9("span", { children: /* @__PURE__ */ jsx9("button", { type: "button", className: "scui-send", "aria-label": mode === "terminal" ? "Start terminal session" : "Start chat", disabled: !draft.trim() && !images.length || !harness || Boolean(starting) || terminalAttachments || mode === "terminal" && !draft.trim(), onClick: send, children: starting ? /* @__PURE__ */ jsx9("i", { className: "scui-control-spinner" }) : /* @__PURE__ */ jsx9(UiIcon, { name: "send", size: 17 }) }) })
|
|
2956
|
+
] })
|
|
2889
2957
|
] })
|
|
2890
2958
|
] })
|
|
2891
2959
|
] });
|
package/package.json
CHANGED
package/react/components.mjs
CHANGED
|
@@ -2477,6 +2477,79 @@ function HarnessReadiness({ harnesses, adapter }) {
|
|
|
2477
2477
|
] }, item.id)) })
|
|
2478
2478
|
] });
|
|
2479
2479
|
}
|
|
2480
|
+
function HarnessPicker({ harnesses, value, disabled = false, adapter, onChange, logo: Logo = HarnessLogo }) {
|
|
2481
|
+
const [open, setOpen] = useState5(false);
|
|
2482
|
+
const menuId = useId2();
|
|
2483
|
+
const root = useRef6(null);
|
|
2484
|
+
const trigger = useRef6(null);
|
|
2485
|
+
const panel = useRef6(null);
|
|
2486
|
+
const available = harnesses.filter((item) => item.startable);
|
|
2487
|
+
const unavailable = harnesses.filter((item) => !item.startable);
|
|
2488
|
+
const selected = available.find((item) => item.id === value) ?? available[0] ?? null;
|
|
2489
|
+
const close = () => {
|
|
2490
|
+
setOpen(false);
|
|
2491
|
+
trigger.current?.focus({ preventScroll: true });
|
|
2492
|
+
};
|
|
2493
|
+
useEffect7(() => {
|
|
2494
|
+
if (!open) return;
|
|
2495
|
+
panel.current?.querySelector('[aria-selected="true"], [role="option"]')?.focus({ preventScroll: true });
|
|
2496
|
+
const dismiss = (event) => {
|
|
2497
|
+
if (event.type === "keydown" && event.key === "Escape") {
|
|
2498
|
+
event.preventDefault();
|
|
2499
|
+
close();
|
|
2500
|
+
} else if (event.type === "pointerdown" && !root.current?.contains(event.target)) {
|
|
2501
|
+
setOpen(false);
|
|
2502
|
+
}
|
|
2503
|
+
};
|
|
2504
|
+
document.addEventListener("keydown", dismiss);
|
|
2505
|
+
document.addEventListener("pointerdown", dismiss, true);
|
|
2506
|
+
return () => {
|
|
2507
|
+
document.removeEventListener("keydown", dismiss);
|
|
2508
|
+
document.removeEventListener("pointerdown", dismiss, true);
|
|
2509
|
+
};
|
|
2510
|
+
}, [open]);
|
|
2511
|
+
const navigate = (event) => {
|
|
2512
|
+
if (!["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) return;
|
|
2513
|
+
const items = [...panel.current.querySelectorAll('[role="option"]')];
|
|
2514
|
+
if (!items.length) return;
|
|
2515
|
+
event.preventDefault();
|
|
2516
|
+
const current = items.indexOf(document.activeElement);
|
|
2517
|
+
const index = event.key === "Home" ? 0 : event.key === "End" ? items.length - 1 : event.key === "ArrowDown" ? (current + 1) % items.length : (current <= 0 ? items.length : current) - 1;
|
|
2518
|
+
items[index].focus({ preventScroll: true });
|
|
2519
|
+
};
|
|
2520
|
+
const select = (id) => {
|
|
2521
|
+
onChange(id);
|
|
2522
|
+
close();
|
|
2523
|
+
};
|
|
2524
|
+
return /* @__PURE__ */ jsxs8("div", { className: "scui-harness-menu", ref: root, onBlur: (event) => {
|
|
2525
|
+
if (event.relatedTarget && !event.currentTarget.contains(event.relatedTarget)) setOpen(false);
|
|
2526
|
+
}, children: [
|
|
2527
|
+
/* @__PURE__ */ jsxs8("button", { ref: trigger, className: "scui-harness-trigger", type: "button", disabled: disabled || !selected, "aria-label": selected ? `Coding harness: ${selected.label}` : "No coding harness available", "aria-haspopup": "dialog", "aria-expanded": open, "aria-controls": open ? menuId : void 0, onClick: () => setOpen((current) => !current), children: [
|
|
2528
|
+
selected ? /* @__PURE__ */ jsx9(Logo, { id: selected.id, size: 20 }) : null,
|
|
2529
|
+
/* @__PURE__ */ jsx9("strong", { children: selected?.label ?? "No harness available" }),
|
|
2530
|
+
/* @__PURE__ */ jsx9(UiIcon, { name: "chevron", size: 13 })
|
|
2531
|
+
] }),
|
|
2532
|
+
open ? /* @__PURE__ */ jsxs8("div", { ref: panel, id: menuId, className: "scui-harness-popover", role: "dialog", "aria-label": "Choose coding harness", onKeyDown: navigate, children: [
|
|
2533
|
+
/* @__PURE__ */ jsx9("strong", { className: "scui-harness-popover-title", children: "Choose coding harness" }),
|
|
2534
|
+
/* @__PURE__ */ jsx9("div", { className: "scui-harness-options", role: "listbox", "aria-label": "Available coding harnesses", children: available.map((item) => /* @__PURE__ */ jsxs8("button", { type: "button", role: "option", "aria-selected": item.id === selected?.id, onClick: () => select(item.id), children: [
|
|
2535
|
+
/* @__PURE__ */ jsx9(Logo, { id: item.id, size: 24 }),
|
|
2536
|
+
/* @__PURE__ */ jsx9("strong", { children: item.label }),
|
|
2537
|
+
/* @__PURE__ */ jsx9("span", { children: item.id === selected?.id ? /* @__PURE__ */ jsx9(UiIcon, { name: "check", size: 15 }) : null })
|
|
2538
|
+
] }, item.id)) }),
|
|
2539
|
+
unavailable.length ? /* @__PURE__ */ jsxs8("details", { className: "scui-harness-manage", children: [
|
|
2540
|
+
/* @__PURE__ */ jsx9("summary", { children: "Manage additional harnesses" }),
|
|
2541
|
+
/* @__PURE__ */ jsx9("div", { children: unavailable.map((item) => /* @__PURE__ */ jsxs8("section", { children: [
|
|
2542
|
+
/* @__PURE__ */ jsx9(Logo, { id: item.id, size: 24 }),
|
|
2543
|
+
/* @__PURE__ */ jsxs8("span", { children: [
|
|
2544
|
+
/* @__PURE__ */ jsx9("strong", { children: item.label }),
|
|
2545
|
+
/* @__PURE__ */ jsx9("small", { children: item.reason || (item.auth === "required" ? "Authentication required" : "Unavailable") })
|
|
2546
|
+
] }),
|
|
2547
|
+
item.repair ? /* @__PURE__ */ jsx9("button", { type: "button", onClick: () => adapter?.copyText?.(item.repair), children: "Copy fix" }) : null
|
|
2548
|
+
] }, item.id)) })
|
|
2549
|
+
] }) : null
|
|
2550
|
+
] }) : null
|
|
2551
|
+
] });
|
|
2552
|
+
}
|
|
2480
2553
|
|
|
2481
2554
|
// src/messenger.jsx
|
|
2482
2555
|
import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
@@ -2770,6 +2843,7 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2770
2843
|
const startSequence = useRef7(0);
|
|
2771
2844
|
const textarea = useRef7(null);
|
|
2772
2845
|
const selectedHarness = startable.find((item) => item.id === harness) ?? null;
|
|
2846
|
+
const Picker = components.HarnessPicker ?? HarnessPicker;
|
|
2773
2847
|
const Readiness = components.HarnessReadiness ?? HarnessReadiness;
|
|
2774
2848
|
const launchModes = selectedHarness?.launchModes?.length ? selectedHarness.launchModes : ["headless"];
|
|
2775
2849
|
const rememberedMode = modes[harness];
|
|
@@ -2907,18 +2981,6 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2907
2981
|
/* @__PURE__ */ jsx10("small", { children: "Choose a coding harness and send the first message." })
|
|
2908
2982
|
] }),
|
|
2909
2983
|
/* @__PURE__ */ jsxs9("div", { className: "scui-compose", children: [
|
|
2910
|
-
/* @__PURE__ */ jsxs9("label", { className: "scui-harness-picker", children: [
|
|
2911
|
-
/* @__PURE__ */ jsx10(HarnessLogo, { id: harness, size: 24 }),
|
|
2912
|
-
/* @__PURE__ */ jsx10("span", { children: "Coding harness" }),
|
|
2913
|
-
/* @__PURE__ */ jsx10("select", { value: harness, disabled: Boolean(starting), onChange: (event) => {
|
|
2914
|
-
const value = event.currentTarget.value;
|
|
2915
|
-
setHarness(value);
|
|
2916
|
-
remember({ harness: value });
|
|
2917
|
-
}, children: state.harnesses.map((item) => /* @__PURE__ */ jsxs9("option", { value: item.id, disabled: !item.startable, children: [
|
|
2918
|
-
item.label,
|
|
2919
|
-
item.startable ? "" : " \xB7 unavailable"
|
|
2920
|
-
] }, item.id)) })
|
|
2921
|
-
] }),
|
|
2922
2984
|
/* @__PURE__ */ jsx10(Readiness, { harnesses: state.harnesses, state, adapter }),
|
|
2923
2985
|
launchModes.length > 1 ? /* @__PURE__ */ jsxs9("fieldset", { className: "scui-launch-modes", disabled: Boolean(starting), children: [
|
|
2924
2986
|
/* @__PURE__ */ jsx10("legend", { children: "Run as" }),
|
|
@@ -2947,7 +3009,7 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2947
3009
|
return next;
|
|
2948
3010
|
}) }),
|
|
2949
3011
|
terminalAttachments ? /* @__PURE__ */ jsx10("small", { className: "scui-context-error", role: "alert", children: "Terminal starts currently accept text only. Remove attachments or choose Chat." }) : pickerError ? /* @__PURE__ */ jsx10("small", { className: "scui-context-error", role: "alert", children: pickerError }) : null,
|
|
2950
|
-
/* @__PURE__ */ jsxs9("div", { className: `scui-envelope${dragging ? " scui-drop-target" : ""}`, onDragEnter: (event) => {
|
|
3012
|
+
/* @__PURE__ */ jsxs9("div", { className: `scui-envelope scui-new-envelope${dragging ? " scui-drop-target" : ""}`, onDragEnter: (event) => {
|
|
2951
3013
|
if (Array.from(event.dataTransfer?.types ?? []).includes("Files")) {
|
|
2952
3014
|
event.preventDefault();
|
|
2953
3015
|
setDragging(true);
|
|
@@ -2957,7 +3019,6 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2957
3019
|
}, onDragLeave: (event) => {
|
|
2958
3020
|
if (!event.currentTarget.contains(event.relatedTarget)) setDragging(false);
|
|
2959
3021
|
}, onDrop: dropImages, children: [
|
|
2960
|
-
adapter.pickContext ? /* @__PURE__ */ jsx10("button", { className: "scui-attach", type: "button", "aria-label": "Attach files or images", disabled: mode === "terminal" || picking || context.length >= MAX_CONTEXT_ITEMS && images.length >= MAX_IMAGE_ITEMS || Boolean(starting), onClick: pickContext, children: picking ? /* @__PURE__ */ jsx10("i", { className: "scui-control-spinner" }) : /* @__PURE__ */ jsx10(UiIcon, { name: "attach", size: 17 }) }) : null,
|
|
2961
3022
|
/* @__PURE__ */ jsx10("textarea", { ref: textarea, rows: 3, "aria-label": "Message coding agent", placeholder: startable.length ? "What should the agent do?" : "No coding harness is available", value: draft, disabled: !startable.length || Boolean(starting), onPaste: pasteImages, onInput: (event) => {
|
|
2962
3023
|
const value = event.currentTarget.value;
|
|
2963
3024
|
setDraft(value);
|
|
@@ -2968,7 +3029,14 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2968
3029
|
send();
|
|
2969
3030
|
}
|
|
2970
3031
|
} }),
|
|
2971
|
-
/* @__PURE__ */
|
|
3032
|
+
/* @__PURE__ */ jsxs9("footer", { className: "scui-new-envelope-controls", children: [
|
|
3033
|
+
adapter.pickContext ? /* @__PURE__ */ jsx10("button", { className: "scui-attach", type: "button", "aria-label": "Attach files or images", disabled: mode === "terminal" || picking || context.length >= MAX_CONTEXT_ITEMS && images.length >= MAX_IMAGE_ITEMS || Boolean(starting), onClick: pickContext, children: picking ? /* @__PURE__ */ jsx10("i", { className: "scui-control-spinner" }) : /* @__PURE__ */ jsx10(UiIcon, { name: "attach", size: 17 }) }) : null,
|
|
3034
|
+
/* @__PURE__ */ jsx10(Picker, { harnesses: state.harnesses, value: harness, disabled: Boolean(starting), adapter, logo: components.HarnessLogo, onChange: (value) => {
|
|
3035
|
+
setHarness(value);
|
|
3036
|
+
remember({ harness: value });
|
|
3037
|
+
} }),
|
|
3038
|
+
/* @__PURE__ */ jsx10("span", { children: /* @__PURE__ */ jsx10("button", { type: "button", className: "scui-send", "aria-label": mode === "terminal" ? "Start terminal session" : "Start chat", disabled: !draft.trim() && !images.length || !harness || Boolean(starting) || terminalAttachments || mode === "terminal" && !draft.trim(), onClick: send, children: starting ? /* @__PURE__ */ jsx10("i", { className: "scui-control-spinner" }) : /* @__PURE__ */ jsx10(UiIcon, { name: "send", size: 17 }) }) })
|
|
3039
|
+
] })
|
|
2972
3040
|
] })
|
|
2973
3041
|
] })
|
|
2974
3042
|
] });
|
|
@@ -3078,6 +3146,7 @@ export {
|
|
|
3078
3146
|
Conversation,
|
|
3079
3147
|
HarnessAdvisory,
|
|
3080
3148
|
HarnessLogo,
|
|
3149
|
+
HarnessPicker,
|
|
3081
3150
|
HarnessReadiness,
|
|
3082
3151
|
HarnessSettingsPanel,
|
|
3083
3152
|
ImageViewer,
|
package/react/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
ContextCandidateProps,
|
|
8
8
|
HarnessAdvisoryProps,
|
|
9
9
|
HarnessId,
|
|
10
|
+
HarnessPickerProps,
|
|
10
11
|
HarnessSettingsPanelProps,
|
|
11
12
|
HarnessOption,
|
|
12
13
|
MessengerLabels,
|
|
@@ -36,6 +37,7 @@ export type {
|
|
|
36
37
|
ContextCandidateProps,
|
|
37
38
|
HarnessAdvisoryProps,
|
|
38
39
|
HarnessId,
|
|
40
|
+
HarnessPickerProps,
|
|
39
41
|
HarnessSettingsPanelProps,
|
|
40
42
|
HarnessOption,
|
|
41
43
|
MessengerLabels,
|
|
@@ -66,6 +68,7 @@ export interface MessengerComponents {
|
|
|
66
68
|
HarnessLogo?: ComponentType<{ id: HarnessId; activity?: SessionActivity; size?: number }>;
|
|
67
69
|
HarnessAdvisory?: ComponentType<HarnessAdvisoryProps>;
|
|
68
70
|
HarnessSettingsPanel?: ComponentType<HarnessSettingsPanelProps>;
|
|
71
|
+
HarnessPicker?: ComponentType<HarnessPickerProps>;
|
|
69
72
|
ContextCandidate?: ComponentType<ContextCandidateProps>;
|
|
70
73
|
HarnessReadiness?: ComponentType<{ harnesses: HarnessOption[]; state: SupercodeUiState; adapter: UiAdapter }>;
|
|
71
74
|
}
|
|
@@ -112,6 +115,7 @@ export function ToolRow(props: ToolRowProps): ReactElement;
|
|
|
112
115
|
export function TaskPlan(props: { plan: TaskPlanModel }): ReactElement | null;
|
|
113
116
|
export function HarnessAdvisory(props: HarnessAdvisoryProps): ReactElement | null;
|
|
114
117
|
export function HarnessSettingsPanel(props: HarnessSettingsPanelProps): ReactElement;
|
|
118
|
+
export function HarnessPicker(props: HarnessPickerProps): ReactElement;
|
|
115
119
|
export function HarnessReadiness(props: { harnesses: HarnessOption[]; state: SupercodeUiState; adapter: UiAdapter }): ReactElement | null;
|
|
116
120
|
export function SessionDetails(props: { semantics: SupercodeUiState['semantics'] }): ReactElement | null;
|
|
117
121
|
export function Conversation(props: { state: SupercodeUiState; adapter: UiAdapter; components?: MessengerComponents; slots?: MessengerSlots; memoryKey?: string; pending?: string | PendingMessageModel | null; unreadAfterMessages?: number | null }): ReactElement;
|
package/react/messenger.mjs
CHANGED
|
@@ -2394,6 +2394,79 @@ function HarnessReadiness({ harnesses, adapter }) {
|
|
|
2394
2394
|
] }, item.id)) })
|
|
2395
2395
|
] });
|
|
2396
2396
|
}
|
|
2397
|
+
function HarnessPicker({ harnesses, value, disabled = false, adapter, onChange, logo: Logo = HarnessLogo }) {
|
|
2398
|
+
const [open, setOpen] = useState5(false);
|
|
2399
|
+
const menuId = useId2();
|
|
2400
|
+
const root = useRef6(null);
|
|
2401
|
+
const trigger = useRef6(null);
|
|
2402
|
+
const panel = useRef6(null);
|
|
2403
|
+
const available = harnesses.filter((item) => item.startable);
|
|
2404
|
+
const unavailable = harnesses.filter((item) => !item.startable);
|
|
2405
|
+
const selected = available.find((item) => item.id === value) ?? available[0] ?? null;
|
|
2406
|
+
const close = () => {
|
|
2407
|
+
setOpen(false);
|
|
2408
|
+
trigger.current?.focus({ preventScroll: true });
|
|
2409
|
+
};
|
|
2410
|
+
useEffect7(() => {
|
|
2411
|
+
if (!open) return;
|
|
2412
|
+
panel.current?.querySelector('[aria-selected="true"], [role="option"]')?.focus({ preventScroll: true });
|
|
2413
|
+
const dismiss = (event) => {
|
|
2414
|
+
if (event.type === "keydown" && event.key === "Escape") {
|
|
2415
|
+
event.preventDefault();
|
|
2416
|
+
close();
|
|
2417
|
+
} else if (event.type === "pointerdown" && !root.current?.contains(event.target)) {
|
|
2418
|
+
setOpen(false);
|
|
2419
|
+
}
|
|
2420
|
+
};
|
|
2421
|
+
document.addEventListener("keydown", dismiss);
|
|
2422
|
+
document.addEventListener("pointerdown", dismiss, true);
|
|
2423
|
+
return () => {
|
|
2424
|
+
document.removeEventListener("keydown", dismiss);
|
|
2425
|
+
document.removeEventListener("pointerdown", dismiss, true);
|
|
2426
|
+
};
|
|
2427
|
+
}, [open]);
|
|
2428
|
+
const navigate = (event) => {
|
|
2429
|
+
if (!["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) return;
|
|
2430
|
+
const items = [...panel.current.querySelectorAll('[role="option"]')];
|
|
2431
|
+
if (!items.length) return;
|
|
2432
|
+
event.preventDefault();
|
|
2433
|
+
const current = items.indexOf(document.activeElement);
|
|
2434
|
+
const index = event.key === "Home" ? 0 : event.key === "End" ? items.length - 1 : event.key === "ArrowDown" ? (current + 1) % items.length : (current <= 0 ? items.length : current) - 1;
|
|
2435
|
+
items[index].focus({ preventScroll: true });
|
|
2436
|
+
};
|
|
2437
|
+
const select = (id) => {
|
|
2438
|
+
onChange(id);
|
|
2439
|
+
close();
|
|
2440
|
+
};
|
|
2441
|
+
return /* @__PURE__ */ jsxs7("div", { className: "scui-harness-menu", ref: root, onBlur: (event) => {
|
|
2442
|
+
if (event.relatedTarget && !event.currentTarget.contains(event.relatedTarget)) setOpen(false);
|
|
2443
|
+
}, children: [
|
|
2444
|
+
/* @__PURE__ */ jsxs7("button", { ref: trigger, className: "scui-harness-trigger", type: "button", disabled: disabled || !selected, "aria-label": selected ? `Coding harness: ${selected.label}` : "No coding harness available", "aria-haspopup": "dialog", "aria-expanded": open, "aria-controls": open ? menuId : void 0, onClick: () => setOpen((current) => !current), children: [
|
|
2445
|
+
selected ? /* @__PURE__ */ jsx8(Logo, { id: selected.id, size: 20 }) : null,
|
|
2446
|
+
/* @__PURE__ */ jsx8("strong", { children: selected?.label ?? "No harness available" }),
|
|
2447
|
+
/* @__PURE__ */ jsx8(UiIcon, { name: "chevron", size: 13 })
|
|
2448
|
+
] }),
|
|
2449
|
+
open ? /* @__PURE__ */ jsxs7("div", { ref: panel, id: menuId, className: "scui-harness-popover", role: "dialog", "aria-label": "Choose coding harness", onKeyDown: navigate, children: [
|
|
2450
|
+
/* @__PURE__ */ jsx8("strong", { className: "scui-harness-popover-title", children: "Choose coding harness" }),
|
|
2451
|
+
/* @__PURE__ */ jsx8("div", { className: "scui-harness-options", role: "listbox", "aria-label": "Available coding harnesses", children: available.map((item) => /* @__PURE__ */ jsxs7("button", { type: "button", role: "option", "aria-selected": item.id === selected?.id, onClick: () => select(item.id), children: [
|
|
2452
|
+
/* @__PURE__ */ jsx8(Logo, { id: item.id, size: 24 }),
|
|
2453
|
+
/* @__PURE__ */ jsx8("strong", { children: item.label }),
|
|
2454
|
+
/* @__PURE__ */ jsx8("span", { children: item.id === selected?.id ? /* @__PURE__ */ jsx8(UiIcon, { name: "check", size: 15 }) : null })
|
|
2455
|
+
] }, item.id)) }),
|
|
2456
|
+
unavailable.length ? /* @__PURE__ */ jsxs7("details", { className: "scui-harness-manage", children: [
|
|
2457
|
+
/* @__PURE__ */ jsx8("summary", { children: "Manage additional harnesses" }),
|
|
2458
|
+
/* @__PURE__ */ jsx8("div", { children: unavailable.map((item) => /* @__PURE__ */ jsxs7("section", { children: [
|
|
2459
|
+
/* @__PURE__ */ jsx8(Logo, { id: item.id, size: 24 }),
|
|
2460
|
+
/* @__PURE__ */ jsxs7("span", { children: [
|
|
2461
|
+
/* @__PURE__ */ jsx8("strong", { children: item.label }),
|
|
2462
|
+
/* @__PURE__ */ jsx8("small", { children: item.reason || (item.auth === "required" ? "Authentication required" : "Unavailable") })
|
|
2463
|
+
] }),
|
|
2464
|
+
item.repair ? /* @__PURE__ */ jsx8("button", { type: "button", onClick: () => adapter?.copyText?.(item.repair), children: "Copy fix" }) : null
|
|
2465
|
+
] }, item.id)) })
|
|
2466
|
+
] }) : null
|
|
2467
|
+
] }) : null
|
|
2468
|
+
] });
|
|
2469
|
+
}
|
|
2397
2470
|
|
|
2398
2471
|
// src/messenger.jsx
|
|
2399
2472
|
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
@@ -2687,6 +2760,7 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2687
2760
|
const startSequence = useRef7(0);
|
|
2688
2761
|
const textarea = useRef7(null);
|
|
2689
2762
|
const selectedHarness = startable.find((item) => item.id === harness) ?? null;
|
|
2763
|
+
const Picker = components.HarnessPicker ?? HarnessPicker;
|
|
2690
2764
|
const Readiness = components.HarnessReadiness ?? HarnessReadiness;
|
|
2691
2765
|
const launchModes = selectedHarness?.launchModes?.length ? selectedHarness.launchModes : ["headless"];
|
|
2692
2766
|
const rememberedMode = modes[harness];
|
|
@@ -2824,18 +2898,6 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2824
2898
|
/* @__PURE__ */ jsx9("small", { children: "Choose a coding harness and send the first message." })
|
|
2825
2899
|
] }),
|
|
2826
2900
|
/* @__PURE__ */ jsxs8("div", { className: "scui-compose", children: [
|
|
2827
|
-
/* @__PURE__ */ jsxs8("label", { className: "scui-harness-picker", children: [
|
|
2828
|
-
/* @__PURE__ */ jsx9(HarnessLogo, { id: harness, size: 24 }),
|
|
2829
|
-
/* @__PURE__ */ jsx9("span", { children: "Coding harness" }),
|
|
2830
|
-
/* @__PURE__ */ jsx9("select", { value: harness, disabled: Boolean(starting), onChange: (event) => {
|
|
2831
|
-
const value = event.currentTarget.value;
|
|
2832
|
-
setHarness(value);
|
|
2833
|
-
remember({ harness: value });
|
|
2834
|
-
}, children: state.harnesses.map((item) => /* @__PURE__ */ jsxs8("option", { value: item.id, disabled: !item.startable, children: [
|
|
2835
|
-
item.label,
|
|
2836
|
-
item.startable ? "" : " \xB7 unavailable"
|
|
2837
|
-
] }, item.id)) })
|
|
2838
|
-
] }),
|
|
2839
2901
|
/* @__PURE__ */ jsx9(Readiness, { harnesses: state.harnesses, state, adapter }),
|
|
2840
2902
|
launchModes.length > 1 ? /* @__PURE__ */ jsxs8("fieldset", { className: "scui-launch-modes", disabled: Boolean(starting), children: [
|
|
2841
2903
|
/* @__PURE__ */ jsx9("legend", { children: "Run as" }),
|
|
@@ -2864,7 +2926,7 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2864
2926
|
return next;
|
|
2865
2927
|
}) }),
|
|
2866
2928
|
terminalAttachments ? /* @__PURE__ */ jsx9("small", { className: "scui-context-error", role: "alert", children: "Terminal starts currently accept text only. Remove attachments or choose Chat." }) : pickerError ? /* @__PURE__ */ jsx9("small", { className: "scui-context-error", role: "alert", children: pickerError }) : null,
|
|
2867
|
-
/* @__PURE__ */ jsxs8("div", { className: `scui-envelope${dragging ? " scui-drop-target" : ""}`, onDragEnter: (event) => {
|
|
2929
|
+
/* @__PURE__ */ jsxs8("div", { className: `scui-envelope scui-new-envelope${dragging ? " scui-drop-target" : ""}`, onDragEnter: (event) => {
|
|
2868
2930
|
if (Array.from(event.dataTransfer?.types ?? []).includes("Files")) {
|
|
2869
2931
|
event.preventDefault();
|
|
2870
2932
|
setDragging(true);
|
|
@@ -2874,7 +2936,6 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2874
2936
|
}, onDragLeave: (event) => {
|
|
2875
2937
|
if (!event.currentTarget.contains(event.relatedTarget)) setDragging(false);
|
|
2876
2938
|
}, onDrop: dropImages, children: [
|
|
2877
|
-
adapter.pickContext ? /* @__PURE__ */ jsx9("button", { className: "scui-attach", type: "button", "aria-label": "Attach files or images", disabled: mode === "terminal" || picking || context.length >= MAX_CONTEXT_ITEMS && images.length >= MAX_IMAGE_ITEMS || Boolean(starting), onClick: pickContext, children: picking ? /* @__PURE__ */ jsx9("i", { className: "scui-control-spinner" }) : /* @__PURE__ */ jsx9(UiIcon, { name: "attach", size: 17 }) }) : null,
|
|
2878
2939
|
/* @__PURE__ */ jsx9("textarea", { ref: textarea, rows: 3, "aria-label": "Message coding agent", placeholder: startable.length ? "What should the agent do?" : "No coding harness is available", value: draft, disabled: !startable.length || Boolean(starting), onPaste: pasteImages, onInput: (event) => {
|
|
2879
2940
|
const value = event.currentTarget.value;
|
|
2880
2941
|
setDraft(value);
|
|
@@ -2885,7 +2946,14 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2885
2946
|
send();
|
|
2886
2947
|
}
|
|
2887
2948
|
} }),
|
|
2888
|
-
/* @__PURE__ */
|
|
2949
|
+
/* @__PURE__ */ jsxs8("footer", { className: "scui-new-envelope-controls", children: [
|
|
2950
|
+
adapter.pickContext ? /* @__PURE__ */ jsx9("button", { className: "scui-attach", type: "button", "aria-label": "Attach files or images", disabled: mode === "terminal" || picking || context.length >= MAX_CONTEXT_ITEMS && images.length >= MAX_IMAGE_ITEMS || Boolean(starting), onClick: pickContext, children: picking ? /* @__PURE__ */ jsx9("i", { className: "scui-control-spinner" }) : /* @__PURE__ */ jsx9(UiIcon, { name: "attach", size: 17 }) }) : null,
|
|
2951
|
+
/* @__PURE__ */ jsx9(Picker, { harnesses: state.harnesses, value: harness, disabled: Boolean(starting), adapter, logo: components.HarnessLogo, onChange: (value) => {
|
|
2952
|
+
setHarness(value);
|
|
2953
|
+
remember({ harness: value });
|
|
2954
|
+
} }),
|
|
2955
|
+
/* @__PURE__ */ jsx9("span", { children: /* @__PURE__ */ jsx9("button", { type: "button", className: "scui-send", "aria-label": mode === "terminal" ? "Start terminal session" : "Start chat", disabled: !draft.trim() && !images.length || !harness || Boolean(starting) || terminalAttachments || mode === "terminal" && !draft.trim(), onClick: send, children: starting ? /* @__PURE__ */ jsx9("i", { className: "scui-control-spinner" }) : /* @__PURE__ */ jsx9(UiIcon, { name: "send", size: 17 }) }) })
|
|
2956
|
+
] })
|
|
2889
2957
|
] })
|
|
2890
2958
|
] })
|
|
2891
2959
|
] });
|
package/react/settings.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export type { HarnessAdvisoryProps, HarnessSettingsPanelProps } from './index.js';
|
|
2
|
-
export { HarnessAdvisory, HarnessSettingsPanel } from './index.js';
|
|
1
|
+
export type { HarnessAdvisoryProps, HarnessPickerProps, HarnessSettingsPanelProps } from './index.js';
|
|
2
|
+
export { HarnessAdvisory, HarnessPicker, HarnessSettingsPanel } from './index.js';
|
package/react/settings.mjs
CHANGED
|
@@ -307,8 +307,82 @@ function HarnessReadiness({ harnesses, adapter }) {
|
|
|
307
307
|
] }, item.id)) })
|
|
308
308
|
] });
|
|
309
309
|
}
|
|
310
|
+
function HarnessPicker({ harnesses, value, disabled = false, adapter, onChange, logo: Logo = HarnessLogo }) {
|
|
311
|
+
const [open, setOpen] = useState(false);
|
|
312
|
+
const menuId = useId();
|
|
313
|
+
const root = useRef(null);
|
|
314
|
+
const trigger = useRef(null);
|
|
315
|
+
const panel = useRef(null);
|
|
316
|
+
const available = harnesses.filter((item) => item.startable);
|
|
317
|
+
const unavailable = harnesses.filter((item) => !item.startable);
|
|
318
|
+
const selected = available.find((item) => item.id === value) ?? available[0] ?? null;
|
|
319
|
+
const close = () => {
|
|
320
|
+
setOpen(false);
|
|
321
|
+
trigger.current?.focus({ preventScroll: true });
|
|
322
|
+
};
|
|
323
|
+
useEffect2(() => {
|
|
324
|
+
if (!open) return;
|
|
325
|
+
panel.current?.querySelector('[aria-selected="true"], [role="option"]')?.focus({ preventScroll: true });
|
|
326
|
+
const dismiss = (event) => {
|
|
327
|
+
if (event.type === "keydown" && event.key === "Escape") {
|
|
328
|
+
event.preventDefault();
|
|
329
|
+
close();
|
|
330
|
+
} else if (event.type === "pointerdown" && !root.current?.contains(event.target)) {
|
|
331
|
+
setOpen(false);
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
document.addEventListener("keydown", dismiss);
|
|
335
|
+
document.addEventListener("pointerdown", dismiss, true);
|
|
336
|
+
return () => {
|
|
337
|
+
document.removeEventListener("keydown", dismiss);
|
|
338
|
+
document.removeEventListener("pointerdown", dismiss, true);
|
|
339
|
+
};
|
|
340
|
+
}, [open]);
|
|
341
|
+
const navigate = (event) => {
|
|
342
|
+
if (!["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) return;
|
|
343
|
+
const items = [...panel.current.querySelectorAll('[role="option"]')];
|
|
344
|
+
if (!items.length) return;
|
|
345
|
+
event.preventDefault();
|
|
346
|
+
const current = items.indexOf(document.activeElement);
|
|
347
|
+
const index = event.key === "Home" ? 0 : event.key === "End" ? items.length - 1 : event.key === "ArrowDown" ? (current + 1) % items.length : (current <= 0 ? items.length : current) - 1;
|
|
348
|
+
items[index].focus({ preventScroll: true });
|
|
349
|
+
};
|
|
350
|
+
const select = (id) => {
|
|
351
|
+
onChange(id);
|
|
352
|
+
close();
|
|
353
|
+
};
|
|
354
|
+
return /* @__PURE__ */ jsxs3("div", { className: "scui-harness-menu", ref: root, onBlur: (event) => {
|
|
355
|
+
if (event.relatedTarget && !event.currentTarget.contains(event.relatedTarget)) setOpen(false);
|
|
356
|
+
}, children: [
|
|
357
|
+
/* @__PURE__ */ jsxs3("button", { ref: trigger, className: "scui-harness-trigger", type: "button", disabled: disabled || !selected, "aria-label": selected ? `Coding harness: ${selected.label}` : "No coding harness available", "aria-haspopup": "dialog", "aria-expanded": open, "aria-controls": open ? menuId : void 0, onClick: () => setOpen((current) => !current), children: [
|
|
358
|
+
selected ? /* @__PURE__ */ jsx3(Logo, { id: selected.id, size: 20 }) : null,
|
|
359
|
+
/* @__PURE__ */ jsx3("strong", { children: selected?.label ?? "No harness available" }),
|
|
360
|
+
/* @__PURE__ */ jsx3(UiIcon, { name: "chevron", size: 13 })
|
|
361
|
+
] }),
|
|
362
|
+
open ? /* @__PURE__ */ jsxs3("div", { ref: panel, id: menuId, className: "scui-harness-popover", role: "dialog", "aria-label": "Choose coding harness", onKeyDown: navigate, children: [
|
|
363
|
+
/* @__PURE__ */ jsx3("strong", { className: "scui-harness-popover-title", children: "Choose coding harness" }),
|
|
364
|
+
/* @__PURE__ */ jsx3("div", { className: "scui-harness-options", role: "listbox", "aria-label": "Available coding harnesses", children: available.map((item) => /* @__PURE__ */ jsxs3("button", { type: "button", role: "option", "aria-selected": item.id === selected?.id, onClick: () => select(item.id), children: [
|
|
365
|
+
/* @__PURE__ */ jsx3(Logo, { id: item.id, size: 24 }),
|
|
366
|
+
/* @__PURE__ */ jsx3("strong", { children: item.label }),
|
|
367
|
+
/* @__PURE__ */ jsx3("span", { children: item.id === selected?.id ? /* @__PURE__ */ jsx3(UiIcon, { name: "check", size: 15 }) : null })
|
|
368
|
+
] }, item.id)) }),
|
|
369
|
+
unavailable.length ? /* @__PURE__ */ jsxs3("details", { className: "scui-harness-manage", children: [
|
|
370
|
+
/* @__PURE__ */ jsx3("summary", { children: "Manage additional harnesses" }),
|
|
371
|
+
/* @__PURE__ */ jsx3("div", { children: unavailable.map((item) => /* @__PURE__ */ jsxs3("section", { children: [
|
|
372
|
+
/* @__PURE__ */ jsx3(Logo, { id: item.id, size: 24 }),
|
|
373
|
+
/* @__PURE__ */ jsxs3("span", { children: [
|
|
374
|
+
/* @__PURE__ */ jsx3("strong", { children: item.label }),
|
|
375
|
+
/* @__PURE__ */ jsx3("small", { children: item.reason || (item.auth === "required" ? "Authentication required" : "Unavailable") })
|
|
376
|
+
] }),
|
|
377
|
+
item.repair ? /* @__PURE__ */ jsx3("button", { type: "button", onClick: () => adapter?.copyText?.(item.repair), children: "Copy fix" }) : null
|
|
378
|
+
] }, item.id)) })
|
|
379
|
+
] }) : null
|
|
380
|
+
] }) : null
|
|
381
|
+
] });
|
|
382
|
+
}
|
|
310
383
|
export {
|
|
311
384
|
HarnessAdvisory,
|
|
385
|
+
HarnessPicker,
|
|
312
386
|
HarnessReadiness,
|
|
313
387
|
HarnessSettingsPanel
|
|
314
388
|
};
|
package/settings.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { HarnessAdvisory, HarnessSettingsPanel } from './index.js';
|
|
2
|
-
export type { HarnessAdvisoryProps, HarnessSettingsPanelProps } from './index.js';
|
|
1
|
+
export { HarnessAdvisory, HarnessPicker, HarnessSettingsPanel } from './index.js';
|
|
2
|
+
export type { HarnessAdvisoryProps, HarnessPickerProps, HarnessSettingsPanelProps } from './index.js';
|
package/settings.mjs
CHANGED
|
@@ -307,8 +307,82 @@ function HarnessReadiness({ harnesses, adapter }) {
|
|
|
307
307
|
] }, item.id)) })
|
|
308
308
|
] });
|
|
309
309
|
}
|
|
310
|
+
function HarnessPicker({ harnesses, value, disabled = false, adapter, onChange, logo: Logo = HarnessLogo }) {
|
|
311
|
+
const [open, setOpen] = useState(false);
|
|
312
|
+
const menuId = useId();
|
|
313
|
+
const root = useRef(null);
|
|
314
|
+
const trigger = useRef(null);
|
|
315
|
+
const panel = useRef(null);
|
|
316
|
+
const available = harnesses.filter((item) => item.startable);
|
|
317
|
+
const unavailable = harnesses.filter((item) => !item.startable);
|
|
318
|
+
const selected = available.find((item) => item.id === value) ?? available[0] ?? null;
|
|
319
|
+
const close = () => {
|
|
320
|
+
setOpen(false);
|
|
321
|
+
trigger.current?.focus({ preventScroll: true });
|
|
322
|
+
};
|
|
323
|
+
useEffect2(() => {
|
|
324
|
+
if (!open) return;
|
|
325
|
+
panel.current?.querySelector('[aria-selected="true"], [role="option"]')?.focus({ preventScroll: true });
|
|
326
|
+
const dismiss = (event) => {
|
|
327
|
+
if (event.type === "keydown" && event.key === "Escape") {
|
|
328
|
+
event.preventDefault();
|
|
329
|
+
close();
|
|
330
|
+
} else if (event.type === "pointerdown" && !root.current?.contains(event.target)) {
|
|
331
|
+
setOpen(false);
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
document.addEventListener("keydown", dismiss);
|
|
335
|
+
document.addEventListener("pointerdown", dismiss, true);
|
|
336
|
+
return () => {
|
|
337
|
+
document.removeEventListener("keydown", dismiss);
|
|
338
|
+
document.removeEventListener("pointerdown", dismiss, true);
|
|
339
|
+
};
|
|
340
|
+
}, [open]);
|
|
341
|
+
const navigate = (event) => {
|
|
342
|
+
if (!["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) return;
|
|
343
|
+
const items = [...panel.current.querySelectorAll('[role="option"]')];
|
|
344
|
+
if (!items.length) return;
|
|
345
|
+
event.preventDefault();
|
|
346
|
+
const current = items.indexOf(document.activeElement);
|
|
347
|
+
const index = event.key === "Home" ? 0 : event.key === "End" ? items.length - 1 : event.key === "ArrowDown" ? (current + 1) % items.length : (current <= 0 ? items.length : current) - 1;
|
|
348
|
+
items[index].focus({ preventScroll: true });
|
|
349
|
+
};
|
|
350
|
+
const select = (id) => {
|
|
351
|
+
onChange(id);
|
|
352
|
+
close();
|
|
353
|
+
};
|
|
354
|
+
return /* @__PURE__ */ jsxs3("div", { className: "scui-harness-menu", ref: root, onBlur: (event) => {
|
|
355
|
+
if (event.relatedTarget && !event.currentTarget.contains(event.relatedTarget)) setOpen(false);
|
|
356
|
+
}, children: [
|
|
357
|
+
/* @__PURE__ */ jsxs3("button", { ref: trigger, className: "scui-harness-trigger", type: "button", disabled: disabled || !selected, "aria-label": selected ? `Coding harness: ${selected.label}` : "No coding harness available", "aria-haspopup": "dialog", "aria-expanded": open, "aria-controls": open ? menuId : void 0, onClick: () => setOpen((current) => !current), children: [
|
|
358
|
+
selected ? /* @__PURE__ */ jsx3(Logo, { id: selected.id, size: 20 }) : null,
|
|
359
|
+
/* @__PURE__ */ jsx3("strong", { children: selected?.label ?? "No harness available" }),
|
|
360
|
+
/* @__PURE__ */ jsx3(UiIcon, { name: "chevron", size: 13 })
|
|
361
|
+
] }),
|
|
362
|
+
open ? /* @__PURE__ */ jsxs3("div", { ref: panel, id: menuId, className: "scui-harness-popover", role: "dialog", "aria-label": "Choose coding harness", onKeyDown: navigate, children: [
|
|
363
|
+
/* @__PURE__ */ jsx3("strong", { className: "scui-harness-popover-title", children: "Choose coding harness" }),
|
|
364
|
+
/* @__PURE__ */ jsx3("div", { className: "scui-harness-options", role: "listbox", "aria-label": "Available coding harnesses", children: available.map((item) => /* @__PURE__ */ jsxs3("button", { type: "button", role: "option", "aria-selected": item.id === selected?.id, onClick: () => select(item.id), children: [
|
|
365
|
+
/* @__PURE__ */ jsx3(Logo, { id: item.id, size: 24 }),
|
|
366
|
+
/* @__PURE__ */ jsx3("strong", { children: item.label }),
|
|
367
|
+
/* @__PURE__ */ jsx3("span", { children: item.id === selected?.id ? /* @__PURE__ */ jsx3(UiIcon, { name: "check", size: 15 }) : null })
|
|
368
|
+
] }, item.id)) }),
|
|
369
|
+
unavailable.length ? /* @__PURE__ */ jsxs3("details", { className: "scui-harness-manage", children: [
|
|
370
|
+
/* @__PURE__ */ jsx3("summary", { children: "Manage additional harnesses" }),
|
|
371
|
+
/* @__PURE__ */ jsx3("div", { children: unavailable.map((item) => /* @__PURE__ */ jsxs3("section", { children: [
|
|
372
|
+
/* @__PURE__ */ jsx3(Logo, { id: item.id, size: 24 }),
|
|
373
|
+
/* @__PURE__ */ jsxs3("span", { children: [
|
|
374
|
+
/* @__PURE__ */ jsx3("strong", { children: item.label }),
|
|
375
|
+
/* @__PURE__ */ jsx3("small", { children: item.reason || (item.auth === "required" ? "Authentication required" : "Unavailable") })
|
|
376
|
+
] }),
|
|
377
|
+
item.repair ? /* @__PURE__ */ jsx3("button", { type: "button", onClick: () => adapter?.copyText?.(item.repair), children: "Copy fix" }) : null
|
|
378
|
+
] }, item.id)) })
|
|
379
|
+
] }) : null
|
|
380
|
+
] }) : null
|
|
381
|
+
] });
|
|
382
|
+
}
|
|
310
383
|
export {
|
|
311
384
|
HarnessAdvisory,
|
|
385
|
+
HarnessPicker,
|
|
312
386
|
HarnessReadiness,
|
|
313
387
|
HarnessSettingsPanel
|
|
314
388
|
};
|
package/styles.css
CHANGED
|
@@ -198,7 +198,10 @@
|
|
|
198
198
|
.scui-send,.scui-stop { display:grid; width:29px; height:29px; padding:0; place-items:center; border:0; border-radius:8px; background:var(--scui-accent); color:#fff; cursor:pointer }.scui-stop { background:var(--scui-danger) }.scui-send:disabled,.scui-stop:disabled { opacity:.4; cursor:default }.scui-control-spinner { box-sizing:border-box; width:13px; height:13px; border:1.5px solid currentColor; border-right-color:transparent; border-radius:50%; animation:scui-spin .75s linear infinite }
|
|
199
199
|
.scui-queue-send { display:grid; width:29px; height:29px; padding:0; place-items:center; border:0; border-radius:8px; background:transparent; color:var(--scui-muted); cursor:pointer }.scui-queue-send:hover { background:var(--scui-fill); color:var(--scui-fg) }
|
|
200
200
|
.scui-queue { display:grid; gap:4px; max-height:85px; margin-bottom:6px; overflow:auto; font-size:10.5px }.scui-queue > span { display:flex; gap:6px; padding:4px 6px; border-radius:5px; background:var(--scui-fill) }.scui-queue > span > span { display:grid; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap }.scui-queue small { color:var(--scui-muted) }.scui-queue > span button { margin-left:auto; border:0; background:transparent }
|
|
201
|
-
.scui-
|
|
201
|
+
.scui-new-envelope { display:grid; align-items:stretch; gap:3px; padding:7px }.scui-new-envelope textarea { box-sizing:border-box; width:100%; min-height:54px; padding:2px 3px }.scui-new-envelope-controls { display:flex; min-width:0; align-items:center; gap:3px }.scui-new-envelope-controls > span { display:flex; margin-left:auto }.scui-new-envelope-controls .scui-attach { flex-basis:29px; width:29px; height:29px }
|
|
202
|
+
.scui-harness-menu { position:relative; min-width:0 }.scui-harness-trigger { display:flex; max-width:170px; height:29px; align-items:center; gap:6px; padding:3px 7px 3px 4px; border:0; border-radius:8px; background:transparent; color:var(--scui-fg); cursor:pointer }.scui-harness-trigger:hover:not(:disabled),.scui-harness-trigger:focus-visible,.scui-harness-trigger[aria-expanded="true"] { background:var(--scui-fill) }.scui-harness-trigger:disabled { cursor:default; opacity:.55 }.scui-harness-trigger > strong { min-width:0; overflow:hidden; font-size:10.5px; font-weight:600; text-overflow:ellipsis; white-space:nowrap }.scui-harness-trigger > .scui-icon { flex:none; color:var(--scui-muted); transform:rotate(90deg); transition:transform 120ms }.scui-harness-trigger[aria-expanded="true"] > .scui-icon { transform:rotate(-90deg) }
|
|
203
|
+
.scui-harness-popover { position:absolute; z-index:25; bottom:calc(100% + 7px); left:0; display:grid; box-sizing:border-box; width:min(250px,calc(100vw - 24px)); max-height:min(330px,calc(100dvh - 90px)); overflow:auto; padding:5px; border:1px solid var(--scui-border-strong); border-radius:10px; background:var(--scui-bg-raised); box-shadow:0 12px 34px rgba(0,0,0,.2) }.scui-harness-popover-title { padding:5px 7px; color:var(--scui-muted); font-size:8.5px; font-weight:650; letter-spacing:.055em; text-transform:uppercase }.scui-harness-options { display:grid; gap:1px }.scui-harness-options > button { display:grid; grid-template-columns:auto minmax(0,1fr) 18px; width:100%; min-height:36px; align-items:center; gap:8px; padding:5px 7px; border:0; border-radius:7px; background:transparent; color:var(--scui-fg); text-align:left; cursor:pointer }.scui-harness-options > button:hover,.scui-harness-options > button:focus-visible { background:var(--scui-fill) }.scui-harness-options > button[aria-selected="true"] { background:color-mix(in srgb,var(--scui-accent) 8%,var(--scui-bg-raised)) }.scui-harness-options > button > strong { min-width:0; overflow:hidden; font-size:11px; font-weight:600; text-overflow:ellipsis; white-space:nowrap }.scui-harness-options > button > span { display:grid; color:var(--scui-accent); place-items:center }
|
|
204
|
+
.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) }
|
|
202
205
|
.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 }
|
|
203
206
|
.scui-launch-modes { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:5px; margin:0 0 7px; padding:0; border:0 }.scui-launch-modes legend { position:absolute; overflow:hidden; width:1px; height:1px; clip:rect(0 0 0 0); white-space:nowrap }.scui-launch-modes label { position:relative; min-width:0; cursor:pointer }.scui-launch-modes input { position:absolute; opacity:0; pointer-events:none }.scui-launch-modes label > span { display:flex; min-height:42px; flex-direction:column; justify-content:center; padding:6px 9px; border:1px solid var(--scui-border); border-radius:7px; background:var(--scui-bg); transition:border-color .14s ease,background .14s ease }.scui-launch-modes strong { font-size:11px; font-weight:650 }.scui-launch-modes small { overflow:hidden; color:var(--scui-muted); font-size:9px; text-overflow:ellipsis; white-space:nowrap }.scui-launch-modes input:checked + span { border-color:color-mix(in srgb,var(--scui-accent) 58%,var(--scui-border)); background:color-mix(in srgb,var(--scui-accent) 8%,var(--scui-bg)) }.scui-launch-modes input:focus-visible + span { outline:2px solid var(--scui-accent); outline-offset:1px }.scui-launch-modes:disabled label { cursor:default; opacity:.62 }
|
|
204
207
|
.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) }
|
|
@@ -215,6 +218,8 @@
|
|
|
215
218
|
.scui-head { min-height:52px }
|
|
216
219
|
.scui-menu-panel button,.scui-request-actions button,.scui-load { min-height:40px }
|
|
217
220
|
.scui-send,.scui-stop { width:40px; height:40px }
|
|
221
|
+
.scui-new-envelope-controls .scui-attach,.scui-harness-trigger { min-height:40px }
|
|
222
|
+
.scui-harness-options > button,.scui-harness-manage section { min-height:44px }
|
|
218
223
|
.scui-message-meta button,.scui-code-copy { min-width:36px; min-height:36px }
|
|
219
224
|
.scui-latest { min-height:36px; padding-inline:12px }
|
|
220
225
|
}
|