@volter-ai-dev/supercode-ui 0.1.62 → 0.1.64
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 +15 -3
- package/activity.mjs +23 -0
- package/components.mjs +48 -7
- package/composer.mjs +1 -0
- package/controller.d.ts +39 -0
- package/controller.mjs +51 -4
- package/conversation.mjs +1 -0
- package/core.mjs +26 -0
- package/embed.mjs +48 -7
- package/index.d.ts +17 -0
- 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
|
@@ -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
|
|
165
|
-
|
|
166
|
-
|
|
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,
|
|
@@ -254,6 +263,9 @@ opaque-key callback and retains the reversible locator map. Its `isWritable` cap
|
|
|
254
263
|
is fail-closed: unread badges remain neutral until the host proves a real send or terminal-control
|
|
255
264
|
path. Runtime activity remains independent, so a read-only channel can still truthfully show that
|
|
256
265
|
its external agent is working or needs input.
|
|
266
|
+
`matchesSessionRef`, `projectAttachedSession`, and `formatWorkspacePath` complete that trusted-host
|
|
267
|
+
adapter so products do not need local copies of active-session matching, fallback header identity,
|
|
268
|
+
or home-relative path formatting.
|
|
257
269
|
|
|
258
270
|
## Modularity contract
|
|
259
271
|
|
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,
|
|
@@ -71,6 +72,23 @@ export interface SessionInventoryProjectionOptions {
|
|
|
71
72
|
isWritable?(descriptor: SessionDescriptor): boolean;
|
|
72
73
|
}
|
|
73
74
|
|
|
75
|
+
export interface ActiveSessionRef {
|
|
76
|
+
harness: string;
|
|
77
|
+
sessionId: string | null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function formatWorkspacePath(cwd: string | null | undefined, home?: string): string;
|
|
81
|
+
export function matchesSessionRef(
|
|
82
|
+
descriptor: SessionDescriptor,
|
|
83
|
+
active: ActiveSessionRef | null | undefined,
|
|
84
|
+
): boolean;
|
|
85
|
+
export function projectAttachedSession(
|
|
86
|
+
active: ActiveSessionRef | null | undefined,
|
|
87
|
+
rows: readonly SessionRowModel[],
|
|
88
|
+
fallbackWorkspace: string,
|
|
89
|
+
home?: string,
|
|
90
|
+
): AttachedSessionModel | null;
|
|
91
|
+
|
|
74
92
|
export function sessionConversationUpdatedAt(descriptor: SessionDescriptor): number | null;
|
|
75
93
|
export function sessionDescriptorRuntimeStatus(
|
|
76
94
|
descriptor: SessionDescriptor,
|
|
@@ -128,7 +146,28 @@ export interface ControllerBindingOptions {
|
|
|
128
146
|
onCloseSubagents?: () => void | Promise<void>;
|
|
129
147
|
onStartTerminal?: (intent: Extract<SupercodeUiIntent, { action: 'new' }>) => void | Promise<void>;
|
|
130
148
|
onResumeTerminal?: (intent: Extract<SupercodeUiIntent, { action: 'resume' }>) => void | Promise<void>;
|
|
149
|
+
/** Shared Supercode authentication lifecycle. The host-specific execution adapter is injected
|
|
150
|
+
* when constructing this controller; the UI only observes and starts the flow. */
|
|
151
|
+
authentication?: {
|
|
152
|
+
getSnapshot(): unknown;
|
|
153
|
+
subscribe(listener: () => void): () => void;
|
|
154
|
+
authenticate(harness: HarnessId, request?: {
|
|
155
|
+
environment?: 'local_browser' | 'headless';
|
|
156
|
+
method?: 'browser' | 'device_code';
|
|
157
|
+
cwd?: string;
|
|
158
|
+
}): Promise<{ phase: string }>;
|
|
159
|
+
};
|
|
160
|
+
authenticationRequest?: (intent: Extract<SupercodeUiIntent, { action: 'authenticateHarness' }>) => {
|
|
161
|
+
environment?: 'local_browser' | 'headless';
|
|
162
|
+
method?: 'browser' | 'device_code';
|
|
163
|
+
cwd?: string;
|
|
164
|
+
} | Promise<{
|
|
165
|
+
environment?: 'local_browser' | 'headless';
|
|
166
|
+
method?: 'browser' | 'device_code';
|
|
167
|
+
cwd?: string;
|
|
168
|
+
}>;
|
|
131
169
|
/** Launch the native harness-owned sign-in flow. The host owns the process and terminal. */
|
|
170
|
+
/** @deprecated Prefer `authentication`; retained for custom legacy hosts. */
|
|
132
171
|
onAuthenticateHarness?: (intent: Extract<SupercodeUiIntent, { action: 'authenticateHarness' }>) => void | Promise<void>;
|
|
133
172
|
copyText?: UiAdapter['copyText'];
|
|
134
173
|
resolveImage?: UiAdapter['resolveImage'];
|
package/controller.mjs
CHANGED
|
@@ -29,12 +29,42 @@ function workspaceName(cwd) {
|
|
|
29
29
|
return cwd.replaceAll('\\', '/').split('/').filter(Boolean).at(-1) ?? cwd;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
function
|
|
32
|
+
export function formatWorkspacePath(cwd, home) {
|
|
33
33
|
if (typeof cwd !== 'string' || !cwd) return '';
|
|
34
34
|
const root = typeof home === 'string' && home.endsWith('/') ? home.slice(0, -1) : home;
|
|
35
35
|
return root && (cwd === root || cwd.startsWith(`${root}/`)) ? `~${cwd.slice(root.length)}` : cwd;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
export function matchesSessionRef(descriptor, active) {
|
|
39
|
+
return Boolean(
|
|
40
|
+
active?.sessionId !== null &&
|
|
41
|
+
active?.sessionId !== undefined &&
|
|
42
|
+
descriptor?.locator?.harness === active.harness &&
|
|
43
|
+
descriptor?.locator?.session_id === active.sessionId,
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function projectAttachedSession(active, rows, fallbackWorkspace, home) {
|
|
48
|
+
if (!active?.harness) return null;
|
|
49
|
+
const row = rows.find((candidate) => candidate.active);
|
|
50
|
+
if (row) {
|
|
51
|
+
return {
|
|
52
|
+
key: row.key,
|
|
53
|
+
harness: row.harness,
|
|
54
|
+
name: row.name,
|
|
55
|
+
cwd: row.cwd,
|
|
56
|
+
title: row.title,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
key: '',
|
|
61
|
+
harness: active.harness,
|
|
62
|
+
name: workspaceName(fallbackWorkspace) || 'no workspace',
|
|
63
|
+
cwd: formatWorkspacePath(fallbackWorkspace, home),
|
|
64
|
+
title: workspaceName(fallbackWorkspace) || 'Untitled chat',
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
38
68
|
function compactTopic(value) {
|
|
39
69
|
const text = typeof value === 'string' ? value.replace(/\s+/g, ' ').trim() : '';
|
|
40
70
|
if (text.length <= 72) return text;
|
|
@@ -115,7 +145,7 @@ export function projectSessionInventory(descriptors, options) {
|
|
|
115
145
|
key,
|
|
116
146
|
harness: descriptor.locator.harness,
|
|
117
147
|
name: workspaceName(descriptor.cwd) || 'no workspace',
|
|
118
|
-
cwd:
|
|
148
|
+
cwd: formatWorkspacePath(descriptor.cwd, options.home),
|
|
119
149
|
title: descriptorTitle(descriptor),
|
|
120
150
|
preview: preview?.text ?? '',
|
|
121
151
|
age: relativeAge(preview?.updatedAt ?? updatedAt, now),
|
|
@@ -670,6 +700,14 @@ export async function dispatchControllerIntent(controller, intent, options = {})
|
|
|
670
700
|
if (intent.action === 'interrupt') return controller.dispatch({ type: 'interrupt' });
|
|
671
701
|
if (intent.action === 'respond') return controller.dispatch({ type: 'respond', requestId: intent.requestId, optionId: intent.optionId });
|
|
672
702
|
if (intent.action === 'authenticateHarness') {
|
|
703
|
+
if (options.authentication) {
|
|
704
|
+
const request = (await options.authenticationRequest?.(intent)) ?? {};
|
|
705
|
+
const result = await options.authentication.authenticate(intent.harness, request);
|
|
706
|
+
if (result?.phase === 'authenticated') {
|
|
707
|
+
await controller.dispatch({ type: 'refresh', autoObserve: false, silent: true });
|
|
708
|
+
}
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
673
711
|
return options.onAuthenticateHarness
|
|
674
712
|
? options.onAuthenticateHarness(intent)
|
|
675
713
|
: options.onUnsupported?.(intent);
|
|
@@ -705,7 +743,12 @@ export function createControllerBinding(controller, options = {}) {
|
|
|
705
743
|
if (!controller || typeof controller.getSnapshot !== 'function' || typeof controller.subscribe !== 'function' || typeof controller.dispatch !== 'function') {
|
|
706
744
|
throw new TypeError('createControllerBinding requires a SupercodeController-compatible object');
|
|
707
745
|
}
|
|
708
|
-
const getState = () =>
|
|
746
|
+
const getState = () => {
|
|
747
|
+
const state = projectClientSnapshot(controller.getSnapshot(), options.projection?.() ?? {});
|
|
748
|
+
return options.authentication
|
|
749
|
+
? normalizeUiState({ ...state, harnessAuthentication: options.authentication.getSnapshot() })
|
|
750
|
+
: state;
|
|
751
|
+
};
|
|
709
752
|
const adapter = {
|
|
710
753
|
onIntent(intent) {
|
|
711
754
|
return Promise.resolve(options.onIntent?.(intent))
|
|
@@ -724,7 +767,11 @@ export function createControllerBinding(controller, options = {}) {
|
|
|
724
767
|
adapter,
|
|
725
768
|
getState,
|
|
726
769
|
subscribe(listener) {
|
|
727
|
-
|
|
770
|
+
const unsubscribers = [controller.subscribe(() => listener(getState()))];
|
|
771
|
+
if (options.authentication?.subscribe) {
|
|
772
|
+
unsubscribers.push(options.authentication.subscribe(() => listener(getState())));
|
|
773
|
+
}
|
|
774
|
+
return () => { for (const unsubscribe of unsubscribers) unsubscribe(); };
|
|
728
775
|
},
|
|
729
776
|
};
|
|
730
777
|
}
|
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) => {
|
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[];
|
|
@@ -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
|
-
|
|
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
|