@cmmd-center/forge 0.13.63 → 0.13.64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.cjs +350 -210
- package/dist/bin.mjs +374 -234
- package/dist/client/assets/{DiffPanel-Mj56e5Vd.js → DiffPanel-CMYTuX9T.js} +2 -2
- package/dist/client/assets/{DiffPanel.logic-Bws9oedp.js → DiffPanel.logic-Bo8iewty.js} +2 -2
- package/dist/client/assets/{DiffPanelShell-CfYAh40Z.js → DiffPanelShell-BOfiU8pF.js} +3 -3
- package/dist/client/assets/{DiffWorkerPoolProvider-CKLNoRVs.js → DiffWorkerPoolProvider-BJM597MG.js} +2 -2
- package/dist/client/assets/{PullRequestCodePanel-7AnSD7oo.js → PullRequestCodePanel-Dp0Gub8R.js} +2 -2
- package/dist/client/assets/{Virtualizer-nWFuwagg.js → Virtualizer-DA9X_YiJ.js} +2 -2
- package/dist/client/assets/{index-DW9f_7Ly.js → index-unGMBg6C.js} +6 -6
- package/dist/client/index.html +4 -4
- 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/bin.cjs
CHANGED
|
@@ -66257,7 +66257,7 @@ function normalizeNumberish(value) {
|
|
|
66257
66257
|
}
|
|
66258
66258
|
//#endregion
|
|
66259
66259
|
//#region package.json
|
|
66260
|
-
var version$1 = "0.13.
|
|
66260
|
+
var version$1 = "0.13.64";
|
|
66261
66261
|
//#endregion
|
|
66262
66262
|
//#region src/sentry.ts
|
|
66263
66263
|
const SERVER_APP_NAME = "forge-server";
|
|
@@ -89347,6 +89347,28 @@ var GitHubBroker = class {
|
|
|
89347
89347
|
runtimeResource: "status"
|
|
89348
89348
|
});
|
|
89349
89349
|
}
|
|
89350
|
+
/**
|
|
89351
|
+
* On a "github" scope cache miss, re-requests it once through the existing
|
|
89352
|
+
* CMMD client before the caller refuses (CMMD-Center/forge#3496). CMMD
|
|
89353
|
+
* delivers the grant proactively on thread.create and the kick, so a miss
|
|
89354
|
+
* on a woken runtime is a cache or ticket TTL problem, not a missing
|
|
89355
|
+
* request: this closes the gap where the ticket lands in the broker
|
|
89356
|
+
* authority cache mid-request, and logs the outcome either way so the
|
|
89357
|
+
* cause is visible instead of a silent refusal.
|
|
89358
|
+
*/
|
|
89359
|
+
async requestRuntimeGithubGrant() {
|
|
89360
|
+
const cached = this.runtimeGrantAuthContext("github");
|
|
89361
|
+
if (cached) return cached;
|
|
89362
|
+
const runtimeId = process.env.FORGE_CMMD_RUNTIME_ID?.trim();
|
|
89363
|
+
if (!runtimeId) return null;
|
|
89364
|
+
const result = await this.status({
|
|
89365
|
+
sessionId: AuthSessionId.make(`cmmd-runtime:${runtimeId}`),
|
|
89366
|
+
subject: `runtime:${runtimeId}`
|
|
89367
|
+
});
|
|
89368
|
+
const grant = this.runtimeGrantAuthContext("github");
|
|
89369
|
+
console.warn(`[github-broker] re-requested the github scope grant for runtime ${runtimeId}: ${grant ? "cache populated" : `still missing (broker answered ${result.ok ? "ok" : result.code ?? "no grant"})`}`);
|
|
89370
|
+
return grant;
|
|
89371
|
+
}
|
|
89350
89372
|
async workspaceStatus(input) {
|
|
89351
89373
|
const cwdValidation = validateCwd(input.cwd);
|
|
89352
89374
|
if (cwdValidation) return cwdValidation;
|
|
@@ -97853,6 +97875,235 @@ function serializeProviderCatalog(providers) {
|
|
|
97853
97875
|
return catalog;
|
|
97854
97876
|
}
|
|
97855
97877
|
//#endregion
|
|
97878
|
+
//#region src/provider/personalClaudeInVm.ts
|
|
97879
|
+
/**
|
|
97880
|
+
* CMMD writes this marker when it activates a personal Claude subscription
|
|
97881
|
+
* inside a running sprite. Activation always happens after boot, so a
|
|
97882
|
+
* boot-time env var alone cannot reflect it (FOR-36249).
|
|
97883
|
+
*
|
|
97884
|
+
* CMMD names the file in the Service env (FORGE_PERSONAL_CLAUDE_MARKER_PATH).
|
|
97885
|
+
* Without that, the marker sits directly under FORGE_HOME, which is the same
|
|
97886
|
+
* guest home CMMD derives every sprite path from. A server with neither has no
|
|
97887
|
+
* sprite home to look in, and a desktop never has a marker, so it reads none.
|
|
97888
|
+
*/
|
|
97889
|
+
const PERSONAL_CLAUDE_IN_VM_MARKER_NAME = ".forge-personal-claude-in-vm";
|
|
97890
|
+
const PERSONAL_CLAUDE_GENERATION_FILE_NAME = ".forge-personal-claude-generation";
|
|
97891
|
+
function markerPath(env) {
|
|
97892
|
+
if (env.FORGE_PERSONAL_CLAUDE_MARKER_PATH) return env.FORGE_PERSONAL_CLAUDE_MARKER_PATH;
|
|
97893
|
+
if (env.FORGE_HOME) return (0, node_path.join)(env.FORGE_HOME, PERSONAL_CLAUDE_IN_VM_MARKER_NAME);
|
|
97894
|
+
return null;
|
|
97895
|
+
}
|
|
97896
|
+
/**
|
|
97897
|
+
* True when this runtime should offer the personal Claude subscription lane.
|
|
97898
|
+
*
|
|
97899
|
+
* Accepts either signal: the boot-time env var (backward compatible) or the
|
|
97900
|
+
* activation marker on disk. Reading the marker at call time lets the provider
|
|
97901
|
+
* catalog and the per-turn readiness guard self-heal once CMMD delivers,
|
|
97902
|
+
* without a sprite reboot. Callers still verify the credential is non-empty
|
|
97903
|
+
* before treating it as usable; this only decides whether the lane is active.
|
|
97904
|
+
*/
|
|
97905
|
+
function personalClaudeInVmEnabled(env = process.env) {
|
|
97906
|
+
if (env.FORGE_PERSONAL_CLAUDE_IN_VM === "true") return true;
|
|
97907
|
+
const marker = markerPath(env);
|
|
97908
|
+
if (!marker) return false;
|
|
97909
|
+
try {
|
|
97910
|
+
return (0, node_fs.existsSync)(marker);
|
|
97911
|
+
} catch {
|
|
97912
|
+
return false;
|
|
97913
|
+
}
|
|
97914
|
+
}
|
|
97915
|
+
/** Exported at boot. This is the restart proof CMMD waits on, so it must never read the file. */
|
|
97916
|
+
function bootExportedPersonalClaudeGenerationHash(env = process.env) {
|
|
97917
|
+
return env.FORGE_PERSONAL_CLAUDE_GENERATION_HASH?.trim() ?? "";
|
|
97918
|
+
}
|
|
97919
|
+
/**
|
|
97920
|
+
* The sha256 of the Claude credential generation this runtime holds, or "" when
|
|
97921
|
+
* it holds none. The readiness guard compares it with the generation CMMD
|
|
97922
|
+
* applied. The restart proof must not use it; it uses the boot-exported hash.
|
|
97923
|
+
*
|
|
97924
|
+
* The boot preload exports FORGE_PERSONAL_CLAUDE_GENERATION_HASH, but only when
|
|
97925
|
+
* the marker already exists at boot. Activation in place writes the generation
|
|
97926
|
+
* file and touches the marker without setting any env, so an empty variable
|
|
97927
|
+
* falls back to that file, hashed the way the preload hashes it. CMMD puts the
|
|
97928
|
+
* file beside the marker in the guest home and names no path for it. A marker
|
|
97929
|
+
* with no generation file is a legacy runtime, and gets no hash here either.
|
|
97930
|
+
*/
|
|
97931
|
+
function personalClaudeGenerationHash(env = process.env) {
|
|
97932
|
+
const exported = bootExportedPersonalClaudeGenerationHash(env);
|
|
97933
|
+
if (exported) return exported;
|
|
97934
|
+
const marker = markerPath(env);
|
|
97935
|
+
if (!marker) return "";
|
|
97936
|
+
try {
|
|
97937
|
+
if (!(0, node_fs.existsSync)(marker)) return "";
|
|
97938
|
+
const generation = (0, node_fs.readFileSync)((0, node_path.join)((0, node_path.dirname)(marker), PERSONAL_CLAUDE_GENERATION_FILE_NAME), "utf8").trim();
|
|
97939
|
+
return generation ? (0, node_crypto.createHash)("sha256").update(generation).digest("hex") : "";
|
|
97940
|
+
} catch {
|
|
97941
|
+
return "";
|
|
97942
|
+
}
|
|
97943
|
+
}
|
|
97944
|
+
//#endregion
|
|
97945
|
+
//#region src/provider/providerAuthFailureCopy.ts
|
|
97946
|
+
/**
|
|
97947
|
+
* Rewrite provider auth failures into an action the user can actually take.
|
|
97948
|
+
*
|
|
97949
|
+
* The provider SDKs assume they are running under a human at a terminal, so
|
|
97950
|
+
* their auth errors name CLI verbs: Claude's is literally
|
|
97951
|
+
* `Not logged in · Please run /login`. On Forge Cloud that reaches a browser
|
|
97952
|
+
* user who has no terminal, no shell, and no way to run `/login` — the turn
|
|
97953
|
+
* dies in ~3 s naming an action that does not exist for them (observed live
|
|
97954
|
+
* 2026-08-05).
|
|
97955
|
+
*
|
|
97956
|
+
* CMMD already writes the right shape for the Codex egress path — "Connect
|
|
97957
|
+
* ChatGPT in Settings > Providers, then retry" — which names a destination the
|
|
97958
|
+
* user can click. This gives the provider-SDK failures the same treatment.
|
|
97959
|
+
*
|
|
97960
|
+
* Scope is deliberately narrow. Only messages that clearly identify a
|
|
97961
|
+
* *credential* problem are rewritten; everything else passes through verbatim,
|
|
97962
|
+
* because a rewritten unknown error loses detail an operator needs and risks
|
|
97963
|
+
* telling the user to reconnect an account that was never the problem.
|
|
97964
|
+
*/
|
|
97965
|
+
/**
|
|
97966
|
+
* Signatures of "you have no usable credential", matched case-insensitively.
|
|
97967
|
+
*
|
|
97968
|
+
* Kept as explicit patterns rather than a broad /auth/i so that genuine
|
|
97969
|
+
* mid-turn failures mentioning authorization (a tool hitting a 403 on some
|
|
97970
|
+
* unrelated API, say) are not misreported as "your subscription is
|
|
97971
|
+
* disconnected".
|
|
97972
|
+
*/
|
|
97973
|
+
const CREDENTIAL_FAILURE_PATTERNS = [
|
|
97974
|
+
/\bnot logged in\b/i,
|
|
97975
|
+
/\bplease run\s*\/login\b/i,
|
|
97976
|
+
/\brun\s*\/login\b/i,
|
|
97977
|
+
/\blogin required\b/i,
|
|
97978
|
+
/\bnot authenticated\b/i,
|
|
97979
|
+
/\bno credentials? found\b/i,
|
|
97980
|
+
/\binvalid api key\b/i,
|
|
97981
|
+
/\bauthentication_error\b/i
|
|
97982
|
+
];
|
|
97983
|
+
/**
|
|
97984
|
+
* Claude's words for a delivered credential whose refresh chain is dead.
|
|
97985
|
+
*
|
|
97986
|
+
* Deliberately NOT in CREDENTIAL_FAILURE_PATTERNS. On a runtime whose Claude
|
|
97987
|
+
* credential CMMD delivers, this is not "you are signed out" and reconnecting
|
|
97988
|
+
* in Settings is not the fix: CMMD's authority rotates the refresh token on
|
|
97989
|
+
* every refresh, the snapshot in the guest dies at the next rotation, and the
|
|
97990
|
+
* repair is a re-delivery the next send triggers (FOR-36425, CMMD-36441).
|
|
97991
|
+
* Anywhere else the credential is the user's own local login, so the CLI text
|
|
97992
|
+
* still passes through untouched.
|
|
97993
|
+
*/
|
|
97994
|
+
const DELIVERED_CREDENTIAL_EXPIRED_PATTERN = /\boauth session expired\b/i;
|
|
97995
|
+
const DELIVERED_CLAUDE_CREDENTIAL_EXPIRED_COPY = "The delivered Claude credential expired. CMMD refreshes it on the next send, so retry this turn.";
|
|
97996
|
+
/** True when the message is about a missing/unusable credential, not a tool failure. */
|
|
97997
|
+
function isProviderCredentialFailure(message) {
|
|
97998
|
+
return CREDENTIAL_FAILURE_PATTERNS.some((pattern) => pattern.test(message));
|
|
97999
|
+
}
|
|
98000
|
+
/**
|
|
98001
|
+
* Map a ProviderKind to the account name a user would recognise.
|
|
98002
|
+
*
|
|
98003
|
+
* NOTE the literal is `claudeAgent`, not `claude`. This read `"claude"` and so
|
|
98004
|
+
* never matched, silently degrading every Claude auth failure to the generic
|
|
98005
|
+
* fallback — "Forge Cloud has no **this provider** subscription connected."
|
|
98006
|
+
* Same provider-name drift class as the model-mapping fix (#2103/#2105).
|
|
98007
|
+
*
|
|
98008
|
+
* The names come from the shared PROVIDER_ACCOUNT_NAMES map rather than a local
|
|
98009
|
+
* switch: this file's copy was the ONLY correct provider→label mapping in the
|
|
98010
|
+
* codebase while four client call sites reimplemented it as binary ternaries.
|
|
98011
|
+
* One Record over ProviderKind means a new provider is a compile error in one
|
|
98012
|
+
* place instead of five sentences that read wrong in production.
|
|
98013
|
+
*
|
|
98014
|
+
* Providers that do not sell a personal subscription stay generic on purpose —
|
|
98015
|
+
* "Forge Cloud has no Ollama subscription connected" names something that does
|
|
98016
|
+
* not exist.
|
|
98017
|
+
*/
|
|
98018
|
+
function providerLabel(provider) {
|
|
98019
|
+
return supportsPersonalSubscription(provider) ? PROVIDER_ACCOUNT_NAMES[provider] : "this provider";
|
|
98020
|
+
}
|
|
98021
|
+
/**
|
|
98022
|
+
* Return the message to show for a failed turn.
|
|
98023
|
+
*
|
|
98024
|
+
* `surface` decides the destination: a cloud runtime has no terminal, so it is
|
|
98025
|
+
* pointed at Settings; a local/desktop runtime CAN run the CLI login, so its
|
|
98026
|
+
* copy still offers that as the concrete fix rather than sending someone to a
|
|
98027
|
+
* settings page that is not how they authenticate.
|
|
98028
|
+
*/
|
|
98029
|
+
function rewriteProviderAuthFailure(input) {
|
|
98030
|
+
const original = input.message ?? "";
|
|
98031
|
+
if (original.length === 0) return {
|
|
98032
|
+
message: original,
|
|
98033
|
+
rewritten: false
|
|
98034
|
+
};
|
|
98035
|
+
if (input.deliveredClaudeCredential === true && DELIVERED_CREDENTIAL_EXPIRED_PATTERN.test(original)) return {
|
|
98036
|
+
message: DELIVERED_CLAUDE_CREDENTIAL_EXPIRED_COPY,
|
|
98037
|
+
rewritten: true
|
|
98038
|
+
};
|
|
98039
|
+
if (!isProviderCredentialFailure(original)) return {
|
|
98040
|
+
message: original,
|
|
98041
|
+
rewritten: false
|
|
98042
|
+
};
|
|
98043
|
+
const who = providerLabel(input.provider);
|
|
98044
|
+
return {
|
|
98045
|
+
message: input.surface === "cloud" ? `Forge Cloud has no ${who} subscription connected for your account. Open Settings > Providers to connect one, then retry this turn.` : `This runtime is not signed in to ${who}. Connect it from Settings > Providers, then retry this turn.`,
|
|
98046
|
+
rewritten: true
|
|
98047
|
+
};
|
|
98048
|
+
}
|
|
98049
|
+
/**
|
|
98050
|
+
* Convenience for call sites that just want the string to show.
|
|
98051
|
+
*
|
|
98052
|
+
* Exists so adapters do not each re-derive the surface and re-handle the
|
|
98053
|
+
* undefined case inline — that inlining is what pushed
|
|
98054
|
+
* ClaudeAdapter.handleResultMessage over the cyclomatic gate. Returns
|
|
98055
|
+
* `undefined` unchanged so "no error" stays distinguishable from "empty error".
|
|
98056
|
+
*/
|
|
98057
|
+
function providerAuthFailureMessage(message, provider, env = process.env) {
|
|
98058
|
+
if (message === void 0) return void 0;
|
|
98059
|
+
return rewriteProviderAuthFailure({
|
|
98060
|
+
message,
|
|
98061
|
+
provider,
|
|
98062
|
+
surface: env.FORGE_CMMD_RUNTIME_MODE === "true" ? "cloud" : "local",
|
|
98063
|
+
deliveredClaudeCredential: provider === "claudeAgent" && personalClaudeInVmEnabled(env)
|
|
98064
|
+
}).message;
|
|
98065
|
+
}
|
|
98066
|
+
//#endregion
|
|
98067
|
+
//#region src/orchestration/turnFailureReason.ts
|
|
98068
|
+
/**
|
|
98069
|
+
* Machine-readable reasons for a turn that failed before it produced any
|
|
98070
|
+
* assistant output, replicated to CMMD on the `turn_status` event
|
|
98071
|
+
* (CMMD-Center/forge#3496, CMMD-Center/CMMD#5272). Codes match the catalog
|
|
98072
|
+
* CMMD renders actions from (CMMD-Center/CMMD#5289): a code CMMD does not
|
|
98073
|
+
* recognize degrades to its own generic fallback, so a new Forge failure
|
|
98074
|
+
* class is safe to ship before CMMD's catalog knows about it.
|
|
98075
|
+
*/
|
|
98076
|
+
const GITHUB_GRANT_DETAIL_PATTERN = /exact scoped runtime GitHub grant/i;
|
|
98077
|
+
/**
|
|
98078
|
+
* The exact-machine broker's own wording (`providerEgressToken.ts`) for all
|
|
98079
|
+
* three reasons it could not produce a provider token: an incomplete runtime
|
|
98080
|
+
* identity, no owner session bound to the request, or no live broker
|
|
98081
|
+
* authority. Every one of those is a real authentication refusal, not a
|
|
98082
|
+
* workspace or adapter failure, and the prefix is unique to that code path.
|
|
98083
|
+
*/
|
|
98084
|
+
const EXACT_MACHINE_BROKER_AUTHORITY_PATTERN = /provider token issuance requires a live exact-machine broker authority/i;
|
|
98085
|
+
/**
|
|
98086
|
+
* Classifies a `provider.turn.start.failed` activity's detail. This activity
|
|
98087
|
+
* kind also covers non-auth causes (a draining runtime, a missing user
|
|
98088
|
+
* message, a rejected workspace, a start-timeout cleanup failure), so only
|
|
98089
|
+
* text that names a known authentication refusal is reported as one; every
|
|
98090
|
+
* other detail degrades to `unspecified_failure` rather than telling CMMD to
|
|
98091
|
+
* offer a reconnect action credentials cannot fix.
|
|
98092
|
+
*/
|
|
98093
|
+
function classifyProviderTurnStartFailureReason(detail) {
|
|
98094
|
+
const message = detail.trim().length > 0 ? detail : "The provider could not start a session for this run.";
|
|
98095
|
+
return {
|
|
98096
|
+
code: GITHUB_GRANT_DETAIL_PATTERN.test(detail) ? "provider_start_refused_github_grant" : EXACT_MACHINE_BROKER_AUTHORITY_PATTERN.test(detail) || isProviderCredentialFailure(detail) ? "provider_start_refused_auth" : "unspecified_failure",
|
|
98097
|
+
message
|
|
98098
|
+
};
|
|
98099
|
+
}
|
|
98100
|
+
function checkpointTimeoutReason(detail) {
|
|
98101
|
+
return {
|
|
98102
|
+
code: "checkpoint_timeout",
|
|
98103
|
+
message: detail.trim().length > 0 ? detail : "The workspace checkpoint timed out before the turn could start."
|
|
98104
|
+
};
|
|
98105
|
+
}
|
|
98106
|
+
//#endregion
|
|
97856
98107
|
//#region src/runtimeReplication/replicaSerializer.ts
|
|
97857
98108
|
const replicaTurnStatuses = new Set([
|
|
97858
98109
|
"pending",
|
|
@@ -98193,6 +98444,53 @@ function serializeFailureActivity(activity) {
|
|
|
98193
98444
|
}
|
|
98194
98445
|
};
|
|
98195
98446
|
}
|
|
98447
|
+
/** Only the pre-turn baseline capture sets this; a post-turn capture failure
|
|
98448
|
+
* never blocked the turn from starting and must not fail it retroactively. */
|
|
98449
|
+
function blocksTurnStart(activity) {
|
|
98450
|
+
const payload = activity.payload;
|
|
98451
|
+
if (!payload || typeof payload !== "object") return false;
|
|
98452
|
+
return payload.blocksTurnStart === true;
|
|
98453
|
+
}
|
|
98454
|
+
function isCheckpointTimeoutDetail(detail) {
|
|
98455
|
+
return /timed out/i.test(detail);
|
|
98456
|
+
}
|
|
98457
|
+
/**
|
|
98458
|
+
* The structured reason a turn never started, when this activity is one of
|
|
98459
|
+
* the two known causes (CMMD-Center/forge#3496): the provider refused to
|
|
98460
|
+
* start a session, or the pre-turn checkpoint that must precede it timed out.
|
|
98461
|
+
* `null` for every other activity, including a checkpoint failure that did
|
|
98462
|
+
* not block turn start or was not a timeout.
|
|
98463
|
+
*/
|
|
98464
|
+
function turnStartFailureReason(activity) {
|
|
98465
|
+
const detail = failureDetail(activity);
|
|
98466
|
+
if (activity.kind === "provider.turn.start.failed") return classifyProviderTurnStartFailureReason(detail ?? "");
|
|
98467
|
+
if (activity.kind === "checkpoint.capture.failed" && blocksTurnStart(activity) && detail !== null && isCheckpointTimeoutDetail(detail)) return checkpointTimeoutReason(detail);
|
|
98468
|
+
return null;
|
|
98469
|
+
}
|
|
98470
|
+
/**
|
|
98471
|
+
* Replicates a turn-start failure as `turn_status: failed` with a structured
|
|
98472
|
+
* `reason`, alongside (not instead of) the free-text `error_summary` above:
|
|
98473
|
+
* CMMD fails the owning Work Session from this event
|
|
98474
|
+
* (CMMD-Center/CMMD#5272/#5286), which `error_summary` alone cannot drive.
|
|
98475
|
+
*/
|
|
98476
|
+
function serializeTurnStartFailureStatus(activity) {
|
|
98477
|
+
const reason = turnStartFailureReason(activity);
|
|
98478
|
+
if (reason === null) return null;
|
|
98479
|
+
return {
|
|
98480
|
+
sourceSequence: null,
|
|
98481
|
+
event: {
|
|
98482
|
+
eventId: `activity:${activity.id}:turn-status`,
|
|
98483
|
+
occurredAt: canonicalRuntimeEventTimestamp(activity.createdAt),
|
|
98484
|
+
...eventTurn(activity.turnId),
|
|
98485
|
+
kind: "turn_status",
|
|
98486
|
+
status: "failed",
|
|
98487
|
+
reason: {
|
|
98488
|
+
code: reason.code,
|
|
98489
|
+
message: text(reason.message, 2e3) ?? reason.message
|
|
98490
|
+
}
|
|
98491
|
+
}
|
|
98492
|
+
};
|
|
98493
|
+
}
|
|
98196
98494
|
const turnUsageKeys = [
|
|
98197
98495
|
"uncachedInputTokens",
|
|
98198
98496
|
"cachedInputTokens",
|
|
@@ -98541,7 +98839,7 @@ function serializeRuntimeThreadEvents(thread) {
|
|
|
98541
98839
|
});
|
|
98542
98840
|
const recordedTurns = serializeRecordedTurns(thread);
|
|
98543
98841
|
const textGenerations = serializeTextGenerations(thread);
|
|
98544
|
-
|
|
98842
|
+
const priorEvents = [
|
|
98545
98843
|
...messages,
|
|
98546
98844
|
...replicaActivities,
|
|
98547
98845
|
...toolActivities,
|
|
@@ -98550,7 +98848,15 @@ function serializeRuntimeThreadEvents(thread) {
|
|
|
98550
98848
|
...failureActivities,
|
|
98551
98849
|
...recordedTurns,
|
|
98552
98850
|
...textGenerations
|
|
98553
|
-
]
|
|
98851
|
+
];
|
|
98852
|
+
const latestPriorOccurredAt = priorEvents.reduce((latest, entry) => latest === null || entry.event.occurredAt > latest ? entry.event.occurredAt : latest, null);
|
|
98853
|
+
const turnStartFailureStatuses = thread.activities.flatMap((activity) => {
|
|
98854
|
+
const event = serializeTurnStartFailureStatus(activity);
|
|
98855
|
+
if (event === null) return [];
|
|
98856
|
+
if (latestPriorOccurredAt !== null && event.event.occurredAt < latestPriorOccurredAt) return [];
|
|
98857
|
+
return [event];
|
|
98858
|
+
});
|
|
98859
|
+
return [...priorEvents, ...turnStartFailureStatuses].toSorted((left, right) => {
|
|
98554
98860
|
if (left.sourceSequence !== null && right.sourceSequence !== null) return left.sourceSequence - right.sourceSequence;
|
|
98555
98861
|
if (left.sourceSequence !== null) return -1;
|
|
98556
98862
|
if (right.sourceSequence !== null) return 1;
|
|
@@ -152498,7 +152804,7 @@ async function prepareWorkspaceRepositoryDependencies(input) {
|
|
|
152498
152804
|
const dependencies = resolveWorkspaceEnvironmentConfig(input.cwd).repositoryDependencies;
|
|
152499
152805
|
if (dependencies.length === 0) return [];
|
|
152500
152806
|
const broker = input.broker ?? new GitHubBroker();
|
|
152501
|
-
const auth = broker.runtimeGrantAuthContext("github");
|
|
152807
|
+
const auth = broker.runtimeGrantAuthContext("github") ?? await broker.requestRuntimeGithubGrant?.() ?? null;
|
|
152502
152808
|
if (auth === null) throw new Error("Repository dependencies require an exact scoped runtime GitHub grant.");
|
|
152503
152809
|
const readOrigin = input.readOrigin ?? readOriginFromGit;
|
|
152504
152810
|
const resolved = resolveRepositoryDependencies(dependencies, input.cloudProjectsRoot);
|
|
@@ -213506,73 +213812,6 @@ function primaryClaudeCredentialMatchesPrepared(env, preparedDirectory) {
|
|
|
213506
213812
|
}
|
|
213507
213813
|
}
|
|
213508
213814
|
//#endregion
|
|
213509
|
-
//#region src/provider/personalClaudeInVm.ts
|
|
213510
|
-
/**
|
|
213511
|
-
* CMMD writes this marker when it activates a personal Claude subscription
|
|
213512
|
-
* inside a running sprite. Activation always happens after boot, so a
|
|
213513
|
-
* boot-time env var alone cannot reflect it (FOR-36249).
|
|
213514
|
-
*
|
|
213515
|
-
* CMMD names the file in the Service env (FORGE_PERSONAL_CLAUDE_MARKER_PATH).
|
|
213516
|
-
* Without that, the marker sits directly under FORGE_HOME, which is the same
|
|
213517
|
-
* guest home CMMD derives every sprite path from. A server with neither has no
|
|
213518
|
-
* sprite home to look in, and a desktop never has a marker, so it reads none.
|
|
213519
|
-
*/
|
|
213520
|
-
const PERSONAL_CLAUDE_IN_VM_MARKER_NAME = ".forge-personal-claude-in-vm";
|
|
213521
|
-
const PERSONAL_CLAUDE_GENERATION_FILE_NAME = ".forge-personal-claude-generation";
|
|
213522
|
-
function markerPath(env) {
|
|
213523
|
-
if (env.FORGE_PERSONAL_CLAUDE_MARKER_PATH) return env.FORGE_PERSONAL_CLAUDE_MARKER_PATH;
|
|
213524
|
-
if (env.FORGE_HOME) return (0, node_path.join)(env.FORGE_HOME, PERSONAL_CLAUDE_IN_VM_MARKER_NAME);
|
|
213525
|
-
return null;
|
|
213526
|
-
}
|
|
213527
|
-
/**
|
|
213528
|
-
* True when this runtime should offer the personal Claude subscription lane.
|
|
213529
|
-
*
|
|
213530
|
-
* Accepts either signal: the boot-time env var (backward compatible) or the
|
|
213531
|
-
* activation marker on disk. Reading the marker at call time lets the provider
|
|
213532
|
-
* catalog and the per-turn readiness guard self-heal once CMMD delivers,
|
|
213533
|
-
* without a sprite reboot. Callers still verify the credential is non-empty
|
|
213534
|
-
* before treating it as usable; this only decides whether the lane is active.
|
|
213535
|
-
*/
|
|
213536
|
-
function personalClaudeInVmEnabled(env = process.env) {
|
|
213537
|
-
if (env.FORGE_PERSONAL_CLAUDE_IN_VM === "true") return true;
|
|
213538
|
-
const marker = markerPath(env);
|
|
213539
|
-
if (!marker) return false;
|
|
213540
|
-
try {
|
|
213541
|
-
return (0, node_fs.existsSync)(marker);
|
|
213542
|
-
} catch {
|
|
213543
|
-
return false;
|
|
213544
|
-
}
|
|
213545
|
-
}
|
|
213546
|
-
/** Exported at boot. This is the restart proof CMMD waits on, so it must never read the file. */
|
|
213547
|
-
function bootExportedPersonalClaudeGenerationHash(env = process.env) {
|
|
213548
|
-
return env.FORGE_PERSONAL_CLAUDE_GENERATION_HASH?.trim() ?? "";
|
|
213549
|
-
}
|
|
213550
|
-
/**
|
|
213551
|
-
* The sha256 of the Claude credential generation this runtime holds, or "" when
|
|
213552
|
-
* it holds none. The readiness guard compares it with the generation CMMD
|
|
213553
|
-
* applied. The restart proof must not use it; it uses the boot-exported hash.
|
|
213554
|
-
*
|
|
213555
|
-
* The boot preload exports FORGE_PERSONAL_CLAUDE_GENERATION_HASH, but only when
|
|
213556
|
-
* the marker already exists at boot. Activation in place writes the generation
|
|
213557
|
-
* file and touches the marker without setting any env, so an empty variable
|
|
213558
|
-
* falls back to that file, hashed the way the preload hashes it. CMMD puts the
|
|
213559
|
-
* file beside the marker in the guest home and names no path for it. A marker
|
|
213560
|
-
* with no generation file is a legacy runtime, and gets no hash here either.
|
|
213561
|
-
*/
|
|
213562
|
-
function personalClaudeGenerationHash(env = process.env) {
|
|
213563
|
-
const exported = bootExportedPersonalClaudeGenerationHash(env);
|
|
213564
|
-
if (exported) return exported;
|
|
213565
|
-
const marker = markerPath(env);
|
|
213566
|
-
if (!marker) return "";
|
|
213567
|
-
try {
|
|
213568
|
-
if (!(0, node_fs.existsSync)(marker)) return "";
|
|
213569
|
-
const generation = (0, node_fs.readFileSync)((0, node_path.join)((0, node_path.dirname)(marker), PERSONAL_CLAUDE_GENERATION_FILE_NAME), "utf8").trim();
|
|
213570
|
-
return generation ? (0, node_crypto.createHash)("sha256").update(generation).digest("hex") : "";
|
|
213571
|
-
} catch {
|
|
213572
|
-
return "";
|
|
213573
|
-
}
|
|
213574
|
-
}
|
|
213575
|
-
//#endregion
|
|
213576
213815
|
//#region src/provider/claudeCredentialContainment.ts
|
|
213577
213816
|
/**
|
|
213578
213817
|
* Containment for provider credentials inherited by the Claude Agent SDK child.
|
|
@@ -215656,128 +215895,6 @@ function createGitHubMcpServer(runBrokeredTool, threadId, settings) {
|
|
|
215656
215895
|
});
|
|
215657
215896
|
}
|
|
215658
215897
|
//#endregion
|
|
215659
|
-
//#region src/provider/providerAuthFailureCopy.ts
|
|
215660
|
-
/**
|
|
215661
|
-
* Rewrite provider auth failures into an action the user can actually take.
|
|
215662
|
-
*
|
|
215663
|
-
* The provider SDKs assume they are running under a human at a terminal, so
|
|
215664
|
-
* their auth errors name CLI verbs: Claude's is literally
|
|
215665
|
-
* `Not logged in · Please run /login`. On Forge Cloud that reaches a browser
|
|
215666
|
-
* user who has no terminal, no shell, and no way to run `/login` — the turn
|
|
215667
|
-
* dies in ~3 s naming an action that does not exist for them (observed live
|
|
215668
|
-
* 2026-08-05).
|
|
215669
|
-
*
|
|
215670
|
-
* CMMD already writes the right shape for the Codex egress path — "Connect
|
|
215671
|
-
* ChatGPT in Settings > Providers, then retry" — which names a destination the
|
|
215672
|
-
* user can click. This gives the provider-SDK failures the same treatment.
|
|
215673
|
-
*
|
|
215674
|
-
* Scope is deliberately narrow. Only messages that clearly identify a
|
|
215675
|
-
* *credential* problem are rewritten; everything else passes through verbatim,
|
|
215676
|
-
* because a rewritten unknown error loses detail an operator needs and risks
|
|
215677
|
-
* telling the user to reconnect an account that was never the problem.
|
|
215678
|
-
*/
|
|
215679
|
-
/**
|
|
215680
|
-
* Signatures of "you have no usable credential", matched case-insensitively.
|
|
215681
|
-
*
|
|
215682
|
-
* Kept as explicit patterns rather than a broad /auth/i so that genuine
|
|
215683
|
-
* mid-turn failures mentioning authorization (a tool hitting a 403 on some
|
|
215684
|
-
* unrelated API, say) are not misreported as "your subscription is
|
|
215685
|
-
* disconnected".
|
|
215686
|
-
*/
|
|
215687
|
-
const CREDENTIAL_FAILURE_PATTERNS = [
|
|
215688
|
-
/\bnot logged in\b/i,
|
|
215689
|
-
/\bplease run\s*\/login\b/i,
|
|
215690
|
-
/\brun\s*\/login\b/i,
|
|
215691
|
-
/\blogin required\b/i,
|
|
215692
|
-
/\bnot authenticated\b/i,
|
|
215693
|
-
/\bno credentials? found\b/i,
|
|
215694
|
-
/\binvalid api key\b/i,
|
|
215695
|
-
/\bauthentication_error\b/i
|
|
215696
|
-
];
|
|
215697
|
-
/**
|
|
215698
|
-
* Claude's words for a delivered credential whose refresh chain is dead.
|
|
215699
|
-
*
|
|
215700
|
-
* Deliberately NOT in CREDENTIAL_FAILURE_PATTERNS. On a runtime whose Claude
|
|
215701
|
-
* credential CMMD delivers, this is not "you are signed out" and reconnecting
|
|
215702
|
-
* in Settings is not the fix: CMMD's authority rotates the refresh token on
|
|
215703
|
-
* every refresh, the snapshot in the guest dies at the next rotation, and the
|
|
215704
|
-
* repair is a re-delivery the next send triggers (FOR-36425, CMMD-36441).
|
|
215705
|
-
* Anywhere else the credential is the user's own local login, so the CLI text
|
|
215706
|
-
* still passes through untouched.
|
|
215707
|
-
*/
|
|
215708
|
-
const DELIVERED_CREDENTIAL_EXPIRED_PATTERN = /\boauth session expired\b/i;
|
|
215709
|
-
const DELIVERED_CLAUDE_CREDENTIAL_EXPIRED_COPY = "The delivered Claude credential expired. CMMD refreshes it on the next send, so retry this turn.";
|
|
215710
|
-
/** True when the message is about a missing/unusable credential, not a tool failure. */
|
|
215711
|
-
function isProviderCredentialFailure(message) {
|
|
215712
|
-
return CREDENTIAL_FAILURE_PATTERNS.some((pattern) => pattern.test(message));
|
|
215713
|
-
}
|
|
215714
|
-
/**
|
|
215715
|
-
* Map a ProviderKind to the account name a user would recognise.
|
|
215716
|
-
*
|
|
215717
|
-
* NOTE the literal is `claudeAgent`, not `claude`. This read `"claude"` and so
|
|
215718
|
-
* never matched, silently degrading every Claude auth failure to the generic
|
|
215719
|
-
* fallback — "Forge Cloud has no **this provider** subscription connected."
|
|
215720
|
-
* Same provider-name drift class as the model-mapping fix (#2103/#2105).
|
|
215721
|
-
*
|
|
215722
|
-
* The names come from the shared PROVIDER_ACCOUNT_NAMES map rather than a local
|
|
215723
|
-
* switch: this file's copy was the ONLY correct provider→label mapping in the
|
|
215724
|
-
* codebase while four client call sites reimplemented it as binary ternaries.
|
|
215725
|
-
* One Record over ProviderKind means a new provider is a compile error in one
|
|
215726
|
-
* place instead of five sentences that read wrong in production.
|
|
215727
|
-
*
|
|
215728
|
-
* Providers that do not sell a personal subscription stay generic on purpose —
|
|
215729
|
-
* "Forge Cloud has no Ollama subscription connected" names something that does
|
|
215730
|
-
* not exist.
|
|
215731
|
-
*/
|
|
215732
|
-
function providerLabel(provider) {
|
|
215733
|
-
return supportsPersonalSubscription(provider) ? PROVIDER_ACCOUNT_NAMES[provider] : "this provider";
|
|
215734
|
-
}
|
|
215735
|
-
/**
|
|
215736
|
-
* Return the message to show for a failed turn.
|
|
215737
|
-
*
|
|
215738
|
-
* `surface` decides the destination: a cloud runtime has no terminal, so it is
|
|
215739
|
-
* pointed at Settings; a local/desktop runtime CAN run the CLI login, so its
|
|
215740
|
-
* copy still offers that as the concrete fix rather than sending someone to a
|
|
215741
|
-
* settings page that is not how they authenticate.
|
|
215742
|
-
*/
|
|
215743
|
-
function rewriteProviderAuthFailure(input) {
|
|
215744
|
-
const original = input.message ?? "";
|
|
215745
|
-
if (original.length === 0) return {
|
|
215746
|
-
message: original,
|
|
215747
|
-
rewritten: false
|
|
215748
|
-
};
|
|
215749
|
-
if (input.deliveredClaudeCredential === true && DELIVERED_CREDENTIAL_EXPIRED_PATTERN.test(original)) return {
|
|
215750
|
-
message: DELIVERED_CLAUDE_CREDENTIAL_EXPIRED_COPY,
|
|
215751
|
-
rewritten: true
|
|
215752
|
-
};
|
|
215753
|
-
if (!isProviderCredentialFailure(original)) return {
|
|
215754
|
-
message: original,
|
|
215755
|
-
rewritten: false
|
|
215756
|
-
};
|
|
215757
|
-
const who = providerLabel(input.provider);
|
|
215758
|
-
return {
|
|
215759
|
-
message: input.surface === "cloud" ? `Forge Cloud has no ${who} subscription connected for your account. Open Settings > Providers to connect one, then retry this turn.` : `This runtime is not signed in to ${who}. Connect it from Settings > Providers, then retry this turn.`,
|
|
215760
|
-
rewritten: true
|
|
215761
|
-
};
|
|
215762
|
-
}
|
|
215763
|
-
/**
|
|
215764
|
-
* Convenience for call sites that just want the string to show.
|
|
215765
|
-
*
|
|
215766
|
-
* Exists so adapters do not each re-derive the surface and re-handle the
|
|
215767
|
-
* undefined case inline — that inlining is what pushed
|
|
215768
|
-
* ClaudeAdapter.handleResultMessage over the cyclomatic gate. Returns
|
|
215769
|
-
* `undefined` unchanged so "no error" stays distinguishable from "empty error".
|
|
215770
|
-
*/
|
|
215771
|
-
function providerAuthFailureMessage(message, provider, env = process.env) {
|
|
215772
|
-
if (message === void 0) return void 0;
|
|
215773
|
-
return rewriteProviderAuthFailure({
|
|
215774
|
-
message,
|
|
215775
|
-
provider,
|
|
215776
|
-
surface: env.FORGE_CMMD_RUNTIME_MODE === "true" ? "cloud" : "local",
|
|
215777
|
-
deliveredClaudeCredential: provider === "claudeAgent" && personalClaudeInVmEnabled(env)
|
|
215778
|
-
}).message;
|
|
215779
|
-
}
|
|
215780
|
-
//#endregion
|
|
215781
215898
|
//#region src/provider/missingWorkspaceCopy.ts
|
|
215782
215899
|
/**
|
|
215783
215900
|
* Refuse a turn whose checkout folder is gone, and say so.
|
|
@@ -234138,6 +234255,8 @@ const CheckpointDiffQueryLive = require_Schema$1.effect(CheckpointDiffQuery, mak
|
|
|
234138
234255
|
* @module CheckpointStoreLive
|
|
234139
234256
|
*/
|
|
234140
234257
|
const CHECKPOINT_PATH_OUTPUT_MAX_BYTES = 16 * 1024 * 1024;
|
|
234258
|
+
const CheckpointCaptureTimeoutConfig = require_Config.number("FORGE_CHECKPOINT_CAPTURE_TIMEOUT_MS").pipe(require_Config.withDefault(6e4));
|
|
234259
|
+
const EFFECT_TIMER_MAX_MS = 2147483647;
|
|
234141
234260
|
function parseNullSeparatedPaths(output) {
|
|
234142
234261
|
return output.split("\0").filter((entry) => entry.length > 0);
|
|
234143
234262
|
}
|
|
@@ -234145,7 +234264,7 @@ const makeCheckpointStore = require_Schema$1.gen(function* () {
|
|
|
234145
234264
|
const fs = yield* require_Path.FileSystem;
|
|
234146
234265
|
const path = yield* require_Path.Path;
|
|
234147
234266
|
const git = yield* GitCore;
|
|
234148
|
-
const resolveHeadCommit = (cwd) => git.execute({
|
|
234267
|
+
const resolveHeadCommit = (cwd, timeoutMs) => git.execute({
|
|
234149
234268
|
operation: "CheckpointStore.resolveHeadCommit",
|
|
234150
234269
|
cwd,
|
|
234151
234270
|
args: [
|
|
@@ -234154,7 +234273,8 @@ const makeCheckpointStore = require_Schema$1.gen(function* () {
|
|
|
234154
234273
|
"--quiet",
|
|
234155
234274
|
"HEAD^{commit}"
|
|
234156
234275
|
],
|
|
234157
|
-
allowNonZeroExit: true
|
|
234276
|
+
allowNonZeroExit: true,
|
|
234277
|
+
...timeoutMs !== void 0 ? { timeoutMs } : {}
|
|
234158
234278
|
}).pipe(require_Schema$1.map((result) => {
|
|
234159
234279
|
if (result.code !== 0) return null;
|
|
234160
234280
|
const commit = result.stdout.trim();
|
|
@@ -234193,7 +234313,9 @@ const makeCheckpointStore = require_Schema$1.gen(function* () {
|
|
|
234193
234313
|
}).pipe(require_Schema$1.map((result) => result.code === 0 && result.stdout.trim() === "true"), require_Schema$1.catch_(() => require_Schema$1.succeed(false)));
|
|
234194
234314
|
const captureCheckpoint = require_Schema$1.fn("captureCheckpoint")(function* (input) {
|
|
234195
234315
|
const operation = "CheckpointStore.captureCheckpoint";
|
|
234196
|
-
const
|
|
234316
|
+
const captureTimeoutMs = yield* CheckpointCaptureTimeoutConfig.asEffect().pipe(require_Schema$1.orDie);
|
|
234317
|
+
if (!Number.isFinite(captureTimeoutMs) || captureTimeoutMs <= 0 || captureTimeoutMs > EFFECT_TIMER_MAX_MS) return yield* require_Schema$1.die(/* @__PURE__ */ new Error(`FORGE_CHECKPOINT_CAPTURE_TIMEOUT_MS must be a finite number greater than zero and at most ${EFFECT_TIMER_MAX_MS}, got ${captureTimeoutMs}.`));
|
|
234318
|
+
const headCommit = yield* resolveHeadCommit(input.cwd, captureTimeoutMs);
|
|
234197
234319
|
const [trackedPathResult, untrackedPathResult] = yield* require_Schema$1.all([git.execute({
|
|
234198
234320
|
operation,
|
|
234199
234321
|
cwd: input.cwd,
|
|
@@ -234210,7 +234332,8 @@ const makeCheckpointStore = require_Schema$1.gen(function* () {
|
|
|
234210
234332
|
"-z",
|
|
234211
234333
|
"--"
|
|
234212
234334
|
],
|
|
234213
|
-
maxOutputBytes: CHECKPOINT_PATH_OUTPUT_MAX_BYTES
|
|
234335
|
+
maxOutputBytes: CHECKPOINT_PATH_OUTPUT_MAX_BYTES,
|
|
234336
|
+
timeoutMs: captureTimeoutMs
|
|
234214
234337
|
}), git.execute({
|
|
234215
234338
|
operation,
|
|
234216
234339
|
cwd: input.cwd,
|
|
@@ -234221,7 +234344,8 @@ const makeCheckpointStore = require_Schema$1.gen(function* () {
|
|
|
234221
234344
|
"-z",
|
|
234222
234345
|
"--"
|
|
234223
234346
|
],
|
|
234224
|
-
maxOutputBytes: CHECKPOINT_PATH_OUTPUT_MAX_BYTES
|
|
234347
|
+
maxOutputBytes: CHECKPOINT_PATH_OUTPUT_MAX_BYTES,
|
|
234348
|
+
timeoutMs: captureTimeoutMs
|
|
234225
234349
|
})], { concurrency: 2 });
|
|
234226
234350
|
const changedPaths = [...new Set([...parseNullSeparatedPaths(trackedPathResult.stdout), ...parseNullSeparatedPaths(untrackedPathResult.stdout)])];
|
|
234227
234351
|
if (headCommit && changedPaths.length === 0) {
|
|
@@ -234232,7 +234356,8 @@ const makeCheckpointStore = require_Schema$1.gen(function* () {
|
|
|
234232
234356
|
"update-ref",
|
|
234233
234357
|
input.checkpointRef,
|
|
234234
234358
|
headCommit
|
|
234235
|
-
]
|
|
234359
|
+
],
|
|
234360
|
+
timeoutMs: captureTimeoutMs
|
|
234236
234361
|
});
|
|
234237
234362
|
return;
|
|
234238
234363
|
}
|
|
@@ -234250,13 +234375,15 @@ const makeCheckpointStore = require_Schema$1.gen(function* () {
|
|
|
234250
234375
|
operation,
|
|
234251
234376
|
cwd: input.cwd,
|
|
234252
234377
|
args: ["read-tree", headCommit],
|
|
234253
|
-
env: commitEnv
|
|
234378
|
+
env: commitEnv,
|
|
234379
|
+
timeoutMs: captureTimeoutMs
|
|
234254
234380
|
});
|
|
234255
234381
|
else yield* git.execute({
|
|
234256
234382
|
operation,
|
|
234257
234383
|
cwd: input.cwd,
|
|
234258
234384
|
args: ["read-tree", "--empty"],
|
|
234259
|
-
env: commitEnv
|
|
234385
|
+
env: commitEnv,
|
|
234386
|
+
timeoutMs: captureTimeoutMs
|
|
234260
234387
|
});
|
|
234261
234388
|
if (changedPaths.length > 0) yield* git.execute({
|
|
234262
234389
|
operation,
|
|
@@ -234269,13 +234396,15 @@ const makeCheckpointStore = require_Schema$1.gen(function* () {
|
|
|
234269
234396
|
"--pathspec-file-nul"
|
|
234270
234397
|
],
|
|
234271
234398
|
stdin: changedPaths.map((changedPath) => `${changedPath}\0`).join(""),
|
|
234272
|
-
env: commitEnv
|
|
234399
|
+
env: commitEnv,
|
|
234400
|
+
timeoutMs: captureTimeoutMs
|
|
234273
234401
|
});
|
|
234274
234402
|
const treeOid = (yield* git.execute({
|
|
234275
234403
|
operation,
|
|
234276
234404
|
cwd: input.cwd,
|
|
234277
234405
|
args: ["write-tree"],
|
|
234278
|
-
env: commitEnv
|
|
234406
|
+
env: commitEnv,
|
|
234407
|
+
timeoutMs: captureTimeoutMs
|
|
234279
234408
|
})).stdout.trim();
|
|
234280
234409
|
if (treeOid.length === 0) return yield* new GitCommandError({
|
|
234281
234410
|
operation,
|
|
@@ -234293,7 +234422,8 @@ const makeCheckpointStore = require_Schema$1.gen(function* () {
|
|
|
234293
234422
|
"-m",
|
|
234294
234423
|
message
|
|
234295
234424
|
],
|
|
234296
|
-
env: commitEnv
|
|
234425
|
+
env: commitEnv,
|
|
234426
|
+
timeoutMs: captureTimeoutMs
|
|
234297
234427
|
})).stdout.trim();
|
|
234298
234428
|
if (commitOid.length === 0) return yield* new GitCommandError({
|
|
234299
234429
|
operation,
|
|
@@ -234308,7 +234438,8 @@ const makeCheckpointStore = require_Schema$1.gen(function* () {
|
|
|
234308
234438
|
"update-ref",
|
|
234309
234439
|
input.checkpointRef,
|
|
234310
234440
|
commitOid
|
|
234311
|
-
]
|
|
234441
|
+
],
|
|
234442
|
+
timeoutMs: captureTimeoutMs
|
|
234312
234443
|
});
|
|
234313
234444
|
}), (tempDir) => fs.remove(tempDir, { recursive: true })).pipe(require_Schema$1.catchTags({ PlatformError: (error) => require_Schema$1.fail(new CheckpointInvariantError({
|
|
234314
234445
|
operation: "CheckpointStore.captureCheckpoint",
|
|
@@ -292201,7 +292332,7 @@ const make$8 = require_Schema$1.gen(function* () {
|
|
|
292201
292332
|
summary: "Agent turn blocked",
|
|
292202
292333
|
detail: "Forge runtime is updating after the current turn. New agent turns are paused until the runtime finishes draining.",
|
|
292203
292334
|
turnId: null,
|
|
292204
|
-
createdAt:
|
|
292335
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
292205
292336
|
});
|
|
292206
292337
|
return;
|
|
292207
292338
|
}
|
|
@@ -292436,7 +292567,7 @@ const make$8 = require_Schema$1.gen(function* () {
|
|
|
292436
292567
|
summary: "Agent turn blocked",
|
|
292437
292568
|
detail: workspaceError,
|
|
292438
292569
|
turnId: null,
|
|
292439
|
-
createdAt:
|
|
292570
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
292440
292571
|
});
|
|
292441
292572
|
return;
|
|
292442
292573
|
}
|
|
@@ -293528,7 +293659,10 @@ const make$7 = require_Schema$1.gen(function* () {
|
|
|
293528
293659
|
tone: "error",
|
|
293529
293660
|
kind: "checkpoint.capture.failed",
|
|
293530
293661
|
summary: "Checkpoint capture failed",
|
|
293531
|
-
payload: {
|
|
293662
|
+
payload: {
|
|
293663
|
+
detail: input.detail,
|
|
293664
|
+
...input.blocksTurnStart ? { blocksTurnStart: true } : {}
|
|
293665
|
+
},
|
|
293532
293666
|
turnId: input.turnId,
|
|
293533
293667
|
createdAt: input.createdAt
|
|
293534
293668
|
},
|
|
@@ -293814,7 +293948,13 @@ const make$7 = require_Schema$1.gen(function* () {
|
|
|
293814
293948
|
yield* checkpointStore.captureCheckpoint({
|
|
293815
293949
|
cwd: checkpointCwd,
|
|
293816
293950
|
checkpointRef: baselineCheckpointRef
|
|
293817
|
-
})
|
|
293951
|
+
}).pipe(require_Schema$1.catch_((error) => appendCaptureFailureActivity({
|
|
293952
|
+
threadId,
|
|
293953
|
+
turnId: null,
|
|
293954
|
+
detail: error.message,
|
|
293955
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
293956
|
+
blocksTurnStart: true
|
|
293957
|
+
}).pipe(require_Schema$1.catch_(() => require_Schema$1.void_))));
|
|
293818
293958
|
yield* receiptBus.publish({
|
|
293819
293959
|
type: "checkpoint.baseline.captured",
|
|
293820
293960
|
threadId,
|
|
@@ -298206,7 +298346,7 @@ function resolveBuildCommitFromEnv(env) {
|
|
|
298206
298346
|
* environment descriptor down instead of reporting an honest "unknown".
|
|
298207
298347
|
*/
|
|
298208
298348
|
function readBakedBuildCommit() {
|
|
298209
|
-
return "
|
|
298349
|
+
return "589c5f6a52f5cd82c598399da0ece13acd43d50d";
|
|
298210
298350
|
}
|
|
298211
298351
|
async function resolveServerBuildCommit(input) {
|
|
298212
298352
|
if (isFullCommitSha(input.baked)) return input.baked;
|