@volter-ai-dev/supercode-ui 0.1.62 → 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 CHANGED
@@ -161,9 +161,13 @@ Harness inventory also retains normalized auth, runtime, protocol, repair, and a
161
161
  evidence. The new-chat view renders unavailable harnesses in a compact `HarnessReadiness` section;
162
162
  hosts can replace that component while continuing to consume the same readiness contract. For an
163
163
  installed Claude Code or Codex that needs authentication, the default component emits the single
164
- `authenticateHarness` intent. A trusted host handles it through `onAuthenticateHarness`, launches
165
- the plan returned by the harness SDK in a visible terminal, and refreshes inventory after native
166
- verification. The browser-only UI never spawns a local process or handles credentials itself.
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.
167
171
 
168
172
  When a controlled runtime truthfully advertises native steering, the composer sends a plain-text
169
173
  message into the active turn and keeps a separate secondary action for queueing a follow-up. With
@@ -179,6 +183,11 @@ Trusted desktop, editor, and Node hosts can avoid rewriting ordinary snapshot an
179
183
  import { createControllerBinding } from '@volter-ai-dev/supercode-ui/controller';
180
184
 
181
185
  const binding = createControllerBinding(controller, {
186
+ authentication,
187
+ authenticationRequest: () => ({
188
+ environment: isRemoteClient ? 'headless' : 'local_browser',
189
+ cwd: projectRoot,
190
+ }),
182
191
  onDraft: saveDraft,
183
192
  onAcknowledge: clearAttention,
184
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
- function HarnessReadiness({ harnesses, adapter }) {
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: item.reason || (item.auth === "required" ? "Authentication required" : "Unavailable") }),
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
- item.installed && ["claude-code", "codex"].includes(item.id) && !["ready", "configured"].includes(item.auth) ? /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => adapter.onIntent({ action: "authenticateHarness", harness: item.id }), children: "Sign in" }) : item.repair ? /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => adapter.copyText?.(item.repair), children: "Copy fix" }) : null
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: item.reason || (item.auth === "required" ? "Authentication required" : "Unavailable") })
2774
+ /* @__PURE__ */ jsx10("small", { children: harnessAuthenticationReason(item, state) })
2735
2775
  ] }),
2736
- item.installed && ["claude-code", "codex"].includes(item.id) && !["ready", "configured"].includes(item.auth) ? /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => adapter?.onIntent({ action: "authenticateHarness", harness: item.id }), children: "Sign in" }) : item.repair ? /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => adapter?.copyText?.(item.repair), children: "Copy fix" }) : null
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
@@ -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([]),
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,7 +129,28 @@ 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
+ }>;
131
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. */
132
154
  onAuthenticateHarness?: (intent: Extract<SupercodeUiIntent, { action: 'authenticateHarness' }>) => void | Promise<void>;
133
155
  copyText?: UiAdapter['copyText'];
134
156
  resolveImage?: UiAdapter['resolveImage'];
package/controller.mjs CHANGED
@@ -670,6 +670,14 @@ export async function dispatchControllerIntent(controller, intent, options = {})
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
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
+ }
673
681
  return options.onAuthenticateHarness
674
682
  ? options.onAuthenticateHarness(intent)
675
683
  : options.onUnsupported?.(intent);
@@ -705,7 +713,12 @@ export function createControllerBinding(controller, options = {}) {
705
713
  if (!controller || typeof controller.getSnapshot !== 'function' || typeof controller.subscribe !== 'function' || typeof controller.dispatch !== 'function') {
706
714
  throw new TypeError('createControllerBinding requires a SupercodeController-compatible object');
707
715
  }
708
- const getState = () => projectClientSnapshot(controller.getSnapshot(), options.projection?.() ?? {});
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
+ };
709
722
  const adapter = {
710
723
  onIntent(intent) {
711
724
  return Promise.resolve(options.onIntent?.(intent))
@@ -724,7 +737,11 @@ export function createControllerBinding(controller, options = {}) {
724
737
  adapter,
725
738
  getState,
726
739
  subscribe(listener) {
727
- return controller.subscribe(() => listener(getState()));
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(); };
728
745
  },
729
746
  };
730
747
  }
package/conversation.mjs CHANGED
@@ -59,6 +59,7 @@ var EMPTY_UI_STATE = Object.freeze({
59
59
  reductionReceipt: null,
60
60
  interopSettings: null,
61
61
  interopSettingsError: null,
62
+ harnessAuthentication: null,
62
63
  error: null,
63
64
  recoverable: false,
64
65
  harnesses: Object.freeze([]),
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) => {
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
- function HarnessReadiness({ harnesses, adapter }) {
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: item.reason || (item.auth === "required" ? "Authentication required" : "Unavailable") }),
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
- item.installed && ["claude-code", "codex"].includes(item.id) && !["ready", "configured"].includes(item.auth) ? /* @__PURE__ */ jsx9("button", { type: "button", onClick: () => adapter.onIntent({ action: "authenticateHarness", harness: item.id }), children: "Sign in" }) : item.repair ? /* @__PURE__ */ jsx9("button", { type: "button", onClick: () => adapter.copyText?.(item.repair), children: "Copy fix" }) : null
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: item.reason || (item.auth === "required" ? "Authentication required" : "Unavailable") })
2691
+ /* @__PURE__ */ jsx9("small", { children: harnessAuthenticationReason(item, state) })
2652
2692
  ] }),
2653
- item.installed && ["claude-code", "codex"].includes(item.id) && !["ready", "configured"].includes(item.auth) ? /* @__PURE__ */ jsx9("button", { type: "button", onClick: () => adapter?.onIntent({ action: "authenticateHarness", harness: item.id }), children: "Sign in" }) : item.repair ? /* @__PURE__ */ jsx9("button", { type: "button", onClick: () => adapter?.copyText?.(item.repair), children: "Copy fix" }) : null
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[];
@@ -468,6 +484,7 @@ export interface HarnessSettingsPanelProps {
468
484
 
469
485
  export interface HarnessPickerProps {
470
486
  harnesses: HarnessOption[];
487
+ state?: SupercodeUiState;
471
488
  value: HarnessId;
472
489
  disabled?: boolean;
473
490
  adapter?: Pick<UiAdapter, 'copyText' | 'onIntent'>;
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
- function HarnessReadiness({ harnesses, adapter }) {
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: item.reason || (item.auth === "required" ? "Authentication required" : "Unavailable") }),
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
- item.installed && ["claude-code", "codex"].includes(item.id) && !["ready", "configured"].includes(item.auth) ? /* @__PURE__ */ jsx9("button", { type: "button", onClick: () => adapter.onIntent({ action: "authenticateHarness", harness: item.id }), children: "Sign in" }) : item.repair ? /* @__PURE__ */ jsx9("button", { type: "button", onClick: () => adapter.copyText?.(item.repair), children: "Copy fix" }) : null
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: item.reason || (item.auth === "required" ? "Authentication required" : "Unavailable") })
2688
+ /* @__PURE__ */ jsx9("small", { children: harnessAuthenticationReason(item, state) })
2649
2689
  ] }),
2650
- item.installed && ["claude-code", "codex"].includes(item.id) && !["ready", "configured"].includes(item.auth) ? /* @__PURE__ */ jsx9("button", { type: "button", onClick: () => adapter?.onIntent({ action: "authenticateHarness", harness: item.id }), children: "Sign in" }) : item.repair ? /* @__PURE__ */ jsx9("button", { type: "button", onClick: () => adapter?.copyText?.(item.repair), children: "Copy fix" }) : null
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volter-ai-dev/supercode-ui",
3
- "version": "0.1.62",
3
+ "version": "0.1.63",
4
4
  "type": "module",
5
5
  "description": "Composable default UI kit for Supercode-powered coding-agent experiences",
6
6
  "exports": {
@@ -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) => {
@@ -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
- function HarnessReadiness({ harnesses, adapter }) {
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: item.reason || (item.auth === "required" ? "Authentication required" : "Unavailable") }),
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
- item.installed && ["claude-code", "codex"].includes(item.id) && !["ready", "configured"].includes(item.auth) ? /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => adapter.onIntent({ action: "authenticateHarness", harness: item.id }), children: "Sign in" }) : item.repair ? /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => adapter.copyText?.(item.repair), children: "Copy fix" }) : null
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: item.reason || (item.auth === "required" ? "Authentication required" : "Unavailable") })
2774
+ /* @__PURE__ */ jsx10("small", { children: harnessAuthenticationReason(item, state) })
2735
2775
  ] }),
2736
- item.installed && ["claude-code", "codex"].includes(item.id) && !["ready", "configured"].includes(item.auth) ? /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => adapter?.onIntent({ action: "authenticateHarness", harness: item.id }), children: "Sign in" }) : item.repair ? /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => adapter?.copyText?.(item.repair), children: "Copy fix" }) : null
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
  } }),
@@ -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([]),
@@ -59,6 +59,7 @@ var EMPTY_UI_STATE = Object.freeze({
59
59
  reductionReceipt: null,
60
60
  interopSettings: null,
61
61
  interopSettingsError: null,
62
+ harnessAuthentication: null,
62
63
  error: null,
63
64
  recoverable: false,
64
65
  harnesses: Object.freeze([]),
@@ -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
- function HarnessReadiness({ harnesses, adapter }) {
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: item.reason || (item.auth === "required" ? "Authentication required" : "Unavailable") }),
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
- item.installed && ["claude-code", "codex"].includes(item.id) && !["ready", "configured"].includes(item.auth) ? /* @__PURE__ */ jsx9("button", { type: "button", onClick: () => adapter.onIntent({ action: "authenticateHarness", harness: item.id }), children: "Sign in" }) : item.repair ? /* @__PURE__ */ jsx9("button", { type: "button", onClick: () => adapter.copyText?.(item.repair), children: "Copy fix" }) : null
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: item.reason || (item.auth === "required" ? "Authentication required" : "Unavailable") })
2688
+ /* @__PURE__ */ jsx9("small", { children: harnessAuthenticationReason(item, state) })
2649
2689
  ] }),
2650
- item.installed && ["claude-code", "codex"].includes(item.id) && !["ready", "configured"].includes(item.auth) ? /* @__PURE__ */ jsx9("button", { type: "button", onClick: () => adapter?.onIntent({ action: "authenticateHarness", harness: item.id }), children: "Sign in" }) : item.repair ? /* @__PURE__ */ jsx9("button", { type: "button", onClick: () => adapter?.copyText?.(item.repair), children: "Copy fix" }) : null
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
  } }),
@@ -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([]),
@@ -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
- function HarnessReadiness({ harnesses, adapter }) {
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: item.reason || (item.auth === "required" ? "Authentication required" : "Unavailable") }),
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
- item.installed && ["claude-code", "codex"].includes(item.id) && !["ready", "configured"].includes(item.auth) ? /* @__PURE__ */ jsx3("button", { type: "button", onClick: () => adapter.onIntent({ action: "authenticateHarness", harness: item.id }), children: "Sign in" }) : item.repair ? /* @__PURE__ */ jsx3("button", { type: "button", onClick: () => adapter.copyText?.(item.repair), children: "Copy fix" }) : null
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: item.reason || (item.auth === "required" ? "Authentication required" : "Unavailable") })
408
+ /* @__PURE__ */ jsx3("small", { children: harnessAuthenticationReason(item, state) })
391
409
  ] }),
392
- item.installed && ["claude-code", "codex"].includes(item.id) && !["ready", "configured"].includes(item.auth) ? /* @__PURE__ */ jsx3("button", { type: "button", onClick: () => adapter?.onIntent({ action: "authenticateHarness", harness: item.id }), children: "Sign in" }) : item.repair ? /* @__PURE__ */ jsx3("button", { type: "button", onClick: () => adapter?.copyText?.(item.repair), children: "Copy fix" }) : null
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
@@ -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([]),
package/sessions.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([]),
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
- function HarnessReadiness({ harnesses, adapter }) {
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: item.reason || (item.auth === "required" ? "Authentication required" : "Unavailable") }),
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
- item.installed && ["claude-code", "codex"].includes(item.id) && !["ready", "configured"].includes(item.auth) ? /* @__PURE__ */ jsx3("button", { type: "button", onClick: () => adapter.onIntent({ action: "authenticateHarness", harness: item.id }), children: "Sign in" }) : item.repair ? /* @__PURE__ */ jsx3("button", { type: "button", onClick: () => adapter.copyText?.(item.repair), children: "Copy fix" }) : null
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: item.reason || (item.auth === "required" ? "Authentication required" : "Unavailable") })
408
+ /* @__PURE__ */ jsx3("small", { children: harnessAuthenticationReason(item, state) })
391
409
  ] }),
392
- item.installed && ["claude-code", "codex"].includes(item.id) && !["ready", "configured"].includes(item.auth) ? /* @__PURE__ */ jsx3("button", { type: "button", onClick: () => adapter?.onIntent({ action: "authenticateHarness", harness: item.id }), children: "Sign in" }) : item.repair ? /* @__PURE__ */ jsx3("button", { type: "button", onClick: () => adapter?.copyText?.(item.repair), children: "Copy fix" }) : null
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/subagents.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([]),