@superblocksteam/gateway 2.0.157-next.5 → 2.0.157
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 +3 -30
- package/dist/capabilities/lifecycle.d.ts +1 -12
- package/dist/capabilities/lifecycle.js +51 -99
- package/dist/capabilities/lifecycle.js.map +1 -1
- package/dist/capabilities/types.d.ts +0 -5
- package/dist/capabilities/types.js.map +1 -1
- package/dist/deps.d.ts +0 -2
- package/dist/integrations/map.d.ts +0 -1
- package/dist/integrations/map.js +1 -1
- package/dist/integrations/map.js.map +1 -1
- package/dist/sabs/editor-client-methods.js +5 -4
- package/dist/sabs/editor-client-methods.js.map +1 -1
- package/dist/sabs/session-peer.d.ts +0 -4
- package/dist/sabs/websocket-session-peer.d.ts +1 -2
- package/dist/sabs/websocket-session-peer.js +11 -21
- package/dist/sabs/websocket-session-peer.js.map +1 -1
- package/dist/server/client.d.ts +4 -10
- package/dist/server/client.js +4 -13
- package/dist/server/client.js.map +1 -1
- package/dist/start.d.ts +0 -10
- package/dist/start.js +2 -5
- package/dist/start.js.map +1 -1
- package/dist/transports/mcp/admin-tools.d.ts +1 -3
- package/dist/transports/mcp/admin-tools.js +1 -12
- package/dist/transports/mcp/admin-tools.js.map +1 -1
- package/dist/transports/mcp/app-status-html.d.ts +2 -2
- package/dist/transports/mcp/app-status-html.js +8 -139
- package/dist/transports/mcp/app-status-html.js.map +1 -1
- package/dist/transports/mcp/mount.js +24 -89
- package/dist/transports/mcp/mount.js.map +1 -1
- package/package.json +4 -5
- package/dist/capabilities/integration-metadata.d.ts +0 -28
- package/dist/capabilities/integration-metadata.js +0 -174
- package/dist/capabilities/integration-metadata.js.map +0 -1
- package/dist/telemetry/mcp-client.d.ts +0 -22
- package/dist/telemetry/mcp-client.js +0 -129
- package/dist/telemetry/mcp-client.js.map +0 -1
- package/dist/telemetry/runtime.d.ts +0 -9
- package/dist/telemetry/runtime.js +0 -121
- package/dist/telemetry/runtime.js.map +0 -1
package/README.md
CHANGED
|
@@ -4,8 +4,8 @@ Standalone Superblocks entry point for a **single MCP connector** (Admin + Build
|
|
|
4
4
|
over **stdio**, running as the already-logged-in Superblocks CLI user.
|
|
5
5
|
|
|
6
6
|
Builder tools (`start_app`, `import_app`, `edit_app`, `check_app_progress`,
|
|
7
|
-
`get_app`, `
|
|
8
|
-
|
|
7
|
+
`get_app`, `preview_app`, `publish_app`) plus customer Admin tools from
|
|
8
|
+
`@superblocksteam/mcp-server` share this process.
|
|
9
9
|
|
|
10
10
|
The MCP host owns process lifecycle: it spawns `superblocks gateway serve`.
|
|
11
11
|
There is no foreground HTTP `/mcp`, no OAuth resource server, and no linked-grant
|
|
@@ -147,18 +147,7 @@ package only the customer Admin surface. Builder tools are not registered.
|
|
|
147
147
|
## MCP tools
|
|
148
148
|
|
|
149
149
|
After `gateway setup`, restart Claude Code or Cursor and call `start_app`,
|
|
150
|
-
`edit_app`, `check_app_progress`, `get_app`, `
|
|
151
|
-
`preview_app`, and `publish_app`. `get_integration_metadata` reads tables,
|
|
152
|
-
columns, and types from a connected integration; use `search`, `limit`, and
|
|
153
|
-
`offset` for large results. It needs no application: without one it mints an
|
|
154
|
-
`integrations:build` token scoped to that single integration. Pass
|
|
155
|
-
`applicationId` only for an integration owned by one application, such as a
|
|
156
|
-
Native DB, which is invisible without app context.
|
|
157
|
-
It resolves the integration through the RBAC-annotated superset list rather than
|
|
158
|
-
the org-wide lookup by id, so it answers `integration_not_permitted` without
|
|
159
|
-
build permission on that integration and `integration_not_supported` for a
|
|
160
|
-
plugin Clark cannot use as a tool.
|
|
161
|
-
`get_integration_config_schema` is the create-integration form, not live data.
|
|
150
|
+
`edit_app`, `check_app_progress`, `get_app`, `preview_app`, and `publish_app`.
|
|
162
151
|
See `.env.example` for optional configuration.
|
|
163
152
|
|
|
164
153
|
## Env
|
|
@@ -179,19 +168,3 @@ Gateway debug logs include tool names, result states, decision branches, and
|
|
|
179
168
|
entry-point stacks. They intentionally omit credentials, prompts, answers, and
|
|
180
169
|
result payloads. Run `superblocks gateway setup --client <client> --debug`, then
|
|
181
170
|
restart the MCP host. Re-run setup without `--debug` to turn them off.
|
|
182
|
-
|
|
183
|
-
## Remote traceability
|
|
184
|
-
|
|
185
|
-
Gateway exports one OpenTelemetry trace per MCP process through the authenticated
|
|
186
|
-
Server `/api/v1/traces` proxy. Each tool call is a child span with the MCP client
|
|
187
|
-
name and version, tool name, duration, outcome, organization ID, and application
|
|
188
|
-
ID when available.
|
|
189
|
-
|
|
190
|
-
Prompts, answers, result payloads, credentials, and raw error messages are never
|
|
191
|
-
added to these spans. Use the application ID to correlate a trace with the
|
|
192
|
-
existing server-side app and build records.
|
|
193
|
-
|
|
194
|
-
Cloud-Prem uses `SUPERBLOCKS_DEPLOYMENT_TYPE=cloud-prem` (or `GATEWAY_LOCAL_AGENT`)
|
|
195
|
-
so the stricter telemetry policy is selected. Laptop agents still drop client,
|
|
196
|
-
organization, and application attributes until the Tier 2 traces contract lists
|
|
197
|
-
them; tool name, duration, and outcome still export.
|
|
@@ -5,7 +5,7 @@ import type { CapturePreviewScreenshot } from "../preview/capture-screenshot.js"
|
|
|
5
5
|
import type { CallerRef, ProgressStore, RecentAppStore, TurnStore } from "../resume/types.js";
|
|
6
6
|
import type { SessionPeer } from "../sabs/session-peer.js";
|
|
7
7
|
import type { SuperblocksServerClient } from "../server/client.js";
|
|
8
|
-
import type { CapabilityResult, CheckAppProgressInput, CheckAppProgressResult, EditAppInput, EditAppResult, GetAppInput, GetAppResult, ImportAppInput, ImportAppResult, PreviewAppInput, PreviewAppResult, Principal, ProgressEvent, PublishAppInput, PublishAppResult,
|
|
8
|
+
import type { CapabilityResult, CheckAppProgressInput, CheckAppProgressResult, EditAppInput, EditAppResult, GetAppInput, GetAppResult, ImportAppInput, ImportAppResult, PreviewAppInput, PreviewAppResult, Principal, ProgressEvent, PublishAppInput, PublishAppResult, StartAppInput, StartAppResult } from "./types.js";
|
|
9
9
|
export { IMPORT_ZIP_MAX_BYTES } from "./types.js";
|
|
10
10
|
export type CapabilityContext = {
|
|
11
11
|
/**
|
|
@@ -23,7 +23,6 @@ export type CapabilityContext = {
|
|
|
23
23
|
/** Injected so pacing and stall thresholds are testable without real time. */
|
|
24
24
|
now?: () => number;
|
|
25
25
|
onProgress?: (event: ProgressEvent) => void;
|
|
26
|
-
onPrincipalResolved?: (principal: ResolvedPrincipal) => void;
|
|
27
26
|
principal: Principal;
|
|
28
27
|
/** Where each caller's place in the event stream is kept between calls. */
|
|
29
28
|
progressCursors?: ProgressStore;
|
|
@@ -45,16 +44,6 @@ export type CapabilityContext = {
|
|
|
45
44
|
signal?: AbortSignal;
|
|
46
45
|
turns: TurnStore;
|
|
47
46
|
};
|
|
48
|
-
/**
|
|
49
|
-
* Resolves the Superblocks user behind the CLI session this Gateway was
|
|
50
|
-
* started with.
|
|
51
|
-
*
|
|
52
|
-
* Identity is the already-logged-in Superblocks CLI user. A rejection here
|
|
53
|
-
* means that personal API key is bad, not that the user needs a second login,
|
|
54
|
-
* so it surfaces as an error rather than an interactive-auth elicitation.
|
|
55
|
-
*/
|
|
56
|
-
export declare function ensurePrincipal(ctx: CapabilityContext): Promise<CapabilityResult<ResolvedPrincipal>>;
|
|
57
|
-
export declare function resolveApplicationId(ctx: CapabilityContext, principal: ResolvedPrincipal, applicationId: string | undefined): Promise<CapabilityResult<string>>;
|
|
58
47
|
export declare function startApp(ctx: CapabilityContext, input: StartAppInput): Promise<CapabilityResult<StartAppResult>>;
|
|
59
48
|
/**
|
|
60
49
|
* Creates a fullstack app, uploads the caller's archive as an app attachment,
|
|
@@ -228,21 +228,19 @@ function defaultAppName(prompt) {
|
|
|
228
228
|
* means that personal API key is bad, not that the user needs a second login,
|
|
229
229
|
* so it surfaces as an error rather than an interactive-auth elicitation.
|
|
230
230
|
*/
|
|
231
|
-
|
|
231
|
+
async function ensurePrincipal(ctx) {
|
|
232
232
|
const { principal } = ctx;
|
|
233
233
|
// MCP already has the CLI session key. Looking it up again would spend a
|
|
234
234
|
// second round trip on `/users/me`, the slowest endpoint the Superblocks
|
|
235
235
|
// API has, when the principal is already resolved (ENG-5806).
|
|
236
236
|
if (principal.organizationId && principal.userId) {
|
|
237
|
-
const resolved = {
|
|
238
|
-
...principal,
|
|
239
|
-
organizationId: principal.organizationId,
|
|
240
|
-
userId: principal.userId,
|
|
241
|
-
};
|
|
242
|
-
ctx.onPrincipalResolved?.(resolved);
|
|
243
237
|
return {
|
|
244
238
|
kind: "ok",
|
|
245
|
-
value:
|
|
239
|
+
value: {
|
|
240
|
+
...principal,
|
|
241
|
+
organizationId: principal.organizationId,
|
|
242
|
+
userId: principal.userId,
|
|
243
|
+
},
|
|
246
244
|
};
|
|
247
245
|
}
|
|
248
246
|
let validated;
|
|
@@ -279,16 +277,14 @@ export async function ensurePrincipal(ctx) {
|
|
|
279
277
|
message: "The Superblocks API rejected the credential issued for this caller.",
|
|
280
278
|
};
|
|
281
279
|
}
|
|
282
|
-
const resolved = {
|
|
283
|
-
...principal,
|
|
284
|
-
email: validated.email,
|
|
285
|
-
organizationId: validated.organizationId,
|
|
286
|
-
userId: validated.userId,
|
|
287
|
-
};
|
|
288
|
-
ctx.onPrincipalResolved?.(resolved);
|
|
289
280
|
return {
|
|
290
281
|
kind: "ok",
|
|
291
|
-
value:
|
|
282
|
+
value: {
|
|
283
|
+
...principal,
|
|
284
|
+
email: validated.email,
|
|
285
|
+
organizationId: validated.organizationId,
|
|
286
|
+
userId: validated.userId,
|
|
287
|
+
},
|
|
292
288
|
};
|
|
293
289
|
}
|
|
294
290
|
/**
|
|
@@ -383,7 +379,7 @@ async function elicitStepUp(ctx, idempotencyKey, applicationId) {
|
|
|
383
379
|
},
|
|
384
380
|
};
|
|
385
381
|
}
|
|
386
|
-
|
|
382
|
+
async function resolveApplicationId(ctx, principal, applicationId) {
|
|
387
383
|
if (applicationId?.trim()) {
|
|
388
384
|
return { kind: "ok", value: applicationId.trim() };
|
|
389
385
|
}
|
|
@@ -517,9 +513,7 @@ function turnSummary(turn) {
|
|
|
517
513
|
return "Superblocks is still working, but only the editor can show it — open the edit URL";
|
|
518
514
|
}
|
|
519
515
|
if (turn.generationStatus === "live_edit_terminated") {
|
|
520
|
-
return
|
|
521
|
-
? "The Superblocks live-edit session terminated before anything was built — send the archive again with import_app"
|
|
522
|
-
: "The Superblocks live-edit session terminated before anything was built — send the prompt again with edit_app";
|
|
516
|
+
return "The Superblocks live-edit session terminated before anything was built — send the prompt again with edit_app";
|
|
523
517
|
}
|
|
524
518
|
if (turn.checkpointCommitId) {
|
|
525
519
|
return `Application ready — checkpoint saved. ${NEXT_STEPS}`;
|
|
@@ -675,7 +669,6 @@ async function forwardClarkPrompt(ctx, input) {
|
|
|
675
669
|
...(forward.recentRuns && forward.recentRuns.length > 0
|
|
676
670
|
? { recentRuns: forward.recentRuns }
|
|
677
671
|
: {}),
|
|
678
|
-
...(forward.retryAction ? { retryAction: forward.retryAction } : {}),
|
|
679
672
|
viewStatus: forward.viewStatus,
|
|
680
673
|
},
|
|
681
674
|
};
|
|
@@ -765,13 +758,17 @@ function namingCreatedApplication(applicationId, capability, result) {
|
|
|
765
758
|
* The recovery to advertise when the machinery around a turn fails: `edit_app`
|
|
766
759
|
* with the same prompt, which is what `retry_build` means.
|
|
767
760
|
*
|
|
768
|
-
*
|
|
769
|
-
*
|
|
770
|
-
*
|
|
761
|
+
* Only for a prompt `edit_app` could actually replay. A prompt carrying
|
|
762
|
+
* attachments is not one: `edit_app` has no way to resupply an attachment, so
|
|
763
|
+
* an import's migration prompt would reach Superblocks describing an archive it
|
|
764
|
+
* cannot see. Advertising a recovery that cannot finish is worse than
|
|
765
|
+
* advertising none, so the import path gets `applicationId` and no hint.
|
|
766
|
+
* TODO(ENG-5917): let `import_app` resume into an application it already
|
|
767
|
+
* created, and give the import path a recovery of its own.
|
|
771
768
|
*/
|
|
772
769
|
function retryIfReplayable(attachments) {
|
|
773
770
|
return attachments && attachments.length > 0
|
|
774
|
-
?
|
|
771
|
+
? undefined
|
|
775
772
|
: { pendingAction: "retry_build" };
|
|
776
773
|
}
|
|
777
774
|
/**
|
|
@@ -813,9 +810,7 @@ function rememberFailedStart(ctx, input) {
|
|
|
813
810
|
organizationId: input.principal.organizationId,
|
|
814
811
|
// Reaches the caller as the dead start's reply on its next poll, so it
|
|
815
812
|
// has to stand on its own there rather than lean on this call's error.
|
|
816
|
-
reason: input.
|
|
817
|
-
`The Superblocks live-edit session for application ${input.applicationId} never opened, so the prompt never reached Superblocks and nothing was built. Nothing is running for that application; send the same instruction again to retry it. (${cause})`,
|
|
818
|
-
...(input.retryAction ? { retryAction: input.retryAction } : {}),
|
|
813
|
+
reason: `The Superblocks live-edit session for application ${input.applicationId} never opened, so the prompt never reached Superblocks and nothing was built. Nothing is running for that application; send the same instruction again to retry it. (${cause})`,
|
|
819
814
|
userId: input.principal.userId,
|
|
820
815
|
});
|
|
821
816
|
}
|
|
@@ -871,12 +866,7 @@ async function promptNewApplication(ctx, args) {
|
|
|
871
866
|
});
|
|
872
867
|
}
|
|
873
868
|
catch (error) {
|
|
874
|
-
rememberFailedStart(ctx, {
|
|
875
|
-
applicationId,
|
|
876
|
-
error,
|
|
877
|
-
principal,
|
|
878
|
-
...(args.attachments?.length ? { retryAction: "retry_import" } : {}),
|
|
879
|
-
});
|
|
869
|
+
rememberFailedStart(ctx, { applicationId, error, principal });
|
|
880
870
|
return liveEditUnavailable(error, args.attachments);
|
|
881
871
|
}
|
|
882
872
|
ctx.onProgress?.({
|
|
@@ -1161,19 +1151,14 @@ function normalizeImportSource(source) {
|
|
|
1161
1151
|
* wizard, without the sessionStorage hop.
|
|
1162
1152
|
*/
|
|
1163
1153
|
export async function importApp(ctx, input) {
|
|
1164
|
-
const resumedApplicationId = input.applicationId?.trim();
|
|
1165
1154
|
const archiveResult = await resolveImportArchive(input, ctx.config.importSearchDirs);
|
|
1166
1155
|
if (archiveResult.kind !== "ok") {
|
|
1167
|
-
return
|
|
1168
|
-
? namingApplication(resumedApplicationId, archiveResult)
|
|
1169
|
-
: archiveResult;
|
|
1156
|
+
return archiveResult;
|
|
1170
1157
|
}
|
|
1171
1158
|
const archive = archiveResult.value;
|
|
1172
1159
|
const principalResult = await ensurePrincipal(ctx);
|
|
1173
1160
|
if (principalResult.kind !== "ok") {
|
|
1174
|
-
return
|
|
1175
|
-
? namingApplication(resumedApplicationId, principalResult)
|
|
1176
|
-
: principalResult;
|
|
1161
|
+
return principalResult;
|
|
1177
1162
|
}
|
|
1178
1163
|
const principal = principalResult.value;
|
|
1179
1164
|
const source = normalizeImportSource(input.source);
|
|
@@ -1184,26 +1169,25 @@ export async function importApp(ctx, input) {
|
|
|
1184
1169
|
});
|
|
1185
1170
|
const explicitName = input.name?.trim();
|
|
1186
1171
|
const name = explicitName || defaultAppName(migrationPrompt);
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
if (created.kind !== "ok") {
|
|
1200
|
-
return created;
|
|
1201
|
-
}
|
|
1202
|
-
applicationId = created.value.id;
|
|
1172
|
+
ctx.onProgress?.({
|
|
1173
|
+
message: "Creating application for import",
|
|
1174
|
+
type: "progress",
|
|
1175
|
+
});
|
|
1176
|
+
const created = await createApplicationForPrompt(ctx, {
|
|
1177
|
+
apiKey: principal.apiKey,
|
|
1178
|
+
name,
|
|
1179
|
+
organizationId: principal.organizationId,
|
|
1180
|
+
templateName: "app-fullstack",
|
|
1181
|
+
});
|
|
1182
|
+
if (created.kind !== "ok") {
|
|
1183
|
+
return created;
|
|
1203
1184
|
}
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1185
|
+
const app = created.value;
|
|
1186
|
+
// See startApp: the row outlives any failure below it, so it is already this
|
|
1187
|
+
// caller's most recent app.
|
|
1188
|
+
await rememberApplication(ctx, principal, app.id);
|
|
1189
|
+
return namingCreatedApplication(app.id, "import_app", await migrateArchiveIntoApplication(ctx, {
|
|
1190
|
+
applicationId: app.id,
|
|
1207
1191
|
archive,
|
|
1208
1192
|
explicitName,
|
|
1209
1193
|
input,
|
|
@@ -1211,10 +1195,7 @@ export async function importApp(ctx, input) {
|
|
|
1211
1195
|
name,
|
|
1212
1196
|
principal,
|
|
1213
1197
|
source,
|
|
1214
|
-
});
|
|
1215
|
-
return resumedApplicationId
|
|
1216
|
-
? namingApplication(applicationId, result)
|
|
1217
|
-
: namingCreatedApplication(applicationId, "import_app", result);
|
|
1198
|
+
}));
|
|
1218
1199
|
}
|
|
1219
1200
|
/**
|
|
1220
1201
|
* Uploads the archive onto an application that already exists and hands
|
|
@@ -1238,18 +1219,10 @@ async function migrateArchiveIntoApplication(ctx, args) {
|
|
|
1238
1219
|
}
|
|
1239
1220
|
catch (error) {
|
|
1240
1221
|
const message = error instanceof Error ? error.message : String(error);
|
|
1241
|
-
rememberFailedStart(ctx, {
|
|
1242
|
-
applicationId,
|
|
1243
|
-
error,
|
|
1244
|
-
principal,
|
|
1245
|
-
reason: `The archive for application ${applicationId} could not be uploaded, so the migration never started and nothing was built. Send the same archive again with import_app to retry it. (${message})`,
|
|
1246
|
-
retryAction: "retry_import",
|
|
1247
|
-
});
|
|
1248
1222
|
return {
|
|
1249
1223
|
kind: "error",
|
|
1250
1224
|
code: "import_upload_failed",
|
|
1251
1225
|
message,
|
|
1252
|
-
pendingAction: "retry_import",
|
|
1253
1226
|
};
|
|
1254
1227
|
}
|
|
1255
1228
|
return promptNewApplication(ctx, {
|
|
@@ -1275,13 +1248,7 @@ async function migrateArchiveIntoApplication(ctx, args) {
|
|
|
1275
1248
|
prompt: args.migrationPrompt,
|
|
1276
1249
|
});
|
|
1277
1250
|
}
|
|
1278
|
-
/**
|
|
1279
|
-
* Machine-readable shape a cancelled wait answers with.
|
|
1280
|
-
*
|
|
1281
|
-
* Callers name the application alongside it. A cancelled wait says nothing
|
|
1282
|
-
* about the work, which carries on: a caller asked to resume it has to be able
|
|
1283
|
-
* to point at the application rather than start a second one.
|
|
1284
|
-
*/
|
|
1251
|
+
/** Machine-readable shape a cancelled wait answers with. */
|
|
1285
1252
|
function cancelled(capability) {
|
|
1286
1253
|
return {
|
|
1287
1254
|
kind: "error",
|
|
@@ -1370,7 +1337,7 @@ export async function checkAppProgress(ctx, input) {
|
|
|
1370
1337
|
// while the credential was being resolved should never reach the point of
|
|
1371
1338
|
// registering a waiter it will not read.
|
|
1372
1339
|
if (ctx.signal?.aborted) {
|
|
1373
|
-
return
|
|
1340
|
+
return cancelled("check_app_progress");
|
|
1374
1341
|
}
|
|
1375
1342
|
const cursorKey = cursorKeyFor(ctx, principal, applicationId);
|
|
1376
1343
|
const stored = cursorKey
|
|
@@ -1384,7 +1351,7 @@ export async function checkAppProgress(ctx, input) {
|
|
|
1384
1351
|
waitMs: hostCallBudgetMs(ctx, ctx.config.clarkProgressWaitMs),
|
|
1385
1352
|
});
|
|
1386
1353
|
if (ctx.signal?.aborted) {
|
|
1387
|
-
return
|
|
1354
|
+
return cancelled("check_app_progress");
|
|
1388
1355
|
}
|
|
1389
1356
|
const snapshot = await readSnapshot(ctx, {
|
|
1390
1357
|
applicationId,
|
|
@@ -1502,9 +1469,6 @@ export async function checkAppProgress(ctx, input) {
|
|
|
1502
1469
|
reply: update.reply,
|
|
1503
1470
|
...(update.decision ? { decision: update.decision } : {}),
|
|
1504
1471
|
generationStatus: update.generationStatus,
|
|
1505
|
-
...(update.retryAction && emptyTurnStatus(update.generationStatus)
|
|
1506
|
-
? { pendingAction: update.retryAction }
|
|
1507
|
-
: {}),
|
|
1508
1472
|
status,
|
|
1509
1473
|
viewStatus: update.viewStatus,
|
|
1510
1474
|
},
|
|
@@ -2089,13 +2053,7 @@ function localUnbuiltReason(turn, pending) {
|
|
|
2089
2053
|
return undefined;
|
|
2090
2054
|
}
|
|
2091
2055
|
const status = emptyTurnStatus(turn.generationStatus);
|
|
2092
|
-
return status
|
|
2093
|
-
? {
|
|
2094
|
-
kind: "empty_turn",
|
|
2095
|
-
retryAction: turn.retryAction ?? "retry_build",
|
|
2096
|
-
status,
|
|
2097
|
-
}
|
|
2098
|
-
: undefined;
|
|
2056
|
+
return status ? { kind: "empty_turn", status } : undefined;
|
|
2099
2057
|
}
|
|
2100
2058
|
/**
|
|
2101
2059
|
* The same question asked of what was persisted, for a caller with no live turn
|
|
@@ -2183,8 +2141,6 @@ function persistedTurnEnd(status) {
|
|
|
2183
2141
|
// plain question and cannot be approved.
|
|
2184
2142
|
case "needs_decision":
|
|
2185
2143
|
return { kind: "awaiting_decision" };
|
|
2186
|
-
// The stream never recorded whether the prompt carried an archive, so
|
|
2187
|
-
// this path cannot pick retry_build vs retry_import. Omit rather than guess.
|
|
2188
2144
|
case "live_edit_terminated":
|
|
2189
2145
|
return { kind: "empty_turn", status };
|
|
2190
2146
|
// A `cancelled` in the tail may still have a real app behind it: the
|
|
@@ -2256,11 +2212,7 @@ async function unbuiltApp(ctx, principal, applicationId) {
|
|
|
2256
2212
|
if (reason.kind === "empty_turn") {
|
|
2257
2213
|
return {
|
|
2258
2214
|
kind: "ok",
|
|
2259
|
-
value: {
|
|
2260
|
-
...app,
|
|
2261
|
-
...(reason.retryAction ? { pendingAction: reason.retryAction } : {}),
|
|
2262
|
-
status: reason.status,
|
|
2263
|
-
},
|
|
2215
|
+
value: { ...app, pendingAction: "retry_build", status: reason.status },
|
|
2264
2216
|
};
|
|
2265
2217
|
}
|
|
2266
2218
|
return {
|
|
@@ -2394,7 +2346,7 @@ async function waitForBuild(ctx, input) {
|
|
|
2394
2346
|
let started = false;
|
|
2395
2347
|
for (;;) {
|
|
2396
2348
|
if (ctx.signal?.aborted) {
|
|
2397
|
-
return
|
|
2349
|
+
return cancelled("get_app");
|
|
2398
2350
|
}
|
|
2399
2351
|
// Checked before the network call, not only after it: a budget already
|
|
2400
2352
|
// exhausted when this loop begins (or used up by the previous
|