@volter-ai-dev/supercode-ui 0.1.61 → 0.1.63
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 +14 -1
- package/activity.mjs +23 -0
- package/components.mjs +48 -7
- package/composer.mjs +1 -0
- package/controller.d.ts +24 -0
- package/controller.mjs +24 -2
- package/conversation.mjs +1 -0
- package/core.mjs +31 -0
- package/embed.mjs +48 -7
- package/index.d.ts +19 -1
- package/messenger.mjs +48 -7
- package/package.json +1 -1
- package/react/activity.mjs +23 -0
- package/react/components.mjs +48 -7
- package/react/composer.mjs +1 -0
- package/react/conversation.mjs +1 -0
- package/react/messenger.mjs +48 -7
- package/react/sessions.mjs +1 -0
- package/react/settings.mjs +25 -6
- package/react/subagents.mjs +1 -0
- package/sessions.mjs +1 -0
- package/settings.mjs +25 -6
- package/subagents.mjs +1 -0
package/README.md
CHANGED
|
@@ -159,7 +159,15 @@ join, branch, reduction, or export so a host can explain ownership and destinati
|
|
|
159
159
|
|
|
160
160
|
Harness inventory also retains normalized auth, runtime, protocol, repair, and action-capability
|
|
161
161
|
evidence. The new-chat view renders unavailable harnesses in a compact `HarnessReadiness` section;
|
|
162
|
-
hosts can replace that component while continuing to consume the same readiness contract.
|
|
162
|
+
hosts can replace that component while continuing to consume the same readiness contract. For an
|
|
163
|
+
installed Claude Code or Codex that needs authentication, the default component emits the single
|
|
164
|
+
`authenticateHarness` intent. A trusted host constructs the client's
|
|
165
|
+
`HarnessAuthenticationController` with a visible terminal/process adapter and supplies it to the
|
|
166
|
+
controller binding as `authentication`. The shared controller selects the native method, handles
|
|
167
|
+
timeout/cancellation/verification, refreshes inventory after success, and exposes only sanitized
|
|
168
|
+
progress to the default component. The browser-only UI never receives a launch command, spawns a
|
|
169
|
+
local process, or handles credentials itself. `onAuthenticateHarness` remains a legacy escape hatch
|
|
170
|
+
for hosts that have not adopted the shared lifecycle.
|
|
163
171
|
|
|
164
172
|
When a controlled runtime truthfully advertises native steering, the composer sends a plain-text
|
|
165
173
|
message into the active turn and keeps a separate secondary action for queueing a follow-up. With
|
|
@@ -175,6 +183,11 @@ Trusted desktop, editor, and Node hosts can avoid rewriting ordinary snapshot an
|
|
|
175
183
|
import { createControllerBinding } from '@volter-ai-dev/supercode-ui/controller';
|
|
176
184
|
|
|
177
185
|
const binding = createControllerBinding(controller, {
|
|
186
|
+
authentication,
|
|
187
|
+
authenticationRequest: () => ({
|
|
188
|
+
environment: isRemoteClient ? 'headless' : 'local_browser',
|
|
189
|
+
cwd: projectRoot,
|
|
190
|
+
}),
|
|
178
191
|
onDraft: saveDraft,
|
|
179
192
|
onAcknowledge: clearAttention,
|
|
180
193
|
onArtifact: materializeArtifactInTrustedHost,
|
package/activity.mjs
CHANGED
|
@@ -55,6 +55,7 @@ var EMPTY_UI_STATE = Object.freeze({
|
|
|
55
55
|
reductionReceipt: null,
|
|
56
56
|
interopSettings: null,
|
|
57
57
|
interopSettingsError: null,
|
|
58
|
+
harnessAuthentication: null,
|
|
58
59
|
error: null,
|
|
59
60
|
recoverable: false,
|
|
60
61
|
harnesses: Object.freeze([]),
|
|
@@ -74,12 +75,33 @@ var STARTUP = /* @__PURE__ */ new Set(["connecting", "starting", "discovering",
|
|
|
74
75
|
var FIDELITY = /* @__PURE__ */ new Set(["byte_lossless", "value_lossless", "semantic"]);
|
|
75
76
|
var TOOL_CATEGORIES = /* @__PURE__ */ new Set(["read", "search", "edit", "command", "test", "web", "agent", "plan", "other"]);
|
|
76
77
|
var TOOL_DETAILS = /* @__PURE__ */ new Set(["file", "matches", "diff", "terminal", "web", "agent", "plan", "fields"]);
|
|
78
|
+
var AUTHENTICATION_PHASES = /* @__PURE__ */ new Set(["idle", "checking", "required", "configured", "unavailable", "launching", "awaiting_user", "verifying", "authenticated", "failed", "cancelled"]);
|
|
77
79
|
var MAX_TOOL_FIELDS = 8;
|
|
78
80
|
var MAX_TOOL_FIELD_CHARS = 800;
|
|
79
81
|
var MAX_TOOL_PREVIEW_CHARS = 4e3;
|
|
80
82
|
function record(value) {
|
|
81
83
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
82
84
|
}
|
|
85
|
+
function readHarnessAuthentication(value) {
|
|
86
|
+
const flow = record(value);
|
|
87
|
+
if (flow?.schema !== "supercode.harness-authentication-flow.v1" || !AUTHENTICATION_PHASES.has(flow.phase)) return null;
|
|
88
|
+
const plan = record(flow.plan);
|
|
89
|
+
const error = record(flow.error);
|
|
90
|
+
return {
|
|
91
|
+
schema: "supercode.harness-authentication-flow.v1",
|
|
92
|
+
revision: Number.isSafeInteger(flow.revision) ? Math.max(0, flow.revision) : 0,
|
|
93
|
+
phase: flow.phase,
|
|
94
|
+
harness: typeof flow.harness === "string" ? boundedString(flow.harness, 100) : null,
|
|
95
|
+
plan: plan ? {
|
|
96
|
+
method: plan.method === "device_code" ? "device_code" : "browser",
|
|
97
|
+
interaction: plan.interaction === "device_code" ? "device_code" : "browser",
|
|
98
|
+
browserBehavior: plan.browserBehavior === "none" ? "none" : "native_auto",
|
|
99
|
+
headless: plan.headless === true,
|
|
100
|
+
instructions: boundedString(plan.instructions, 2e3)
|
|
101
|
+
} : null,
|
|
102
|
+
error: error && typeof error.message === "string" ? { code: boundedString(error.code, 100), message: boundedString(error.message, 2e3) } : null
|
|
103
|
+
};
|
|
104
|
+
}
|
|
83
105
|
function string(value, fallback = "") {
|
|
84
106
|
return typeof value === "string" ? value : fallback;
|
|
85
107
|
}
|
|
@@ -754,6 +776,7 @@ function normalizeUiState(value) {
|
|
|
754
776
|
reductionReceipt: readReductionReceipt(raw.reductionReceipt),
|
|
755
777
|
interopSettings: readInteropSettings(raw.interopSettings),
|
|
756
778
|
interopSettingsError: typeof raw.interopSettingsError === "string" ? boundedString(raw.interopSettingsError) : null,
|
|
779
|
+
harnessAuthentication: readHarnessAuthentication(raw.harnessAuthentication),
|
|
757
780
|
error: typeof raw.error === "string" ? raw.error : null,
|
|
758
781
|
recoverable: raw.recoverable === true,
|
|
759
782
|
harnesses: Array.isArray(raw.harnesses) ? raw.harnesses.flatMap((candidate) => {
|
package/components.mjs
CHANGED
|
@@ -58,6 +58,7 @@ var EMPTY_UI_STATE = Object.freeze({
|
|
|
58
58
|
reductionReceipt: null,
|
|
59
59
|
interopSettings: null,
|
|
60
60
|
interopSettingsError: null,
|
|
61
|
+
harnessAuthentication: null,
|
|
61
62
|
error: null,
|
|
62
63
|
recoverable: false,
|
|
63
64
|
harnesses: Object.freeze([]),
|
|
@@ -77,12 +78,33 @@ var STARTUP = /* @__PURE__ */ new Set(["connecting", "starting", "discovering",
|
|
|
77
78
|
var FIDELITY = /* @__PURE__ */ new Set(["byte_lossless", "value_lossless", "semantic"]);
|
|
78
79
|
var TOOL_CATEGORIES = /* @__PURE__ */ new Set(["read", "search", "edit", "command", "test", "web", "agent", "plan", "other"]);
|
|
79
80
|
var TOOL_DETAILS = /* @__PURE__ */ new Set(["file", "matches", "diff", "terminal", "web", "agent", "plan", "fields"]);
|
|
81
|
+
var AUTHENTICATION_PHASES = /* @__PURE__ */ new Set(["idle", "checking", "required", "configured", "unavailable", "launching", "awaiting_user", "verifying", "authenticated", "failed", "cancelled"]);
|
|
80
82
|
var MAX_TOOL_FIELDS = 8;
|
|
81
83
|
var MAX_TOOL_FIELD_CHARS = 800;
|
|
82
84
|
var MAX_TOOL_PREVIEW_CHARS = 4e3;
|
|
83
85
|
function record(value) {
|
|
84
86
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
85
87
|
}
|
|
88
|
+
function readHarnessAuthentication(value) {
|
|
89
|
+
const flow = record(value);
|
|
90
|
+
if (flow?.schema !== "supercode.harness-authentication-flow.v1" || !AUTHENTICATION_PHASES.has(flow.phase)) return null;
|
|
91
|
+
const plan = record(flow.plan);
|
|
92
|
+
const error = record(flow.error);
|
|
93
|
+
return {
|
|
94
|
+
schema: "supercode.harness-authentication-flow.v1",
|
|
95
|
+
revision: Number.isSafeInteger(flow.revision) ? Math.max(0, flow.revision) : 0,
|
|
96
|
+
phase: flow.phase,
|
|
97
|
+
harness: typeof flow.harness === "string" ? boundedString(flow.harness, 100) : null,
|
|
98
|
+
plan: plan ? {
|
|
99
|
+
method: plan.method === "device_code" ? "device_code" : "browser",
|
|
100
|
+
interaction: plan.interaction === "device_code" ? "device_code" : "browser",
|
|
101
|
+
browserBehavior: plan.browserBehavior === "none" ? "none" : "native_auto",
|
|
102
|
+
headless: plan.headless === true,
|
|
103
|
+
instructions: boundedString(plan.instructions, 2e3)
|
|
104
|
+
} : null,
|
|
105
|
+
error: error && typeof error.message === "string" ? { code: boundedString(error.code, 100), message: boundedString(error.message, 2e3) } : null
|
|
106
|
+
};
|
|
107
|
+
}
|
|
86
108
|
function string(value, fallback = "") {
|
|
87
109
|
return typeof value === "string" ? value : fallback;
|
|
88
110
|
}
|
|
@@ -766,6 +788,7 @@ function normalizeUiState(value) {
|
|
|
766
788
|
reductionReceipt: readReductionReceipt(raw.reductionReceipt),
|
|
767
789
|
interopSettings: readInteropSettings(raw.interopSettings),
|
|
768
790
|
interopSettingsError: typeof raw.interopSettingsError === "string" ? boundedString(raw.interopSettingsError) : null,
|
|
791
|
+
harnessAuthentication: readHarnessAuthentication(raw.harnessAuthentication),
|
|
769
792
|
error: typeof raw.error === "string" ? raw.error : null,
|
|
770
793
|
recoverable: raw.recoverable === true,
|
|
771
794
|
harnesses: Array.isArray(raw.harnesses) ? raw.harnesses.flatMap((candidate) => {
|
|
@@ -2646,7 +2669,23 @@ function HarnessSettingsPanel({ state, adapter, onClose, recommendedChange = nul
|
|
|
2646
2669
|
] })
|
|
2647
2670
|
] });
|
|
2648
2671
|
}
|
|
2649
|
-
|
|
2672
|
+
var ACTIVE_AUTHENTICATION_PHASES = /* @__PURE__ */ new Set(["checking", "launching", "awaiting_user", "verifying"]);
|
|
2673
|
+
function HarnessAuthenticationButton({ item, state, adapter }) {
|
|
2674
|
+
if (!item.installed || !["claude-code", "codex"].includes(item.id) || ["ready", "configured"].includes(item.auth)) return null;
|
|
2675
|
+
const flow = state?.harnessAuthentication?.harness === item.id ? state.harnessAuthentication : null;
|
|
2676
|
+
const busy = flow && ACTIVE_AUTHENTICATION_PHASES.has(flow.phase);
|
|
2677
|
+
const completed = flow?.phase === "authenticated";
|
|
2678
|
+
const label = flow?.phase === "checking" ? "Checking\u2026" : flow?.phase === "launching" ? "Opening\u2026" : flow?.phase === "awaiting_user" ? "Finish sign-in" : flow?.phase === "verifying" ? "Verifying\u2026" : flow?.phase === "authenticated" ? "Signed in" : flow?.phase === "failed" ? "Try again" : "Sign in";
|
|
2679
|
+
return /* @__PURE__ */ jsx10("button", { type: "button", disabled: Boolean(busy || completed), "aria-busy": Boolean(busy), onClick: () => adapter?.onIntent({ action: "authenticateHarness", harness: item.id }), children: label });
|
|
2680
|
+
}
|
|
2681
|
+
function canAuthenticateHarness(item) {
|
|
2682
|
+
return item.installed && ["claude-code", "codex"].includes(item.id) && !["ready", "configured"].includes(item.auth);
|
|
2683
|
+
}
|
|
2684
|
+
function harnessAuthenticationReason(item, state) {
|
|
2685
|
+
const flow = state?.harnessAuthentication?.harness === item.id ? state.harnessAuthentication : null;
|
|
2686
|
+
return flow?.error?.message || flow?.plan?.instructions || item.reason || (item.auth === "required" ? "Authentication required" : "Unavailable");
|
|
2687
|
+
}
|
|
2688
|
+
function HarnessReadiness({ harnesses, state, adapter }) {
|
|
2650
2689
|
const blocked = harnesses.filter((item) => !item.startable);
|
|
2651
2690
|
if (!blocked.length || harnesses.some((item) => item.startable)) return null;
|
|
2652
2691
|
return /* @__PURE__ */ jsxs9("details", { className: "scui-readiness", open: true, children: [
|
|
@@ -2655,18 +2694,19 @@ function HarnessReadiness({ harnesses, adapter }) {
|
|
|
2655
2694
|
/* @__PURE__ */ jsx10(HarnessLogo, { id: item.id, size: 25 }),
|
|
2656
2695
|
/* @__PURE__ */ jsxs9("span", { children: [
|
|
2657
2696
|
/* @__PURE__ */ jsx10("strong", { children: item.label }),
|
|
2658
|
-
/* @__PURE__ */ jsx10("small", { children:
|
|
2697
|
+
/* @__PURE__ */ jsx10("small", { children: harnessAuthenticationReason(item, state) }),
|
|
2659
2698
|
item.protocol ? /* @__PURE__ */ jsxs9("em", { children: [
|
|
2660
2699
|
item.protocol,
|
|
2661
2700
|
" \xB7 ",
|
|
2662
2701
|
item.runtime
|
|
2663
2702
|
] }) : null
|
|
2664
2703
|
] }),
|
|
2665
|
-
|
|
2704
|
+
/* @__PURE__ */ jsx10(HarnessAuthenticationButton, { item, state, adapter }),
|
|
2705
|
+
!canAuthenticateHarness(item) && item.repair ? /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => adapter.copyText?.(item.repair), children: "Copy fix" }) : null
|
|
2666
2706
|
] }, item.id)) })
|
|
2667
2707
|
] });
|
|
2668
2708
|
}
|
|
2669
|
-
function HarnessPicker({ harnesses, value, disabled = false, adapter, onChange, logo: Logo = HarnessLogo }) {
|
|
2709
|
+
function HarnessPicker({ harnesses, state, value, disabled = false, adapter, onChange, logo: Logo = HarnessLogo }) {
|
|
2670
2710
|
const [open, setOpen] = useState6(false);
|
|
2671
2711
|
const menuId = useId2();
|
|
2672
2712
|
const root = useRef7(null);
|
|
@@ -2731,9 +2771,10 @@ function HarnessPicker({ harnesses, value, disabled = false, adapter, onChange,
|
|
|
2731
2771
|
/* @__PURE__ */ jsx10(Logo, { id: item.id, size: 24 }),
|
|
2732
2772
|
/* @__PURE__ */ jsxs9("span", { children: [
|
|
2733
2773
|
/* @__PURE__ */ jsx10("strong", { children: item.label }),
|
|
2734
|
-
/* @__PURE__ */ jsx10("small", { children:
|
|
2774
|
+
/* @__PURE__ */ jsx10("small", { children: harnessAuthenticationReason(item, state) })
|
|
2735
2775
|
] }),
|
|
2736
|
-
|
|
2776
|
+
/* @__PURE__ */ jsx10(HarnessAuthenticationButton, { item, state, adapter }),
|
|
2777
|
+
!canAuthenticateHarness(item) && item.repair ? /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => adapter?.copyText?.(item.repair), children: "Copy fix" }) : null
|
|
2737
2778
|
] }, item.id)) })
|
|
2738
2779
|
] }) : null
|
|
2739
2780
|
] }) : null
|
|
@@ -3231,7 +3272,7 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
3231
3272
|
} }),
|
|
3232
3273
|
/* @__PURE__ */ jsxs10("footer", { className: "scui-new-envelope-controls", children: [
|
|
3233
3274
|
adapter.pickContext ? /* @__PURE__ */ jsx11("button", { className: "scui-attach", type: "button", "aria-label": labels.attachContext ?? DEFAULT_LABELS.attachContext, disabled: mode === "terminal" || picking || context.length >= MAX_CONTEXT_ITEMS && images.length >= MAX_IMAGE_ITEMS || Boolean(starting), onClick: pickContext, children: picking ? /* @__PURE__ */ jsx11("i", { className: "scui-control-spinner" }) : /* @__PURE__ */ jsx11(UiIcon, { name: "attach", size: 17 }) }) : null,
|
|
3234
|
-
/* @__PURE__ */ jsx11(Picker, { harnesses: state.harnesses, value: harness, disabled: Boolean(starting), adapter, logo: components.HarnessLogo, onChange: (value) => {
|
|
3275
|
+
/* @__PURE__ */ jsx11(Picker, { harnesses: state.harnesses, state, value: harness, disabled: Boolean(starting), adapter, logo: components.HarnessLogo, onChange: (value) => {
|
|
3235
3276
|
setHarness(value);
|
|
3236
3277
|
remember({ harness: value });
|
|
3237
3278
|
} }),
|
package/composer.mjs
CHANGED
package/controller.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type {
|
|
2
|
+
HarnessId,
|
|
2
3
|
SessionArtifact,
|
|
3
4
|
SessionDescriptor,
|
|
4
5
|
SessionFormat,
|
|
@@ -128,6 +129,29 @@ export interface ControllerBindingOptions {
|
|
|
128
129
|
onCloseSubagents?: () => void | Promise<void>;
|
|
129
130
|
onStartTerminal?: (intent: Extract<SupercodeUiIntent, { action: 'new' }>) => void | Promise<void>;
|
|
130
131
|
onResumeTerminal?: (intent: Extract<SupercodeUiIntent, { action: 'resume' }>) => void | Promise<void>;
|
|
132
|
+
/** Shared Supercode authentication lifecycle. The host-specific execution adapter is injected
|
|
133
|
+
* when constructing this controller; the UI only observes and starts the flow. */
|
|
134
|
+
authentication?: {
|
|
135
|
+
getSnapshot(): unknown;
|
|
136
|
+
subscribe(listener: () => void): () => void;
|
|
137
|
+
authenticate(harness: HarnessId, request?: {
|
|
138
|
+
environment?: 'local_browser' | 'headless';
|
|
139
|
+
method?: 'browser' | 'device_code';
|
|
140
|
+
cwd?: string;
|
|
141
|
+
}): Promise<{ phase: string }>;
|
|
142
|
+
};
|
|
143
|
+
authenticationRequest?: (intent: Extract<SupercodeUiIntent, { action: 'authenticateHarness' }>) => {
|
|
144
|
+
environment?: 'local_browser' | 'headless';
|
|
145
|
+
method?: 'browser' | 'device_code';
|
|
146
|
+
cwd?: string;
|
|
147
|
+
} | Promise<{
|
|
148
|
+
environment?: 'local_browser' | 'headless';
|
|
149
|
+
method?: 'browser' | 'device_code';
|
|
150
|
+
cwd?: string;
|
|
151
|
+
}>;
|
|
152
|
+
/** Launch the native harness-owned sign-in flow. The host owns the process and terminal. */
|
|
153
|
+
/** @deprecated Prefer `authentication`; retained for custom legacy hosts. */
|
|
154
|
+
onAuthenticateHarness?: (intent: Extract<SupercodeUiIntent, { action: 'authenticateHarness' }>) => void | Promise<void>;
|
|
131
155
|
copyText?: UiAdapter['copyText'];
|
|
132
156
|
resolveImage?: UiAdapter['resolveImage'];
|
|
133
157
|
confirmIntent?: UiAdapter['confirmIntent'];
|
package/controller.mjs
CHANGED
|
@@ -669,6 +669,19 @@ export async function dispatchControllerIntent(controller, intent, options = {})
|
|
|
669
669
|
if (intent.action === 'terminal') return controller.dispatch({ type: 'openTerminal' });
|
|
670
670
|
if (intent.action === 'interrupt') return controller.dispatch({ type: 'interrupt' });
|
|
671
671
|
if (intent.action === 'respond') return controller.dispatch({ type: 'respond', requestId: intent.requestId, optionId: intent.optionId });
|
|
672
|
+
if (intent.action === 'authenticateHarness') {
|
|
673
|
+
if (options.authentication) {
|
|
674
|
+
const request = (await options.authenticationRequest?.(intent)) ?? {};
|
|
675
|
+
const result = await options.authentication.authenticate(intent.harness, request);
|
|
676
|
+
if (result?.phase === 'authenticated') {
|
|
677
|
+
await controller.dispatch({ type: 'refresh', autoObserve: false, silent: true });
|
|
678
|
+
}
|
|
679
|
+
return;
|
|
680
|
+
}
|
|
681
|
+
return options.onAuthenticateHarness
|
|
682
|
+
? options.onAuthenticateHarness(intent)
|
|
683
|
+
: options.onUnsupported?.(intent);
|
|
684
|
+
}
|
|
672
685
|
if (intent.action === 'configureHarness') return controller.dispatch({
|
|
673
686
|
type: 'configureHarness',
|
|
674
687
|
harness: intent.harness,
|
|
@@ -700,7 +713,12 @@ export function createControllerBinding(controller, options = {}) {
|
|
|
700
713
|
if (!controller || typeof controller.getSnapshot !== 'function' || typeof controller.subscribe !== 'function' || typeof controller.dispatch !== 'function') {
|
|
701
714
|
throw new TypeError('createControllerBinding requires a SupercodeController-compatible object');
|
|
702
715
|
}
|
|
703
|
-
const getState = () =>
|
|
716
|
+
const getState = () => {
|
|
717
|
+
const state = projectClientSnapshot(controller.getSnapshot(), options.projection?.() ?? {});
|
|
718
|
+
return options.authentication
|
|
719
|
+
? normalizeUiState({ ...state, harnessAuthentication: options.authentication.getSnapshot() })
|
|
720
|
+
: state;
|
|
721
|
+
};
|
|
704
722
|
const adapter = {
|
|
705
723
|
onIntent(intent) {
|
|
706
724
|
return Promise.resolve(options.onIntent?.(intent))
|
|
@@ -719,7 +737,11 @@ export function createControllerBinding(controller, options = {}) {
|
|
|
719
737
|
adapter,
|
|
720
738
|
getState,
|
|
721
739
|
subscribe(listener) {
|
|
722
|
-
|
|
740
|
+
const unsubscribers = [controller.subscribe(() => listener(getState()))];
|
|
741
|
+
if (options.authentication?.subscribe) {
|
|
742
|
+
unsubscribers.push(options.authentication.subscribe(() => listener(getState())));
|
|
743
|
+
}
|
|
744
|
+
return () => { for (const unsubscribe of unsubscribers) unsubscribe(); };
|
|
723
745
|
},
|
|
724
746
|
};
|
|
725
747
|
}
|
package/conversation.mjs
CHANGED
package/core.mjs
CHANGED
|
@@ -56,6 +56,7 @@ export const EMPTY_UI_STATE = Object.freeze({
|
|
|
56
56
|
reductionReceipt: null,
|
|
57
57
|
interopSettings: null,
|
|
58
58
|
interopSettingsError: null,
|
|
59
|
+
harnessAuthentication: null,
|
|
59
60
|
error: null,
|
|
60
61
|
recoverable: false,
|
|
61
62
|
harnesses: Object.freeze([]),
|
|
@@ -76,6 +77,7 @@ const STARTUP = new Set(['connecting', 'starting', 'discovering', 'ready']);
|
|
|
76
77
|
const FIDELITY = new Set(['byte_lossless', 'value_lossless', 'semantic']);
|
|
77
78
|
const TOOL_CATEGORIES = new Set(['read', 'search', 'edit', 'command', 'test', 'web', 'agent', 'plan', 'other']);
|
|
78
79
|
const TOOL_DETAILS = new Set(['file', 'matches', 'diff', 'terminal', 'web', 'agent', 'plan', 'fields']);
|
|
80
|
+
const AUTHENTICATION_PHASES = new Set(['idle', 'checking', 'required', 'configured', 'unavailable', 'launching', 'awaiting_user', 'verifying', 'authenticated', 'failed', 'cancelled']);
|
|
79
81
|
const MAX_TOOL_FIELDS = 8;
|
|
80
82
|
const MAX_TOOL_FIELD_CHARS = 800;
|
|
81
83
|
const MAX_TOOL_PREVIEW_CHARS = 4_000;
|
|
@@ -84,6 +86,29 @@ function record(value) {
|
|
|
84
86
|
return value !== null && typeof value === 'object' && !Array.isArray(value) ? value : null;
|
|
85
87
|
}
|
|
86
88
|
|
|
89
|
+
function readHarnessAuthentication(value) {
|
|
90
|
+
const flow = record(value);
|
|
91
|
+
if (flow?.schema !== 'supercode.harness-authentication-flow.v1' || !AUTHENTICATION_PHASES.has(flow.phase)) return null;
|
|
92
|
+
const plan = record(flow.plan);
|
|
93
|
+
const error = record(flow.error);
|
|
94
|
+
return {
|
|
95
|
+
schema: 'supercode.harness-authentication-flow.v1',
|
|
96
|
+
revision: Number.isSafeInteger(flow.revision) ? Math.max(0, flow.revision) : 0,
|
|
97
|
+
phase: flow.phase,
|
|
98
|
+
harness: typeof flow.harness === 'string' ? boundedString(flow.harness, 100) : null,
|
|
99
|
+
plan: plan ? {
|
|
100
|
+
method: plan.method === 'device_code' ? 'device_code' : 'browser',
|
|
101
|
+
interaction: plan.interaction === 'device_code' ? 'device_code' : 'browser',
|
|
102
|
+
browserBehavior: plan.browserBehavior === 'none' ? 'none' : 'native_auto',
|
|
103
|
+
headless: plan.headless === true,
|
|
104
|
+
instructions: boundedString(plan.instructions, 2_000),
|
|
105
|
+
} : null,
|
|
106
|
+
error: error && typeof error.message === 'string'
|
|
107
|
+
? { code: boundedString(error.code, 100), message: boundedString(error.message, 2_000) }
|
|
108
|
+
: null,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
87
112
|
function string(value, fallback = '') {
|
|
88
113
|
return typeof value === 'string' ? value : fallback;
|
|
89
114
|
}
|
|
@@ -819,6 +844,7 @@ export function normalizeUiState(value) {
|
|
|
819
844
|
reductionReceipt: readReductionReceipt(raw.reductionReceipt),
|
|
820
845
|
interopSettings: readInteropSettings(raw.interopSettings),
|
|
821
846
|
interopSettingsError: typeof raw.interopSettingsError === 'string' ? boundedString(raw.interopSettingsError) : null,
|
|
847
|
+
harnessAuthentication: readHarnessAuthentication(raw.harnessAuthentication),
|
|
822
848
|
error: typeof raw.error === 'string' ? raw.error : null,
|
|
823
849
|
recoverable: raw.recoverable === true,
|
|
824
850
|
harnesses: Array.isArray(raw.harnesses) ? raw.harnesses.flatMap((candidate) => {
|
|
@@ -1165,6 +1191,11 @@ export function parseSupercodeUiIntent(value) {
|
|
|
1165
1191
|
? { action: 'respond', requestId: intent.requestId, optionId: intent.optionId }
|
|
1166
1192
|
: null;
|
|
1167
1193
|
}
|
|
1194
|
+
if (intent.action === 'authenticateHarness') {
|
|
1195
|
+
return exact('harness') && typeof intent.harness === 'string' && intent.harness.trim() && intent.harness.length <= 100
|
|
1196
|
+
? { action: 'authenticateHarness', harness: intent.harness.trim() }
|
|
1197
|
+
: null;
|
|
1198
|
+
}
|
|
1168
1199
|
if (intent.action === 'configureHarness') {
|
|
1169
1200
|
if (!exact('harness', 'changes', 'expectedRevision')) return null;
|
|
1170
1201
|
if (typeof intent.harness !== 'string' || !intent.harness || intent.harness.length > 100) return null;
|
package/embed.mjs
CHANGED
|
@@ -61,6 +61,7 @@ var EMPTY_UI_STATE = Object.freeze({
|
|
|
61
61
|
reductionReceipt: null,
|
|
62
62
|
interopSettings: null,
|
|
63
63
|
interopSettingsError: null,
|
|
64
|
+
harnessAuthentication: null,
|
|
64
65
|
error: null,
|
|
65
66
|
recoverable: false,
|
|
66
67
|
harnesses: Object.freeze([]),
|
|
@@ -80,12 +81,33 @@ var STARTUP = /* @__PURE__ */ new Set(["connecting", "starting", "discovering",
|
|
|
80
81
|
var FIDELITY = /* @__PURE__ */ new Set(["byte_lossless", "value_lossless", "semantic"]);
|
|
81
82
|
var TOOL_CATEGORIES = /* @__PURE__ */ new Set(["read", "search", "edit", "command", "test", "web", "agent", "plan", "other"]);
|
|
82
83
|
var TOOL_DETAILS = /* @__PURE__ */ new Set(["file", "matches", "diff", "terminal", "web", "agent", "plan", "fields"]);
|
|
84
|
+
var AUTHENTICATION_PHASES = /* @__PURE__ */ new Set(["idle", "checking", "required", "configured", "unavailable", "launching", "awaiting_user", "verifying", "authenticated", "failed", "cancelled"]);
|
|
83
85
|
var MAX_TOOL_FIELDS = 8;
|
|
84
86
|
var MAX_TOOL_FIELD_CHARS = 800;
|
|
85
87
|
var MAX_TOOL_PREVIEW_CHARS = 4e3;
|
|
86
88
|
function record(value) {
|
|
87
89
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
88
90
|
}
|
|
91
|
+
function readHarnessAuthentication(value) {
|
|
92
|
+
const flow = record(value);
|
|
93
|
+
if (flow?.schema !== "supercode.harness-authentication-flow.v1" || !AUTHENTICATION_PHASES.has(flow.phase)) return null;
|
|
94
|
+
const plan = record(flow.plan);
|
|
95
|
+
const error = record(flow.error);
|
|
96
|
+
return {
|
|
97
|
+
schema: "supercode.harness-authentication-flow.v1",
|
|
98
|
+
revision: Number.isSafeInteger(flow.revision) ? Math.max(0, flow.revision) : 0,
|
|
99
|
+
phase: flow.phase,
|
|
100
|
+
harness: typeof flow.harness === "string" ? boundedString(flow.harness, 100) : null,
|
|
101
|
+
plan: plan ? {
|
|
102
|
+
method: plan.method === "device_code" ? "device_code" : "browser",
|
|
103
|
+
interaction: plan.interaction === "device_code" ? "device_code" : "browser",
|
|
104
|
+
browserBehavior: plan.browserBehavior === "none" ? "none" : "native_auto",
|
|
105
|
+
headless: plan.headless === true,
|
|
106
|
+
instructions: boundedString(plan.instructions, 2e3)
|
|
107
|
+
} : null,
|
|
108
|
+
error: error && typeof error.message === "string" ? { code: boundedString(error.code, 100), message: boundedString(error.message, 2e3) } : null
|
|
109
|
+
};
|
|
110
|
+
}
|
|
89
111
|
function string(value, fallback = "") {
|
|
90
112
|
return typeof value === "string" ? value : fallback;
|
|
91
113
|
}
|
|
@@ -769,6 +791,7 @@ function normalizeUiState(value) {
|
|
|
769
791
|
reductionReceipt: readReductionReceipt(raw.reductionReceipt),
|
|
770
792
|
interopSettings: readInteropSettings(raw.interopSettings),
|
|
771
793
|
interopSettingsError: typeof raw.interopSettingsError === "string" ? boundedString(raw.interopSettingsError) : null,
|
|
794
|
+
harnessAuthentication: readHarnessAuthentication(raw.harnessAuthentication),
|
|
772
795
|
error: typeof raw.error === "string" ? raw.error : null,
|
|
773
796
|
recoverable: raw.recoverable === true,
|
|
774
797
|
harnesses: Array.isArray(raw.harnesses) ? raw.harnesses.flatMap((candidate) => {
|
|
@@ -2563,7 +2586,23 @@ function HarnessSettingsPanel({ state, adapter, onClose, recommendedChange = nul
|
|
|
2563
2586
|
] })
|
|
2564
2587
|
] });
|
|
2565
2588
|
}
|
|
2566
|
-
|
|
2589
|
+
var ACTIVE_AUTHENTICATION_PHASES = /* @__PURE__ */ new Set(["checking", "launching", "awaiting_user", "verifying"]);
|
|
2590
|
+
function HarnessAuthenticationButton({ item, state, adapter }) {
|
|
2591
|
+
if (!item.installed || !["claude-code", "codex"].includes(item.id) || ["ready", "configured"].includes(item.auth)) return null;
|
|
2592
|
+
const flow = state?.harnessAuthentication?.harness === item.id ? state.harnessAuthentication : null;
|
|
2593
|
+
const busy = flow && ACTIVE_AUTHENTICATION_PHASES.has(flow.phase);
|
|
2594
|
+
const completed = flow?.phase === "authenticated";
|
|
2595
|
+
const label = flow?.phase === "checking" ? "Checking\u2026" : flow?.phase === "launching" ? "Opening\u2026" : flow?.phase === "awaiting_user" ? "Finish sign-in" : flow?.phase === "verifying" ? "Verifying\u2026" : flow?.phase === "authenticated" ? "Signed in" : flow?.phase === "failed" ? "Try again" : "Sign in";
|
|
2596
|
+
return /* @__PURE__ */ jsx9("button", { type: "button", disabled: Boolean(busy || completed), "aria-busy": Boolean(busy), onClick: () => adapter?.onIntent({ action: "authenticateHarness", harness: item.id }), children: label });
|
|
2597
|
+
}
|
|
2598
|
+
function canAuthenticateHarness(item) {
|
|
2599
|
+
return item.installed && ["claude-code", "codex"].includes(item.id) && !["ready", "configured"].includes(item.auth);
|
|
2600
|
+
}
|
|
2601
|
+
function harnessAuthenticationReason(item, state) {
|
|
2602
|
+
const flow = state?.harnessAuthentication?.harness === item.id ? state.harnessAuthentication : null;
|
|
2603
|
+
return flow?.error?.message || flow?.plan?.instructions || item.reason || (item.auth === "required" ? "Authentication required" : "Unavailable");
|
|
2604
|
+
}
|
|
2605
|
+
function HarnessReadiness({ harnesses, state, adapter }) {
|
|
2567
2606
|
const blocked = harnesses.filter((item) => !item.startable);
|
|
2568
2607
|
if (!blocked.length || harnesses.some((item) => item.startable)) return null;
|
|
2569
2608
|
return /* @__PURE__ */ jsxs8("details", { className: "scui-readiness", open: true, children: [
|
|
@@ -2572,18 +2611,19 @@ function HarnessReadiness({ harnesses, adapter }) {
|
|
|
2572
2611
|
/* @__PURE__ */ jsx9(HarnessLogo, { id: item.id, size: 25 }),
|
|
2573
2612
|
/* @__PURE__ */ jsxs8("span", { children: [
|
|
2574
2613
|
/* @__PURE__ */ jsx9("strong", { children: item.label }),
|
|
2575
|
-
/* @__PURE__ */ jsx9("small", { children:
|
|
2614
|
+
/* @__PURE__ */ jsx9("small", { children: harnessAuthenticationReason(item, state) }),
|
|
2576
2615
|
item.protocol ? /* @__PURE__ */ jsxs8("em", { children: [
|
|
2577
2616
|
item.protocol,
|
|
2578
2617
|
" \xB7 ",
|
|
2579
2618
|
item.runtime
|
|
2580
2619
|
] }) : null
|
|
2581
2620
|
] }),
|
|
2582
|
-
|
|
2621
|
+
/* @__PURE__ */ jsx9(HarnessAuthenticationButton, { item, state, adapter }),
|
|
2622
|
+
!canAuthenticateHarness(item) && item.repair ? /* @__PURE__ */ jsx9("button", { type: "button", onClick: () => adapter.copyText?.(item.repair), children: "Copy fix" }) : null
|
|
2583
2623
|
] }, item.id)) })
|
|
2584
2624
|
] });
|
|
2585
2625
|
}
|
|
2586
|
-
function HarnessPicker({ harnesses, value, disabled = false, adapter, onChange, logo: Logo = HarnessLogo }) {
|
|
2626
|
+
function HarnessPicker({ harnesses, state, value, disabled = false, adapter, onChange, logo: Logo = HarnessLogo }) {
|
|
2587
2627
|
const [open, setOpen] = useState6(false);
|
|
2588
2628
|
const menuId = useId2();
|
|
2589
2629
|
const root = useRef7(null);
|
|
@@ -2648,9 +2688,10 @@ function HarnessPicker({ harnesses, value, disabled = false, adapter, onChange,
|
|
|
2648
2688
|
/* @__PURE__ */ jsx9(Logo, { id: item.id, size: 24 }),
|
|
2649
2689
|
/* @__PURE__ */ jsxs8("span", { children: [
|
|
2650
2690
|
/* @__PURE__ */ jsx9("strong", { children: item.label }),
|
|
2651
|
-
/* @__PURE__ */ jsx9("small", { children:
|
|
2691
|
+
/* @__PURE__ */ jsx9("small", { children: harnessAuthenticationReason(item, state) })
|
|
2652
2692
|
] }),
|
|
2653
|
-
|
|
2693
|
+
/* @__PURE__ */ jsx9(HarnessAuthenticationButton, { item, state, adapter }),
|
|
2694
|
+
!canAuthenticateHarness(item) && item.repair ? /* @__PURE__ */ jsx9("button", { type: "button", onClick: () => adapter?.copyText?.(item.repair), children: "Copy fix" }) : null
|
|
2654
2695
|
] }, item.id)) })
|
|
2655
2696
|
] }) : null
|
|
2656
2697
|
] }) : null
|
|
@@ -3148,7 +3189,7 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
3148
3189
|
} }),
|
|
3149
3190
|
/* @__PURE__ */ jsxs9("footer", { className: "scui-new-envelope-controls", children: [
|
|
3150
3191
|
adapter.pickContext ? /* @__PURE__ */ jsx10("button", { className: "scui-attach", type: "button", "aria-label": labels.attachContext ?? DEFAULT_LABELS.attachContext, 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,
|
|
3151
|
-
/* @__PURE__ */ jsx10(Picker, { harnesses: state.harnesses, value: harness, disabled: Boolean(starting), adapter, logo: components.HarnessLogo, onChange: (value) => {
|
|
3192
|
+
/* @__PURE__ */ jsx10(Picker, { harnesses: state.harnesses, state, value: harness, disabled: Boolean(starting), adapter, logo: components.HarnessLogo, onChange: (value) => {
|
|
3152
3193
|
setHarness(value);
|
|
3153
3194
|
remember({ harness: value });
|
|
3154
3195
|
} }),
|
package/index.d.ts
CHANGED
|
@@ -258,6 +258,21 @@ export interface HarnessInteropSettingsModel {
|
|
|
258
258
|
advisories: HarnessInteropAdvisoryModel[];
|
|
259
259
|
}
|
|
260
260
|
|
|
261
|
+
export interface HarnessAuthenticationUiState {
|
|
262
|
+
schema: 'supercode.harness-authentication-flow.v1';
|
|
263
|
+
revision: number;
|
|
264
|
+
phase: 'idle' | 'checking' | 'required' | 'configured' | 'unavailable' | 'launching' | 'awaiting_user' | 'verifying' | 'authenticated' | 'failed' | 'cancelled';
|
|
265
|
+
harness: HarnessId | null;
|
|
266
|
+
plan: {
|
|
267
|
+
method: 'browser' | 'device_code';
|
|
268
|
+
interaction: 'browser' | 'device_code';
|
|
269
|
+
browserBehavior: 'native_auto' | 'none';
|
|
270
|
+
headless: boolean;
|
|
271
|
+
instructions: string;
|
|
272
|
+
} | null;
|
|
273
|
+
error: { code: string; message: string } | null;
|
|
274
|
+
}
|
|
275
|
+
|
|
261
276
|
export interface SessionAttention {
|
|
262
277
|
key: string;
|
|
263
278
|
kind: 'unseen' | 'finished' | 'failed';
|
|
@@ -314,6 +329,7 @@ export interface SupercodeUiState {
|
|
|
314
329
|
reductionReceipt: ReductionReceiptModel | null;
|
|
315
330
|
interopSettings: HarnessInteropSettingsModel | null;
|
|
316
331
|
interopSettingsError: string | null;
|
|
332
|
+
harnessAuthentication: HarnessAuthenticationUiState | null;
|
|
317
333
|
error: string | null;
|
|
318
334
|
recoverable: boolean;
|
|
319
335
|
harnesses: HarnessOption[];
|
|
@@ -355,6 +371,7 @@ export type SupercodeUiIntent =
|
|
|
355
371
|
| { action: 'export'; targetHarness: HarnessId }
|
|
356
372
|
| { action: 'interrupt' }
|
|
357
373
|
| { action: 'respond'; requestId: unknown; optionId: string | null }
|
|
374
|
+
| { action: 'authenticateHarness'; harness: HarnessId }
|
|
358
375
|
| { action: 'configureHarness'; harness: HarnessId; changes: HarnessSettingChangeModel[]; expectedRevision: string }
|
|
359
376
|
| { action: 'refresh' }
|
|
360
377
|
| { action: 'release' };
|
|
@@ -467,9 +484,10 @@ export interface HarnessSettingsPanelProps {
|
|
|
467
484
|
|
|
468
485
|
export interface HarnessPickerProps {
|
|
469
486
|
harnesses: HarnessOption[];
|
|
487
|
+
state?: SupercodeUiState;
|
|
470
488
|
value: HarnessId;
|
|
471
489
|
disabled?: boolean;
|
|
472
|
-
adapter?: Pick<UiAdapter, 'copyText'>;
|
|
490
|
+
adapter?: Pick<UiAdapter, 'copyText' | 'onIntent'>;
|
|
473
491
|
onChange(harness: HarnessId): void;
|
|
474
492
|
logo?: ComponentType<{ id: HarnessId; activity?: SessionActivity; size?: number }>;
|
|
475
493
|
}
|
package/messenger.mjs
CHANGED
|
@@ -58,6 +58,7 @@ var EMPTY_UI_STATE = Object.freeze({
|
|
|
58
58
|
reductionReceipt: null,
|
|
59
59
|
interopSettings: null,
|
|
60
60
|
interopSettingsError: null,
|
|
61
|
+
harnessAuthentication: null,
|
|
61
62
|
error: null,
|
|
62
63
|
recoverable: false,
|
|
63
64
|
harnesses: Object.freeze([]),
|
|
@@ -77,12 +78,33 @@ var STARTUP = /* @__PURE__ */ new Set(["connecting", "starting", "discovering",
|
|
|
77
78
|
var FIDELITY = /* @__PURE__ */ new Set(["byte_lossless", "value_lossless", "semantic"]);
|
|
78
79
|
var TOOL_CATEGORIES = /* @__PURE__ */ new Set(["read", "search", "edit", "command", "test", "web", "agent", "plan", "other"]);
|
|
79
80
|
var TOOL_DETAILS = /* @__PURE__ */ new Set(["file", "matches", "diff", "terminal", "web", "agent", "plan", "fields"]);
|
|
81
|
+
var AUTHENTICATION_PHASES = /* @__PURE__ */ new Set(["idle", "checking", "required", "configured", "unavailable", "launching", "awaiting_user", "verifying", "authenticated", "failed", "cancelled"]);
|
|
80
82
|
var MAX_TOOL_FIELDS = 8;
|
|
81
83
|
var MAX_TOOL_FIELD_CHARS = 800;
|
|
82
84
|
var MAX_TOOL_PREVIEW_CHARS = 4e3;
|
|
83
85
|
function record(value) {
|
|
84
86
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
85
87
|
}
|
|
88
|
+
function readHarnessAuthentication(value) {
|
|
89
|
+
const flow = record(value);
|
|
90
|
+
if (flow?.schema !== "supercode.harness-authentication-flow.v1" || !AUTHENTICATION_PHASES.has(flow.phase)) return null;
|
|
91
|
+
const plan = record(flow.plan);
|
|
92
|
+
const error = record(flow.error);
|
|
93
|
+
return {
|
|
94
|
+
schema: "supercode.harness-authentication-flow.v1",
|
|
95
|
+
revision: Number.isSafeInteger(flow.revision) ? Math.max(0, flow.revision) : 0,
|
|
96
|
+
phase: flow.phase,
|
|
97
|
+
harness: typeof flow.harness === "string" ? boundedString(flow.harness, 100) : null,
|
|
98
|
+
plan: plan ? {
|
|
99
|
+
method: plan.method === "device_code" ? "device_code" : "browser",
|
|
100
|
+
interaction: plan.interaction === "device_code" ? "device_code" : "browser",
|
|
101
|
+
browserBehavior: plan.browserBehavior === "none" ? "none" : "native_auto",
|
|
102
|
+
headless: plan.headless === true,
|
|
103
|
+
instructions: boundedString(plan.instructions, 2e3)
|
|
104
|
+
} : null,
|
|
105
|
+
error: error && typeof error.message === "string" ? { code: boundedString(error.code, 100), message: boundedString(error.message, 2e3) } : null
|
|
106
|
+
};
|
|
107
|
+
}
|
|
86
108
|
function string(value, fallback = "") {
|
|
87
109
|
return typeof value === "string" ? value : fallback;
|
|
88
110
|
}
|
|
@@ -766,6 +788,7 @@ function normalizeUiState(value) {
|
|
|
766
788
|
reductionReceipt: readReductionReceipt(raw.reductionReceipt),
|
|
767
789
|
interopSettings: readInteropSettings(raw.interopSettings),
|
|
768
790
|
interopSettingsError: typeof raw.interopSettingsError === "string" ? boundedString(raw.interopSettingsError) : null,
|
|
791
|
+
harnessAuthentication: readHarnessAuthentication(raw.harnessAuthentication),
|
|
769
792
|
error: typeof raw.error === "string" ? raw.error : null,
|
|
770
793
|
recoverable: raw.recoverable === true,
|
|
771
794
|
harnesses: Array.isArray(raw.harnesses) ? raw.harnesses.flatMap((candidate) => {
|
|
@@ -2560,7 +2583,23 @@ function HarnessSettingsPanel({ state, adapter, onClose, recommendedChange = nul
|
|
|
2560
2583
|
] })
|
|
2561
2584
|
] });
|
|
2562
2585
|
}
|
|
2563
|
-
|
|
2586
|
+
var ACTIVE_AUTHENTICATION_PHASES = /* @__PURE__ */ new Set(["checking", "launching", "awaiting_user", "verifying"]);
|
|
2587
|
+
function HarnessAuthenticationButton({ item, state, adapter }) {
|
|
2588
|
+
if (!item.installed || !["claude-code", "codex"].includes(item.id) || ["ready", "configured"].includes(item.auth)) return null;
|
|
2589
|
+
const flow = state?.harnessAuthentication?.harness === item.id ? state.harnessAuthentication : null;
|
|
2590
|
+
const busy = flow && ACTIVE_AUTHENTICATION_PHASES.has(flow.phase);
|
|
2591
|
+
const completed = flow?.phase === "authenticated";
|
|
2592
|
+
const label = flow?.phase === "checking" ? "Checking\u2026" : flow?.phase === "launching" ? "Opening\u2026" : flow?.phase === "awaiting_user" ? "Finish sign-in" : flow?.phase === "verifying" ? "Verifying\u2026" : flow?.phase === "authenticated" ? "Signed in" : flow?.phase === "failed" ? "Try again" : "Sign in";
|
|
2593
|
+
return /* @__PURE__ */ jsx9("button", { type: "button", disabled: Boolean(busy || completed), "aria-busy": Boolean(busy), onClick: () => adapter?.onIntent({ action: "authenticateHarness", harness: item.id }), children: label });
|
|
2594
|
+
}
|
|
2595
|
+
function canAuthenticateHarness(item) {
|
|
2596
|
+
return item.installed && ["claude-code", "codex"].includes(item.id) && !["ready", "configured"].includes(item.auth);
|
|
2597
|
+
}
|
|
2598
|
+
function harnessAuthenticationReason(item, state) {
|
|
2599
|
+
const flow = state?.harnessAuthentication?.harness === item.id ? state.harnessAuthentication : null;
|
|
2600
|
+
return flow?.error?.message || flow?.plan?.instructions || item.reason || (item.auth === "required" ? "Authentication required" : "Unavailable");
|
|
2601
|
+
}
|
|
2602
|
+
function HarnessReadiness({ harnesses, state, adapter }) {
|
|
2564
2603
|
const blocked = harnesses.filter((item) => !item.startable);
|
|
2565
2604
|
if (!blocked.length || harnesses.some((item) => item.startable)) return null;
|
|
2566
2605
|
return /* @__PURE__ */ jsxs8("details", { className: "scui-readiness", open: true, children: [
|
|
@@ -2569,18 +2608,19 @@ function HarnessReadiness({ harnesses, adapter }) {
|
|
|
2569
2608
|
/* @__PURE__ */ jsx9(HarnessLogo, { id: item.id, size: 25 }),
|
|
2570
2609
|
/* @__PURE__ */ jsxs8("span", { children: [
|
|
2571
2610
|
/* @__PURE__ */ jsx9("strong", { children: item.label }),
|
|
2572
|
-
/* @__PURE__ */ jsx9("small", { children:
|
|
2611
|
+
/* @__PURE__ */ jsx9("small", { children: harnessAuthenticationReason(item, state) }),
|
|
2573
2612
|
item.protocol ? /* @__PURE__ */ jsxs8("em", { children: [
|
|
2574
2613
|
item.protocol,
|
|
2575
2614
|
" \xB7 ",
|
|
2576
2615
|
item.runtime
|
|
2577
2616
|
] }) : null
|
|
2578
2617
|
] }),
|
|
2579
|
-
|
|
2618
|
+
/* @__PURE__ */ jsx9(HarnessAuthenticationButton, { item, state, adapter }),
|
|
2619
|
+
!canAuthenticateHarness(item) && item.repair ? /* @__PURE__ */ jsx9("button", { type: "button", onClick: () => adapter.copyText?.(item.repair), children: "Copy fix" }) : null
|
|
2580
2620
|
] }, item.id)) })
|
|
2581
2621
|
] });
|
|
2582
2622
|
}
|
|
2583
|
-
function HarnessPicker({ harnesses, value, disabled = false, adapter, onChange, logo: Logo = HarnessLogo }) {
|
|
2623
|
+
function HarnessPicker({ harnesses, state, value, disabled = false, adapter, onChange, logo: Logo = HarnessLogo }) {
|
|
2584
2624
|
const [open, setOpen] = useState6(false);
|
|
2585
2625
|
const menuId = useId2();
|
|
2586
2626
|
const root = useRef7(null);
|
|
@@ -2645,9 +2685,10 @@ function HarnessPicker({ harnesses, value, disabled = false, adapter, onChange,
|
|
|
2645
2685
|
/* @__PURE__ */ jsx9(Logo, { id: item.id, size: 24 }),
|
|
2646
2686
|
/* @__PURE__ */ jsxs8("span", { children: [
|
|
2647
2687
|
/* @__PURE__ */ jsx9("strong", { children: item.label }),
|
|
2648
|
-
/* @__PURE__ */ jsx9("small", { children:
|
|
2688
|
+
/* @__PURE__ */ jsx9("small", { children: harnessAuthenticationReason(item, state) })
|
|
2649
2689
|
] }),
|
|
2650
|
-
|
|
2690
|
+
/* @__PURE__ */ jsx9(HarnessAuthenticationButton, { item, state, adapter }),
|
|
2691
|
+
!canAuthenticateHarness(item) && item.repair ? /* @__PURE__ */ jsx9("button", { type: "button", onClick: () => adapter?.copyText?.(item.repair), children: "Copy fix" }) : null
|
|
2651
2692
|
] }, item.id)) })
|
|
2652
2693
|
] }) : null
|
|
2653
2694
|
] }) : null
|
|
@@ -3145,7 +3186,7 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
3145
3186
|
} }),
|
|
3146
3187
|
/* @__PURE__ */ jsxs9("footer", { className: "scui-new-envelope-controls", children: [
|
|
3147
3188
|
adapter.pickContext ? /* @__PURE__ */ jsx10("button", { className: "scui-attach", type: "button", "aria-label": labels.attachContext ?? DEFAULT_LABELS.attachContext, 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,
|
|
3148
|
-
/* @__PURE__ */ jsx10(Picker, { harnesses: state.harnesses, value: harness, disabled: Boolean(starting), adapter, logo: components.HarnessLogo, onChange: (value) => {
|
|
3189
|
+
/* @__PURE__ */ jsx10(Picker, { harnesses: state.harnesses, state, value: harness, disabled: Boolean(starting), adapter, logo: components.HarnessLogo, onChange: (value) => {
|
|
3149
3190
|
setHarness(value);
|
|
3150
3191
|
remember({ harness: value });
|
|
3151
3192
|
} }),
|
package/package.json
CHANGED
package/react/activity.mjs
CHANGED
|
@@ -55,6 +55,7 @@ var EMPTY_UI_STATE = Object.freeze({
|
|
|
55
55
|
reductionReceipt: null,
|
|
56
56
|
interopSettings: null,
|
|
57
57
|
interopSettingsError: null,
|
|
58
|
+
harnessAuthentication: null,
|
|
58
59
|
error: null,
|
|
59
60
|
recoverable: false,
|
|
60
61
|
harnesses: Object.freeze([]),
|
|
@@ -74,12 +75,33 @@ var STARTUP = /* @__PURE__ */ new Set(["connecting", "starting", "discovering",
|
|
|
74
75
|
var FIDELITY = /* @__PURE__ */ new Set(["byte_lossless", "value_lossless", "semantic"]);
|
|
75
76
|
var TOOL_CATEGORIES = /* @__PURE__ */ new Set(["read", "search", "edit", "command", "test", "web", "agent", "plan", "other"]);
|
|
76
77
|
var TOOL_DETAILS = /* @__PURE__ */ new Set(["file", "matches", "diff", "terminal", "web", "agent", "plan", "fields"]);
|
|
78
|
+
var AUTHENTICATION_PHASES = /* @__PURE__ */ new Set(["idle", "checking", "required", "configured", "unavailable", "launching", "awaiting_user", "verifying", "authenticated", "failed", "cancelled"]);
|
|
77
79
|
var MAX_TOOL_FIELDS = 8;
|
|
78
80
|
var MAX_TOOL_FIELD_CHARS = 800;
|
|
79
81
|
var MAX_TOOL_PREVIEW_CHARS = 4e3;
|
|
80
82
|
function record(value) {
|
|
81
83
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
82
84
|
}
|
|
85
|
+
function readHarnessAuthentication(value) {
|
|
86
|
+
const flow = record(value);
|
|
87
|
+
if (flow?.schema !== "supercode.harness-authentication-flow.v1" || !AUTHENTICATION_PHASES.has(flow.phase)) return null;
|
|
88
|
+
const plan = record(flow.plan);
|
|
89
|
+
const error = record(flow.error);
|
|
90
|
+
return {
|
|
91
|
+
schema: "supercode.harness-authentication-flow.v1",
|
|
92
|
+
revision: Number.isSafeInteger(flow.revision) ? Math.max(0, flow.revision) : 0,
|
|
93
|
+
phase: flow.phase,
|
|
94
|
+
harness: typeof flow.harness === "string" ? boundedString(flow.harness, 100) : null,
|
|
95
|
+
plan: plan ? {
|
|
96
|
+
method: plan.method === "device_code" ? "device_code" : "browser",
|
|
97
|
+
interaction: plan.interaction === "device_code" ? "device_code" : "browser",
|
|
98
|
+
browserBehavior: plan.browserBehavior === "none" ? "none" : "native_auto",
|
|
99
|
+
headless: plan.headless === true,
|
|
100
|
+
instructions: boundedString(plan.instructions, 2e3)
|
|
101
|
+
} : null,
|
|
102
|
+
error: error && typeof error.message === "string" ? { code: boundedString(error.code, 100), message: boundedString(error.message, 2e3) } : null
|
|
103
|
+
};
|
|
104
|
+
}
|
|
83
105
|
function string(value, fallback = "") {
|
|
84
106
|
return typeof value === "string" ? value : fallback;
|
|
85
107
|
}
|
|
@@ -754,6 +776,7 @@ function normalizeUiState(value) {
|
|
|
754
776
|
reductionReceipt: readReductionReceipt(raw.reductionReceipt),
|
|
755
777
|
interopSettings: readInteropSettings(raw.interopSettings),
|
|
756
778
|
interopSettingsError: typeof raw.interopSettingsError === "string" ? boundedString(raw.interopSettingsError) : null,
|
|
779
|
+
harnessAuthentication: readHarnessAuthentication(raw.harnessAuthentication),
|
|
757
780
|
error: typeof raw.error === "string" ? raw.error : null,
|
|
758
781
|
recoverable: raw.recoverable === true,
|
|
759
782
|
harnesses: Array.isArray(raw.harnesses) ? raw.harnesses.flatMap((candidate) => {
|
package/react/components.mjs
CHANGED
|
@@ -58,6 +58,7 @@ var EMPTY_UI_STATE = Object.freeze({
|
|
|
58
58
|
reductionReceipt: null,
|
|
59
59
|
interopSettings: null,
|
|
60
60
|
interopSettingsError: null,
|
|
61
|
+
harnessAuthentication: null,
|
|
61
62
|
error: null,
|
|
62
63
|
recoverable: false,
|
|
63
64
|
harnesses: Object.freeze([]),
|
|
@@ -77,12 +78,33 @@ var STARTUP = /* @__PURE__ */ new Set(["connecting", "starting", "discovering",
|
|
|
77
78
|
var FIDELITY = /* @__PURE__ */ new Set(["byte_lossless", "value_lossless", "semantic"]);
|
|
78
79
|
var TOOL_CATEGORIES = /* @__PURE__ */ new Set(["read", "search", "edit", "command", "test", "web", "agent", "plan", "other"]);
|
|
79
80
|
var TOOL_DETAILS = /* @__PURE__ */ new Set(["file", "matches", "diff", "terminal", "web", "agent", "plan", "fields"]);
|
|
81
|
+
var AUTHENTICATION_PHASES = /* @__PURE__ */ new Set(["idle", "checking", "required", "configured", "unavailable", "launching", "awaiting_user", "verifying", "authenticated", "failed", "cancelled"]);
|
|
80
82
|
var MAX_TOOL_FIELDS = 8;
|
|
81
83
|
var MAX_TOOL_FIELD_CHARS = 800;
|
|
82
84
|
var MAX_TOOL_PREVIEW_CHARS = 4e3;
|
|
83
85
|
function record(value) {
|
|
84
86
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
85
87
|
}
|
|
88
|
+
function readHarnessAuthentication(value) {
|
|
89
|
+
const flow = record(value);
|
|
90
|
+
if (flow?.schema !== "supercode.harness-authentication-flow.v1" || !AUTHENTICATION_PHASES.has(flow.phase)) return null;
|
|
91
|
+
const plan = record(flow.plan);
|
|
92
|
+
const error = record(flow.error);
|
|
93
|
+
return {
|
|
94
|
+
schema: "supercode.harness-authentication-flow.v1",
|
|
95
|
+
revision: Number.isSafeInteger(flow.revision) ? Math.max(0, flow.revision) : 0,
|
|
96
|
+
phase: flow.phase,
|
|
97
|
+
harness: typeof flow.harness === "string" ? boundedString(flow.harness, 100) : null,
|
|
98
|
+
plan: plan ? {
|
|
99
|
+
method: plan.method === "device_code" ? "device_code" : "browser",
|
|
100
|
+
interaction: plan.interaction === "device_code" ? "device_code" : "browser",
|
|
101
|
+
browserBehavior: plan.browserBehavior === "none" ? "none" : "native_auto",
|
|
102
|
+
headless: plan.headless === true,
|
|
103
|
+
instructions: boundedString(plan.instructions, 2e3)
|
|
104
|
+
} : null,
|
|
105
|
+
error: error && typeof error.message === "string" ? { code: boundedString(error.code, 100), message: boundedString(error.message, 2e3) } : null
|
|
106
|
+
};
|
|
107
|
+
}
|
|
86
108
|
function string(value, fallback = "") {
|
|
87
109
|
return typeof value === "string" ? value : fallback;
|
|
88
110
|
}
|
|
@@ -766,6 +788,7 @@ function normalizeUiState(value) {
|
|
|
766
788
|
reductionReceipt: readReductionReceipt(raw.reductionReceipt),
|
|
767
789
|
interopSettings: readInteropSettings(raw.interopSettings),
|
|
768
790
|
interopSettingsError: typeof raw.interopSettingsError === "string" ? boundedString(raw.interopSettingsError) : null,
|
|
791
|
+
harnessAuthentication: readHarnessAuthentication(raw.harnessAuthentication),
|
|
769
792
|
error: typeof raw.error === "string" ? raw.error : null,
|
|
770
793
|
recoverable: raw.recoverable === true,
|
|
771
794
|
harnesses: Array.isArray(raw.harnesses) ? raw.harnesses.flatMap((candidate) => {
|
|
@@ -2646,7 +2669,23 @@ function HarnessSettingsPanel({ state, adapter, onClose, recommendedChange = nul
|
|
|
2646
2669
|
] })
|
|
2647
2670
|
] });
|
|
2648
2671
|
}
|
|
2649
|
-
|
|
2672
|
+
var ACTIVE_AUTHENTICATION_PHASES = /* @__PURE__ */ new Set(["checking", "launching", "awaiting_user", "verifying"]);
|
|
2673
|
+
function HarnessAuthenticationButton({ item, state, adapter }) {
|
|
2674
|
+
if (!item.installed || !["claude-code", "codex"].includes(item.id) || ["ready", "configured"].includes(item.auth)) return null;
|
|
2675
|
+
const flow = state?.harnessAuthentication?.harness === item.id ? state.harnessAuthentication : null;
|
|
2676
|
+
const busy = flow && ACTIVE_AUTHENTICATION_PHASES.has(flow.phase);
|
|
2677
|
+
const completed = flow?.phase === "authenticated";
|
|
2678
|
+
const label = flow?.phase === "checking" ? "Checking\u2026" : flow?.phase === "launching" ? "Opening\u2026" : flow?.phase === "awaiting_user" ? "Finish sign-in" : flow?.phase === "verifying" ? "Verifying\u2026" : flow?.phase === "authenticated" ? "Signed in" : flow?.phase === "failed" ? "Try again" : "Sign in";
|
|
2679
|
+
return /* @__PURE__ */ jsx10("button", { type: "button", disabled: Boolean(busy || completed), "aria-busy": Boolean(busy), onClick: () => adapter?.onIntent({ action: "authenticateHarness", harness: item.id }), children: label });
|
|
2680
|
+
}
|
|
2681
|
+
function canAuthenticateHarness(item) {
|
|
2682
|
+
return item.installed && ["claude-code", "codex"].includes(item.id) && !["ready", "configured"].includes(item.auth);
|
|
2683
|
+
}
|
|
2684
|
+
function harnessAuthenticationReason(item, state) {
|
|
2685
|
+
const flow = state?.harnessAuthentication?.harness === item.id ? state.harnessAuthentication : null;
|
|
2686
|
+
return flow?.error?.message || flow?.plan?.instructions || item.reason || (item.auth === "required" ? "Authentication required" : "Unavailable");
|
|
2687
|
+
}
|
|
2688
|
+
function HarnessReadiness({ harnesses, state, adapter }) {
|
|
2650
2689
|
const blocked = harnesses.filter((item) => !item.startable);
|
|
2651
2690
|
if (!blocked.length || harnesses.some((item) => item.startable)) return null;
|
|
2652
2691
|
return /* @__PURE__ */ jsxs9("details", { className: "scui-readiness", open: true, children: [
|
|
@@ -2655,18 +2694,19 @@ function HarnessReadiness({ harnesses, adapter }) {
|
|
|
2655
2694
|
/* @__PURE__ */ jsx10(HarnessLogo, { id: item.id, size: 25 }),
|
|
2656
2695
|
/* @__PURE__ */ jsxs9("span", { children: [
|
|
2657
2696
|
/* @__PURE__ */ jsx10("strong", { children: item.label }),
|
|
2658
|
-
/* @__PURE__ */ jsx10("small", { children:
|
|
2697
|
+
/* @__PURE__ */ jsx10("small", { children: harnessAuthenticationReason(item, state) }),
|
|
2659
2698
|
item.protocol ? /* @__PURE__ */ jsxs9("em", { children: [
|
|
2660
2699
|
item.protocol,
|
|
2661
2700
|
" \xB7 ",
|
|
2662
2701
|
item.runtime
|
|
2663
2702
|
] }) : null
|
|
2664
2703
|
] }),
|
|
2665
|
-
|
|
2704
|
+
/* @__PURE__ */ jsx10(HarnessAuthenticationButton, { item, state, adapter }),
|
|
2705
|
+
!canAuthenticateHarness(item) && item.repair ? /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => adapter.copyText?.(item.repair), children: "Copy fix" }) : null
|
|
2666
2706
|
] }, item.id)) })
|
|
2667
2707
|
] });
|
|
2668
2708
|
}
|
|
2669
|
-
function HarnessPicker({ harnesses, value, disabled = false, adapter, onChange, logo: Logo = HarnessLogo }) {
|
|
2709
|
+
function HarnessPicker({ harnesses, state, value, disabled = false, adapter, onChange, logo: Logo = HarnessLogo }) {
|
|
2670
2710
|
const [open, setOpen] = useState6(false);
|
|
2671
2711
|
const menuId = useId2();
|
|
2672
2712
|
const root = useRef7(null);
|
|
@@ -2731,9 +2771,10 @@ function HarnessPicker({ harnesses, value, disabled = false, adapter, onChange,
|
|
|
2731
2771
|
/* @__PURE__ */ jsx10(Logo, { id: item.id, size: 24 }),
|
|
2732
2772
|
/* @__PURE__ */ jsxs9("span", { children: [
|
|
2733
2773
|
/* @__PURE__ */ jsx10("strong", { children: item.label }),
|
|
2734
|
-
/* @__PURE__ */ jsx10("small", { children:
|
|
2774
|
+
/* @__PURE__ */ jsx10("small", { children: harnessAuthenticationReason(item, state) })
|
|
2735
2775
|
] }),
|
|
2736
|
-
|
|
2776
|
+
/* @__PURE__ */ jsx10(HarnessAuthenticationButton, { item, state, adapter }),
|
|
2777
|
+
!canAuthenticateHarness(item) && item.repair ? /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => adapter?.copyText?.(item.repair), children: "Copy fix" }) : null
|
|
2737
2778
|
] }, item.id)) })
|
|
2738
2779
|
] }) : null
|
|
2739
2780
|
] }) : null
|
|
@@ -3231,7 +3272,7 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
3231
3272
|
} }),
|
|
3232
3273
|
/* @__PURE__ */ jsxs10("footer", { className: "scui-new-envelope-controls", children: [
|
|
3233
3274
|
adapter.pickContext ? /* @__PURE__ */ jsx11("button", { className: "scui-attach", type: "button", "aria-label": labels.attachContext ?? DEFAULT_LABELS.attachContext, disabled: mode === "terminal" || picking || context.length >= MAX_CONTEXT_ITEMS && images.length >= MAX_IMAGE_ITEMS || Boolean(starting), onClick: pickContext, children: picking ? /* @__PURE__ */ jsx11("i", { className: "scui-control-spinner" }) : /* @__PURE__ */ jsx11(UiIcon, { name: "attach", size: 17 }) }) : null,
|
|
3234
|
-
/* @__PURE__ */ jsx11(Picker, { harnesses: state.harnesses, value: harness, disabled: Boolean(starting), adapter, logo: components.HarnessLogo, onChange: (value) => {
|
|
3275
|
+
/* @__PURE__ */ jsx11(Picker, { harnesses: state.harnesses, state, value: harness, disabled: Boolean(starting), adapter, logo: components.HarnessLogo, onChange: (value) => {
|
|
3235
3276
|
setHarness(value);
|
|
3236
3277
|
remember({ harness: value });
|
|
3237
3278
|
} }),
|
package/react/composer.mjs
CHANGED
package/react/conversation.mjs
CHANGED
package/react/messenger.mjs
CHANGED
|
@@ -58,6 +58,7 @@ var EMPTY_UI_STATE = Object.freeze({
|
|
|
58
58
|
reductionReceipt: null,
|
|
59
59
|
interopSettings: null,
|
|
60
60
|
interopSettingsError: null,
|
|
61
|
+
harnessAuthentication: null,
|
|
61
62
|
error: null,
|
|
62
63
|
recoverable: false,
|
|
63
64
|
harnesses: Object.freeze([]),
|
|
@@ -77,12 +78,33 @@ var STARTUP = /* @__PURE__ */ new Set(["connecting", "starting", "discovering",
|
|
|
77
78
|
var FIDELITY = /* @__PURE__ */ new Set(["byte_lossless", "value_lossless", "semantic"]);
|
|
78
79
|
var TOOL_CATEGORIES = /* @__PURE__ */ new Set(["read", "search", "edit", "command", "test", "web", "agent", "plan", "other"]);
|
|
79
80
|
var TOOL_DETAILS = /* @__PURE__ */ new Set(["file", "matches", "diff", "terminal", "web", "agent", "plan", "fields"]);
|
|
81
|
+
var AUTHENTICATION_PHASES = /* @__PURE__ */ new Set(["idle", "checking", "required", "configured", "unavailable", "launching", "awaiting_user", "verifying", "authenticated", "failed", "cancelled"]);
|
|
80
82
|
var MAX_TOOL_FIELDS = 8;
|
|
81
83
|
var MAX_TOOL_FIELD_CHARS = 800;
|
|
82
84
|
var MAX_TOOL_PREVIEW_CHARS = 4e3;
|
|
83
85
|
function record(value) {
|
|
84
86
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
85
87
|
}
|
|
88
|
+
function readHarnessAuthentication(value) {
|
|
89
|
+
const flow = record(value);
|
|
90
|
+
if (flow?.schema !== "supercode.harness-authentication-flow.v1" || !AUTHENTICATION_PHASES.has(flow.phase)) return null;
|
|
91
|
+
const plan = record(flow.plan);
|
|
92
|
+
const error = record(flow.error);
|
|
93
|
+
return {
|
|
94
|
+
schema: "supercode.harness-authentication-flow.v1",
|
|
95
|
+
revision: Number.isSafeInteger(flow.revision) ? Math.max(0, flow.revision) : 0,
|
|
96
|
+
phase: flow.phase,
|
|
97
|
+
harness: typeof flow.harness === "string" ? boundedString(flow.harness, 100) : null,
|
|
98
|
+
plan: plan ? {
|
|
99
|
+
method: plan.method === "device_code" ? "device_code" : "browser",
|
|
100
|
+
interaction: plan.interaction === "device_code" ? "device_code" : "browser",
|
|
101
|
+
browserBehavior: plan.browserBehavior === "none" ? "none" : "native_auto",
|
|
102
|
+
headless: plan.headless === true,
|
|
103
|
+
instructions: boundedString(plan.instructions, 2e3)
|
|
104
|
+
} : null,
|
|
105
|
+
error: error && typeof error.message === "string" ? { code: boundedString(error.code, 100), message: boundedString(error.message, 2e3) } : null
|
|
106
|
+
};
|
|
107
|
+
}
|
|
86
108
|
function string(value, fallback = "") {
|
|
87
109
|
return typeof value === "string" ? value : fallback;
|
|
88
110
|
}
|
|
@@ -766,6 +788,7 @@ function normalizeUiState(value) {
|
|
|
766
788
|
reductionReceipt: readReductionReceipt(raw.reductionReceipt),
|
|
767
789
|
interopSettings: readInteropSettings(raw.interopSettings),
|
|
768
790
|
interopSettingsError: typeof raw.interopSettingsError === "string" ? boundedString(raw.interopSettingsError) : null,
|
|
791
|
+
harnessAuthentication: readHarnessAuthentication(raw.harnessAuthentication),
|
|
769
792
|
error: typeof raw.error === "string" ? raw.error : null,
|
|
770
793
|
recoverable: raw.recoverable === true,
|
|
771
794
|
harnesses: Array.isArray(raw.harnesses) ? raw.harnesses.flatMap((candidate) => {
|
|
@@ -2560,7 +2583,23 @@ function HarnessSettingsPanel({ state, adapter, onClose, recommendedChange = nul
|
|
|
2560
2583
|
] })
|
|
2561
2584
|
] });
|
|
2562
2585
|
}
|
|
2563
|
-
|
|
2586
|
+
var ACTIVE_AUTHENTICATION_PHASES = /* @__PURE__ */ new Set(["checking", "launching", "awaiting_user", "verifying"]);
|
|
2587
|
+
function HarnessAuthenticationButton({ item, state, adapter }) {
|
|
2588
|
+
if (!item.installed || !["claude-code", "codex"].includes(item.id) || ["ready", "configured"].includes(item.auth)) return null;
|
|
2589
|
+
const flow = state?.harnessAuthentication?.harness === item.id ? state.harnessAuthentication : null;
|
|
2590
|
+
const busy = flow && ACTIVE_AUTHENTICATION_PHASES.has(flow.phase);
|
|
2591
|
+
const completed = flow?.phase === "authenticated";
|
|
2592
|
+
const label = flow?.phase === "checking" ? "Checking\u2026" : flow?.phase === "launching" ? "Opening\u2026" : flow?.phase === "awaiting_user" ? "Finish sign-in" : flow?.phase === "verifying" ? "Verifying\u2026" : flow?.phase === "authenticated" ? "Signed in" : flow?.phase === "failed" ? "Try again" : "Sign in";
|
|
2593
|
+
return /* @__PURE__ */ jsx9("button", { type: "button", disabled: Boolean(busy || completed), "aria-busy": Boolean(busy), onClick: () => adapter?.onIntent({ action: "authenticateHarness", harness: item.id }), children: label });
|
|
2594
|
+
}
|
|
2595
|
+
function canAuthenticateHarness(item) {
|
|
2596
|
+
return item.installed && ["claude-code", "codex"].includes(item.id) && !["ready", "configured"].includes(item.auth);
|
|
2597
|
+
}
|
|
2598
|
+
function harnessAuthenticationReason(item, state) {
|
|
2599
|
+
const flow = state?.harnessAuthentication?.harness === item.id ? state.harnessAuthentication : null;
|
|
2600
|
+
return flow?.error?.message || flow?.plan?.instructions || item.reason || (item.auth === "required" ? "Authentication required" : "Unavailable");
|
|
2601
|
+
}
|
|
2602
|
+
function HarnessReadiness({ harnesses, state, adapter }) {
|
|
2564
2603
|
const blocked = harnesses.filter((item) => !item.startable);
|
|
2565
2604
|
if (!blocked.length || harnesses.some((item) => item.startable)) return null;
|
|
2566
2605
|
return /* @__PURE__ */ jsxs8("details", { className: "scui-readiness", open: true, children: [
|
|
@@ -2569,18 +2608,19 @@ function HarnessReadiness({ harnesses, adapter }) {
|
|
|
2569
2608
|
/* @__PURE__ */ jsx9(HarnessLogo, { id: item.id, size: 25 }),
|
|
2570
2609
|
/* @__PURE__ */ jsxs8("span", { children: [
|
|
2571
2610
|
/* @__PURE__ */ jsx9("strong", { children: item.label }),
|
|
2572
|
-
/* @__PURE__ */ jsx9("small", { children:
|
|
2611
|
+
/* @__PURE__ */ jsx9("small", { children: harnessAuthenticationReason(item, state) }),
|
|
2573
2612
|
item.protocol ? /* @__PURE__ */ jsxs8("em", { children: [
|
|
2574
2613
|
item.protocol,
|
|
2575
2614
|
" \xB7 ",
|
|
2576
2615
|
item.runtime
|
|
2577
2616
|
] }) : null
|
|
2578
2617
|
] }),
|
|
2579
|
-
|
|
2618
|
+
/* @__PURE__ */ jsx9(HarnessAuthenticationButton, { item, state, adapter }),
|
|
2619
|
+
!canAuthenticateHarness(item) && item.repair ? /* @__PURE__ */ jsx9("button", { type: "button", onClick: () => adapter.copyText?.(item.repair), children: "Copy fix" }) : null
|
|
2580
2620
|
] }, item.id)) })
|
|
2581
2621
|
] });
|
|
2582
2622
|
}
|
|
2583
|
-
function HarnessPicker({ harnesses, value, disabled = false, adapter, onChange, logo: Logo = HarnessLogo }) {
|
|
2623
|
+
function HarnessPicker({ harnesses, state, value, disabled = false, adapter, onChange, logo: Logo = HarnessLogo }) {
|
|
2584
2624
|
const [open, setOpen] = useState6(false);
|
|
2585
2625
|
const menuId = useId2();
|
|
2586
2626
|
const root = useRef7(null);
|
|
@@ -2645,9 +2685,10 @@ function HarnessPicker({ harnesses, value, disabled = false, adapter, onChange,
|
|
|
2645
2685
|
/* @__PURE__ */ jsx9(Logo, { id: item.id, size: 24 }),
|
|
2646
2686
|
/* @__PURE__ */ jsxs8("span", { children: [
|
|
2647
2687
|
/* @__PURE__ */ jsx9("strong", { children: item.label }),
|
|
2648
|
-
/* @__PURE__ */ jsx9("small", { children:
|
|
2688
|
+
/* @__PURE__ */ jsx9("small", { children: harnessAuthenticationReason(item, state) })
|
|
2649
2689
|
] }),
|
|
2650
|
-
|
|
2690
|
+
/* @__PURE__ */ jsx9(HarnessAuthenticationButton, { item, state, adapter }),
|
|
2691
|
+
!canAuthenticateHarness(item) && item.repair ? /* @__PURE__ */ jsx9("button", { type: "button", onClick: () => adapter?.copyText?.(item.repair), children: "Copy fix" }) : null
|
|
2651
2692
|
] }, item.id)) })
|
|
2652
2693
|
] }) : null
|
|
2653
2694
|
] }) : null
|
|
@@ -3145,7 +3186,7 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
3145
3186
|
} }),
|
|
3146
3187
|
/* @__PURE__ */ jsxs9("footer", { className: "scui-new-envelope-controls", children: [
|
|
3147
3188
|
adapter.pickContext ? /* @__PURE__ */ jsx10("button", { className: "scui-attach", type: "button", "aria-label": labels.attachContext ?? DEFAULT_LABELS.attachContext, 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,
|
|
3148
|
-
/* @__PURE__ */ jsx10(Picker, { harnesses: state.harnesses, value: harness, disabled: Boolean(starting), adapter, logo: components.HarnessLogo, onChange: (value) => {
|
|
3189
|
+
/* @__PURE__ */ jsx10(Picker, { harnesses: state.harnesses, state, value: harness, disabled: Boolean(starting), adapter, logo: components.HarnessLogo, onChange: (value) => {
|
|
3149
3190
|
setHarness(value);
|
|
3150
3191
|
remember({ harness: value });
|
|
3151
3192
|
} }),
|
package/react/sessions.mjs
CHANGED
package/react/settings.mjs
CHANGED
|
@@ -58,6 +58,7 @@ var EMPTY_UI_STATE = Object.freeze({
|
|
|
58
58
|
reductionReceipt: null,
|
|
59
59
|
interopSettings: null,
|
|
60
60
|
interopSettingsError: null,
|
|
61
|
+
harnessAuthentication: null,
|
|
61
62
|
error: null,
|
|
62
63
|
recoverable: false,
|
|
63
64
|
harnesses: Object.freeze([]),
|
|
@@ -302,7 +303,23 @@ function HarnessSettingsPanel({ state, adapter, onClose, recommendedChange = nul
|
|
|
302
303
|
] })
|
|
303
304
|
] });
|
|
304
305
|
}
|
|
305
|
-
|
|
306
|
+
var ACTIVE_AUTHENTICATION_PHASES = /* @__PURE__ */ new Set(["checking", "launching", "awaiting_user", "verifying"]);
|
|
307
|
+
function HarnessAuthenticationButton({ item, state, adapter }) {
|
|
308
|
+
if (!item.installed || !["claude-code", "codex"].includes(item.id) || ["ready", "configured"].includes(item.auth)) return null;
|
|
309
|
+
const flow = state?.harnessAuthentication?.harness === item.id ? state.harnessAuthentication : null;
|
|
310
|
+
const busy = flow && ACTIVE_AUTHENTICATION_PHASES.has(flow.phase);
|
|
311
|
+
const completed = flow?.phase === "authenticated";
|
|
312
|
+
const label = flow?.phase === "checking" ? "Checking\u2026" : flow?.phase === "launching" ? "Opening\u2026" : flow?.phase === "awaiting_user" ? "Finish sign-in" : flow?.phase === "verifying" ? "Verifying\u2026" : flow?.phase === "authenticated" ? "Signed in" : flow?.phase === "failed" ? "Try again" : "Sign in";
|
|
313
|
+
return /* @__PURE__ */ jsx3("button", { type: "button", disabled: Boolean(busy || completed), "aria-busy": Boolean(busy), onClick: () => adapter?.onIntent({ action: "authenticateHarness", harness: item.id }), children: label });
|
|
314
|
+
}
|
|
315
|
+
function canAuthenticateHarness(item) {
|
|
316
|
+
return item.installed && ["claude-code", "codex"].includes(item.id) && !["ready", "configured"].includes(item.auth);
|
|
317
|
+
}
|
|
318
|
+
function harnessAuthenticationReason(item, state) {
|
|
319
|
+
const flow = state?.harnessAuthentication?.harness === item.id ? state.harnessAuthentication : null;
|
|
320
|
+
return flow?.error?.message || flow?.plan?.instructions || item.reason || (item.auth === "required" ? "Authentication required" : "Unavailable");
|
|
321
|
+
}
|
|
322
|
+
function HarnessReadiness({ harnesses, state, adapter }) {
|
|
306
323
|
const blocked = harnesses.filter((item) => !item.startable);
|
|
307
324
|
if (!blocked.length || harnesses.some((item) => item.startable)) return null;
|
|
308
325
|
return /* @__PURE__ */ jsxs3("details", { className: "scui-readiness", open: true, children: [
|
|
@@ -311,18 +328,19 @@ function HarnessReadiness({ harnesses, adapter }) {
|
|
|
311
328
|
/* @__PURE__ */ jsx3(HarnessLogo, { id: item.id, size: 25 }),
|
|
312
329
|
/* @__PURE__ */ jsxs3("span", { children: [
|
|
313
330
|
/* @__PURE__ */ jsx3("strong", { children: item.label }),
|
|
314
|
-
/* @__PURE__ */ jsx3("small", { children:
|
|
331
|
+
/* @__PURE__ */ jsx3("small", { children: harnessAuthenticationReason(item, state) }),
|
|
315
332
|
item.protocol ? /* @__PURE__ */ jsxs3("em", { children: [
|
|
316
333
|
item.protocol,
|
|
317
334
|
" \xB7 ",
|
|
318
335
|
item.runtime
|
|
319
336
|
] }) : null
|
|
320
337
|
] }),
|
|
321
|
-
|
|
338
|
+
/* @__PURE__ */ jsx3(HarnessAuthenticationButton, { item, state, adapter }),
|
|
339
|
+
!canAuthenticateHarness(item) && item.repair ? /* @__PURE__ */ jsx3("button", { type: "button", onClick: () => adapter.copyText?.(item.repair), children: "Copy fix" }) : null
|
|
322
340
|
] }, item.id)) })
|
|
323
341
|
] });
|
|
324
342
|
}
|
|
325
|
-
function HarnessPicker({ harnesses, value, disabled = false, adapter, onChange, logo: Logo = HarnessLogo }) {
|
|
343
|
+
function HarnessPicker({ harnesses, state, value, disabled = false, adapter, onChange, logo: Logo = HarnessLogo }) {
|
|
326
344
|
const [open, setOpen] = useState(false);
|
|
327
345
|
const menuId = useId();
|
|
328
346
|
const root = useRef(null);
|
|
@@ -387,9 +405,10 @@ function HarnessPicker({ harnesses, value, disabled = false, adapter, onChange,
|
|
|
387
405
|
/* @__PURE__ */ jsx3(Logo, { id: item.id, size: 24 }),
|
|
388
406
|
/* @__PURE__ */ jsxs3("span", { children: [
|
|
389
407
|
/* @__PURE__ */ jsx3("strong", { children: item.label }),
|
|
390
|
-
/* @__PURE__ */ jsx3("small", { children:
|
|
408
|
+
/* @__PURE__ */ jsx3("small", { children: harnessAuthenticationReason(item, state) })
|
|
391
409
|
] }),
|
|
392
|
-
|
|
410
|
+
/* @__PURE__ */ jsx3(HarnessAuthenticationButton, { item, state, adapter }),
|
|
411
|
+
!canAuthenticateHarness(item) && item.repair ? /* @__PURE__ */ jsx3("button", { type: "button", onClick: () => adapter?.copyText?.(item.repair), children: "Copy fix" }) : null
|
|
393
412
|
] }, item.id)) })
|
|
394
413
|
] }) : null
|
|
395
414
|
] }) : null
|
package/react/subagents.mjs
CHANGED
package/sessions.mjs
CHANGED
package/settings.mjs
CHANGED
|
@@ -58,6 +58,7 @@ var EMPTY_UI_STATE = Object.freeze({
|
|
|
58
58
|
reductionReceipt: null,
|
|
59
59
|
interopSettings: null,
|
|
60
60
|
interopSettingsError: null,
|
|
61
|
+
harnessAuthentication: null,
|
|
61
62
|
error: null,
|
|
62
63
|
recoverable: false,
|
|
63
64
|
harnesses: Object.freeze([]),
|
|
@@ -302,7 +303,23 @@ function HarnessSettingsPanel({ state, adapter, onClose, recommendedChange = nul
|
|
|
302
303
|
] })
|
|
303
304
|
] });
|
|
304
305
|
}
|
|
305
|
-
|
|
306
|
+
var ACTIVE_AUTHENTICATION_PHASES = /* @__PURE__ */ new Set(["checking", "launching", "awaiting_user", "verifying"]);
|
|
307
|
+
function HarnessAuthenticationButton({ item, state, adapter }) {
|
|
308
|
+
if (!item.installed || !["claude-code", "codex"].includes(item.id) || ["ready", "configured"].includes(item.auth)) return null;
|
|
309
|
+
const flow = state?.harnessAuthentication?.harness === item.id ? state.harnessAuthentication : null;
|
|
310
|
+
const busy = flow && ACTIVE_AUTHENTICATION_PHASES.has(flow.phase);
|
|
311
|
+
const completed = flow?.phase === "authenticated";
|
|
312
|
+
const label = flow?.phase === "checking" ? "Checking\u2026" : flow?.phase === "launching" ? "Opening\u2026" : flow?.phase === "awaiting_user" ? "Finish sign-in" : flow?.phase === "verifying" ? "Verifying\u2026" : flow?.phase === "authenticated" ? "Signed in" : flow?.phase === "failed" ? "Try again" : "Sign in";
|
|
313
|
+
return /* @__PURE__ */ jsx3("button", { type: "button", disabled: Boolean(busy || completed), "aria-busy": Boolean(busy), onClick: () => adapter?.onIntent({ action: "authenticateHarness", harness: item.id }), children: label });
|
|
314
|
+
}
|
|
315
|
+
function canAuthenticateHarness(item) {
|
|
316
|
+
return item.installed && ["claude-code", "codex"].includes(item.id) && !["ready", "configured"].includes(item.auth);
|
|
317
|
+
}
|
|
318
|
+
function harnessAuthenticationReason(item, state) {
|
|
319
|
+
const flow = state?.harnessAuthentication?.harness === item.id ? state.harnessAuthentication : null;
|
|
320
|
+
return flow?.error?.message || flow?.plan?.instructions || item.reason || (item.auth === "required" ? "Authentication required" : "Unavailable");
|
|
321
|
+
}
|
|
322
|
+
function HarnessReadiness({ harnesses, state, adapter }) {
|
|
306
323
|
const blocked = harnesses.filter((item) => !item.startable);
|
|
307
324
|
if (!blocked.length || harnesses.some((item) => item.startable)) return null;
|
|
308
325
|
return /* @__PURE__ */ jsxs3("details", { className: "scui-readiness", open: true, children: [
|
|
@@ -311,18 +328,19 @@ function HarnessReadiness({ harnesses, adapter }) {
|
|
|
311
328
|
/* @__PURE__ */ jsx3(HarnessLogo, { id: item.id, size: 25 }),
|
|
312
329
|
/* @__PURE__ */ jsxs3("span", { children: [
|
|
313
330
|
/* @__PURE__ */ jsx3("strong", { children: item.label }),
|
|
314
|
-
/* @__PURE__ */ jsx3("small", { children:
|
|
331
|
+
/* @__PURE__ */ jsx3("small", { children: harnessAuthenticationReason(item, state) }),
|
|
315
332
|
item.protocol ? /* @__PURE__ */ jsxs3("em", { children: [
|
|
316
333
|
item.protocol,
|
|
317
334
|
" \xB7 ",
|
|
318
335
|
item.runtime
|
|
319
336
|
] }) : null
|
|
320
337
|
] }),
|
|
321
|
-
|
|
338
|
+
/* @__PURE__ */ jsx3(HarnessAuthenticationButton, { item, state, adapter }),
|
|
339
|
+
!canAuthenticateHarness(item) && item.repair ? /* @__PURE__ */ jsx3("button", { type: "button", onClick: () => adapter.copyText?.(item.repair), children: "Copy fix" }) : null
|
|
322
340
|
] }, item.id)) })
|
|
323
341
|
] });
|
|
324
342
|
}
|
|
325
|
-
function HarnessPicker({ harnesses, value, disabled = false, adapter, onChange, logo: Logo = HarnessLogo }) {
|
|
343
|
+
function HarnessPicker({ harnesses, state, value, disabled = false, adapter, onChange, logo: Logo = HarnessLogo }) {
|
|
326
344
|
const [open, setOpen] = useState(false);
|
|
327
345
|
const menuId = useId();
|
|
328
346
|
const root = useRef(null);
|
|
@@ -387,9 +405,10 @@ function HarnessPicker({ harnesses, value, disabled = false, adapter, onChange,
|
|
|
387
405
|
/* @__PURE__ */ jsx3(Logo, { id: item.id, size: 24 }),
|
|
388
406
|
/* @__PURE__ */ jsxs3("span", { children: [
|
|
389
407
|
/* @__PURE__ */ jsx3("strong", { children: item.label }),
|
|
390
|
-
/* @__PURE__ */ jsx3("small", { children:
|
|
408
|
+
/* @__PURE__ */ jsx3("small", { children: harnessAuthenticationReason(item, state) })
|
|
391
409
|
] }),
|
|
392
|
-
|
|
410
|
+
/* @__PURE__ */ jsx3(HarnessAuthenticationButton, { item, state, adapter }),
|
|
411
|
+
!canAuthenticateHarness(item) && item.repair ? /* @__PURE__ */ jsx3("button", { type: "button", onClick: () => adapter?.copyText?.(item.repair), children: "Copy fix" }) : null
|
|
393
412
|
] }, item.id)) })
|
|
394
413
|
] }) : null
|
|
395
414
|
] }) : null
|