@superblocksteam/gateway 2.0.164 → 2.0.166-next.0

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.
Files changed (59) hide show
  1. package/dist/agents/resolve-orchestrator-url.d.ts +19 -1
  2. package/dist/agents/resolve-orchestrator-url.js +71 -20
  3. package/dist/agents/resolve-orchestrator-url.js.map +1 -1
  4. package/dist/capabilities/integration-metadata.d.ts +3 -0
  5. package/dist/capabilities/integration-metadata.js +34 -11
  6. package/dist/capabilities/integration-metadata.js.map +1 -1
  7. package/dist/capabilities/lifecycle.d.ts +16 -1
  8. package/dist/capabilities/lifecycle.js +72 -25
  9. package/dist/capabilities/lifecycle.js.map +1 -1
  10. package/dist/capabilities/query-integration.d.ts +5 -0
  11. package/dist/capabilities/query-integration.js +61 -18
  12. package/dist/capabilities/query-integration.js.map +1 -1
  13. package/dist/{transports/mcp → capture}/cowork-editor-url.d.ts +2 -2
  14. package/dist/capture/cowork-editor-url.js +12 -0
  15. package/dist/capture/cowork-editor-url.js.map +1 -0
  16. package/dist/integrations/profile-key.d.ts +50 -6
  17. package/dist/integrations/profile-key.js +101 -22
  18. package/dist/integrations/profile-key.js.map +1 -1
  19. package/dist/integrations/resolve-profile.d.ts +30 -0
  20. package/dist/integrations/resolve-profile.js +104 -0
  21. package/dist/integrations/resolve-profile.js.map +1 -0
  22. package/dist/orchestrator/client.d.ts +1 -1
  23. package/dist/orchestrator/client.js +1 -1
  24. package/dist/orchestrator/client.js.map +1 -1
  25. package/dist/sabs/editor-client-methods.d.ts +7 -2
  26. package/dist/sabs/editor-client-methods.js +10 -2
  27. package/dist/sabs/editor-client-methods.js.map +1 -1
  28. package/dist/sabs/recent-tool-runs.d.ts +1 -1
  29. package/dist/sabs/recent-tool-runs.js +2 -2
  30. package/dist/sabs/recent-tool-runs.js.map +1 -1
  31. package/dist/sabs/websocket-session-peer.d.ts +31 -0
  32. package/dist/sabs/websocket-session-peer.js +202 -35
  33. package/dist/sabs/websocket-session-peer.js.map +1 -1
  34. package/dist/server/client.d.ts +67 -15
  35. package/dist/server/client.js +403 -51
  36. package/dist/server/client.js.map +1 -1
  37. package/dist/telemetry/metrics.d.ts +14 -0
  38. package/dist/telemetry/metrics.js +25 -0
  39. package/dist/telemetry/metrics.js.map +1 -1
  40. package/dist/transports/mcp/instructions/tools/check-app-progress.js +6 -2
  41. package/dist/transports/mcp/instructions/tools/check-app-progress.js.map +1 -1
  42. package/dist/transports/mcp/instructions/tools/copy.d.ts +2 -0
  43. package/dist/transports/mcp/instructions/tools/copy.js +31 -1
  44. package/dist/transports/mcp/instructions/tools/copy.js.map +1 -1
  45. package/dist/transports/mcp/instructions/tools/edit-app.js +4 -1
  46. package/dist/transports/mcp/instructions/tools/edit-app.js.map +1 -1
  47. package/dist/transports/mcp/instructions/tools/get-integration-metadata.js +3 -0
  48. package/dist/transports/mcp/instructions/tools/get-integration-metadata.js.map +1 -1
  49. package/dist/transports/mcp/instructions/tools/start-app.js +4 -1
  50. package/dist/transports/mcp/instructions/tools/start-app.js.map +1 -1
  51. package/dist/transports/mcp/mount.d.ts +1 -1
  52. package/dist/transports/mcp/mount.js +80 -10
  53. package/dist/transports/mcp/mount.js.map +1 -1
  54. package/dist/transports/mcp/plan-approval.d.ts +29 -0
  55. package/dist/transports/mcp/plan-approval.js +72 -18
  56. package/dist/transports/mcp/plan-approval.js.map +1 -1
  57. package/package.json +5 -5
  58. package/dist/transports/mcp/cowork-editor-url.js +0 -10
  59. package/dist/transports/mcp/cowork-editor-url.js.map +0 -1
@@ -19,8 +19,12 @@ export type OrchestratorAgentCandidate = {
19
19
  export type PickOrchestratorBaseUrlInput = {
20
20
  agentType: number;
21
21
  agents: OrchestratorAgentCandidate[];
22
- profileKey: string;
22
+ controlPlaneUrl?: string;
23
+ profileKey?: string;
23
24
  };
25
+ /** Matches `@superblocksteam/shared` `AgentType.ONPREMISE`. */
26
+ export declare const AGENT_TYPE_ONPREMISE = 2;
27
+ export declare function cloudOrchestratorBaseUrlFromControlPlane(url: string | undefined): string | undefined;
24
28
  /**
25
29
  * Rewrites a Superblocks control-plane `/agent` URL to the dedicated
26
30
  * orchestrator host. Leaves on-prem, ephemeral `agent-<host>`, and already
@@ -32,6 +36,20 @@ export type PickOrchestratorBaseUrlInput = {
32
36
  * prefix. DEDICATED agents advertise a real URL; do not invent a host.
33
37
  */
34
38
  export declare function canonicalizeOrchestratorBaseUrl(url: string, agentType?: number): string;
39
+ /**
40
+ * Whether moving between two profile keys can move the orchestrator URL.
41
+ *
42
+ * Only on-prem inventories tag agents by profile. Cloud resolves to one agent
43
+ * host per control plane. A key changing value there picks the same URL
44
+ * so no need to evict the cache.
45
+ *
46
+ * When agent is undefined, the profile key is changing from unset to a value.
47
+ */
48
+ export declare function orchestratorUrlDependsOnProfile(input: {
49
+ agentType?: number;
50
+ nextProfileKey?: string;
51
+ previousProfileKey?: string;
52
+ }): boolean;
35
53
  /**
36
54
  * Returns a single orchestrator base URL from Server-reported agents.
37
55
  * Throws when none are eligible — same failure mode as the browser's
@@ -1,18 +1,9 @@
1
- /**
2
- * Picks an orchestrator (agent) base URL the way the browser does: from the
3
- * Server's agent inventory for the org, filtered by org agent type, Active
4
- * status, and profile tags. Operators never set this URL.
5
- *
6
- * Cloud editor execute then ignores that inventory URL and posts to
7
- * SUPERBLOCKS_UI_AGENT_BASE_URL (`https://agent.<env>.superblocks.com/` on
8
- * SaaS, `https://agent.<zone>/` on cloud-prem). The cloud sentinel still
9
- * advertises `https://<control-plane>/agent`, and nginx on that path returns
10
- * 405 for POST /v2/execute and /v3/execute. Canonicalize those known-broken
11
- * paths so Gateway hits the same host the browser uses.
12
- */
1
+ import { isIP } from "node:net";
13
2
  const ACTIVE_STATUS = "Active";
14
3
  /** Matches `@superblocksteam/shared` `AgentType.MULTITENANT`. */
15
4
  const AGENT_TYPE_MULTITENANT = 0;
5
+ /** Matches `@superblocksteam/shared` `AgentType.ONPREMISE`. */
6
+ export const AGENT_TYPE_ONPREMISE = 2;
16
7
  /**
17
8
  * Control-plane hosts whose `/agent` path is not the orchestrator. US prod is
18
9
  * the exception to `agent.<control-plane>` (`app.` → `agent.superblocks.com`).
@@ -25,6 +16,26 @@ const CLOUD_ORCHESTRATOR_URL_BY_CONTROL_PLANE_HOST = {
25
16
  "staging.superblocks.com": "https://agent.staging.superblocks.com/",
26
17
  "dev.superblocks.com": "https://agent.dev.superblocks.com/",
27
18
  };
19
+ export function cloudOrchestratorBaseUrlFromControlPlane(url) {
20
+ if (!url) {
21
+ return undefined;
22
+ }
23
+ let parsed;
24
+ try {
25
+ parsed = new URL(url);
26
+ }
27
+ catch {
28
+ return undefined;
29
+ }
30
+ if (parsed.protocol !== "https:" ||
31
+ parsed.port ||
32
+ parsed.hostname === "localhost" ||
33
+ parsed.hostname.endsWith(".localhost") ||
34
+ isIP(parsed.hostname) !== 0) {
35
+ return undefined;
36
+ }
37
+ return CLOUD_ORCHESTRATOR_URL_BY_CONTROL_PLANE_HOST[parsed.hostname];
38
+ }
28
39
  function matchesProfile(tags, profileKey) {
29
40
  const profiles = tags.profile;
30
41
  if (!profiles || profiles.length === 0) {
@@ -33,6 +44,10 @@ function matchesProfile(tags, profileKey) {
33
44
  }
34
45
  return profiles.includes("*") || profiles.includes(profileKey);
35
46
  }
47
+ function isUniversalProfile(tags) {
48
+ const profiles = tags.profile;
49
+ return !profiles || profiles.length === 0 || profiles.includes("*");
50
+ }
36
51
  function withTrailingSlash(url) {
37
52
  return url.endsWith("/") ? url : `${url}/`;
38
53
  }
@@ -44,6 +59,14 @@ function withTrailingSlash(url) {
44
59
  function isAgentPath(pathname) {
45
60
  return pathname === "/agent" || pathname === "/agent/";
46
61
  }
62
+ function hasAgentPath(url) {
63
+ try {
64
+ return isAgentPath(new URL(url).pathname);
65
+ }
66
+ catch {
67
+ return false;
68
+ }
69
+ }
47
70
  function isAlreadyDedicatedAgentHost(hostname) {
48
71
  return hostname === "agent" || hostname.startsWith("agent.");
49
72
  }
@@ -78,23 +101,51 @@ export function canonicalizeOrchestratorBaseUrl(url, agentType) {
78
101
  }
79
102
  return url;
80
103
  }
104
+ /**
105
+ * Whether moving between two profile keys can move the orchestrator URL.
106
+ *
107
+ * Only on-prem inventories tag agents by profile. Cloud resolves to one agent
108
+ * host per control plane. A key changing value there picks the same URL
109
+ * so no need to evict the cache.
110
+ *
111
+ * When agent is undefined, the profile key is changing from unset to a value.
112
+ */
113
+ export function orchestratorUrlDependsOnProfile(input) {
114
+ if (input.agentType === undefined ||
115
+ input.agentType === AGENT_TYPE_ONPREMISE) {
116
+ return true;
117
+ }
118
+ return Boolean(input.previousProfileKey) !== Boolean(input.nextProfileKey);
119
+ }
81
120
  /**
82
121
  * Returns a single orchestrator base URL from Server-reported agents.
83
122
  * Throws when none are eligible — same failure mode as the browser's
84
123
  * "No active agent found".
85
124
  */
86
125
  export function pickOrchestratorBaseUrl(input) {
87
- const eligible = input.agents.filter((candidate) => candidate.type === input.agentType &&
126
+ const active = input.agents.filter((candidate) => candidate.type === input.agentType &&
88
127
  candidate.status === ACTIVE_STATUS &&
89
- Boolean(candidate.url) &&
90
- matchesProfile(candidate.tags ?? {}, input.profileKey));
91
- if (eligible.length === 0) {
92
- throw new Error(`No active agent found for agentType=${input.agentType} profile=${input.profileKey}`);
128
+ Boolean(candidate.url));
129
+ let chosen;
130
+ if (input.agentType !== AGENT_TYPE_ONPREMISE) {
131
+ const mapped = cloudOrchestratorBaseUrlFromControlPlane(input.controlPlaneUrl);
132
+ if (mapped) {
133
+ return mapped;
134
+ }
135
+ chosen = active.find((candidate) => hasAgentPath(candidate.url));
136
+ }
137
+ else if (input.profileKey) {
138
+ const profileKey = input.profileKey;
139
+ chosen = active.find((candidate) => matchesProfile(candidate.tags ?? {}, profileKey));
140
+ }
141
+ if (!chosen && !input.profileKey) {
142
+ chosen = active.find((candidate) => isUniversalProfile(candidate.tags ?? {}));
143
+ }
144
+ if (input.agentType !== AGENT_TYPE_ONPREMISE) {
145
+ chosen ??= active[0];
93
146
  }
94
- // Browser picks randomly among matches; stable first is fine for gateway.
95
- const chosen = eligible[0];
96
147
  if (!chosen) {
97
- throw new Error(`No active agent found for agentType=${input.agentType} profile=${input.profileKey}`);
148
+ throw new Error(`No active agent found for agentType=${input.agentType} profile=${input.profileKey ?? "<unset>"}`);
98
149
  }
99
150
  return withTrailingSlash(canonicalizeOrchestratorBaseUrl(chosen.url, input.agentType));
100
151
  }
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-orchestrator-url.js","sourceRoot":"","sources":["../../src/agents/resolve-orchestrator-url.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAeH,MAAM,aAAa,GAAG,QAAQ,CAAC;AAE/B,iEAAiE;AACjE,MAAM,sBAAsB,GAAG,CAAC,CAAC;AAEjC;;;;;GAKG;AACH,MAAM,4CAA4C,GAA2B;IAC3E,qBAAqB,EAAE,gCAAgC;IACvD,oBAAoB,EAAE,mCAAmC;IACzD,yBAAyB,EAAE,wCAAwC;IACnE,qBAAqB,EAAE,oCAAoC;CAC5D,CAAC;AAEF,SAAS,cAAc,CACrB,IAA8B,EAC9B,UAAkB;IAElB,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC;IAC9B,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvC,mEAAmE;QACnE,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;AACjE,CAAC;AAED,SAAS,iBAAiB,CAAC,GAAW;IACpC,OAAO,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC;AAC7C,CAAC;AAED;;;;GAIG;AACH,SAAS,WAAW,CAAC,QAAgB;IACnC,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,SAAS,CAAC;AACzD,CAAC;AAED,SAAS,2BAA2B,CAAC,QAAgB;IACnD,OAAO,QAAQ,KAAK,OAAO,IAAI,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;AAC/D,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,+BAA+B,CAC7C,GAAW,EACX,SAAkB;IAElB,IAAI,MAAW,CAAC;IAChB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,CAAC;IACb,CAAC;IACD,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;QAClC,OAAO,GAAG,CAAC;IACb,CAAC;IACD,MAAM,MAAM,GAAG,4CAA4C,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC7E,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,IACE,SAAS,KAAK,sBAAsB;QACpC,CAAC,2BAA2B,CAAC,MAAM,CAAC,QAAQ,CAAC,EAC7C,CAAC;QACD,OAAO,iBAAiB,MAAM,CAAC,QAAQ,GAAG,CAAC;IAC7C,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CACrC,KAAmC;IAEnC,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,CAClC,CAAC,SAAS,EAAE,EAAE,CACZ,SAAS,CAAC,IAAI,KAAK,KAAK,CAAC,SAAS;QAClC,SAAS,CAAC,MAAM,KAAK,aAAa;QAClC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC;QACtB,cAAc,CAAC,SAAS,CAAC,IAAI,IAAI,EAAE,EAAE,KAAK,CAAC,UAAU,CAAC,CACzD,CAAC;IACF,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CACb,uCAAuC,KAAK,CAAC,SAAS,YAAY,KAAK,CAAC,UAAU,EAAE,CACrF,CAAC;IACJ,CAAC;IACD,0EAA0E;IAC1E,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC3B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,uCAAuC,KAAK,CAAC,SAAS,YAAY,KAAK,CAAC,UAAU,EAAE,CACrF,CAAC;IACJ,CAAC;IACD,OAAO,iBAAiB,CACtB,+BAA+B,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,SAAS,CAAC,CAC7D,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"resolve-orchestrator-url.js","sourceRoot":"","sources":["../../src/agents/resolve-orchestrator-url.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { type ResolvedProfileSummary } from "../integrations/resolve-profile.js";
1
2
  import { type CapabilityContext } from "./lifecycle.js";
2
3
  import type { CapabilityResult } from "./types.js";
3
4
  export type GetIntegrationMetadataInput = {
@@ -21,6 +22,8 @@ export type GetIntegrationMetadataResult = {
21
22
  nextOffset: number | null;
22
23
  offset: number;
23
24
  pluginId: string;
25
+ /** Which profile's data this is, so a later change of profile is explainable. */
26
+ profile: ResolvedProfileSummary;
24
27
  returnedCount: number;
25
28
  totalCount: number;
26
29
  };
@@ -1,7 +1,7 @@
1
- import { pickOrchestratorBaseUrl } from "../agents/resolve-orchestrator-url.js";
1
+ import { AGENT_TYPE_ONPREMISE, pickOrchestratorBaseUrl, } from "../agents/resolve-orchestrator-url.js";
2
2
  import { integrationIsToolSupported } from "../integrations/filters.js";
3
3
  import { hasBuildPermission } from "../integrations/map.js";
4
- import { pickEditorProfileKey } from "../integrations/profile-key.js";
4
+ import { describeProfile, profileSummary, profileUnresolvedMessage, resolveProfileForApplication, } from "../integrations/resolve-profile.js";
5
5
  import { HttpOrchestratorClient } from "../orchestrator/client.js";
6
6
  import { sanitizeAgentFacingText, sanitizeAgentFacingValue, } from "../sabs/agent-facing-text.js";
7
7
  import { ensurePrincipal, resolveApplicationId, } from "./lifecycle.js";
@@ -59,6 +59,7 @@ export async function getIntegrationMetadata(context, input) {
59
59
  return principal;
60
60
  }
61
61
  let applicationId;
62
+ let profileResolution;
62
63
  // Named for the agent before the integration resolves, so a failure on the
63
64
  // way to the metadata still reports which integration it was reaching for.
64
65
  let label = sanitizeAgentFacingText(input.integrationId);
@@ -105,20 +106,41 @@ export async function getIntegrationMetadata(context, input) {
105
106
  message: `${integrationName} is a ${pluginId} integration, which this tool cannot inspect.`,
106
107
  };
107
108
  }
108
- const profiles = await context.server.getOrganizationProfiles({
109
+ ({ resolution: profileResolution } = await resolveProfileForApplication({
109
110
  apiKey: principal.value.apiKey,
111
+ applicationId,
112
+ configuredKey: context.config.profileKey,
110
113
  organizationId: principal.value.organizationId,
111
- });
112
- const profileKey = pickEditorProfileKey(context.config.profileKey, profiles);
114
+ scope: "integration_metadata",
115
+ server: context.server,
116
+ }));
117
+ const profileKey = profileResolution.key;
113
118
  const inventory = await context.server.getAgentInventory({
114
119
  apiKey: principal.value.apiKey,
115
120
  organizationId: principal.value.organizationId,
116
121
  });
117
- const orchestratorUrl = pickOrchestratorBaseUrl({
118
- agentType: inventory.agentType,
119
- agents: inventory.agents,
120
- profileKey,
121
- });
122
+ let orchestratorUrl;
123
+ try {
124
+ orchestratorUrl = pickOrchestratorBaseUrl({
125
+ agentType: inventory.agentType,
126
+ agents: inventory.agents,
127
+ controlPlaneUrl: inventory.controlPlaneUrl,
128
+ profileKey,
129
+ });
130
+ }
131
+ catch (error) {
132
+ // Only on-prem agents are picked by profile tag, so only there does a
133
+ // missing profile explain a missing agent.
134
+ if (profileKey || inventory.agentType !== AGENT_TYPE_ONPREMISE) {
135
+ throw error;
136
+ }
137
+ return {
138
+ ...(applicationId && { applicationId }),
139
+ kind: "error",
140
+ code: "integration_profile_unresolved",
141
+ message: profileUnresolvedMessage(integrationName, profileResolution),
142
+ };
143
+ }
122
144
  const scopedToken = await context.server.issueScopedToken(applicationId
123
145
  ? {
124
146
  apiKey: principal.value.apiKey,
@@ -156,6 +178,7 @@ export async function getIntegrationMetadata(context, input) {
156
178
  nextOffset,
157
179
  offset,
158
180
  pluginId,
181
+ profile: profileSummary(profileResolution),
159
182
  returnedCount: entries.length,
160
183
  totalCount: matched.length,
161
184
  },
@@ -167,7 +190,7 @@ export async function getIntegrationMetadata(context, input) {
167
190
  ...(applicationId && { applicationId }),
168
191
  kind: "error",
169
192
  code: "integration_metadata_unavailable",
170
- message: `Could not load metadata for ${label}: ${detail}`,
193
+ message: `Could not load metadata for ${label}${profileResolution ? ` (${describeProfile(profileResolution)})` : ""}: ${detail}`,
171
194
  };
172
195
  }
173
196
  }
@@ -1 +1 @@
1
- {"version":3,"file":"integration-metadata.js","sourceRoot":"","sources":["../../src/capabilities/integration-metadata.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"integration-metadata.js","sourceRoot":"","sources":["../../src/capabilities/integration-metadata.ts"],"names":[],"mappings":"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"}
@@ -60,10 +60,25 @@ export declare function resolveApplicationId(ctx: CapabilityContext, principal:
60
60
  options?: {
61
61
  unambiguous?: boolean;
62
62
  }): Promise<CapabilityResult<string>>;
63
+ /**
64
+ * Settles a user's plan approval against what became of the prompt it
65
+ * approved.
66
+ *
67
+ * The approval is claimed before the prompt goes out and spent only once
68
+ * Superblocks accepts it. A prompt that never went out hands the approval
69
+ * back, so the retry builds the plan the user already approved instead of
70
+ * failing with `approval_not_from_user`. A prompt that may have reached
71
+ * Superblocks settles neither way: handing the approval back could build the
72
+ * plan twice.
73
+ */
74
+ export type ApprovalSettlement = {
75
+ onAccepted(): void;
76
+ onNotSent(): void;
77
+ };
63
78
  export declare function startApp(ctx: CapabilityContext, input: StartAppInput): Promise<CapabilityResult<StartAppResult>>;
64
79
  export declare function uploadArtifact(ctx: CapabilityContext, input: UploadArtifactInput): Promise<CapabilityResult<UploadArtifactResult>>;
65
80
  export declare function checkAppProgress(ctx: CapabilityContext, input: CheckAppProgressInput): Promise<CapabilityResult<CheckAppProgressResult>>;
66
- export declare function editApp(ctx: CapabilityContext, input: EditAppInput, approvedPlan?: object): Promise<CapabilityResult<EditAppResult>>;
81
+ export declare function editApp(ctx: CapabilityContext, input: EditAppInput, approvedPlan?: object, approvalSettlement?: ApprovalSettlement): Promise<CapabilityResult<EditAppResult>>;
67
82
  /**
68
83
  * Shows the app's current work on a real URL without deploying it - the
69
84
  * editor's Preview button, driven from here.
@@ -2,7 +2,8 @@ import { randomUUID } from "node:crypto";
2
2
  import { readFile, realpath, stat } from "node:fs/promises";
3
3
  import path from "node:path";
4
4
  import { detectAttachmentArchiveType, getAttachmentMimeTypeFromFileName, getTextAttachmentType, isSupportedAttachmentUploadType, } from "@superblocksteam/shared";
5
- import { buildBrowserDriverContract, needsBrowserDriverError, } from "../capture/browser-contract.js";
5
+ import { buildBrowserDriverContract, HOST_BROWSER_TOOLS_COWORK, needsBrowserDriverError, } from "../capture/browser-contract.js";
6
+ import { withCoworkEditorHost } from "../capture/cowork-editor-url.js";
6
7
  import { resolveCaptureMode } from "../capture/mode.js";
7
8
  import { gatewayDebug } from "../debug.js";
8
9
  import { playwrightChromiumPresent } from "../playwright/ensure-chromium.js";
@@ -30,18 +31,25 @@ const RECENT_APP_FALLBACK_WINDOW_MS = 30 * 60 * 1000;
30
31
  * the UI serves from `/code-mode` — the legacy `/applications/:id/edit` route
31
32
  * does not open it.
32
33
  */
33
- function editUrl(config, applicationId, branch) {
34
- const base = `${config.uiBaseUrl.replace(/\/$/, "")}/code-mode/applications/edit/${applicationId}`;
35
- return branch
34
+ function editorBaseUrl(config, applicationId) {
35
+ return `${config.uiBaseUrl.replace(/\/$/, "")}/code-mode/applications/edit/${applicationId}`;
36
+ }
37
+ /** The editor URL handed to the caller, in the host mode its client renders. */
38
+ function editUrl(ctx, applicationId, branch) {
39
+ const base = editorBaseUrl(ctx.config, applicationId);
40
+ const url = branch
36
41
  ? `${base}?${new URLSearchParams({ branch }).toString()}`
37
42
  : base;
43
+ return ctx.hostBrowserTools === HOST_BROWSER_TOOLS_COWORK
44
+ ? withCoworkEditorHost(url)
45
+ : url;
38
46
  }
39
47
  function fullscreenPreviewUrl(config, applicationId, branch) {
40
48
  const params = new URLSearchParams({ fullscreen: "true" });
41
49
  if (branch) {
42
50
  params.set("branch", branch);
43
51
  }
44
- return `${editUrl(config, applicationId)}?${params.toString()}`;
52
+ return `${editorBaseUrl(config, applicationId)}?${params.toString()}`;
45
53
  }
46
54
  function uiOrigin(config) {
47
55
  return config.uiBaseUrl.replace(/\/$/, "");
@@ -237,7 +245,7 @@ function publishUrl(config, applicationId) {
237
245
  return `${config.uiBaseUrl.replace(/\/$/, "")}/code-mode/applications/${applicationId}`;
238
246
  }
239
247
  function publishDetailsUrl(config, applicationId, commitId) {
240
- return `${editUrl(config, applicationId)}?${new URLSearchParams({ commitId }).toString()}`;
248
+ return `${editorBaseUrl(config, applicationId)}?${new URLSearchParams({ commitId }).toString()}`;
241
249
  }
242
250
  /**
243
251
  * Where a built, undeployed commit can be opened — what the editor's Preview
@@ -380,7 +388,7 @@ async function elicitStepUp(ctx, idempotencyKey, applicationId, branch) {
380
388
  message: "Step-up authentication completed. Re-invoke the capability to continue.",
381
389
  };
382
390
  }
383
- const browser = await browserContractFor(ctx, editUrl(ctx.config, applicationId, branch));
391
+ const browser = await browserContractFor(ctx, editUrl(ctx, applicationId, branch));
384
392
  if (existing?.status === "pending") {
385
393
  return {
386
394
  kind: "auth_required",
@@ -838,7 +846,7 @@ async function forwardClarkPrompt(ctx, input) {
838
846
  return {
839
847
  kind: "error",
840
848
  code: "superblocks_turn_timeout",
841
- message: `Superblocks reported that the turn timed out.${forward.reply ? ` Partial reply: ${forward.reply.slice(0, 500)}` : ""} Continue in the editor at ${editUrl(ctx.config, input.applicationId, input.branch)}.`,
849
+ message: `Superblocks reported that the turn timed out.${forward.reply ? ` Partial reply: ${forward.reply.slice(0, 500)}` : ""} Continue in the editor at ${editUrl(ctx, input.applicationId, input.branch)}.`,
842
850
  pendingAction: "retry_build",
843
851
  };
844
852
  }
@@ -1170,7 +1178,7 @@ async function promptNewApplication(ctx, args) {
1170
1178
  activity: started.value.activity,
1171
1179
  applicationId,
1172
1180
  ...(branch ? { branch } : {}),
1173
- editUrl: editUrl(ctx.config, applicationId, branch),
1181
+ editUrl: editUrl(ctx, applicationId, branch),
1174
1182
  liveEditId: started.value.liveEditId ?? session.liveEditId,
1175
1183
  mode: promptArgs.mode,
1176
1184
  name: await named(),
@@ -1196,7 +1204,7 @@ async function promptNewApplication(ctx, args) {
1196
1204
  : {}),
1197
1205
  reply: forward.value.reply,
1198
1206
  ...(forward.value.decision ? { decision: forward.value.decision } : {}),
1199
- editUrl: editUrl(ctx.config, applicationId, branch),
1207
+ editUrl: editUrl(ctx, applicationId, branch),
1200
1208
  generationStatus: forward.value.generationStatus,
1201
1209
  liveEditId: forward.value.liveEditId ?? session.liveEditId,
1202
1210
  mode: promptArgs.mode,
@@ -1216,6 +1224,13 @@ async function promptNewApplication(ctx, args) {
1216
1224
  });
1217
1225
  return { kind: "ok", value: await withBrowser(ctx, result) };
1218
1226
  }
1227
+ /** Whether a result is {@link elicitStepUp} turning the prompt back. */
1228
+ function isStepUp(result) {
1229
+ return (result.kind === "auth_required" ||
1230
+ (result.kind === "error" &&
1231
+ (result.code === "needs_browser_driver" ||
1232
+ result.code === "reinvoke_required")));
1233
+ }
1219
1234
  async function runAcknowledgedStart(ctx, args) {
1220
1235
  const scope = {
1221
1236
  applicationId: args.applicationId,
@@ -1241,23 +1256,33 @@ async function runAcknowledgedStart(ctx, args) {
1241
1256
  });
1242
1257
  try {
1243
1258
  const result = await args.start();
1259
+ if (result.kind === "ok") {
1260
+ args.approvalSettlement?.onAccepted();
1261
+ }
1262
+ else {
1263
+ // An acknowledged start sends from here and nowhere else, and a send
1264
+ // that fails throws instead, so any other answer came back before the
1265
+ // prompt went out.
1266
+ args.approvalSettlement?.onNotSent();
1267
+ }
1244
1268
  if (result.kind === "error" && result.code === "reinvoke_required") {
1245
1269
  failed(new Error(result.message), `Authentication completed before Superblocks accepted the prompt for application ${args.applicationId}. Call edit_app with that applicationId and the same prompt to continue.`, "live_edit_terminated", "retry_build");
1246
1270
  }
1247
1271
  else if (result.kind === "auth_required" ||
1248
1272
  (result.kind === "error" && result.code === "needs_browser_driver")) {
1249
- failed(new Error("authentication required"), `Authentication is required before the prompt can continue. Open ${editUrl(ctx.config, args.applicationId, args.branch)} and authenticate, then call edit_app with that applicationId and the same prompt.`, "live_edit_terminated", "retry_build");
1273
+ failed(new Error("authentication required"), `Authentication is required before the prompt can continue. Open ${editUrl(ctx, args.applicationId, args.branch)} and authenticate, then call edit_app with that applicationId and the same prompt.`, "live_edit_terminated", "retry_build");
1250
1274
  }
1251
1275
  }
1252
1276
  catch (error) {
1253
1277
  if (error instanceof PromptNotSentError) {
1278
+ args.approvalSettlement?.onNotSent();
1254
1279
  const retryable = error.retryable !== false;
1255
1280
  failed(error, retryable
1256
1281
  ? `The prompt was not sent, so nothing was built. Call edit_app for application ${args.applicationId} with the same instruction to retry. (${error.message})`
1257
1282
  : `The replacement live-edit session also stopped responding, so Gateway cannot safely retry this build. Start a new application instead. (${error.message})`, "live_edit_terminated", retryable ? "retry_build" : undefined, error.retryable, error.recoveryAction);
1258
1283
  }
1259
1284
  else {
1260
- failed(error, `The prompt acknowledgement was lost and the prompt may have reached Superblocks. Do not resend it; open ${editUrl(ctx.config, args.applicationId, args.branch)} to check the existing application. (${error instanceof Error ? error.message : String(error)})`, "detached");
1285
+ failed(error, `The prompt acknowledgement was lost and the prompt may have reached Superblocks. Do not resend it; open ${editUrl(ctx, args.applicationId, args.branch)} to check the existing application. (${error instanceof Error ? error.message : String(error)})`, "detached");
1261
1286
  }
1262
1287
  }
1263
1288
  finally {
@@ -1355,7 +1380,7 @@ export async function startApp(ctx, input) {
1355
1380
  value: await withBrowser(ctx, {
1356
1381
  applicationId: app.id,
1357
1382
  ...(branch ? { branch } : {}),
1358
- editUrl: editUrl(ctx.config, app.id, branch),
1383
+ editUrl: editUrl(ctx, app.id, branch),
1359
1384
  mode: input.mode ?? "PLAN",
1360
1385
  name,
1361
1386
  status: "building",
@@ -1892,7 +1917,7 @@ export async function checkAppProgress(ctx, input) {
1892
1917
  activity,
1893
1918
  applicationId,
1894
1919
  ...(branch ? { branch } : {}),
1895
- editUrl: editUrl(ctx.config, applicationId, branch),
1920
+ editUrl: editUrl(ctx, applicationId, branch),
1896
1921
  elapsedSeconds,
1897
1922
  ...(update.viewStatus ? { viewStatus: update.viewStatus } : {}),
1898
1923
  ...("recentRuns" in update &&
@@ -2024,7 +2049,7 @@ async function recordTurnSignals(ctx, input) {
2024
2049
  }
2025
2050
  return stallHint ? { stallHint } : {};
2026
2051
  }
2027
- export async function editApp(ctx, input, approvedPlan) {
2052
+ export async function editApp(ctx, input, approvedPlan, approvalSettlement) {
2028
2053
  const principalResult = await ensurePrincipal(ctx);
2029
2054
  if (principalResult.kind !== "ok") {
2030
2055
  return principalResult;
@@ -2038,6 +2063,7 @@ export async function editApp(ctx, input, approvedPlan) {
2038
2063
  return namingApplication(applicationId, await promptExistingApplication(ctx, {
2039
2064
  applicationId,
2040
2065
  approvedPlan,
2066
+ ...(approvalSettlement ? { approvalSettlement } : {}),
2041
2067
  input,
2042
2068
  principal,
2043
2069
  }));
@@ -2104,14 +2130,18 @@ async function promptExistingApplication(ctx, args) {
2104
2130
  userId: principal.userId,
2105
2131
  });
2106
2132
  const { signal: _requestSignal, ...backgroundContext } = ctx;
2133
+ // Settled by the background start alone, which is the only part that
2134
+ // learns whether the prompt went out.
2135
+ const { approvalSettlement, ...startArgs } = args;
2107
2136
  void runAcknowledgedStart(backgroundContext, {
2108
2137
  applicationId,
2138
+ ...(approvalSettlement ? { approvalSettlement } : {}),
2109
2139
  branch,
2110
2140
  idempotencyKey: input.idempotencyKey,
2111
2141
  pendingStartToken,
2112
2142
  principal,
2113
2143
  start: () => promptExistingApplication(backgroundContext, {
2114
- ...args,
2144
+ ...startArgs,
2115
2145
  ...(approvingUncapturedPlan ? { approvingUncapturedPlan } : {}),
2116
2146
  input: { ...input, ...(branch ? { branch } : {}) },
2117
2147
  pendingStartToken,
@@ -2126,7 +2156,7 @@ async function promptExistingApplication(ctx, args) {
2126
2156
  value: await withBrowser(ctx, {
2127
2157
  applicationId,
2128
2158
  ...(branch ? { branch } : {}),
2129
- editUrl: editUrl(ctx.config, applicationId, branch),
2159
+ editUrl: editUrl(ctx, applicationId, branch),
2130
2160
  mode,
2131
2161
  status: "building",
2132
2162
  }),
@@ -2310,13 +2340,30 @@ async function promptExistingApplication(ctx, args) {
2310
2340
  activity: started.value.activity,
2311
2341
  applicationId,
2312
2342
  ...(branch ? { branch } : {}),
2313
- editUrl: editUrl(ctx.config, applicationId, branch),
2343
+ editUrl: editUrl(ctx, applicationId, branch),
2314
2344
  mode: promptArgs.mode,
2315
2345
  status: "building",
2316
2346
  }),
2317
2347
  };
2318
2348
  }
2319
- const forward = await forwardClarkPrompt(ctx, promptArgs);
2349
+ let forward;
2350
+ try {
2351
+ forward = await forwardClarkPrompt(ctx, promptArgs);
2352
+ }
2353
+ catch (error) {
2354
+ if (error instanceof PromptNotSentError) {
2355
+ args.approvalSettlement?.onNotSent();
2356
+ }
2357
+ throw error;
2358
+ }
2359
+ // A blocking forward returns only once Superblocks took the prompt and ran
2360
+ // the turn, so any answer but a step-up means the approval was used.
2361
+ if (isStepUp(forward)) {
2362
+ args.approvalSettlement?.onNotSent();
2363
+ }
2364
+ else {
2365
+ args.approvalSettlement?.onAccepted();
2366
+ }
2320
2367
  if (forward.kind !== "ok") {
2321
2368
  return forward;
2322
2369
  }
@@ -2335,7 +2382,7 @@ async function promptExistingApplication(ctx, args) {
2335
2382
  : {}),
2336
2383
  reply: forward.value.reply,
2337
2384
  ...(forward.value.decision ? { decision: forward.value.decision } : {}),
2338
- editUrl: editUrl(ctx.config, applicationId, branch),
2385
+ editUrl: editUrl(ctx, applicationId, branch),
2339
2386
  generationStatus: forward.value.generationStatus,
2340
2387
  mode: promptArgs.mode,
2341
2388
  ...(forward.value.recentRuns && forward.value.recentRuns.length > 0
@@ -2545,7 +2592,7 @@ export async function previewApp(ctx, input) {
2545
2592
  ...(input.branch ? { branch: input.branch } : {}),
2546
2593
  commitId: commit.commitId,
2547
2594
  directoryHash,
2548
- editUrl: editUrl(ctx.config, applicationId, input.branch),
2595
+ editUrl: editUrl(ctx, applicationId, input.branch),
2549
2596
  ...(name ? { name } : {}),
2550
2597
  ...(needsBrowserDriver ? { needsBrowserDriver: true } : {}),
2551
2598
  openableViaHttps: openable.openableViaHttps,
@@ -2616,7 +2663,7 @@ export async function getPreviewStatus(ctx, input) {
2616
2663
  kind: "ok",
2617
2664
  value: {
2618
2665
  ...preview,
2619
- editUrl: editUrl(ctx.config, input.applicationId, input.branch),
2666
+ editUrl: editUrl(ctx, input.applicationId, input.branch),
2620
2667
  status,
2621
2668
  },
2622
2669
  };
@@ -2773,7 +2820,7 @@ async function unbuiltApp(ctx, principal, applicationId, requestedBranch) {
2773
2820
  const app = await withBrowser(ctx, {
2774
2821
  applicationId,
2775
2822
  ...(actualBranch ? { branch: actualBranch } : {}),
2776
- editUrl: editUrl(ctx.config, applicationId, actualBranch),
2823
+ editUrl: editUrl(ctx, applicationId, actualBranch),
2777
2824
  ...(name ? { name } : {}),
2778
2825
  });
2779
2826
  if (reason.kind === "awaiting_decision") {
@@ -2872,7 +2919,7 @@ export async function askUser(ctx, input) {
2872
2919
  const app = {
2873
2920
  applicationId,
2874
2921
  ...(branch ? { branch } : {}),
2875
- editUrl: editUrl(ctx.config, applicationId, branch),
2922
+ editUrl: editUrl(ctx, applicationId, branch),
2876
2923
  ...(unbuilt?.value.name ? { name: unbuilt.value.name } : {}),
2877
2924
  };
2878
2925
  if (!unbuilt || unbuilt.value.status !== "needs_decision") {
@@ -2959,7 +3006,7 @@ export async function getApp(ctx, input) {
2959
3006
  value: await withBrowser(ctx, {
2960
3007
  applicationId,
2961
3008
  ...(branch ? { branch } : {}),
2962
- editUrl: editUrl(ctx.config, applicationId, branch),
3009
+ editUrl: editUrl(ctx, applicationId, branch),
2963
3010
  ...(name ? { name } : {}),
2964
3011
  ...(liveShot.needsBrowserDriver ? { needsBrowserDriver: true } : {}),
2965
3012
  openableViaHttps: isHttpsUrl(previewUrl),