@cmmd-center/forge 0.14.1 → 0.14.2
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/dist/bin.cjs +487 -41
- package/dist/bin.mjs +511 -65
- package/dist/client/assets/{CanvasPanel-BeSvnc85.js → CanvasPanel-Bk1rL0LG.js} +3 -3
- package/dist/client/assets/CompositeItem-D1GrQhpu.js +2 -0
- package/dist/client/assets/CompositeList-CEBk8sf_.js +2 -0
- package/dist/client/assets/DiffPanel-jC25MVg8.js +64 -0
- package/dist/client/assets/{DiffPanel.logic-CAb-hngG.js → DiffPanel.logic-DHo4jHZM.js} +6 -6
- package/dist/client/assets/{DiffWorkerPoolProvider-BbyQb-ye.js → DiffWorkerPoolProvider-r1DUfA1d.js} +10 -10
- package/dist/client/assets/Effect-CyyMOw4X.js +15 -0
- package/dist/client/assets/PullRequestCodePanel-BWuWxI6X.js +5 -0
- package/dist/client/assets/Schema-8EGdYSms.js +3 -0
- package/dist/client/assets/Stream-Bvl2Z6qI.js +2 -0
- package/dist/client/assets/ThemeEditorPanel-BOkxNR3t.js +2 -0
- package/dist/client/assets/Virtualizer-DOL71mrP.js +2 -0
- package/dist/client/assets/WorkerPoolContext-gI2-7Koc.js +2538 -0
- package/dist/client/assets/activeOrganizationId-CySrJzMX.js +2 -0
- package/dist/client/assets/atomRegistry-CzI2zp7d.js +3 -0
- package/dist/client/assets/{canvasStateStore-DYt9MgFu.js → canvasStateStore-dUmp5NFj.js} +2 -2
- package/dist/client/assets/chevron-left-BXpfeqsT.js +2 -0
- package/dist/client/assets/chevron-right-B103tjaJ.js +2 -0
- package/dist/client/assets/cmmdAuthRedirect-CHlAAdAc.js +3 -0
- package/dist/client/assets/cmmdEmbedMode-DhVvltxi.js +2 -0
- package/dist/client/assets/currentForgeWorkspaceStore-eKCBxKgv.js +2 -0
- package/dist/client/assets/dialog-BfhVD7Kq.js +2 -0
- package/dist/client/assets/getPseudoElementBounds-DBf0dPO9.js +2 -0
- package/dist/client/assets/index-BS4FABiE.js +301 -0
- package/dist/client/assets/minus-CbEeUDFT.js +2 -0
- package/dist/client/assets/popover-D8qvi5AD.js +2 -0
- package/dist/client/assets/{react-D4GEJ3ir.js → react-A0DLYjwn.js} +2 -2
- package/dist/client/assets/scroll-area-BDuz0PnB.js +2 -0
- package/dist/client/assets/sidebarV2CustomSnoozeDialog-pxOuwuY2.js +2 -0
- package/dist/client/assets/src-7C4X1Oy2.js +2 -0
- package/dist/client/assets/switch-BeaQwtm7.js +2 -0
- package/dist/client/assets/{themePalette-BWvBK22X.js → themePalette-D4rx0k29.js} +2 -2
- package/dist/client/assets/toggle--uJ9LmDV.js +2 -0
- package/dist/client/assets/toggle-group-6UcL78FY.js +2 -0
- package/dist/client/assets/tooltip-C_eHCky0.js +2 -0
- package/dist/client/assets/useOpenInteractionType-BFjAYgzR.js +2 -0
- package/dist/client/assets/{workspaceReadinessAtom-D6bgTvKb.js → workspaceReadinessAtom-BIm13kLJ.js} +2 -2
- package/dist/client/index.html +33 -31
- package/dist/forge-build.json +1 -1
- package/dist/{open-yHTUkd2Y.mjs → open-2-reBrpv.mjs} +3 -3
- package/package.json +1 -1
- package/dist/client/assets/CompositeItem-DTyKsv13.js +0 -2
- package/dist/client/assets/CompositeList-Bc8TYCyy.js +0 -2
- package/dist/client/assets/DiffPanel-3EEekk0W.js +0 -64
- package/dist/client/assets/PullRequestCodePanel--fricLiS.js +0 -5
- package/dist/client/assets/Stream-mUTFnSY9.js +0 -15
- package/dist/client/assets/ThemeEditorPanel-BCJuZ6ai.js +0 -2
- package/dist/client/assets/Virtualizer-DX75f7Mw.js +0 -2
- package/dist/client/assets/WorkerPoolContext-D_2lN-9Y.js +0 -1533
- package/dist/client/assets/atomRegistry-C1yW8tyM.js +0 -3
- package/dist/client/assets/chevron-left-1XbEOuXj.js +0 -2
- package/dist/client/assets/chevron-right-DAF000Jz.js +0 -2
- package/dist/client/assets/cmmdAuthRedirect-DRkKjx0G.js +0 -3
- package/dist/client/assets/cmmdForgeRuntimeListResource-Df9wlF4U.js +0 -1008
- package/dist/client/assets/currentForgeWorkspaceStore-CiCPSq18.js +0 -2
- package/dist/client/assets/dialog-C0bK23D8.js +0 -2
- package/dist/client/assets/getPseudoElementBounds-DJTX-eyW.js +0 -2
- package/dist/client/assets/index-BHReJBiJ.js +0 -301
- package/dist/client/assets/minus-_j91i8bf.js +0 -2
- package/dist/client/assets/popover-ClRgm7hB.js +0 -2
- package/dist/client/assets/scroll-area-BHqISEYq.js +0 -2
- package/dist/client/assets/sidebarV2CustomSnoozeDialog-lbAJoff_.js +0 -2
- package/dist/client/assets/src-B_wrKHuq.js +0 -3
- package/dist/client/assets/switch-BWQHMJkU.js +0 -2
- package/dist/client/assets/toggle-CORC1vE9.js +0 -2
- package/dist/client/assets/toggle-group-C9nAr6VB.js +0 -2
- package/dist/client/assets/tooltip-CrS-TEbN.js +0 -2
- package/dist/client/assets/useOpenInteractionType-KsRrk6uH.js +0 -2
- package/dist/client/assets/utils-xQJ3ak-X.js +0 -2
package/dist/bin.cjs
CHANGED
|
@@ -27136,14 +27136,15 @@ function nonEmptyString$3(value) {
|
|
|
27136
27136
|
}
|
|
27137
27137
|
/**
|
|
27138
27138
|
* Resolve the operational Sprite name for provision / connect / readiness gates.
|
|
27139
|
+
* Only the authoritative `spriteName` counts: missing, empty, and explicit-null
|
|
27140
|
+
* values all resolve to null.
|
|
27139
27141
|
*
|
|
27140
|
-
* @see CmmdRuntimeSpriteIdentitySource for the
|
|
27142
|
+
* @see CmmdRuntimeSpriteIdentitySource for the identity rules.
|
|
27141
27143
|
*/
|
|
27142
27144
|
function resolveCmmdRuntimeSpriteName(runtime) {
|
|
27143
|
-
|
|
27144
|
-
return nonEmptyString$3(runtime.flyMachineId);
|
|
27145
|
+
return nonEmptyString$3(runtime.spriteName);
|
|
27145
27146
|
}
|
|
27146
|
-
/** True when the payload carries an
|
|
27147
|
+
/** True when the payload carries an authoritative Sprite name. */
|
|
27147
27148
|
function hasCmmdRuntimeSpriteIdentity(runtime) {
|
|
27148
27149
|
return resolveCmmdRuntimeSpriteName(runtime) !== null;
|
|
27149
27150
|
}
|
|
@@ -27218,7 +27219,8 @@ const WORKTREE_LAUNCH_ACTIVITY_KINDS = new Set([
|
|
|
27218
27219
|
"setup-script.skipped",
|
|
27219
27220
|
"setup-script.failed",
|
|
27220
27221
|
"launch.agent-starting",
|
|
27221
|
-
"launch.cancelled"
|
|
27222
|
+
"launch.cancelled",
|
|
27223
|
+
"checkout-launch"
|
|
27222
27224
|
]);
|
|
27223
27225
|
function encodeCmmdRuntimeWorktreeLaunchActivityPayload(kind, payload) {
|
|
27224
27226
|
return {
|
|
@@ -27272,6 +27274,258 @@ function decodeCmmdRuntimePlanActivity(payload) {
|
|
|
27272
27274
|
};
|
|
27273
27275
|
}
|
|
27274
27276
|
//#endregion
|
|
27277
|
+
//#region ../../packages/contracts/src/checkoutLaunch.ts
|
|
27278
|
+
/**
|
|
27279
|
+
* One Checkout launch snapshot for a thread.
|
|
27280
|
+
*
|
|
27281
|
+
* Upstream (`pingdotgg/t3code`, WorktreeSetupTracker) owns this shape: one
|
|
27282
|
+
* snapshot, fixed activity id, handoff when the agent stage is done and the
|
|
27283
|
+
* turn has started. Forge keeps its own stage names. The admission wait is
|
|
27284
|
+
* the first stage of this same snapshot, because a shared Environment can be
|
|
27285
|
+
* busy before any Checkout activity exists.
|
|
27286
|
+
*/
|
|
27287
|
+
const CHECKOUT_LAUNCH_ACTIVITY_KIND = "checkout-launch";
|
|
27288
|
+
const PREPARATION_STAGES = [
|
|
27289
|
+
{
|
|
27290
|
+
id: "resolve",
|
|
27291
|
+
label: "Resolve base branch"
|
|
27292
|
+
},
|
|
27293
|
+
{
|
|
27294
|
+
id: "checkout",
|
|
27295
|
+
label: "Check out files"
|
|
27296
|
+
},
|
|
27297
|
+
{
|
|
27298
|
+
id: "dependencies",
|
|
27299
|
+
label: "Prepare dependencies"
|
|
27300
|
+
},
|
|
27301
|
+
{
|
|
27302
|
+
id: "setup",
|
|
27303
|
+
label: "Start setup script"
|
|
27304
|
+
},
|
|
27305
|
+
{
|
|
27306
|
+
id: "agent",
|
|
27307
|
+
label: "Start agent"
|
|
27308
|
+
}
|
|
27309
|
+
];
|
|
27310
|
+
function checkoutLaunchActivityId(threadId) {
|
|
27311
|
+
return `checkout-launch:${threadId}`;
|
|
27312
|
+
}
|
|
27313
|
+
function preparationStages(statusFor, detailFor = () => null) {
|
|
27314
|
+
return PREPARATION_STAGES.map((stage) => ({
|
|
27315
|
+
id: stage.id,
|
|
27316
|
+
label: stage.label,
|
|
27317
|
+
status: statusFor(stage.id),
|
|
27318
|
+
detail: detailFor(stage.id)
|
|
27319
|
+
}));
|
|
27320
|
+
}
|
|
27321
|
+
function beginPreparationCheckoutLaunch(input) {
|
|
27322
|
+
return {
|
|
27323
|
+
phase: "running",
|
|
27324
|
+
stages: preparationStages((id) => id === "resolve" ? "running" : "pending"),
|
|
27325
|
+
startedAt: input.startedAt,
|
|
27326
|
+
completedAt: null,
|
|
27327
|
+
error: null,
|
|
27328
|
+
cancellable: true,
|
|
27329
|
+
worktreePath: input.worktreePath ?? null,
|
|
27330
|
+
turnStartedAt: null
|
|
27331
|
+
};
|
|
27332
|
+
}
|
|
27333
|
+
function replaceStage(snapshot, id, patch) {
|
|
27334
|
+
return {
|
|
27335
|
+
...snapshot,
|
|
27336
|
+
stages: snapshot.stages.map((stage) => stage.id === id ? {
|
|
27337
|
+
...stage,
|
|
27338
|
+
...patch
|
|
27339
|
+
} : stage)
|
|
27340
|
+
};
|
|
27341
|
+
}
|
|
27342
|
+
function ensurePreparation(snapshot, startedAt) {
|
|
27343
|
+
if (snapshot && snapshot.stages.some((stage) => stage.id === "resolve")) return snapshot;
|
|
27344
|
+
return beginPreparationCheckoutLaunch({
|
|
27345
|
+
startedAt: snapshot?.startedAt ?? startedAt,
|
|
27346
|
+
worktreePath: snapshot?.worktreePath ?? null
|
|
27347
|
+
});
|
|
27348
|
+
}
|
|
27349
|
+
function settlePhase(snapshot) {
|
|
27350
|
+
if (snapshot.phase === "failed" || snapshot.phase === "cancelled") return snapshot;
|
|
27351
|
+
const agent = snapshot.stages.find((stage) => stage.id === "agent");
|
|
27352
|
+
const setup = snapshot.stages.find((stage) => stage.id === "setup");
|
|
27353
|
+
const agentDone = agent?.status === "done" && snapshot.turnStartedAt !== null;
|
|
27354
|
+
const setupStillRunning = setup?.status === "running";
|
|
27355
|
+
if (!agentDone || setupStillRunning) return snapshot;
|
|
27356
|
+
return {
|
|
27357
|
+
...snapshot,
|
|
27358
|
+
phase: "done",
|
|
27359
|
+
completedAt: snapshot.completedAt ?? snapshot.turnStartedAt,
|
|
27360
|
+
cancellable: false
|
|
27361
|
+
};
|
|
27362
|
+
}
|
|
27363
|
+
function payloadString(payload, key) {
|
|
27364
|
+
const value = payload?.[key];
|
|
27365
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
27366
|
+
}
|
|
27367
|
+
function payloadNumber(payload, key) {
|
|
27368
|
+
const value = payload?.[key];
|
|
27369
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
27370
|
+
}
|
|
27371
|
+
const STAGE_IDS = new Set([
|
|
27372
|
+
"resolve",
|
|
27373
|
+
"checkout",
|
|
27374
|
+
"dependencies",
|
|
27375
|
+
"setup",
|
|
27376
|
+
"agent"
|
|
27377
|
+
]);
|
|
27378
|
+
const STAGE_STATUSES = new Set([
|
|
27379
|
+
"done",
|
|
27380
|
+
"failed",
|
|
27381
|
+
"skipped",
|
|
27382
|
+
"running"
|
|
27383
|
+
]);
|
|
27384
|
+
const LAUNCH_FAILING_STAGES = new Set([
|
|
27385
|
+
"resolve",
|
|
27386
|
+
"checkout",
|
|
27387
|
+
"dependencies"
|
|
27388
|
+
]);
|
|
27389
|
+
function stageIdFromPayload(payload) {
|
|
27390
|
+
const id = payloadString(payload, "id") ?? payloadString(payload, "stage");
|
|
27391
|
+
return id !== null && STAGE_IDS.has(id) ? id : null;
|
|
27392
|
+
}
|
|
27393
|
+
function stageStatus(status) {
|
|
27394
|
+
return status !== null && STAGE_STATUSES.has(status) ? status : "running";
|
|
27395
|
+
}
|
|
27396
|
+
function applyStage(snapshot, event) {
|
|
27397
|
+
const id = stageIdFromPayload(event.payload);
|
|
27398
|
+
if (!id) return snapshot;
|
|
27399
|
+
snapshot = ensurePreparation(snapshot, event.createdAt);
|
|
27400
|
+
const nextStatus = stageStatus(payloadString(event.payload, "status"));
|
|
27401
|
+
const percent = payloadNumber(event.payload, "percent");
|
|
27402
|
+
const detail = percent !== null ? `${Math.round(percent)}%` : payloadString(event.payload, "detail");
|
|
27403
|
+
const next = replaceStage(snapshot, id, {
|
|
27404
|
+
status: nextStatus,
|
|
27405
|
+
detail
|
|
27406
|
+
});
|
|
27407
|
+
if (nextStatus !== "failed" || !LAUNCH_FAILING_STAGES.has(id)) return next;
|
|
27408
|
+
return {
|
|
27409
|
+
...next,
|
|
27410
|
+
phase: "failed",
|
|
27411
|
+
error: event.summary ?? next.error,
|
|
27412
|
+
completedAt: event.createdAt,
|
|
27413
|
+
cancellable: false
|
|
27414
|
+
};
|
|
27415
|
+
}
|
|
27416
|
+
/**
|
|
27417
|
+
* Fold one launch activity into the snapshot. A recorded `checkout-launch`
|
|
27418
|
+
* payload replaces the snapshot. Older per-step activities still fold so a
|
|
27419
|
+
* thread that never received the snapshot does not go blank.
|
|
27420
|
+
*/
|
|
27421
|
+
function reduceCheckoutLaunch(snapshot, event) {
|
|
27422
|
+
if (event.kind === "checkout-launch") return readCheckoutLaunchSnapshot(event) ?? snapshot;
|
|
27423
|
+
if (event.kind === "worktree.requested") return beginPreparationCheckoutLaunch({
|
|
27424
|
+
startedAt: snapshot?.startedAt ?? event.createdAt,
|
|
27425
|
+
worktreePath: payloadString(event.payload, "worktreePath") ?? snapshot?.worktreePath ?? null
|
|
27426
|
+
});
|
|
27427
|
+
if (!snapshot && event.kind !== "worktree.stage" && event.kind !== "worktree.failed") snapshot = beginPreparationCheckoutLaunch({ startedAt: event.createdAt });
|
|
27428
|
+
if (!snapshot) return snapshot;
|
|
27429
|
+
return CHECKOUT_LAUNCH_EVENT_HANDLERS[event.kind]?.(snapshot, event) ?? snapshot;
|
|
27430
|
+
}
|
|
27431
|
+
function setSetup(snapshot, event, status, detail) {
|
|
27432
|
+
return replaceStage(ensurePreparation(snapshot, event.createdAt), "setup", {
|
|
27433
|
+
status,
|
|
27434
|
+
detail
|
|
27435
|
+
});
|
|
27436
|
+
}
|
|
27437
|
+
function applyCreated(snapshot, event) {
|
|
27438
|
+
return {
|
|
27439
|
+
...snapshot,
|
|
27440
|
+
worktreePath: payloadString(event.payload, "worktreePath") ?? snapshot.worktreePath
|
|
27441
|
+
};
|
|
27442
|
+
}
|
|
27443
|
+
function applyOutput(snapshot, event) {
|
|
27444
|
+
const detail = payloadString(event.payload, "detail") ?? event.summary ?? null;
|
|
27445
|
+
const match = detail ? /Updating files:\s+(\d+)%/.exec(detail) : null;
|
|
27446
|
+
if (!match) return snapshot;
|
|
27447
|
+
return replaceStage(ensurePreparation(snapshot, event.createdAt), "checkout", {
|
|
27448
|
+
status: "running",
|
|
27449
|
+
detail: `${match[1]}%`
|
|
27450
|
+
});
|
|
27451
|
+
}
|
|
27452
|
+
function applyAgentStarting(snapshot, event) {
|
|
27453
|
+
const prepared = ensurePreparation(snapshot, event.createdAt);
|
|
27454
|
+
return {
|
|
27455
|
+
...replaceStage(event.payload?.setupRequested === false ? setSetup(prepared, event, "skipped", "Not requested") : prepared, "agent", {
|
|
27456
|
+
status: "running",
|
|
27457
|
+
detail: event.summary ?? "Starting agent"
|
|
27458
|
+
}),
|
|
27459
|
+
cancellable: false
|
|
27460
|
+
};
|
|
27461
|
+
}
|
|
27462
|
+
function applyFailed(snapshot, event) {
|
|
27463
|
+
snapshot = ensurePreparation(snapshot, event.createdAt);
|
|
27464
|
+
const detail = payloadString(event.payload, "detail") ?? event.summary ?? snapshot.error;
|
|
27465
|
+
const running = snapshot.stages.find((stage) => stage.status === "running");
|
|
27466
|
+
return {
|
|
27467
|
+
...running ? replaceStage(snapshot, running.id, {
|
|
27468
|
+
status: "failed",
|
|
27469
|
+
detail
|
|
27470
|
+
}) : snapshot,
|
|
27471
|
+
phase: "failed",
|
|
27472
|
+
error: detail ?? "Checkout launch failed",
|
|
27473
|
+
completedAt: event.createdAt,
|
|
27474
|
+
cancellable: false
|
|
27475
|
+
};
|
|
27476
|
+
}
|
|
27477
|
+
function applyCancelled(snapshot, event) {
|
|
27478
|
+
return {
|
|
27479
|
+
...snapshot,
|
|
27480
|
+
phase: "cancelled",
|
|
27481
|
+
error: event.summary ?? "Launch cancelled",
|
|
27482
|
+
completedAt: event.createdAt,
|
|
27483
|
+
cancellable: false
|
|
27484
|
+
};
|
|
27485
|
+
}
|
|
27486
|
+
const CHECKOUT_LAUNCH_EVENT_HANDLERS = {
|
|
27487
|
+
"worktree.stage": applyStage,
|
|
27488
|
+
"worktree.created": applyCreated,
|
|
27489
|
+
"worktree.output": applyOutput,
|
|
27490
|
+
"setup-script.skipped": (snapshot, event) => setSetup(snapshot, event, "skipped", event.summary ?? "No setup script configured"),
|
|
27491
|
+
"setup-script.running": (snapshot, event) => setSetup(snapshot, event, "running", event.summary ?? null),
|
|
27492
|
+
"setup-script.started": (snapshot, event) => setSetup(snapshot, event, "done", event.summary ?? "Running in terminal"),
|
|
27493
|
+
"setup-script.completed": (snapshot, event) => setSetup(snapshot, event, "done", event.summary ?? null),
|
|
27494
|
+
"setup-script.failed": (snapshot, event) => setSetup(snapshot, event, "failed", event.summary ?? "Setup script failed"),
|
|
27495
|
+
"launch.agent-starting": applyAgentStarting,
|
|
27496
|
+
"worktree.failed": applyFailed,
|
|
27497
|
+
"launch.cancelled": applyCancelled
|
|
27498
|
+
};
|
|
27499
|
+
function withCheckoutLaunchTurnStarted(snapshot, turnStartedAt) {
|
|
27500
|
+
if (!turnStartedAt) return snapshot;
|
|
27501
|
+
const agent = snapshot.stages.find((stage) => stage.id === "agent");
|
|
27502
|
+
return settlePhase({
|
|
27503
|
+
...agent && (agent.status === "running" || agent.status === "done") ? replaceStage(snapshot, "agent", {
|
|
27504
|
+
status: "done",
|
|
27505
|
+
detail: agent.detail
|
|
27506
|
+
}) : snapshot,
|
|
27507
|
+
turnStartedAt
|
|
27508
|
+
});
|
|
27509
|
+
}
|
|
27510
|
+
function readCheckoutLaunchSnapshot(activity) {
|
|
27511
|
+
if (activity.kind !== "checkout-launch") return null;
|
|
27512
|
+
const payload = activity.payload;
|
|
27513
|
+
if (!payload || typeof payload !== "object") return null;
|
|
27514
|
+
const record = payload;
|
|
27515
|
+
if (record.phase !== "running" && record.phase !== "done" && record.phase !== "failed" && record.phase !== "cancelled") return null;
|
|
27516
|
+
if (!Array.isArray(record.stages) || typeof record.startedAt !== "string") return null;
|
|
27517
|
+
return {
|
|
27518
|
+
phase: record.phase,
|
|
27519
|
+
stages: record.stages,
|
|
27520
|
+
startedAt: record.startedAt,
|
|
27521
|
+
completedAt: record.completedAt ?? null,
|
|
27522
|
+
error: record.error ?? null,
|
|
27523
|
+
cancellable: record.cancellable === true,
|
|
27524
|
+
worktreePath: record.worktreePath ?? null,
|
|
27525
|
+
turnStartedAt: record.turnStartedAt ?? null
|
|
27526
|
+
};
|
|
27527
|
+
}
|
|
27528
|
+
//#endregion
|
|
27275
27529
|
//#region ../../packages/contracts/src/cmmdProjectPatch.ts
|
|
27276
27530
|
const CMMD_PROJECT_PATCH_FIELDS = {
|
|
27277
27531
|
title: "requiredText",
|
|
@@ -66433,7 +66687,7 @@ function normalizeNumberish(value) {
|
|
|
66433
66687
|
}
|
|
66434
66688
|
//#endregion
|
|
66435
66689
|
//#region package.json
|
|
66436
|
-
var version$1 = "0.14.
|
|
66690
|
+
var version$1 = "0.14.2";
|
|
66437
66691
|
//#endregion
|
|
66438
66692
|
//#region src/sentry.ts
|
|
66439
66693
|
const SERVER_APP_NAME = "forge-server";
|
|
@@ -66719,6 +66973,12 @@ function deriveAuthClientMetadata(input) {
|
|
|
66719
66973
|
* Hosts a PaaS assigns automatically. They are reachable, but they are not the
|
|
66720
66974
|
* domain the product is registered under, so they must never end up in an OAuth
|
|
66721
66975
|
* `redirect_uri`.
|
|
66976
|
+
*
|
|
66977
|
+
* The hosted web channels (forge#3557) are the deliberate exception: their
|
|
66978
|
+
* `.up.railway.app` hosts ARE product surfaces, the operator enumerates them in
|
|
66979
|
+
* `FORGE_WEB_CHANNEL_ORIGINS`, and CMMD's `cmmd-forge-web` OAuth client lists
|
|
66980
|
+
* their callback URIs as registered redirect URIs. Every other platform host
|
|
66981
|
+
* stays excluded.
|
|
66722
66982
|
*/
|
|
66723
66983
|
const PLATFORM_DEFAULT_HOST_SUFFIXES = [".up.railway.app"];
|
|
66724
66984
|
function isPlatformDefaultHost(hostname) {
|
|
@@ -66757,6 +67017,41 @@ function resolveForgePublicUrl(env = process.env) {
|
|
|
66757
67017
|
if (canonicalDomain.toLowerCase() === configuredHost.toLowerCase()) return configured;
|
|
66758
67018
|
return `https://${canonicalDomain}`.replace(/\/$/, "");
|
|
66759
67019
|
}
|
|
67020
|
+
/**
|
|
67021
|
+
* Hosted web channel origins (forge#3557) allowed to complete OAuth against
|
|
67022
|
+
* this server, from `FORGE_WEB_CHANNEL_ORIGINS`.
|
|
67023
|
+
*
|
|
67024
|
+
* The channels serve the web bundle from their own domains and forward `/api`
|
|
67025
|
+
* here with `x-forwarded-host` set to the channel host. Login must build its
|
|
67026
|
+
* `redirect_uri` from that host, or CMMD's authorize round-trip returns the
|
|
67027
|
+
* browser to `FORGE_PUBLIC_URL` — an origin where the login's state and PKCE
|
|
67028
|
+
* cookies do not exist. Because anything on the internet can also send this
|
|
67029
|
+
* server an `x-forwarded-host` header, the accepted hosts are never inferred
|
|
67030
|
+
* from the request: the operator enumerates the exact channel origins, and
|
|
67031
|
+
* only those count.
|
|
67032
|
+
*
|
|
67033
|
+
* Entries are comma-separated origins (`https://host[:port]`); a bare hostname
|
|
67034
|
+
* assumes https. Every entry normalizes to its URL origin, so stray path,
|
|
67035
|
+
* query, or userinfo components never reach a redirect URI. Whitespace,
|
|
67036
|
+
* trailing slashes, and unparseable entries are dropped.
|
|
67037
|
+
*/
|
|
67038
|
+
function resolveForgeWebChannelOrigins(env = process.env) {
|
|
67039
|
+
return (env.FORGE_WEB_CHANNEL_ORIGINS ?? "").split(",").map((entry) => entry.trim().replace(/\/+$/, "")).filter((entry) => entry.length > 0).map((entry) => entry.includes("://") ? entry : `https://${entry}`).filter((entry) => URL.canParse(entry)).map((entry) => new URL(entry).origin).filter((origin) => origin !== "null");
|
|
67040
|
+
}
|
|
67041
|
+
/**
|
|
67042
|
+
* The allowlisted channel origin for a forwarded host, or null when the host
|
|
67043
|
+
* is not one. Matching is on the URL host — hostname plus explicit port — so
|
|
67044
|
+
* an entry with a port only matches that exact host:port, and a lookalike or
|
|
67045
|
+
* suffix host never matches. The returned origin is the operator's registered
|
|
67046
|
+
* form, scheme included, so it is exactly the redirect URI CMMD's client
|
|
67047
|
+
* registry holds.
|
|
67048
|
+
*/
|
|
67049
|
+
function matchForgeWebChannelOrigin(forwardedHost, env = process.env) {
|
|
67050
|
+
const candidate = forwardedHost.trim().toLowerCase();
|
|
67051
|
+
if (!candidate) return null;
|
|
67052
|
+
for (const origin of resolveForgeWebChannelOrigins(env)) if (new URL(origin).host.toLowerCase() === candidate) return origin;
|
|
67053
|
+
return null;
|
|
67054
|
+
}
|
|
66760
67055
|
function forgeConfiguredPublicUrl() {
|
|
66761
67056
|
return resolveForgePublicUrl();
|
|
66762
67057
|
}
|
|
@@ -66798,7 +67093,11 @@ function forgePublicUrlForRequest(request) {
|
|
|
66798
67093
|
const forwardedHost = normalizeForwardedHeaderValue(request.headers["x-forwarded-host"]);
|
|
66799
67094
|
const forwardedProto = normalizeForwardedHeaderValue(request.headers["x-forwarded-proto"]) ?? "https";
|
|
66800
67095
|
if (forwardedHost && (isLoopbackOAuthHost(forwardedHost) || isPrivateDevOAuthHost(forwardedHost))) return `${forwardedProto === "https" ? "https" : "http"}://${forwardedHost}`.replace(/\/$/, "");
|
|
66801
|
-
if (forwardedHost)
|
|
67096
|
+
if (forwardedHost) {
|
|
67097
|
+
const channelOrigin = matchForgeWebChannelOrigin(forwardedHost);
|
|
67098
|
+
if (channelOrigin) return channelOrigin;
|
|
67099
|
+
return forgeConfiguredPublicUrl();
|
|
67100
|
+
}
|
|
66802
67101
|
const directHost = normalizeForwardedHeaderValue(request.headers["host"]);
|
|
66803
67102
|
if (directHost && (isLoopbackOAuthHost(directHost) || isPrivateDevOAuthHost(directHost))) return `http://${directHost}`.replace(/\/$/, "");
|
|
66804
67103
|
return forgeConfiguredPublicUrl();
|
|
@@ -70750,6 +71049,19 @@ function createCloudflareTurnIceServerResolver(options) {
|
|
|
70750
71049
|
}
|
|
70751
71050
|
//#endregion
|
|
70752
71051
|
//#region src/http.ts
|
|
71052
|
+
/**
|
|
71053
|
+
* What the catch-all does with a non-API GET. A managed cloud surface is
|
|
71054
|
+
* runtime-only no matter what files exist on disk — the web client's single
|
|
71055
|
+
* home is the static channels (forge#3567) — while a local server either
|
|
71056
|
+
* serves its bundle or reports itself unconfigured.
|
|
71057
|
+
*/
|
|
71058
|
+
function resolveWebServingOutcome(input) {
|
|
71059
|
+
if (input.managedCloudSurface) return { kind: "runtime-only" };
|
|
71060
|
+
return input.staticDir ? {
|
|
71061
|
+
kind: "serve",
|
|
71062
|
+
staticDir: input.staticDir
|
|
71063
|
+
} : { kind: "unconfigured" };
|
|
71064
|
+
}
|
|
70753
71065
|
const PROJECT_FAVICON_CACHE_CONTROL = "public, max-age=3600";
|
|
70754
71066
|
const PROJECT_FAVICON_MISS_CACHE_CONTROL = "public, max-age=300";
|
|
70755
71067
|
/**
|
|
@@ -71012,8 +71324,16 @@ const staticAndDevRouteLayer = add$1("GET", "*", require_Schema$1.gen(function*
|
|
|
71012
71324
|
}, { status: 404 });
|
|
71013
71325
|
const config = yield* ServerConfig;
|
|
71014
71326
|
if (config.devUrl && isLoopbackHostname(url.value.hostname)) return require_HttpServer.redirect(resolveDevRedirectUrl(config.devUrl, url.value), { status: 302 });
|
|
71015
|
-
const
|
|
71016
|
-
|
|
71327
|
+
const outcome = resolveWebServingOutcome({
|
|
71328
|
+
staticDir: config.staticDir ?? (config.devUrl ? yield* resolveStaticDir() : void 0),
|
|
71329
|
+
managedCloudSurface: (config.forgeCloudShellMode ?? false) || (config.forgeCmmdRuntimeMode ?? false)
|
|
71330
|
+
});
|
|
71331
|
+
if (outcome.kind === "runtime-only") return require_HttpServer.jsonUnsafe({
|
|
71332
|
+
error: "not_found",
|
|
71333
|
+
message: "This server does not serve the web client."
|
|
71334
|
+
}, { status: 404 });
|
|
71335
|
+
if (outcome.kind === "unconfigured") return require_HttpServer.text("No static directory configured and no dev URL set.", { status: 503 });
|
|
71336
|
+
const staticDir = outcome.staticDir;
|
|
71017
71337
|
const fileSystem = yield* require_Path.FileSystem;
|
|
71018
71338
|
const path = yield* require_Path.Path;
|
|
71019
71339
|
const staticRoot = path.resolve(staticDir);
|
|
@@ -88846,7 +89166,7 @@ function refreshForgeManagedGitHubRemoteCredentials(input, dependencies = {
|
|
|
88846
89166
|
}));
|
|
88847
89167
|
isCacheManaged = helper.code === 0 && helper.stdout.includes("cache");
|
|
88848
89168
|
}
|
|
88849
|
-
if (!isEmbedded && !isCacheManaged) return {
|
|
89169
|
+
if (!isEmbedded && !isCacheManaged && !input.allowUnmanagedRemote) return {
|
|
88850
89170
|
status: 200,
|
|
88851
89171
|
body: {
|
|
88852
89172
|
refreshed: false,
|
|
@@ -94548,6 +94868,37 @@ const toBootstrapDispatchCommandCauseError = (cause) => {
|
|
|
94548
94868
|
});
|
|
94549
94869
|
};
|
|
94550
94870
|
const bootstrapCommandId = (command, stage) => CommandId.make(`server:${stage}:${command.commandId}`);
|
|
94871
|
+
const publishCheckoutLaunchSnapshot = (input) => input.orchestrationEngine.dispatch({
|
|
94872
|
+
type: "thread.activity.append",
|
|
94873
|
+
commandId: CommandId.make(`server:checkout-launch:${crypto.randomUUID()}`),
|
|
94874
|
+
threadId: input.threadId,
|
|
94875
|
+
activity: {
|
|
94876
|
+
id: EventId.make(checkoutLaunchActivityId(input.threadId)),
|
|
94877
|
+
tone: input.snapshot.phase === "failed" ? "error" : "info",
|
|
94878
|
+
kind: CHECKOUT_LAUNCH_ACTIVITY_KIND,
|
|
94879
|
+
summary: "Checkout launch",
|
|
94880
|
+
payload: input.snapshot,
|
|
94881
|
+
turnId: null,
|
|
94882
|
+
createdAt: input.createdAt
|
|
94883
|
+
},
|
|
94884
|
+
createdAt: input.createdAt
|
|
94885
|
+
});
|
|
94886
|
+
const recordCheckoutLaunchEvent = (input) => {
|
|
94887
|
+
const next = reduceCheckoutLaunch(input.launch.snapshot, {
|
|
94888
|
+
kind: input.kind,
|
|
94889
|
+
createdAt: input.createdAt,
|
|
94890
|
+
summary: input.summary,
|
|
94891
|
+
payload: input.payload
|
|
94892
|
+
});
|
|
94893
|
+
input.launch.snapshot = next;
|
|
94894
|
+
if (!next) return require_Schema$1.void_;
|
|
94895
|
+
return publishCheckoutLaunchSnapshot({
|
|
94896
|
+
orchestrationEngine: input.orchestrationEngine,
|
|
94897
|
+
threadId: input.threadId,
|
|
94898
|
+
snapshot: next,
|
|
94899
|
+
createdAt: input.createdAt
|
|
94900
|
+
});
|
|
94901
|
+
};
|
|
94551
94902
|
const appendSetupScriptActivity = (input) => input.orchestrationEngine.dispatch({
|
|
94552
94903
|
type: "thread.activity.append",
|
|
94553
94904
|
commandId: input.commandId,
|
|
@@ -94562,7 +94913,15 @@ const appendSetupScriptActivity = (input) => input.orchestrationEngine.dispatch(
|
|
|
94562
94913
|
createdAt: input.createdAt
|
|
94563
94914
|
},
|
|
94564
94915
|
createdAt: input.createdAt
|
|
94565
|
-
})
|
|
94916
|
+
}).pipe(require_Schema$1.andThen(() => recordCheckoutLaunchEvent({
|
|
94917
|
+
orchestrationEngine: input.orchestrationEngine,
|
|
94918
|
+
threadId: input.threadId,
|
|
94919
|
+
launch: input.launch,
|
|
94920
|
+
kind: input.kind,
|
|
94921
|
+
summary: input.summary,
|
|
94922
|
+
createdAt: input.createdAt,
|
|
94923
|
+
payload: input.payload
|
|
94924
|
+
})));
|
|
94566
94925
|
const appendWorktreeActivity = (input) => input.orchestrationEngine.dispatch({
|
|
94567
94926
|
type: "thread.activity.append",
|
|
94568
94927
|
commandId: input.commandId,
|
|
@@ -94577,7 +94936,15 @@ const appendWorktreeActivity = (input) => input.orchestrationEngine.dispatch({
|
|
|
94577
94936
|
createdAt: input.createdAt
|
|
94578
94937
|
},
|
|
94579
94938
|
createdAt: input.createdAt
|
|
94580
|
-
})
|
|
94939
|
+
}).pipe(require_Schema$1.andThen(() => recordCheckoutLaunchEvent({
|
|
94940
|
+
orchestrationEngine: input.orchestrationEngine,
|
|
94941
|
+
threadId: input.threadId,
|
|
94942
|
+
launch: input.launch,
|
|
94943
|
+
kind: input.kind,
|
|
94944
|
+
summary: input.summary,
|
|
94945
|
+
createdAt: input.createdAt,
|
|
94946
|
+
payload: input.payload
|
|
94947
|
+
})));
|
|
94581
94948
|
const truncateBootstrapOutputLine = (line) => {
|
|
94582
94949
|
const trimmed = line.trim();
|
|
94583
94950
|
if (trimmed.length <= MAX_BOOTSTRAP_OUTPUT_LINE_LENGTH) return trimmed;
|
|
@@ -94687,9 +95054,11 @@ const prepareBootstrapWorktree = (input) => require_Schema$1.gen(function* () {
|
|
|
94687
95054
|
summary: "Creating worktree",
|
|
94688
95055
|
createdAt: requestedAt,
|
|
94689
95056
|
payload: requestedPayload,
|
|
94690
|
-
tone: "info"
|
|
95057
|
+
tone: "info",
|
|
95058
|
+
launch: input.launch
|
|
94691
95059
|
});
|
|
94692
95060
|
if (bootstrapWorktree.startFromOrigin) {
|
|
95061
|
+
if (input.refreshSourceControlCredentials) yield* input.refreshSourceControlCredentials(projectCwd);
|
|
94693
95062
|
if (!input.git.fetch) return yield* require_Schema$1.fail(/* @__PURE__ */ new Error("Git fetch is unavailable for origin worktree preparation."));
|
|
94694
95063
|
yield* input.git.fetch({
|
|
94695
95064
|
cwd: projectCwd,
|
|
@@ -94711,7 +95080,8 @@ const prepareBootstrapWorktree = (input) => require_Schema$1.gen(function* () {
|
|
|
94711
95080
|
detail,
|
|
94712
95081
|
stage: "fetch"
|
|
94713
95082
|
},
|
|
94714
|
-
tone: "error"
|
|
95083
|
+
tone: "error",
|
|
95084
|
+
launch: input.launch
|
|
94715
95085
|
}).pipe(require_Schema$1.andThen(require_Schema$1.failCause(cause)));
|
|
94716
95086
|
}));
|
|
94717
95087
|
}
|
|
@@ -94729,7 +95099,8 @@ const prepareBootstrapWorktree = (input) => require_Schema$1.gen(function* () {
|
|
|
94729
95099
|
summary: "Preparing worktree",
|
|
94730
95100
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
94731
95101
|
payload: update,
|
|
94732
|
-
tone: "info"
|
|
95102
|
+
tone: "info",
|
|
95103
|
+
launch: input.launch
|
|
94733
95104
|
}).pipe(require_Schema$1.asVoid, require_Schema$1.ignore),
|
|
94734
95105
|
progress: {
|
|
94735
95106
|
onStdoutLine: (line) => {
|
|
@@ -94747,7 +95118,8 @@ const prepareBootstrapWorktree = (input) => require_Schema$1.gen(function* () {
|
|
|
94747
95118
|
stream: "stdout",
|
|
94748
95119
|
detail
|
|
94749
95120
|
},
|
|
94750
|
-
tone: "info"
|
|
95121
|
+
tone: "info",
|
|
95122
|
+
launch: input.launch
|
|
94751
95123
|
}).pipe(require_Schema$1.asVoid, require_Schema$1.ignore);
|
|
94752
95124
|
},
|
|
94753
95125
|
onStderrLine: (line) => {
|
|
@@ -94765,7 +95137,8 @@ const prepareBootstrapWorktree = (input) => require_Schema$1.gen(function* () {
|
|
|
94765
95137
|
stream: "stderr",
|
|
94766
95138
|
detail
|
|
94767
95139
|
},
|
|
94768
|
-
tone: "info"
|
|
95140
|
+
tone: "info",
|
|
95141
|
+
launch: input.launch
|
|
94769
95142
|
}).pipe(require_Schema$1.asVoid, require_Schema$1.ignore);
|
|
94770
95143
|
}
|
|
94771
95144
|
}
|
|
@@ -94784,7 +95157,8 @@ const prepareBootstrapWorktree = (input) => require_Schema$1.gen(function* () {
|
|
|
94784
95157
|
...requestedPayload,
|
|
94785
95158
|
detail
|
|
94786
95159
|
},
|
|
94787
|
-
tone: "error"
|
|
95160
|
+
tone: "error",
|
|
95161
|
+
launch: input.launch
|
|
94788
95162
|
}).pipe(require_Schema$1.andThen(require_Schema$1.failCause(cause)));
|
|
94789
95163
|
}));
|
|
94790
95164
|
const worktreePath = worktree.worktree.path;
|
|
@@ -94808,7 +95182,8 @@ const prepareBootstrapWorktree = (input) => require_Schema$1.gen(function* () {
|
|
|
94808
95182
|
worktreePath,
|
|
94809
95183
|
checkedOutBranch: worktree.worktree.branch
|
|
94810
95184
|
},
|
|
94811
|
-
tone: "info"
|
|
95185
|
+
tone: "info",
|
|
95186
|
+
launch: input.launch
|
|
94812
95187
|
});
|
|
94813
95188
|
return {
|
|
94814
95189
|
worktreePath,
|
|
@@ -94824,6 +95199,7 @@ const dispatchBootstrapTurnStart$1 = (input, command) => require_Schema$1.gen(fu
|
|
|
94824
95199
|
let targetProjectCwd = bootstrap?.prepareWorktree?.projectCwd;
|
|
94825
95200
|
let targetWorktreePath = bootstrap?.createThread?.worktreePath ?? null;
|
|
94826
95201
|
let worktreeFailureReported = false;
|
|
95202
|
+
const launch = { snapshot: null };
|
|
94827
95203
|
const cleanupCreatedThread = () => createdThread && !worktreeFailureReported ? orchestrationEngine.dispatch({
|
|
94828
95204
|
type: "thread.delete",
|
|
94829
95205
|
commandId: bootstrapCommandId(command, "bootstrap-thread-delete"),
|
|
@@ -94842,7 +95218,8 @@ const dispatchBootstrapTurnStart$1 = (input, command) => require_Schema$1.gen(fu
|
|
|
94842
95218
|
detail,
|
|
94843
95219
|
worktreePath: record.worktreePath
|
|
94844
95220
|
},
|
|
94845
|
-
tone: "error"
|
|
95221
|
+
tone: "error",
|
|
95222
|
+
launch
|
|
94846
95223
|
}).pipe(require_Schema$1.ignoreCause({ log: false }), require_Schema$1.flatMap(() => require_Schema$1.logWarning("bootstrap turn start failed to launch setup script", {
|
|
94847
95224
|
threadId: command.threadId,
|
|
94848
95225
|
worktreePath: record.worktreePath,
|
|
@@ -94864,7 +95241,8 @@ const dispatchBootstrapTurnStart$1 = (input, command) => require_Schema$1.gen(fu
|
|
|
94864
95241
|
summary: "Starting setup script",
|
|
94865
95242
|
createdAt: record.requestedAt,
|
|
94866
95243
|
payload,
|
|
94867
|
-
tone: "info"
|
|
95244
|
+
tone: "info",
|
|
95245
|
+
launch
|
|
94868
95246
|
}), appendSetupScriptActivity({
|
|
94869
95247
|
orchestrationEngine,
|
|
94870
95248
|
threadId: command.threadId,
|
|
@@ -94873,7 +95251,8 @@ const dispatchBootstrapTurnStart$1 = (input, command) => require_Schema$1.gen(fu
|
|
|
94873
95251
|
summary: "Setup script started",
|
|
94874
95252
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
94875
95253
|
payload,
|
|
94876
|
-
tone: "info"
|
|
95254
|
+
tone: "info",
|
|
95255
|
+
launch
|
|
94877
95256
|
})]).pipe(require_Schema$1.asVoid, require_Schema$1.catch_((error) => require_Schema$1.logWarning("bootstrap turn start launched setup script but failed to record setup activity", {
|
|
94878
95257
|
threadId: command.threadId,
|
|
94879
95258
|
worktreePath: record.worktreePath,
|
|
@@ -94905,7 +95284,8 @@ const dispatchBootstrapTurnStart$1 = (input, command) => require_Schema$1.gen(fu
|
|
|
94905
95284
|
summary: "No setup script configured",
|
|
94906
95285
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
94907
95286
|
payload: {},
|
|
94908
|
-
tone: "info"
|
|
95287
|
+
tone: "info",
|
|
95288
|
+
launch
|
|
94909
95289
|
}).pipe(require_Schema$1.asVoid, require_Schema$1.ignore);
|
|
94910
95290
|
return recordSetupScriptStarted({
|
|
94911
95291
|
requestedAt,
|
|
@@ -94926,7 +95306,9 @@ const dispatchBootstrapTurnStart$1 = (input, command) => require_Schema$1.gen(fu
|
|
|
94926
95306
|
orchestrationEngine,
|
|
94927
95307
|
git,
|
|
94928
95308
|
gitStatusBroadcaster,
|
|
94929
|
-
|
|
95309
|
+
...input.refreshSourceControlCredentials ? { refreshSourceControlCredentials: input.refreshSourceControlCredentials } : {},
|
|
95310
|
+
command,
|
|
95311
|
+
launch
|
|
94930
95312
|
}).pipe(require_Schema$1.catchCause((cause) => {
|
|
94931
95313
|
if (!require_Schema$1.hasInterruptsOnly(cause)) worktreeFailureReported = true;
|
|
94932
95314
|
return require_Schema$1.failCause(cause);
|
|
@@ -94944,10 +95326,22 @@ const dispatchBootstrapTurnStart$1 = (input, command) => require_Schema$1.gen(fu
|
|
|
94944
95326
|
summary: "Starting agent",
|
|
94945
95327
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
94946
95328
|
payload: { setupRequested: bootstrap.runSetupScript === true },
|
|
94947
|
-
tone: "info"
|
|
95329
|
+
tone: "info",
|
|
95330
|
+
launch
|
|
94948
95331
|
}).pipe(require_Schema$1.ignore);
|
|
94949
95332
|
sealBootstrapCommand(orchestrationEngine, command.commandId);
|
|
94950
|
-
|
|
95333
|
+
const started = yield* orchestrationEngine.dispatch(finalTurnStartCommand);
|
|
95334
|
+
if (launch.snapshot && bootstrap?.prepareWorktree) {
|
|
95335
|
+
const settledAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
95336
|
+
launch.snapshot = withCheckoutLaunchTurnStarted(launch.snapshot, settledAt);
|
|
95337
|
+
yield* publishCheckoutLaunchSnapshot({
|
|
95338
|
+
orchestrationEngine,
|
|
95339
|
+
threadId: command.threadId,
|
|
95340
|
+
snapshot: launch.snapshot,
|
|
95341
|
+
createdAt: settledAt
|
|
95342
|
+
}).pipe(require_Schema$1.ignore);
|
|
95343
|
+
}
|
|
95344
|
+
return started;
|
|
94951
95345
|
});
|
|
94952
95346
|
return yield* runBootstrapCommand(orchestrationEngine, command.commandId, bootstrapProgram.pipe(require_Schema$1.onInterrupt(() => appendWorktreeActivity({
|
|
94953
95347
|
orchestrationEngine,
|
|
@@ -94957,7 +95351,8 @@ const dispatchBootstrapTurnStart$1 = (input, command) => require_Schema$1.gen(fu
|
|
|
94957
95351
|
summary: "Launch cancelled",
|
|
94958
95352
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
94959
95353
|
payload: {},
|
|
94960
|
-
tone: "info"
|
|
95354
|
+
tone: "info",
|
|
95355
|
+
launch
|
|
94961
95356
|
}).pipe(require_Schema$1.ignore)), require_Schema$1.catchCause((cause) => {
|
|
94962
95357
|
const dispatchError = toBootstrapDispatchCommandCauseError(cause);
|
|
94963
95358
|
if (require_Schema$1.hasInterruptsOnly(cause)) return require_Schema$1.fail(dispatchError);
|
|
@@ -291634,6 +292029,21 @@ function readProviderAccountId(selection) {
|
|
|
291634
292029
|
return "providerAccountId" in selection ? selection.providerAccountId : void 0;
|
|
291635
292030
|
}
|
|
291636
292031
|
//#endregion
|
|
292032
|
+
//#region src/orchestration/expiredProviderEgressToken.ts
|
|
292033
|
+
const EXPIRED_PROVIDER_EGRESS_TOKEN = "Provider egress token is invalid or expired";
|
|
292034
|
+
/**
|
|
292035
|
+
* The CMMD egress authorizer uses this sentence for a token it will not
|
|
292036
|
+
* accept. A workspace reconnect 401 is a different failure and must not
|
|
292037
|
+
* take this path.
|
|
292038
|
+
*
|
|
292039
|
+
* The token lives in the provider process environment. Stopping that process
|
|
292040
|
+
* lets the next session start mint a new one. A later send of this same turn
|
|
292041
|
+
* delivers the user message a second time, so the recovery stops at the session.
|
|
292042
|
+
*/
|
|
292043
|
+
function isExpiredProviderEgressTokenError(message) {
|
|
292044
|
+
return typeof message === "string" && message.includes(EXPIRED_PROVIDER_EGRESS_TOKEN);
|
|
292045
|
+
}
|
|
292046
|
+
//#endregion
|
|
291637
292047
|
//#region src/persistence/Layers/ProjectionTurns.ts
|
|
291638
292048
|
const ProjectionTurnDbRowSchema = ProjectionTurn.mapFields(require_Schema$1.assign({
|
|
291639
292049
|
checkpointFiles: require_Schema$1.fromJsonString(require_Schema$1.ArraySchema(OrchestrationCheckpointFile)),
|
|
@@ -293528,6 +293938,7 @@ const make$8 = require_Schema$1.fn("make")(function* () {
|
|
|
293528
293938
|
const handleRuntimeError = require_Schema$1.fn("handleRuntimeError")(function* (event, thread, eventTurnId, activeTurnId) {
|
|
293529
293939
|
if (event.type !== "runtime.error") return;
|
|
293530
293940
|
if (!shouldApplyRuntimeErrorEvent(activeTurnId, eventTurnId)) return;
|
|
293941
|
+
if (isExpiredProviderEgressTokenError(event.payload.message)) yield* providerService.stopSession({ threadId: thread.id }).pipe(require_Schema$1.catchCause(() => require_Schema$1.void_));
|
|
293531
293942
|
yield* orchestrationEngine.dispatch({
|
|
293532
293943
|
type: "thread.session.set",
|
|
293533
293944
|
commandId: providerCommandId(event, "runtime-error-session-set"),
|
|
@@ -301215,7 +301626,7 @@ function resolveBuildCommitFromEnv(env) {
|
|
|
301215
301626
|
* environment descriptor down instead of reporting an honest "unknown".
|
|
301216
301627
|
*/
|
|
301217
301628
|
function readBakedBuildCommit() {
|
|
301218
|
-
return "
|
|
301629
|
+
return "a00cf0b653c5ad41933b286a3f108c74a8b61780";
|
|
301219
301630
|
}
|
|
301220
301631
|
async function resolveServerBuildCommit(input) {
|
|
301221
301632
|
if (isFullCommitSha(input.baked)) return input.baked;
|
|
@@ -310454,6 +310865,26 @@ function readNonEmptyString(value) {
|
|
|
310454
310865
|
//#region src/orchestration/http.ts
|
|
310455
310866
|
const DISPATCH_CAUSE_DETAIL_LIMIT = 500;
|
|
310456
310867
|
const DISPATCH_CAUSE_MAX_DEPTH = 8;
|
|
310868
|
+
const resolveBootstrapGithubAuth = (input) => {
|
|
310869
|
+
const runtimeGrantAuth = resolveRuntimeGitHubGrantAuth(input.config, input.headers);
|
|
310870
|
+
return runtimeGrantAuth ? require_Schema$1.succeed(runtimeGrantAuth) : resolveCmmdJwtForSession({
|
|
310871
|
+
sessionId: input.session.sessionId,
|
|
310872
|
+
subject: input.session.subject,
|
|
310873
|
+
logPrefix: "bootstrap-github"
|
|
310874
|
+
});
|
|
310875
|
+
};
|
|
310876
|
+
const refreshBootstrapSourceControlCredentials = (input) => require_Schema$1.gen(function* () {
|
|
310877
|
+
if (!input.auth) return yield* require_Schema$1.fail(/* @__PURE__ */ new Error("CMMD GitHub authorization is unavailable for Work Session bootstrap."));
|
|
310878
|
+
const result = yield* refreshForgeManagedGitHubRemoteCredentials({
|
|
310879
|
+
cwd: input.cwd,
|
|
310880
|
+
auth: typeof input.auth === "object" ? input.auth : {
|
|
310881
|
+
kind: "cmmd-jwt",
|
|
310882
|
+
jwt: input.auth
|
|
310883
|
+
},
|
|
310884
|
+
allowUnmanagedRemote: true
|
|
310885
|
+
}, void 0, input.forgeGitCredentialCache ? "cache" : "embed");
|
|
310886
|
+
if (result.status >= 400) return yield* require_Schema$1.fail(new Error(typeof result.body.error === "string" ? result.body.error : "CMMD GitHub authorization failed for Work Session bootstrap."));
|
|
310887
|
+
});
|
|
310457
310888
|
/**
|
|
310458
310889
|
* Render the underlying failure of a dispatch refusal as a single line.
|
|
310459
310890
|
*
|
|
@@ -310894,7 +311325,9 @@ const orchestrationSnapshotRouteLayer = add$1("GET", "/api/orchestration/snapsho
|
|
|
310894
311325
|
return require_HttpServer.jsonUnsafe(snapshot, { status: 200 });
|
|
310895
311326
|
}).pipe(require_Schema$1.catchTag("AuthError", respondToOrchestrationAuthError), require_Schema$1.catchTag("OrchestrationGetSnapshotError", respondToOrchestrationHttpError)));
|
|
310896
311327
|
const orchestrationDispatchRouteLayer = add$1("POST", "/api/orchestration/dispatch", require_Schema$1.gen(function* () {
|
|
311328
|
+
const request = yield* require_HttpServer.HttpServerRequest;
|
|
310897
311329
|
const session = yield* authenticateOwnerSession$1;
|
|
311330
|
+
const config = yield* ServerConfig;
|
|
310898
311331
|
const orchestrationEngine = yield* OrchestrationEngineService;
|
|
310899
311332
|
const startup = yield* ServerRuntimeStartup;
|
|
310900
311333
|
const { result } = yield* admitNormalizedDispatchCommand(yield* require_HttpServer.schemaBodyJson(ClientOrchestrationCommand).pipe(require_Schema$1.mapError((cause) => new OrchestrationDispatchCommandError({
|
|
@@ -310912,6 +311345,11 @@ const orchestrationDispatchRouteLayer = add$1("POST", "/api/orchestration/dispat
|
|
|
310912
311345
|
});
|
|
310913
311346
|
if (admissionRefusal !== null) return yield* new OrchestrationDispatchCommandError({ message: admissionRefusal });
|
|
310914
311347
|
if (normalizedCommand.type === "thread.turn.start") recordThreadSession(normalizedCommand.threadId, session.sessionId);
|
|
311348
|
+
const bootstrapGithubAuth = normalizedCommand.type === "thread.turn.start" && normalizedCommand.bootstrap ? yield* resolveBootstrapGithubAuth({
|
|
311349
|
+
config,
|
|
311350
|
+
headers: request.headers,
|
|
311351
|
+
session
|
|
311352
|
+
}) : null;
|
|
310915
311353
|
const dispatchEffect = normalizedCommand.type === "thread.turn.start" && normalizedCommand.bootstrap ? require_Schema$1.gen(function* () {
|
|
310916
311354
|
const git = yield* require_Schema$1.serviceOption(GitCore);
|
|
310917
311355
|
const gitStatusBroadcaster = yield* require_Schema$1.serviceOption(GitStatusBroadcaster);
|
|
@@ -310921,7 +311359,12 @@ const orchestrationDispatchRouteLayer = add$1("POST", "/api/orchestration/dispat
|
|
|
310921
311359
|
orchestrationEngine,
|
|
310922
311360
|
git: git.value,
|
|
310923
311361
|
gitStatusBroadcaster: gitStatusBroadcaster.value,
|
|
310924
|
-
projectSetupScriptRunner: projectSetupScriptRunner.value
|
|
311362
|
+
projectSetupScriptRunner: projectSetupScriptRunner.value,
|
|
311363
|
+
refreshSourceControlCredentials: (cwd) => refreshBootstrapSourceControlCredentials({
|
|
311364
|
+
forgeGitCredentialCache: config.forgeGitCredentialCache,
|
|
311365
|
+
auth: bootstrapGithubAuth,
|
|
311366
|
+
cwd
|
|
311367
|
+
})
|
|
310925
311368
|
}, normalizedCommand);
|
|
310926
311369
|
}).pipe(require_Schema$1.mapError((cause) => new OrchestrationDispatchCommandError({
|
|
310927
311370
|
message: "Failed to dispatch orchestration command.",
|
|
@@ -314090,12 +314533,15 @@ registerProxyRoute({
|
|
|
314090
314533
|
orgIdSource: "none"
|
|
314091
314534
|
});
|
|
314092
314535
|
const cmmdForgeCloudProjectsListRouteLayer = add$1("GET", "/api/cmmd/forge-cloud-projects", require_Schema$1.gen(function* () {
|
|
314536
|
+
const request = yield* require_HttpServer.HttpServerRequest;
|
|
314537
|
+
const organizationId = normalizeOrgIdQueryParam(new URL(request.url, "http://localhost").searchParams.get("orgId"));
|
|
314093
314538
|
const { session, jwt: accessToken } = yield* makeCmmdProxyAccessTokenEffect("forge-cloud-projects");
|
|
314094
314539
|
if (!accessToken) return yield* respondCmmdConnectionRequired(session.sessionId);
|
|
314095
314540
|
const upstreamUrl = `${resolveCommandAppUrl()}${CMMD_CLOUD_PROJECTS_PATH}`;
|
|
314096
314541
|
const upstreamOrError = yield* fetchCmmdUpstreamWithRetry(() => fetch(upstreamUrl, { headers: {
|
|
314097
314542
|
Authorization: `Bearer ${accessToken}`,
|
|
314098
|
-
Accept: "application/json"
|
|
314543
|
+
Accept: "application/json",
|
|
314544
|
+
...organizationId !== void 0 ? { "X-Organization-ID": organizationId } : {}
|
|
314099
314545
|
} }), "idempotent");
|
|
314100
314546
|
if (!upstreamOrError.ok) return require_HttpServer.jsonUnsafe({
|
|
314101
314547
|
error: "CMMD is unreachable. Check your connection.",
|
|
@@ -314199,10 +314645,11 @@ const FORGE_RUNTIMES_KICKOFF_FRAME = new TextEncoder().encode(": ok\n\n");
|
|
|
314199
314645
|
* is the designed failure mode. Retrying here would stack a second backoff
|
|
314200
314646
|
* inside the first and delay the frame the client is waiting on.
|
|
314201
314647
|
*/
|
|
314202
|
-
function makeFetchForgeCatalogFrameEffect(proxy, upstreamUrl, accessToken) {
|
|
314648
|
+
function makeFetchForgeCatalogFrameEffect(proxy, upstreamUrl, accessToken, organizationId) {
|
|
314203
314649
|
return require_Schema$1.tryPromise(() => fetch(upstreamUrl, { headers: {
|
|
314204
314650
|
Authorization: `Bearer ${accessToken}`,
|
|
314205
|
-
Accept: "application/json"
|
|
314651
|
+
Accept: "application/json",
|
|
314652
|
+
...organizationId !== void 0 ? { "X-Organization-ID": organizationId } : {}
|
|
314206
314653
|
} }).then(async (res) => {
|
|
314207
314654
|
if (res.status === 401 || res.status === 403) {
|
|
314208
314655
|
console.warn(`[${proxy.logTag}] upstream auth failure: ${res.status}`);
|
|
@@ -314227,9 +314674,11 @@ function makeFetchForgeCatalogFrameEffect(proxy, upstreamUrl, accessToken) {
|
|
|
314227
314674
|
*/
|
|
314228
314675
|
function makeForgeCatalogEventsHandler(proxy, upstreamUrl) {
|
|
314229
314676
|
return require_Schema$1.gen(function* () {
|
|
314677
|
+
const request = yield* require_HttpServer.HttpServerRequest;
|
|
314678
|
+
const organizationId = normalizeOrgIdQueryParam(new URL(request.url, "http://localhost").searchParams.get("orgId"));
|
|
314230
314679
|
const { session, jwt: accessToken } = yield* makeCmmdProxyAccessTokenEffect(proxy.logTag);
|
|
314231
314680
|
if (!accessToken) return yield* respondCmmdConnectionRequired(session.sessionId);
|
|
314232
|
-
const fetchFrame = makeFetchForgeCatalogFrameEffect(proxy, upstreamUrl, accessToken);
|
|
314681
|
+
const fetchFrame = makeFetchForgeCatalogFrameEffect(proxy, upstreamUrl, accessToken, organizationId);
|
|
314233
314682
|
const dataStream = require_Path.concat(require_Path.fromEffect(fetchFrame), require_Path.tick(FORGE_RUNTIMES_POLL_INTERVAL).pipe(require_Path.mapEffect(() => fetchFrame))).pipe(require_Path.filter((frame) => frame !== null));
|
|
314234
314683
|
const keepaliveStream = require_Path.tick(FORGE_RUNTIMES_KEEPALIVE_INTERVAL).pipe(require_Path.map(() => FORGE_RUNTIMES_KEEPALIVE_FRAME));
|
|
314235
314684
|
const frames = require_Path.concat(require_Path.succeed(FORGE_RUNTIMES_KICKOFF_FRAME), require_Path.merge(dataStream, keepaliveStream)).pipe(require_Path.ensuring(require_Schema$1.sync(() => {
|
|
@@ -314720,10 +315169,7 @@ function isLegacyRuntimeConnection(value, expectedRuntimeId) {
|
|
|
314720
315169
|
return [
|
|
314721
315170
|
runtime.runtimeId === expectedRuntimeId,
|
|
314722
315171
|
runtime.runtimeCapabilityMode === "legacy_env",
|
|
314723
|
-
hasCmmdRuntimeSpriteIdentity({
|
|
314724
|
-
...Object.hasOwn(runtime, "spriteName") ? { spriteName: typeof runtime.spriteName === "string" ? runtime.spriteName : null } : {},
|
|
314725
|
-
...Object.hasOwn(runtime, "flyMachineId") ? { flyMachineId: typeof runtime.flyMachineId === "string" ? runtime.flyMachineId : null } : {}
|
|
314726
|
-
}),
|
|
315172
|
+
hasCmmdRuntimeSpriteIdentity({ spriteName: typeof runtime.spriteName === "string" ? runtime.spriteName : null }),
|
|
314727
315173
|
!Object.hasOwn(runtime, "brokerAuthorityAttestedForgeGitCommit"),
|
|
314728
315174
|
runtime.brokerAuthorityAttestedImageRef === null,
|
|
314729
315175
|
runtime.brokerAuthorityAttestedImageVersion === null,
|
|
@@ -327262,7 +327708,7 @@ const resolveServerConfig = (flags, cliLogLevel, options) => require_Schema$1.ge
|
|
|
327262
327708
|
const isManagedCloudSurface = (env.forgeCmmdRuntimeMode ?? false) || (env.forgeCloudShellMode ?? false);
|
|
327263
327709
|
const autoBootstrapProjectFromCwd = require_Schema$1.getOrElse(resolveOptionPrecedence(require_Schema$1.fromUndefinedOr(options?.forceAutoBootstrapProjectFromCwd), isHeadlessStartup ? require_Schema$1.some(false) : require_Schema$1.none(), normalizedFlags.autoBootstrapProjectFromCwd, require_Schema$1.fromUndefinedOr(env.autoBootstrapProjectFromCwd), require_Schema$1.fromUndefinedOr(bootstrap?.autoBootstrapProjectFromCwd)), () => mode === "web" && !isManagedCloudSurface);
|
|
327264
327710
|
const logWebSocketEvents = require_Schema$1.getOrElse(resolveOptionPrecedence(normalizedFlags.logWebSocketEvents, require_Schema$1.fromUndefinedOr(env.logWebSocketEvents), require_Schema$1.fromUndefinedOr(bootstrap?.logWebSocketEvents)), () => Boolean(devUrl));
|
|
327265
|
-
const staticDir = devUrl ? void 0 : yield* resolveStaticDir();
|
|
327711
|
+
const staticDir = devUrl || isManagedCloudSurface ? void 0 : yield* resolveStaticDir();
|
|
327266
327712
|
const host = require_Schema$1.getOrElse(resolveOptionPrecedence(normalizedFlags.host, require_Schema$1.fromUndefinedOr(env.host), require_Schema$1.fromUndefinedOr(bootstrap?.host)), () => mode === "desktop" ? "127.0.0.1" : void 0);
|
|
327267
327713
|
const logLevel = require_Schema$1.getOrElse(cliLogLevel, () => env.logLevel);
|
|
327268
327714
|
const browserWebRtcIceServers = parseBrowserWebRtcIceServers(env.browserWebRtcIceServers);
|
|
@@ -327446,16 +327892,16 @@ const findActiveProjectTarget = require_Schema$1.fn("findActiveProjectTarget")(f
|
|
|
327446
327892
|
workspaceRoot: resolved.workspaceRoot
|
|
327447
327893
|
};
|
|
327448
327894
|
});
|
|
327449
|
-
const fetchLiveOrchestrationSnapshot = (origin, bearerToken$
|
|
327895
|
+
const fetchLiveOrchestrationSnapshot = (origin, bearerToken$3) => runLiveServerRequest(require_HttpServer.get(`${origin}/api/orchestration/snapshot`).pipe(require_HttpServer.acceptJson, require_HttpServer.bearerToken(bearerToken$3)), require_HttpServer.matchStatus({
|
|
327450
327896
|
"2xx": decodeOrchestrationReadModelResponse,
|
|
327451
327897
|
orElse: (response) => readErrorMessageFromResponse(response).pipe(require_Schema$1.flatMap((message) => require_Schema$1.fail(new Error(message))))
|
|
327452
327898
|
}));
|
|
327453
327899
|
const ProjectLeadExplanationEnvelope = require_Schema$1.Struct({ data: ProjectLeadExplanationSchema });
|
|
327454
|
-
const fetchLiveProjectLeadExplanation = (origin, bearerToken$
|
|
327900
|
+
const fetchLiveProjectLeadExplanation = (origin, bearerToken$2, projectId) => runLiveServerRequest(require_HttpServer.get(`${origin}/api/cmmd/projects/${projectId}/project-lead/explain`).pipe(require_HttpServer.acceptJson, require_HttpServer.bearerToken(bearerToken$2)), require_HttpServer.matchStatus({
|
|
327455
327901
|
"2xx": (response) => require_HttpServer.schemaBodyJson$1(ProjectLeadExplanationEnvelope)(response).pipe(require_Schema$1.map((body) => body.data)),
|
|
327456
327902
|
orElse: (response) => readErrorMessageFromResponse(response).pipe(require_Schema$1.flatMap((message) => require_Schema$1.fail(new Error(message))))
|
|
327457
327903
|
}));
|
|
327458
|
-
const dispatchLiveOrchestrationCommand = (origin, bearerToken$
|
|
327904
|
+
const dispatchLiveOrchestrationCommand = (origin, bearerToken$1, command) => require_HttpServer.post(`${origin}/api/orchestration/dispatch`).pipe(require_HttpServer.acceptJson, require_HttpServer.bearerToken(bearerToken$1), require_HttpServer.bodyJson(command), require_Schema$1.flatMap((request) => runLiveServerRequest(request, require_HttpServer.matchStatus({
|
|
327459
327905
|
"2xx": () => require_Schema$1.void_,
|
|
327460
327906
|
orElse: (response) => readErrorMessageFromResponse(response).pipe(require_Schema$1.flatMap((message) => require_Schema$1.fail(new Error(message))))
|
|
327461
327907
|
}))));
|