From b041bbcba8cd3f4518d5b7495285df9acd5debb7 Mon Sep 17 00:00:00 2001 From: kate bonner Date: Wed, 22 Jul 2026 15:59:10 -0400 Subject: [PATCH] feat(cloud): Connect Cloud opens the solver toggle's connect flow (#200 AC6) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The solver toggle owns the Company Compute connection (fork PR harmoniqs/opencode#45), so every entrance now converges on that ONE ui flow: - amicode.setCloudKey deep-links the chat panel into the capsule's connect form via a new 'open-compute-connect' bridge envelope (posted now + 1.5s so a freshly created panel's iframe catches it; app-side idempotent within its freshness window). Legacy input-box prompt remains only as the fallback when no ready server exists to host the panel. - chat_panel relay: the extension→iframe lane forwards the new envelope kind (allowlist unchanged otherwise). - agent routing copy points at the solver control first, naming the palette command as the same flow. Closes #200 Co-Authored-By: Claude Fable 5 --- packages/extension/src/chat_panel.ts | 12 +++++++++++- packages/extension/src/extension.ts | 15 ++++++++++++++- packages/extension/src/opencode_config.ts | 6 ++++-- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/packages/extension/src/chat_panel.ts b/packages/extension/src/chat_panel.ts index 6c299cdb2..e339ef7ed 100644 --- a/packages/extension/src/chat_panel.ts +++ b/packages/extension/src/chat_panel.ts @@ -204,6 +204,16 @@ export class ChatPanel { * serverAuthToken(). The app adopts it for its authenticated-fetch path and * strips it from the URL (entry-level history.replaceState). One value per * activation, so revealing an existing panel never needs a re-render. */ + /** amicode#200 AC6: deep-link the framed app into the defaults capsule's + * Company Compute connect flow. Posted twice (now + 1.5s) because a freshly + * created panel's iframe may not be listening yet; the app side treats the + * request as idempotent within its freshness window. */ + postComputeConnect(): void { + const envelope = { source: "amicode", kind: "open-compute-connect" }; + void this.panel.webview.postMessage(envelope); + setTimeout(() => void this.panel.webview.postMessage(envelope), 1500); + } + static openOrReveal(ctx: vscode.ExtensionContext, opencodeUrl: URL, authToken?: string): ChatPanel { if (ChatPanel.current) { ChatPanel.current.panel.reveal(vscode.ViewColumn.One); @@ -286,7 +296,7 @@ export class ChatPanel { // Lane 2 — extension → iframe (theme): posted by the extension host // (webview-internal origin, never the opencode origin). Forward only // our own theme envelope, pinned to the opencode origin. - if (d && d.source === "amicode" && (d.kind === "theme" || d.kind === "clipboard")) { + if (d && d.source === "amicode" && (d.kind === "theme" || d.kind === "clipboard" || d.kind === "open-compute-connect")) { var f = document.querySelector("iframe"); if (f && f.contentWindow) f.contentWindow.postMessage(d, ${origin}); } diff --git a/packages/extension/src/extension.ts b/packages/extension/src/extension.ts index 765bccaef..f8ece2cff 100644 --- a/packages/extension/src/extension.ts +++ b/packages/extension/src/extension.ts @@ -890,7 +890,20 @@ export async function activate(ctx: vscode.ExtensionContext): Promise { : undefined, log: (line) => opencodeChannel.appendLine(line), }); - ctx.subscriptions.push(vscode.commands.registerCommand("amicode.setCloudKey", () => void runSetCloudKey())); + // amicode#200 AC6: the solver toggle owns the connect flow — the palette + // command deep-links the chat's defaults capsule into it, so command, panel, + // and agent copy converge on ONE ui flow. The legacy input-box prompt stays + // only as the fallback when no ready server exists to host the panel. + ctx.subscriptions.push( + vscode.commands.registerCommand("amicode.setCloudKey", () => { + const readyUrl = opencodeReadyUrl; + if (readyUrl) { + ChatPanel.openOrReveal(ctx, readyUrl, serverAuthToken(serverPassword)).postComputeConnect(); + return; + } + void runSetCloudKey(); + }), + ); // 5. Commands ctx.subscriptions.push( diff --git a/packages/extension/src/opencode_config.ts b/packages/extension/src/opencode_config.ts index dc248c2aa..5f84bbd82 100644 --- a/packages/extension/src/opencode_config.ts +++ b/packages/extension/src/opencode_config.ts @@ -297,8 +297,10 @@ function solverModeSection(): string { : "The cloud is NOT connected (no API key). High-Performance + Cloud is a PAID cloud tier and CANNOT " + "run locally — do NOT attempt a local Piccolissimo solve (it will fail: the private package can't be " + "instantiated in a sandbox, and the gate rejects a local hpc run). Instead, STOP and tell the user: " + - '"High-Performance + Cloud needs a cloud connection — run **Amico: Connect Cloud** to enter your API ' + - "key.\" Offer to switch back to the free local Piccolo solver if they'd rather not connect now."; + '"High-Performance + Cloud needs a cloud connection — click **Piccolissimo + Altissimo** in the ' + + "model · solver control on the dashboard and connect there (or run **Amico: Connect Cloud**, which " + + 'opens the same flow)." Offer to switch back to the free local Piccolo solver if they\'d rather not ' + + "connect now."; return ( "\n\n## Solver mode\n" + "**HIGH-PERFORMANCE + CLOUD (Piccolissimo + Altissimo).** The user selected the paid " +