@cmmd-center/forge 0.13.14 → 0.13.16
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 +655 -275
- package/dist/bin.mjs +654 -275
- package/dist/client/assets/{DiffPanel-P3t5Fq1q.js → DiffPanel-DI782ZMI.js} +3 -3
- package/dist/client/assets/{DiffPanel.logic-BXQ1C0-e.js → DiffPanel.logic-DtVm1IjE.js} +2 -2
- package/dist/client/assets/DiffPanelShell-IB1GWoYr.js +2533 -0
- package/dist/client/assets/{DiffWorkerPoolProvider-3_hkcEDq.js → DiffWorkerPoolProvider-DDMgJC0H.js} +9 -9
- package/dist/client/assets/PullRequestCodePanel-DPwb2trb.js +5 -0
- package/dist/client/assets/{Virtualizer-DCt36RGD.js → Virtualizer-CU-TBcmx.js} +2 -2
- package/dist/client/assets/index-B9000khV.css +1 -0
- package/dist/client/assets/index-CB-vPC0y.js +153 -0
- package/dist/client/index.html +5 -5
- package/dist/forge-build.json +1 -1
- package/dist/runtimeBootstrap.cjs +1 -1
- package/dist/runtimeBootstrap.mjs +1 -1
- package/dist/{runtimeControlAuthority-BkVB0uAA.cjs → runtimeControlAuthority-DCitZFTk.cjs} +3 -1
- package/dist/{runtimeControlAuthority-E_kdeD_P.mjs → runtimeControlAuthority-DpRIoWqP.mjs} +3 -1
- package/package.json +1 -1
- package/dist/client/assets/DiffPanelShell-3EpWEr7p.js +0 -2532
- package/dist/client/assets/PullRequestCodePanel-B2T6MPcE.js +0 -5
- package/dist/client/assets/index-C3pC5t1K.css +0 -1
- package/dist/client/assets/index-DvwXD11B.js +0 -154
package/dist/bin.cjs
CHANGED
|
@@ -12,7 +12,7 @@ const require_Cache = require("./Cache-BmGc_2BZ.cjs");
|
|
|
12
12
|
const require_SqlError = require("./SqlError-g4pLzNWR.cjs");
|
|
13
13
|
const require_Mime = require("./Mime-Bilnh8zE.cjs");
|
|
14
14
|
const require_esm = require("./esm-BZhXwX5p.cjs");
|
|
15
|
-
const require_runtimeControlAuthority = require("./runtimeControlAuthority-
|
|
15
|
+
const require_runtimeControlAuthority = require("./runtimeControlAuthority-DCitZFTk.cjs");
|
|
16
16
|
const require_PTY = require("./PTY-B4ZctbwQ.cjs");
|
|
17
17
|
let node_child_process = require("node:child_process");
|
|
18
18
|
node_child_process = require_chunk.__toESM(node_child_process);
|
|
@@ -27208,6 +27208,44 @@ function encodeCmmdRuntimeWorktreeLaunchActivityPayload(kind, payload) {
|
|
|
27208
27208
|
function isCmmdRuntimeWorktreeLaunchActivityKind(kind) {
|
|
27209
27209
|
return WORKTREE_LAUNCH_ACTIVITY_KINDS.has(kind);
|
|
27210
27210
|
}
|
|
27211
|
+
/**
|
|
27212
|
+
* A plan update rides the `tool_call` event kind because the forge-context
|
|
27213
|
+
* contract has no plan event kind, the same trade the launch rows make. The
|
|
27214
|
+
* steps are carried verbatim under a versioned marker so a cloud client can
|
|
27215
|
+
* rebuild the composer plan banner from the durable replica. (#3319)
|
|
27216
|
+
*/
|
|
27217
|
+
const CMMD_RUNTIME_PLAN_ACTIVITY_KIND = "turn.plan.updated";
|
|
27218
|
+
function encodeCmmdRuntimePlanActivityPayload(kind, payload) {
|
|
27219
|
+
return {
|
|
27220
|
+
...isRecord$23(payload) ? payload : { sourcePayload: payload },
|
|
27221
|
+
forgePlanActivity: {
|
|
27222
|
+
schemaVersion: 1,
|
|
27223
|
+
source: "native",
|
|
27224
|
+
kind
|
|
27225
|
+
}
|
|
27226
|
+
};
|
|
27227
|
+
}
|
|
27228
|
+
function decodeCmmdRuntimePlanActivity(payload) {
|
|
27229
|
+
if (!isRecord$23(payload)) return null;
|
|
27230
|
+
const metadata = payload["forgePlanActivity"];
|
|
27231
|
+
if (!isRecord$23(metadata)) return null;
|
|
27232
|
+
if (metadata["schemaVersion"] !== 1 || metadata["source"] !== "native" || metadata["kind"] !== "turn.plan.updated") return null;
|
|
27233
|
+
const rawPlan = payload["plan"];
|
|
27234
|
+
return {
|
|
27235
|
+
kind: CMMD_RUNTIME_PLAN_ACTIVITY_KIND,
|
|
27236
|
+
plan: Array.isArray(rawPlan) ? rawPlan.flatMap((entry) => {
|
|
27237
|
+
if (!isRecord$23(entry)) return [];
|
|
27238
|
+
const step = entry["step"];
|
|
27239
|
+
const status = entry["status"];
|
|
27240
|
+
if (typeof step !== "string" || step.trim().length === 0) return [];
|
|
27241
|
+
if (status !== "pending" && status !== "inProgress" && status !== "completed") return [];
|
|
27242
|
+
return [{
|
|
27243
|
+
step,
|
|
27244
|
+
status
|
|
27245
|
+
}];
|
|
27246
|
+
}) : []
|
|
27247
|
+
};
|
|
27248
|
+
}
|
|
27211
27249
|
//#endregion
|
|
27212
27250
|
//#region ../../packages/contracts/src/cmmdProjectPatch.ts
|
|
27213
27251
|
const CMMD_PROJECT_PATCH_FIELDS = {
|
|
@@ -66380,7 +66418,7 @@ function normalizeNumberish(value) {
|
|
|
66380
66418
|
}
|
|
66381
66419
|
//#endregion
|
|
66382
66420
|
//#region package.json
|
|
66383
|
-
var version$1 = "0.13.
|
|
66421
|
+
var version$1 = "0.13.16";
|
|
66384
66422
|
//#endregion
|
|
66385
66423
|
//#region src/sentry.ts
|
|
66386
66424
|
const SERVER_APP_NAME = "forge-server";
|
|
@@ -67260,6 +67298,121 @@ function verifyCmmdForgeCloudOwnerAssertion(token, publicKeyPem, expectedKeyId,
|
|
|
67260
67298
|
};
|
|
67261
67299
|
}
|
|
67262
67300
|
//#endregion
|
|
67301
|
+
//#region src/observability/Attributes.ts
|
|
67302
|
+
function isPlainObject$1(value) {
|
|
67303
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
67304
|
+
}
|
|
67305
|
+
function markSeen(value, seen) {
|
|
67306
|
+
if (seen.has(value)) return true;
|
|
67307
|
+
seen.add(value);
|
|
67308
|
+
return false;
|
|
67309
|
+
}
|
|
67310
|
+
function normalizeJsonValue(value, seen = /* @__PURE__ */ new WeakSet()) {
|
|
67311
|
+
if (value === null || value === void 0 || typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value ?? null;
|
|
67312
|
+
if (typeof value === "bigint") return value.toString();
|
|
67313
|
+
if (value instanceof Date) return Number.isNaN(value.getTime()) ? "Invalid Date" : value.toISOString();
|
|
67314
|
+
if (value instanceof Error) return {
|
|
67315
|
+
name: value.name,
|
|
67316
|
+
message: value.message,
|
|
67317
|
+
...value.stack ? { stack: value.stack } : {}
|
|
67318
|
+
};
|
|
67319
|
+
if (Array.isArray(value)) {
|
|
67320
|
+
if (markSeen(value, seen)) return "[Circular]";
|
|
67321
|
+
return value.map((entry) => normalizeJsonValue(entry, seen));
|
|
67322
|
+
}
|
|
67323
|
+
if (value instanceof Map) {
|
|
67324
|
+
if (markSeen(value, seen)) return "[Circular]";
|
|
67325
|
+
return Object.fromEntries(Array.from(value.entries(), ([key, entryValue]) => [String(key), normalizeJsonValue(entryValue, seen)]));
|
|
67326
|
+
}
|
|
67327
|
+
if (value instanceof Set) {
|
|
67328
|
+
if (markSeen(value, seen)) return "[Circular]";
|
|
67329
|
+
return Array.from(value.values(), (entry) => normalizeJsonValue(entry, seen));
|
|
67330
|
+
}
|
|
67331
|
+
if (!isPlainObject$1(value)) return String(value);
|
|
67332
|
+
if (markSeen(value, seen)) return "[Circular]";
|
|
67333
|
+
return Object.fromEntries(Object.entries(value).map(([key, entryValue]) => [key, normalizeJsonValue(entryValue, seen)]));
|
|
67334
|
+
}
|
|
67335
|
+
function compactTraceAttributes(attributes) {
|
|
67336
|
+
return Object.fromEntries(Object.entries(attributes).filter(([, value]) => value !== void 0).map(([key, value]) => [key, normalizeJsonValue(value)]));
|
|
67337
|
+
}
|
|
67338
|
+
function compactMetricAttributes(attributes) {
|
|
67339
|
+
return Object.fromEntries(Object.entries(attributes).flatMap(([key, value]) => {
|
|
67340
|
+
if (value === void 0 || value === null) return [];
|
|
67341
|
+
if (typeof value === "string") return [[key, value]];
|
|
67342
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") return [[key, String(value)]];
|
|
67343
|
+
return [];
|
|
67344
|
+
}));
|
|
67345
|
+
}
|
|
67346
|
+
function outcomeFromExit(exit) {
|
|
67347
|
+
if (require_Schema$1.isSuccess(exit)) return "success";
|
|
67348
|
+
return require_Schema$1.hasInterruptsOnly(exit.cause) ? "interrupt" : "failure";
|
|
67349
|
+
}
|
|
67350
|
+
function normalizeModelMetricLabel(model) {
|
|
67351
|
+
const normalized = model?.trim().toLowerCase();
|
|
67352
|
+
if (!normalized) return;
|
|
67353
|
+
if (normalized.includes("gpt")) return "gpt";
|
|
67354
|
+
if (normalized.includes("claude")) return "claude";
|
|
67355
|
+
if (normalized.includes("gemini")) return "gemini";
|
|
67356
|
+
return "other";
|
|
67357
|
+
}
|
|
67358
|
+
//#endregion
|
|
67359
|
+
//#region src/observability/Metrics.ts
|
|
67360
|
+
const rpcRequestsTotal = require_Schema$1.counter("t3_rpc_requests_total", { description: "Total RPC requests handled by the websocket RPC server." });
|
|
67361
|
+
const rpcRequestDuration = require_Schema$1.timer("t3_rpc_request_duration", { description: "RPC request handling duration." });
|
|
67362
|
+
const orchestrationCommandsTotal = require_Schema$1.counter("t3_orchestration_commands_total", { description: "Total orchestration commands dispatched." });
|
|
67363
|
+
const orchestrationCommandDuration = require_Schema$1.timer("t3_orchestration_command_duration", { description: "Orchestration command dispatch duration." });
|
|
67364
|
+
const orchestrationCommandAckDuration = require_Schema$1.timer("t3_orchestration_command_ack_duration", { description: "Time from orchestration command dispatch to the first committed domain event emitted for that command." });
|
|
67365
|
+
const orchestrationEventsProcessedTotal = require_Schema$1.counter("t3_orchestration_events_processed_total", { description: "Total orchestration intent events processed by runtime reactors." });
|
|
67366
|
+
const providerSessionsTotal = require_Schema$1.counter("t3_provider_sessions_total", { description: "Total provider session lifecycle operations." });
|
|
67367
|
+
const providerTurnsTotal = require_Schema$1.counter("t3_provider_turns_total", { description: "Total provider turn lifecycle operations." });
|
|
67368
|
+
const providerTurnDuration = require_Schema$1.timer("t3_provider_turn_duration", { description: "Provider turn request duration." });
|
|
67369
|
+
const providerRuntimeEventsTotal = require_Schema$1.counter("t3_provider_runtime_events_total", { description: "Total canonical provider runtime events processed." });
|
|
67370
|
+
const gitCommandsTotal = require_Schema$1.counter("t3_git_commands_total", { description: "Total git commands executed by the server runtime." });
|
|
67371
|
+
const gitCommandDuration = require_Schema$1.timer("t3_git_command_duration", { description: "Git command execution duration." });
|
|
67372
|
+
const terminalSessionsTotal = require_Schema$1.counter("t3_terminal_sessions_total", { description: "Total terminal sessions started." });
|
|
67373
|
+
const browserSessionsReapedTotal = require_Schema$1.counter("browser_sessions_reaped_total", { description: "Browser sessions and Chromium processes reclaimed by the orphan reaper, by reason (orphan | ttl | stale_profile)." });
|
|
67374
|
+
const terminalRestartsTotal = require_Schema$1.counter("t3_terminal_restarts_total", { description: "Total terminal restart requests handled." });
|
|
67375
|
+
const runtimeReplicationOutboxDepth = require_Schema$1.gauge("t3_runtime_replication_outbox_depth", { description: "Current runtime replication outbox items by durable state." });
|
|
67376
|
+
const runtimeReplicationOutboxOldestEventAge = require_Schema$1.gauge("t3_runtime_replication_outbox_oldest_event_age_seconds", { description: "Age in seconds of the oldest undelivered runtime replication payload." });
|
|
67377
|
+
const runtimeReplicationPublicationAttemptsTotal = require_Schema$1.counter("t3_runtime_replication_publication_attempts_total", { description: "Total canonical runtime replication publication attempts." });
|
|
67378
|
+
const runtimeReplicationPublicationRetriesTotal = require_Schema$1.counter("t3_runtime_replication_publication_retries_total", { description: "Total runtime replication retries scheduled after recoverable failures." });
|
|
67379
|
+
const runtimeReplicationPublicationLatency = require_Schema$1.timer("t3_runtime_replication_publication_latency", { description: "Time from durable enqueue to canonical CMMD acknowledgement." });
|
|
67380
|
+
const cmmdCredentialRefreshTotal = require_Schema$1.counter("t3_cmmd_credential_refresh_total", { description: "CMMD JWT refresh attempts for a Forge session, by rung (self-refresh | grant-redemption) and outcome (attempted | succeeded)." });
|
|
67381
|
+
const cmmdRotationFenceAppliedTotal = require_Schema$1.counter("t3_cmmd_rotation_fence_applied_total", { description: "Sessions Forge refused to rotate CMMD credentials for, because the rotation fence applied." });
|
|
67382
|
+
const cmmdCredentialRowDeletedTotal = require_Schema$1.counter("t3_cmmd_credential_row_deleted_total", { description: "command_access_tokens rows actually deleted by clearUnrecoverableCmmdAuthForSession, by reason." });
|
|
67383
|
+
const metricAttributes = (attributes) => Object.entries(compactMetricAttributes(attributes));
|
|
67384
|
+
const increment = (metric, attributes, amount = 1) => require_Schema$1.update(require_Schema$1.withAttributes(metric, metricAttributes(attributes)), amount);
|
|
67385
|
+
const withMetricsImpl = (effect, options) => require_Schema$1.gen(function* () {
|
|
67386
|
+
const startedAt = Date.now();
|
|
67387
|
+
const exit$2 = yield* require_Schema$1.exit(effect);
|
|
67388
|
+
const duration = require_Schema$1.millis(Math.max(0, Date.now() - startedAt));
|
|
67389
|
+
const baseAttributes = typeof options.attributes === "function" ? options.attributes() : options.attributes ?? {};
|
|
67390
|
+
if (options.timer) yield* require_Schema$1.update(require_Schema$1.withAttributes(options.timer, metricAttributes(baseAttributes)), duration);
|
|
67391
|
+
if (options.counter) {
|
|
67392
|
+
const outcome = outcomeFromExit(exit$2);
|
|
67393
|
+
yield* require_Schema$1.update(require_Schema$1.withAttributes(options.counter, metricAttributes({
|
|
67394
|
+
...baseAttributes,
|
|
67395
|
+
outcome,
|
|
67396
|
+
...options.outcomeAttributes ? options.outcomeAttributes(outcome) : {}
|
|
67397
|
+
})), 1);
|
|
67398
|
+
}
|
|
67399
|
+
if (require_Schema$1.isSuccess(exit$2)) return exit$2.value;
|
|
67400
|
+
return yield* require_Schema$1.failCause(exit$2.cause);
|
|
67401
|
+
});
|
|
67402
|
+
const withMetrics = require_Schema$1.dual(2, withMetricsImpl);
|
|
67403
|
+
const providerMetricAttributes = (provider, extra) => compactMetricAttributes({
|
|
67404
|
+
provider,
|
|
67405
|
+
...extra
|
|
67406
|
+
});
|
|
67407
|
+
const providerTurnMetricAttributes = (input) => {
|
|
67408
|
+
const modelFamily = normalizeModelMetricLabel(input.model);
|
|
67409
|
+
return compactMetricAttributes({
|
|
67410
|
+
provider: input.provider,
|
|
67411
|
+
...modelFamily ? { modelFamily } : {},
|
|
67412
|
+
...input.extra
|
|
67413
|
+
});
|
|
67414
|
+
};
|
|
67415
|
+
//#endregion
|
|
67263
67416
|
//#region src/persistence/Errors.ts
|
|
67264
67417
|
var PersistenceSqlError = class extends require_Schema$1.TaggedErrorClass()("PersistenceSqlError", {
|
|
67265
67418
|
operation: require_Schema$1.String,
|
|
@@ -67950,8 +68103,14 @@ const scheduleExpiredForgeCloudOwnerCredentialMaintenance = require_Schema$1.sle
|
|
|
67950
68103
|
*
|
|
67951
68104
|
* Clearing every active owner row unconditionally (the pre-CMMD-1871 behaviour)
|
|
67952
68105
|
* turned a single expired tab into a sign-out on every browser and device.
|
|
68106
|
+
*
|
|
68107
|
+
* Destroys a refresh token good for months, so every call is logged with a
|
|
68108
|
+
* `reason` naming the caller's own decision (never the credential itself) and
|
|
68109
|
+
* the actual row count deleted, at info level so it shows up without raising
|
|
68110
|
+
* the server's log level. `reason` is optional only so a caller that has not
|
|
68111
|
+
* been updated yet still compiles; every current caller passes one.
|
|
67953
68112
|
*/
|
|
67954
|
-
const clearUnrecoverableCmmdAuthForSession = (sessionId) => require_Schema$1.gen(function* () {
|
|
68113
|
+
const clearUnrecoverableCmmdAuthForSession = (sessionId, reason) => require_Schema$1.gen(function* () {
|
|
67955
68114
|
const sql = yield* require_SqlError.SqlClient;
|
|
67956
68115
|
const rows = yield* sql`
|
|
67957
68116
|
DELETE FROM command_access_tokens
|
|
@@ -67976,6 +68135,14 @@ const clearUnrecoverableCmmdAuthForSession = (sessionId) => require_Schema$1.gen
|
|
|
67976
68135
|
`.pipe(require_Schema$1.mapError(toPersistenceSqlError("CommandAccessTokenStore.clearUnrecoverableCmmdAuth:query")));
|
|
67977
68136
|
forgetCommandAccessTokenCachesForSession(sessionId);
|
|
67978
68137
|
for (const row of rows) forgetCommandAccessTokenCachesForSession(row.sessionId);
|
|
68138
|
+
if (rows.length > 0) {
|
|
68139
|
+
yield* require_Schema$1.logInfo("CMMD credential row deleted.", {
|
|
68140
|
+
sessionId,
|
|
68141
|
+
reason: reason ?? "unspecified",
|
|
68142
|
+
rowsDeleted: rows.length
|
|
68143
|
+
});
|
|
68144
|
+
yield* require_Schema$1.update(require_Schema$1.withAttributes(cmmdCredentialRowDeletedTotal, metricAttributes({ reason: reason ?? "unspecified" })), rows.length);
|
|
68145
|
+
}
|
|
67979
68146
|
});
|
|
67980
68147
|
/**
|
|
67981
68148
|
* Retire refresh credentials copied into historical desktop bearer sessions.
|
|
@@ -68031,6 +68198,23 @@ const isDesktopBearerAuthSession = (sessionId) => require_Schema$1.gen(function*
|
|
|
68031
68198
|
`.pipe(require_Schema$1.mapError(toPersistenceSqlError("CommandAccessTokenStore.isDesktopBearerSession:query")));
|
|
68032
68199
|
return rows[0]?.method === "bearer-session-token" && rows[0].clientDeviceType === "desktop";
|
|
68033
68200
|
});
|
|
68201
|
+
/**
|
|
68202
|
+
* The device type a session's bearer bootstrap declared, for log lines only.
|
|
68203
|
+
*
|
|
68204
|
+
* Mirrors `isDesktopBearerAuthSession`'s read but returns the raw column
|
|
68205
|
+
* instead of collapsing it into a rotation verdict — a log line wants to say
|
|
68206
|
+
* what made the request, not whether Forge may rotate for it. Never fails:
|
|
68207
|
+
* an unreadable or missing row logs as `"unknown"` rather than losing the
|
|
68208
|
+
* decision-point log line it is attached to.
|
|
68209
|
+
*/
|
|
68210
|
+
const readClientDeviceTypeForSession = (sessionId) => require_Schema$1.gen(function* () {
|
|
68211
|
+
return (yield* (yield* require_SqlError.SqlClient)`
|
|
68212
|
+
SELECT client_device_type AS "clientDeviceType"
|
|
68213
|
+
FROM auth_sessions
|
|
68214
|
+
WHERE session_id = ${sessionId}
|
|
68215
|
+
LIMIT 1
|
|
68216
|
+
`.pipe(require_Schema$1.mapError(toPersistenceSqlError("CommandAccessTokenStore.readClientDeviceType:query"))))[0]?.clientDeviceType ?? "unknown";
|
|
68217
|
+
}).pipe(require_Schema$1.orElseSucceed(() => "unknown"));
|
|
68034
68218
|
//#endregion
|
|
68035
68219
|
//#region src/auth/http/oauthCookies.ts
|
|
68036
68220
|
const OAUTH_STATE_COOKIE = "forge_oauth_state";
|
|
@@ -68233,9 +68417,21 @@ const authLogoutRouteLayer = add$1("POST", "/api/auth/logout", require_Schema$1.
|
|
|
68233
68417
|
onSuccess: (session) => session.sessionId
|
|
68234
68418
|
}));
|
|
68235
68419
|
if (sessionId) {
|
|
68420
|
+
const deviceType = yield* readClientDeviceTypeForSession(sessionId);
|
|
68421
|
+
yield* require_Schema$1.logInfo("Auth logout.", {
|
|
68422
|
+
sessionId,
|
|
68423
|
+
deviceType,
|
|
68424
|
+
outcome: "session-cleared",
|
|
68425
|
+
reason: cloudShell ? "forge-cloud-shell-session" : "local-session"
|
|
68426
|
+
});
|
|
68236
68427
|
if (!cloudShell) yield* sessions.revoke(sessionId).pipe(require_Schema$1.ignore({ log: false }));
|
|
68237
68428
|
yield* clearCommandAccessTokenForSession(sessionId).pipe(require_Schema$1.ignore({ log: false }));
|
|
68238
|
-
}
|
|
68429
|
+
} else yield* require_Schema$1.logInfo("Auth logout.", {
|
|
68430
|
+
sessionId: null,
|
|
68431
|
+
deviceType: "unknown",
|
|
68432
|
+
outcome: "no-op",
|
|
68433
|
+
reason: "no authenticated session presented"
|
|
68434
|
+
});
|
|
68239
68435
|
const secure = shouldUseSecureCookie(forgePublicUrlForRequest(request));
|
|
68240
68436
|
let response = yield* require_HttpServer.jsonUnsafe({ loggedOut: true }, { status: 200 }).pipe(require_HttpServer.setCookie(sessions.cookieName, "", {
|
|
68241
68437
|
expires: /* @__PURE__ */ new Date(0),
|
|
@@ -68834,16 +69030,32 @@ const authCommandBearerBootstrapRouteLayer = add$1("POST", "/api/auth/bootstrap/
|
|
|
68834
69030
|
if (limited) return limited;
|
|
68835
69031
|
const serverAuth = yield* ServerAuth;
|
|
68836
69032
|
const sessions = yield* SessionCredentialService;
|
|
68837
|
-
if (serverAuth.isForgeCloudShell?.() === true)
|
|
68838
|
-
|
|
68839
|
-
|
|
68840
|
-
|
|
69033
|
+
if (serverAuth.isForgeCloudShell?.() === true) {
|
|
69034
|
+
yield* require_Schema$1.logWarning("CMMD bearer bootstrap failed.", {
|
|
69035
|
+
deviceType: "unknown",
|
|
69036
|
+
outcome: "failed",
|
|
69037
|
+
reason: "forge-cloud-shell-rejects-non-cmmd-bootstrap"
|
|
69038
|
+
});
|
|
69039
|
+
return yield* new AuthError({
|
|
69040
|
+
message: "Forge Cloud accepts owner assertions from CMMD only.",
|
|
69041
|
+
status: 403
|
|
69042
|
+
});
|
|
69043
|
+
}
|
|
68841
69044
|
const payload = yield* require_HttpServer.schemaBodyJson(CommandBootstrapInput).pipe(require_Schema$1.mapError((cause) => new AuthError({
|
|
68842
69045
|
message: "Invalid CMMD OAuth bearer bootstrap payload.",
|
|
68843
69046
|
status: 400,
|
|
68844
69047
|
cause
|
|
69048
|
+
})), require_Schema$1.tapError(() => require_Schema$1.logWarning("CMMD bearer bootstrap failed.", {
|
|
69049
|
+
deviceType: "unknown",
|
|
69050
|
+
outcome: "failed",
|
|
69051
|
+
reason: "invalid-payload"
|
|
69052
|
+
})));
|
|
69053
|
+
const deviceType = payload.clientDeviceType ?? "desktop";
|
|
69054
|
+
const validated = yield* validateCommandBootstrapPayload(payload).pipe(require_Schema$1.tapError(() => require_Schema$1.logWarning("CMMD bearer bootstrap failed.", {
|
|
69055
|
+
deviceType,
|
|
69056
|
+
outcome: "failed",
|
|
69057
|
+
reason: "invalid-command-bootstrap-payload"
|
|
68845
69058
|
})));
|
|
68846
|
-
const validated = yield* validateCommandBootstrapPayload(payload);
|
|
68847
69059
|
const sessionSubject = resolveCommandOAuthSubject(validated.subjectUserId);
|
|
68848
69060
|
const issued = yield* sessions.issue({
|
|
68849
69061
|
method: "bearer-session-token",
|
|
@@ -68856,20 +69068,34 @@ const authCommandBearerBootstrapRouteLayer = add$1("POST", "/api/auth/bootstrap/
|
|
|
68856
69068
|
}).pipe(require_Schema$1.mapError((cause) => new AuthError({
|
|
68857
69069
|
message: "Failed to issue authenticated bearer session.",
|
|
68858
69070
|
cause
|
|
69071
|
+
})), require_Schema$1.tapError(() => require_Schema$1.logWarning("CMMD bearer bootstrap failed.", {
|
|
69072
|
+
deviceType,
|
|
69073
|
+
outcome: "failed",
|
|
69074
|
+
reason: "session-issuance-failed"
|
|
68859
69075
|
})));
|
|
68860
69076
|
const cmmdIdentity = yield* persistCommandBootstrapSessionArtifacts({
|
|
68861
69077
|
sessionId: issued.sessionId,
|
|
68862
69078
|
payload,
|
|
68863
69079
|
cmmdIdentity: validated.cmmdIdentity
|
|
68864
69080
|
});
|
|
68865
|
-
if (
|
|
69081
|
+
if (deviceType === "desktop" && !payload.refreshToken?.trim()) yield* clearDesktopBearerRefreshTokensForSubject({
|
|
68866
69082
|
subject: sessionSubject,
|
|
68867
69083
|
clientUserAgent: request.headers["user-agent"]
|
|
68868
69084
|
}).pipe(require_Schema$1.mapError((cause) => new AuthError({
|
|
68869
69085
|
message: "Failed to retire legacy desktop refresh credentials.",
|
|
68870
69086
|
status: 500,
|
|
68871
69087
|
cause
|
|
69088
|
+
})), require_Schema$1.tapError(() => require_Schema$1.logWarning("CMMD bearer bootstrap failed.", {
|
|
69089
|
+
sessionId: issued.sessionId,
|
|
69090
|
+
deviceType,
|
|
69091
|
+
outcome: "failed",
|
|
69092
|
+
reason: "legacy-desktop-refresh-retirement-failed"
|
|
68872
69093
|
})));
|
|
69094
|
+
yield* require_Schema$1.logInfo("CMMD bearer bootstrap succeeded.", {
|
|
69095
|
+
sessionId: issued.sessionId,
|
|
69096
|
+
deviceType,
|
|
69097
|
+
outcome: "succeeded"
|
|
69098
|
+
});
|
|
68873
69099
|
return require_HttpServer.jsonUnsafe({
|
|
68874
69100
|
authenticated: true,
|
|
68875
69101
|
role: issued.role,
|
|
@@ -70177,64 +70403,6 @@ function parseAttachmentIdFromRelativePath(relativePath) {
|
|
|
70177
70403
|
return id.length > 0 && !id.includes(".") ? id : null;
|
|
70178
70404
|
}
|
|
70179
70405
|
//#endregion
|
|
70180
|
-
//#region src/observability/Attributes.ts
|
|
70181
|
-
function isPlainObject$1(value) {
|
|
70182
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
70183
|
-
}
|
|
70184
|
-
function markSeen(value, seen) {
|
|
70185
|
-
if (seen.has(value)) return true;
|
|
70186
|
-
seen.add(value);
|
|
70187
|
-
return false;
|
|
70188
|
-
}
|
|
70189
|
-
function normalizeJsonValue(value, seen = /* @__PURE__ */ new WeakSet()) {
|
|
70190
|
-
if (value === null || value === void 0 || typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value ?? null;
|
|
70191
|
-
if (typeof value === "bigint") return value.toString();
|
|
70192
|
-
if (value instanceof Date) return Number.isNaN(value.getTime()) ? "Invalid Date" : value.toISOString();
|
|
70193
|
-
if (value instanceof Error) return {
|
|
70194
|
-
name: value.name,
|
|
70195
|
-
message: value.message,
|
|
70196
|
-
...value.stack ? { stack: value.stack } : {}
|
|
70197
|
-
};
|
|
70198
|
-
if (Array.isArray(value)) {
|
|
70199
|
-
if (markSeen(value, seen)) return "[Circular]";
|
|
70200
|
-
return value.map((entry) => normalizeJsonValue(entry, seen));
|
|
70201
|
-
}
|
|
70202
|
-
if (value instanceof Map) {
|
|
70203
|
-
if (markSeen(value, seen)) return "[Circular]";
|
|
70204
|
-
return Object.fromEntries(Array.from(value.entries(), ([key, entryValue]) => [String(key), normalizeJsonValue(entryValue, seen)]));
|
|
70205
|
-
}
|
|
70206
|
-
if (value instanceof Set) {
|
|
70207
|
-
if (markSeen(value, seen)) return "[Circular]";
|
|
70208
|
-
return Array.from(value.values(), (entry) => normalizeJsonValue(entry, seen));
|
|
70209
|
-
}
|
|
70210
|
-
if (!isPlainObject$1(value)) return String(value);
|
|
70211
|
-
if (markSeen(value, seen)) return "[Circular]";
|
|
70212
|
-
return Object.fromEntries(Object.entries(value).map(([key, entryValue]) => [key, normalizeJsonValue(entryValue, seen)]));
|
|
70213
|
-
}
|
|
70214
|
-
function compactTraceAttributes(attributes) {
|
|
70215
|
-
return Object.fromEntries(Object.entries(attributes).filter(([, value]) => value !== void 0).map(([key, value]) => [key, normalizeJsonValue(value)]));
|
|
70216
|
-
}
|
|
70217
|
-
function compactMetricAttributes(attributes) {
|
|
70218
|
-
return Object.fromEntries(Object.entries(attributes).flatMap(([key, value]) => {
|
|
70219
|
-
if (value === void 0 || value === null) return [];
|
|
70220
|
-
if (typeof value === "string") return [[key, value]];
|
|
70221
|
-
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") return [[key, String(value)]];
|
|
70222
|
-
return [];
|
|
70223
|
-
}));
|
|
70224
|
-
}
|
|
70225
|
-
function outcomeFromExit(exit) {
|
|
70226
|
-
if (require_Schema$1.isSuccess(exit)) return "success";
|
|
70227
|
-
return require_Schema$1.hasInterruptsOnly(exit.cause) ? "interrupt" : "failure";
|
|
70228
|
-
}
|
|
70229
|
-
function normalizeModelMetricLabel(model) {
|
|
70230
|
-
const normalized = model?.trim().toLowerCase();
|
|
70231
|
-
if (!normalized) return;
|
|
70232
|
-
if (normalized.includes("gpt")) return "gpt";
|
|
70233
|
-
if (normalized.includes("claude")) return "claude";
|
|
70234
|
-
if (normalized.includes("gemini")) return "gemini";
|
|
70235
|
-
return "other";
|
|
70236
|
-
}
|
|
70237
|
-
//#endregion
|
|
70238
70406
|
//#region src/observability/TraceRecord.ts
|
|
70239
70407
|
function formatTraceExit(exit) {
|
|
70240
70408
|
if (require_Schema$1.isSuccess(exit)) return { _tag: "Success" };
|
|
@@ -71297,6 +71465,22 @@ async function readOAuthErrorCode(response) {
|
|
|
71297
71465
|
//#endregion
|
|
71298
71466
|
//#region src/command/cmmdRotationFence.ts
|
|
71299
71467
|
/**
|
|
71468
|
+
* Log and count a fence application, without changing the verdict it reports.
|
|
71469
|
+
*
|
|
71470
|
+
* The two facts named in the log line are exactly the ones the predicate
|
|
71471
|
+
* above the caller already computed — whether this session ever deposited a
|
|
71472
|
+
* refresh token of its own, and (only when that was false) whether the
|
|
71473
|
+
* session row reads as a desktop bearer session. Neither fact nor the log
|
|
71474
|
+
* line changes what the caller returns.
|
|
71475
|
+
*/
|
|
71476
|
+
function logRotationFenceApplied(input) {
|
|
71477
|
+
return require_Schema$1.logInfo("CMMD rotation fence applied: session may not rotate its own credential.", {
|
|
71478
|
+
sessionId: input.sessionId,
|
|
71479
|
+
hasStoredRefreshToken: input.hasStoredRefreshToken,
|
|
71480
|
+
isDesktopBearerSession: input.isDesktopBearerSession
|
|
71481
|
+
}).pipe(require_Schema$1.andThen(() => require_Schema$1.update(require_Schema$1.withAttributes(cmmdRotationFenceAppliedTotal, metricAttributes({})), 1)));
|
|
71482
|
+
}
|
|
71483
|
+
/**
|
|
71300
71484
|
* True when Forge must not rotate this session's CMMD credentials.
|
|
71301
71485
|
*
|
|
71302
71486
|
* Fails closed: if the session row cannot be read, assume the fence applies.
|
|
@@ -71304,8 +71488,22 @@ async function readOAuthErrorCode(response) {
|
|
|
71304
71488
|
* reconnect.
|
|
71305
71489
|
*/
|
|
71306
71490
|
function isRotationFencedSession(sessionId) {
|
|
71307
|
-
|
|
71308
|
-
|
|
71491
|
+
const hasStoredRefreshToken = readCommandRefreshTokenForSession(sessionId) !== null;
|
|
71492
|
+
if (hasStoredRefreshToken) return require_Schema$1.succeed(false);
|
|
71493
|
+
return isDesktopBearerAuthSession(sessionId).pipe(require_Schema$1.match({
|
|
71494
|
+
onFailure: () => ({
|
|
71495
|
+
fenced: true,
|
|
71496
|
+
isDesktopBearerSession: null
|
|
71497
|
+
}),
|
|
71498
|
+
onSuccess: (isDesktopBearerSession) => ({
|
|
71499
|
+
fenced: isDesktopBearerSession,
|
|
71500
|
+
isDesktopBearerSession
|
|
71501
|
+
})
|
|
71502
|
+
}), require_Schema$1.tap(({ fenced, isDesktopBearerSession }) => fenced ? logRotationFenceApplied({
|
|
71503
|
+
sessionId,
|
|
71504
|
+
hasStoredRefreshToken,
|
|
71505
|
+
isDesktopBearerSession
|
|
71506
|
+
}) : require_Schema$1.void_), require_Schema$1.map(({ fenced }) => fenced));
|
|
71309
71507
|
}
|
|
71310
71508
|
//#endregion
|
|
71311
71509
|
//#region src/cmmdConnection/cmmdCredentialRejection.ts
|
|
@@ -71342,7 +71540,7 @@ function forgetCmmdCredentialRejection(sessionId) {
|
|
|
71342
71540
|
*/
|
|
71343
71541
|
const clearCmmdAuthAfterCmmdRejection = (sessionId) => require_Schema$1.gen(function* () {
|
|
71344
71542
|
if (!hasCmmdCredentialRejection(sessionId)) return;
|
|
71345
|
-
yield* clearUnrecoverableCmmdAuthForSession(sessionId);
|
|
71543
|
+
yield* clearUnrecoverableCmmdAuthForSession(sessionId, "cmmd-rejected-credential");
|
|
71346
71544
|
forgetCmmdCredentialRejection(sessionId);
|
|
71347
71545
|
});
|
|
71348
71546
|
//#endregion
|
|
@@ -71353,6 +71551,23 @@ function usableCmmdUserJwt(token) {
|
|
|
71353
71551
|
function storeResolvedJwt(sessionId, accessToken, refreshToken) {
|
|
71354
71552
|
return setCommandJwtForSession(sessionId, accessToken, refreshToken ? { refreshToken } : {}).pipe(require_Schema$1.ignore({ log: true }));
|
|
71355
71553
|
}
|
|
71554
|
+
function logCmmdJwtRung(context, rung, outcome, reason) {
|
|
71555
|
+
return (outcome === "failed" ? require_Schema$1.logWarning : require_Schema$1.logInfo)("CMMD JWT resolver rung.", {
|
|
71556
|
+
sessionId: context.sessionId,
|
|
71557
|
+
subject: context.subject,
|
|
71558
|
+
deviceType: context.deviceType,
|
|
71559
|
+
caller: context.caller,
|
|
71560
|
+
rung,
|
|
71561
|
+
outcome,
|
|
71562
|
+
reason
|
|
71563
|
+
});
|
|
71564
|
+
}
|
|
71565
|
+
function recordCmmdCredentialRefreshMetric(rung, outcome) {
|
|
71566
|
+
return require_Schema$1.update(require_Schema$1.withAttributes(cmmdCredentialRefreshTotal, metricAttributes({
|
|
71567
|
+
rung,
|
|
71568
|
+
outcome
|
|
71569
|
+
})), 1);
|
|
71570
|
+
}
|
|
71356
71571
|
const inFlightRefreshes = /* @__PURE__ */ new Map();
|
|
71357
71572
|
function refreshOnceForSession(sessionId, refreshToken) {
|
|
71358
71573
|
return require_Schema$1.promise(() => {
|
|
@@ -71374,15 +71589,21 @@ function refreshOnceForSession(sessionId, refreshToken) {
|
|
|
71374
71589
|
* sibling session's token silently invalidates that sibling's stored copy and
|
|
71375
71590
|
* signs it out.
|
|
71376
71591
|
*/
|
|
71377
|
-
function trySelfRefresh(sessionId,
|
|
71592
|
+
function trySelfRefresh(sessionId, context) {
|
|
71378
71593
|
const currentRefreshToken = readCommandRefreshTokenForSession(sessionId);
|
|
71379
|
-
if (!currentRefreshToken) return require_Schema$1.
|
|
71594
|
+
if (!currentRefreshToken) return logCmmdJwtRung(context, "self-refresh", "skipped", "no refresh token stored for this session").pipe(require_Schema$1.as(null));
|
|
71380
71595
|
return require_Schema$1.gen(function* () {
|
|
71596
|
+
yield* logCmmdJwtRung(context, "self-refresh", "attempted", "rotating this session's own stored refresh token");
|
|
71597
|
+
yield* recordCmmdCredentialRefreshMetric("self-refresh", "attempted");
|
|
71381
71598
|
const refreshed = yield* refreshOnceForSession(sessionId, currentRefreshToken);
|
|
71382
71599
|
const accessToken = usableCmmdUserJwt(refreshed?.accessToken);
|
|
71383
|
-
if (!accessToken)
|
|
71600
|
+
if (!accessToken) {
|
|
71601
|
+
yield* logCmmdJwtRung(context, "self-refresh", "failed", "CMMD refresh did not return a usable user access JWT");
|
|
71602
|
+
return null;
|
|
71603
|
+
}
|
|
71384
71604
|
yield* storeResolvedJwt(sessionId, accessToken, refreshed?.refreshToken);
|
|
71385
|
-
|
|
71605
|
+
yield* recordCmmdCredentialRefreshMetric("self-refresh", "succeeded");
|
|
71606
|
+
yield* logCmmdJwtRung(context, "self-refresh", "succeeded", "CMMD rotated the stored refresh token");
|
|
71386
71607
|
return accessToken;
|
|
71387
71608
|
});
|
|
71388
71609
|
}
|
|
@@ -71399,16 +71620,22 @@ function trySelfRefresh(sessionId, logPrefix) {
|
|
|
71399
71620
|
* CMMD owns its lifetime, and a transient network failure must not throw away
|
|
71400
71621
|
* the one credential that can still recover the session.
|
|
71401
71622
|
*/
|
|
71402
|
-
function tryGrantRedemption(sessionId,
|
|
71623
|
+
function tryGrantRedemption(sessionId, context) {
|
|
71403
71624
|
const grantToken = readCommandSessionGrantForSession(sessionId);
|
|
71404
|
-
if (!grantToken) return require_Schema$1.
|
|
71625
|
+
if (!grantToken) return logCmmdJwtRung(context, "grant-redemption", "skipped", "no session grant stored for this session").pipe(require_Schema$1.as(null));
|
|
71405
71626
|
return require_Schema$1.gen(function* () {
|
|
71627
|
+
yield* logCmmdJwtRung(context, "grant-redemption", "attempted", "redeeming this session's durable CMMD session grant");
|
|
71628
|
+
yield* recordCmmdCredentialRefreshMetric("grant-redemption", "attempted");
|
|
71406
71629
|
const redeemed = yield* require_Schema$1.promise(() => redeemCmmdSessionGrant(grantToken)).pipe(require_Schema$1.orElseSucceed(() => null));
|
|
71407
71630
|
const accessToken = usableCmmdUserJwt(redeemed?.accessToken);
|
|
71408
|
-
if (!accessToken)
|
|
71631
|
+
if (!accessToken) {
|
|
71632
|
+
yield* logCmmdJwtRung(context, "grant-redemption", "failed", "session grant redemption did not return a usable user access JWT");
|
|
71633
|
+
return null;
|
|
71634
|
+
}
|
|
71409
71635
|
if (redeemed?.mcpToken) yield* setCommandAccessTokenForSession(sessionId, redeemed.mcpToken).pipe(require_Schema$1.ignore({ log: true }));
|
|
71410
71636
|
yield* storeResolvedJwt(sessionId, accessToken, redeemed?.refreshToken);
|
|
71411
|
-
|
|
71637
|
+
yield* recordCmmdCredentialRefreshMetric("grant-redemption", "succeeded");
|
|
71638
|
+
yield* logCmmdJwtRung(context, "grant-redemption", "succeeded", "session grant redeemed");
|
|
71412
71639
|
return accessToken;
|
|
71413
71640
|
});
|
|
71414
71641
|
}
|
|
@@ -71419,23 +71646,28 @@ function tryGrantRedemption(sessionId, logPrefix) {
|
|
|
71419
71646
|
* fallback for when that rotation is already gone. Neither touches another
|
|
71420
71647
|
* session's credentials, so this ladder is safe to run from any path.
|
|
71421
71648
|
*/
|
|
71422
|
-
function tryOwnCredentialRecovery(sessionId,
|
|
71649
|
+
function tryOwnCredentialRecovery(sessionId, context) {
|
|
71423
71650
|
return require_Schema$1.gen(function* () {
|
|
71424
|
-
const refreshed = yield* trySelfRefresh(sessionId,
|
|
71651
|
+
const refreshed = yield* trySelfRefresh(sessionId, context);
|
|
71425
71652
|
if (refreshed) return refreshed;
|
|
71426
|
-
return yield* tryGrantRedemption(sessionId,
|
|
71653
|
+
return yield* tryGrantRedemption(sessionId, context);
|
|
71427
71654
|
});
|
|
71428
71655
|
}
|
|
71429
|
-
function tryPromoteBootstrap(sessionId, subject, forceRefresh) {
|
|
71430
|
-
if (subject !== "owner-bootstrap" && subject !== "desktop-bootstrap") return require_Schema$1.
|
|
71656
|
+
function tryPromoteBootstrap(sessionId, subject, forceRefresh, context) {
|
|
71657
|
+
if (subject !== "owner-bootstrap" && subject !== "desktop-bootstrap") return logCmmdJwtRung(context, "promote-bootstrap", "skipped", "subject is not a bootstrap subject").pipe(require_Schema$1.as(null));
|
|
71431
71658
|
return require_Schema$1.gen(function* () {
|
|
71659
|
+
yield* logCmmdJwtRung(context, "promote-bootstrap", "attempted", "promoting the most recent owner CMMD auth to this bootstrap session");
|
|
71432
71660
|
yield* promoteMostRecentOwnerCommandAuthToSession(sessionId).pipe(require_Schema$1.catch_((error) => require_Schema$1.logWarning("Failed to promote owner CMMD auth for REST JWT resolution.", {
|
|
71433
71661
|
cause: error,
|
|
71434
71662
|
sessionId,
|
|
71435
71663
|
subject
|
|
71436
71664
|
})));
|
|
71437
71665
|
const promotedJwt = usableCmmdUserJwt(readCommandJwtForSession(sessionId));
|
|
71438
|
-
if (!forceRefresh && promotedJwt && !isJwtExpiredForSession(sessionId))
|
|
71666
|
+
if (!forceRefresh && promotedJwt && !isJwtExpiredForSession(sessionId)) {
|
|
71667
|
+
yield* logCmmdJwtRung(context, "promote-bootstrap", "succeeded", "promoted owner JWT is usable");
|
|
71668
|
+
return promotedJwt;
|
|
71669
|
+
}
|
|
71670
|
+
yield* logCmmdJwtRung(context, "promote-bootstrap", "failed", forceRefresh ? "forced refresh: a promoted JWT is never reused as-is" : "no promoted JWT available, or it is already expired");
|
|
71439
71671
|
return null;
|
|
71440
71672
|
});
|
|
71441
71673
|
}
|
|
@@ -71448,17 +71680,50 @@ function tryPromoteBootstrap(sessionId, subject, forceRefresh) {
|
|
|
71448
71680
|
* must stay private to the session it was issued to (see `trySelfRefresh`).
|
|
71449
71681
|
* Copying it is what let one expired tab sign the user out everywhere.
|
|
71450
71682
|
*/
|
|
71451
|
-
function trySubjectFallback(sessionId, subject,
|
|
71683
|
+
function trySubjectFallback(sessionId, subject, context) {
|
|
71452
71684
|
return require_Schema$1.gen(function* () {
|
|
71453
|
-
|
|
71454
|
-
const fallbackJwt = usableCmmdUserJwt(
|
|
71455
|
-
if (!fallbackJwt)
|
|
71685
|
+
yield* logCmmdJwtRung(context, "subject-fallback", "attempted", "looking for a sibling session's still-valid JWT for this subject");
|
|
71686
|
+
const fallbackJwt = usableCmmdUserJwt((yield* readMostRecentJwtForSubject(subject).pipe(require_Schema$1.orElseSucceed(() => null)))?.jwt);
|
|
71687
|
+
if (!fallbackJwt) {
|
|
71688
|
+
yield* logCmmdJwtRung(context, "subject-fallback", "failed", "no sibling session holds a still-valid JWT for this subject");
|
|
71689
|
+
return null;
|
|
71690
|
+
}
|
|
71456
71691
|
yield* storeResolvedJwt(sessionId, fallbackJwt, null);
|
|
71457
|
-
|
|
71692
|
+
yield* logCmmdJwtRung(context, "subject-fallback", "succeeded", "borrowed a sibling session's still-valid JWT");
|
|
71458
71693
|
return fallbackJwt;
|
|
71459
71694
|
});
|
|
71460
71695
|
}
|
|
71461
71696
|
/**
|
|
71697
|
+
* The rungs below the rotation fence: forced own-credential recovery,
|
|
71698
|
+
* bootstrap promotion, subject fallback, then own-credential recovery again
|
|
71699
|
+
* as the last resort. Split out of `resolveCmmdJwtForSession` so each half of
|
|
71700
|
+
* the ladder stays independently readable (and independently testable) —
|
|
71701
|
+
* the fence check above is the one decision the split does not touch.
|
|
71702
|
+
*/
|
|
71703
|
+
function runRecoveryLadder(sessionId, normalizedSubject, forceRefresh, context) {
|
|
71704
|
+
return require_Schema$1.gen(function* () {
|
|
71705
|
+
if (forceRefresh) {
|
|
71706
|
+
const forced = yield* tryOwnCredentialRecovery(sessionId, context);
|
|
71707
|
+
if (forced) return forced;
|
|
71708
|
+
}
|
|
71709
|
+
if (normalizedSubject) {
|
|
71710
|
+
const promoted = yield* tryPromoteBootstrap(sessionId, normalizedSubject, forceRefresh, context);
|
|
71711
|
+
if (promoted) return promoted;
|
|
71712
|
+
}
|
|
71713
|
+
if (!normalizedSubject) {
|
|
71714
|
+
yield* logCmmdJwtRung(context, "cache", "failed", "no subject to resolve and forced recovery already exhausted");
|
|
71715
|
+
return null;
|
|
71716
|
+
}
|
|
71717
|
+
if (!forceRefresh) {
|
|
71718
|
+
const fallback = yield* trySubjectFallback(sessionId, normalizedSubject, context);
|
|
71719
|
+
if (fallback) return fallback;
|
|
71720
|
+
}
|
|
71721
|
+
const recovered = yield* tryOwnCredentialRecovery(sessionId, context);
|
|
71722
|
+
if (!recovered) yield* logCmmdJwtRung(context, "cache", "failed", "recovery ladder exhausted: no rung produced a usable JWT");
|
|
71723
|
+
return recovered;
|
|
71724
|
+
});
|
|
71725
|
+
}
|
|
71726
|
+
/**
|
|
71462
71727
|
* Resolve the CMMD REST JWT for a Forge session.
|
|
71463
71728
|
*
|
|
71464
71729
|
* Forge session auth is long-lived compared with the short-lived CMMD JWT.
|
|
@@ -71472,26 +71737,30 @@ function resolveCmmdJwtForSession({ sessionId, subject, logPrefix = "cmmd-auth",
|
|
|
71472
71737
|
const cached = usableCmmdUserJwt(readCommandJwtForSession(sessionId));
|
|
71473
71738
|
if (cached && !isJwtExpiredForSession(sessionId)) {
|
|
71474
71739
|
if (!forceRefresh) return require_Schema$1.succeed(cached);
|
|
71475
|
-
if (staleAccessToken && cached !== staleAccessToken) return require_Schema$1.succeed(cached)
|
|
71740
|
+
if (staleAccessToken && cached !== staleAccessToken) return require_Schema$1.succeed(cached).pipe(require_Schema$1.tap(() => require_Schema$1.gen(function* () {
|
|
71741
|
+
const deviceType = yield* readClientDeviceTypeForSession(sessionId);
|
|
71742
|
+
yield* logCmmdJwtRung({
|
|
71743
|
+
sessionId,
|
|
71744
|
+
subject: subject?.trim() || null,
|
|
71745
|
+
deviceType,
|
|
71746
|
+
caller: logPrefix
|
|
71747
|
+
}, "cache", "skipped", "forced refresh skipped: cache already holds a token another caller rotated");
|
|
71748
|
+
})));
|
|
71476
71749
|
}
|
|
71477
71750
|
const normalizedSubject = subject?.trim() || null;
|
|
71478
71751
|
if (!normalizedSubject && !forceRefresh) return require_Schema$1.succeed(null);
|
|
71479
71752
|
return require_Schema$1.gen(function* () {
|
|
71480
|
-
|
|
71481
|
-
|
|
71482
|
-
|
|
71483
|
-
|
|
71484
|
-
|
|
71485
|
-
|
|
71486
|
-
|
|
71487
|
-
|
|
71488
|
-
|
|
71489
|
-
if (!normalizedSubject) return null;
|
|
71490
|
-
if (!forceRefresh) {
|
|
71491
|
-
const fallback = yield* trySubjectFallback(sessionId, normalizedSubject, logPrefix);
|
|
71492
|
-
if (fallback) return fallback;
|
|
71753
|
+
const context = {
|
|
71754
|
+
sessionId,
|
|
71755
|
+
subject: normalizedSubject,
|
|
71756
|
+
deviceType: yield* readClientDeviceTypeForSession(sessionId),
|
|
71757
|
+
caller: logPrefix
|
|
71758
|
+
};
|
|
71759
|
+
if (yield* isRotationFencedSession(sessionId)) {
|
|
71760
|
+
yield* logCmmdJwtRung(context, "rotation-fence", "failed", "session is fenced from rotating CMMD credentials");
|
|
71761
|
+
return null;
|
|
71493
71762
|
}
|
|
71494
|
-
return yield*
|
|
71763
|
+
return yield* runRecoveryLadder(sessionId, normalizedSubject, forceRefresh, context);
|
|
71495
71764
|
});
|
|
71496
71765
|
}
|
|
71497
71766
|
//#endregion
|
|
@@ -72228,9 +72497,14 @@ function buildProxyErrorResponse(error) {
|
|
|
72228
72497
|
* warning rather than failing the request if the clear itself errors — a
|
|
72229
72498
|
* session that already has no usable credential must still get its 401,
|
|
72230
72499
|
* not a 500 from a failed best-effort cleanup.
|
|
72500
|
+
*
|
|
72501
|
+
* Reached only after CMMD itself rejected the request with both the original
|
|
72502
|
+
* and (if retried) the refreshed JWT, so — unlike `respondCmmdConnectionRequired`
|
|
72503
|
+
* below — this always deletes the row. `clearUnrecoverableCmmdAuthForSession`
|
|
72504
|
+
* logs the row count and the reason itself; this only names the reason.
|
|
72231
72505
|
*/
|
|
72232
72506
|
function clearCmmdAuthAfterFailure(sessionId) {
|
|
72233
|
-
return clearUnrecoverableCmmdAuthForSession(sessionId).pipe(require_Schema$1.catch_((error) => require_Schema$1.logWarning("Failed to clear unrecoverable CMMD auth after CMMD auth failure.", {
|
|
72507
|
+
return clearUnrecoverableCmmdAuthForSession(sessionId, "cmmd-proxy-auth-error").pipe(require_Schema$1.catch_((error) => require_Schema$1.logWarning("Failed to clear unrecoverable CMMD auth after CMMD auth failure.", {
|
|
72234
72508
|
cause: error,
|
|
72235
72509
|
sessionId
|
|
72236
72510
|
})));
|
|
@@ -72251,7 +72525,7 @@ function clearCmmdAuthAfterFailure(sessionId) {
|
|
|
72251
72525
|
* refused the credential, which `clearCmmdAuthAfterCmmdRejection` checks.
|
|
72252
72526
|
*/
|
|
72253
72527
|
function respondCmmdConnectionRequired(sessionId) {
|
|
72254
|
-
return
|
|
72528
|
+
return require_Schema$1.logInfo("CMMD proxy request answered CMMD_AUTH_REQUIRED.", { sessionId }).pipe(require_Schema$1.andThen(() => clearCmmdAuthAfterCmmdRejection(sessionId)), require_Schema$1.catch_((error) => require_Schema$1.logWarning("Failed to clear CMMD auth that CMMD itself rejected.", {
|
|
72255
72529
|
cause: error,
|
|
72256
72530
|
sessionId
|
|
72257
72531
|
})), require_Schema$1.as(buildProxyErrorResponse(new CmmdProxyAuthenticationRequiredError("CMMD connection required. Reconnect CMMD to continue."))));
|
|
@@ -95034,60 +95308,6 @@ const dispatchBootstrapTurnStart = (input, command) => require_Schema$1.gen(func
|
|
|
95034
95308
|
*/
|
|
95035
95309
|
var OrchestrationEngineService = class extends require_Schema$1.Service()("forge/orchestration/Services/OrchestrationEngine/OrchestrationEngineService") {};
|
|
95036
95310
|
//#endregion
|
|
95037
|
-
//#region src/observability/Metrics.ts
|
|
95038
|
-
const rpcRequestsTotal = require_Schema$1.counter("t3_rpc_requests_total", { description: "Total RPC requests handled by the websocket RPC server." });
|
|
95039
|
-
const rpcRequestDuration = require_Schema$1.timer("t3_rpc_request_duration", { description: "RPC request handling duration." });
|
|
95040
|
-
const orchestrationCommandsTotal = require_Schema$1.counter("t3_orchestration_commands_total", { description: "Total orchestration commands dispatched." });
|
|
95041
|
-
const orchestrationCommandDuration = require_Schema$1.timer("t3_orchestration_command_duration", { description: "Orchestration command dispatch duration." });
|
|
95042
|
-
const orchestrationCommandAckDuration = require_Schema$1.timer("t3_orchestration_command_ack_duration", { description: "Time from orchestration command dispatch to the first committed domain event emitted for that command." });
|
|
95043
|
-
const orchestrationEventsProcessedTotal = require_Schema$1.counter("t3_orchestration_events_processed_total", { description: "Total orchestration intent events processed by runtime reactors." });
|
|
95044
|
-
const providerSessionsTotal = require_Schema$1.counter("t3_provider_sessions_total", { description: "Total provider session lifecycle operations." });
|
|
95045
|
-
const providerTurnsTotal = require_Schema$1.counter("t3_provider_turns_total", { description: "Total provider turn lifecycle operations." });
|
|
95046
|
-
const providerTurnDuration = require_Schema$1.timer("t3_provider_turn_duration", { description: "Provider turn request duration." });
|
|
95047
|
-
const providerRuntimeEventsTotal = require_Schema$1.counter("t3_provider_runtime_events_total", { description: "Total canonical provider runtime events processed." });
|
|
95048
|
-
const gitCommandsTotal = require_Schema$1.counter("t3_git_commands_total", { description: "Total git commands executed by the server runtime." });
|
|
95049
|
-
const gitCommandDuration = require_Schema$1.timer("t3_git_command_duration", { description: "Git command execution duration." });
|
|
95050
|
-
const terminalSessionsTotal = require_Schema$1.counter("t3_terminal_sessions_total", { description: "Total terminal sessions started." });
|
|
95051
|
-
const browserSessionsReapedTotal = require_Schema$1.counter("browser_sessions_reaped_total", { description: "Browser sessions and Chromium processes reclaimed by the orphan reaper, by reason (orphan | ttl | stale_profile)." });
|
|
95052
|
-
const terminalRestartsTotal = require_Schema$1.counter("t3_terminal_restarts_total", { description: "Total terminal restart requests handled." });
|
|
95053
|
-
const runtimeReplicationOutboxDepth = require_Schema$1.gauge("t3_runtime_replication_outbox_depth", { description: "Current runtime replication outbox items by durable state." });
|
|
95054
|
-
const runtimeReplicationOutboxOldestEventAge = require_Schema$1.gauge("t3_runtime_replication_outbox_oldest_event_age_seconds", { description: "Age in seconds of the oldest undelivered runtime replication payload." });
|
|
95055
|
-
const runtimeReplicationPublicationAttemptsTotal = require_Schema$1.counter("t3_runtime_replication_publication_attempts_total", { description: "Total canonical runtime replication publication attempts." });
|
|
95056
|
-
const runtimeReplicationPublicationRetriesTotal = require_Schema$1.counter("t3_runtime_replication_publication_retries_total", { description: "Total runtime replication retries scheduled after recoverable failures." });
|
|
95057
|
-
const runtimeReplicationPublicationLatency = require_Schema$1.timer("t3_runtime_replication_publication_latency", { description: "Time from durable enqueue to canonical CMMD acknowledgement." });
|
|
95058
|
-
const metricAttributes = (attributes) => Object.entries(compactMetricAttributes(attributes));
|
|
95059
|
-
const increment = (metric, attributes, amount = 1) => require_Schema$1.update(require_Schema$1.withAttributes(metric, metricAttributes(attributes)), amount);
|
|
95060
|
-
const withMetricsImpl = (effect, options) => require_Schema$1.gen(function* () {
|
|
95061
|
-
const startedAt = Date.now();
|
|
95062
|
-
const exit$2 = yield* require_Schema$1.exit(effect);
|
|
95063
|
-
const duration = require_Schema$1.millis(Math.max(0, Date.now() - startedAt));
|
|
95064
|
-
const baseAttributes = typeof options.attributes === "function" ? options.attributes() : options.attributes ?? {};
|
|
95065
|
-
if (options.timer) yield* require_Schema$1.update(require_Schema$1.withAttributes(options.timer, metricAttributes(baseAttributes)), duration);
|
|
95066
|
-
if (options.counter) {
|
|
95067
|
-
const outcome = outcomeFromExit(exit$2);
|
|
95068
|
-
yield* require_Schema$1.update(require_Schema$1.withAttributes(options.counter, metricAttributes({
|
|
95069
|
-
...baseAttributes,
|
|
95070
|
-
outcome,
|
|
95071
|
-
...options.outcomeAttributes ? options.outcomeAttributes(outcome) : {}
|
|
95072
|
-
})), 1);
|
|
95073
|
-
}
|
|
95074
|
-
if (require_Schema$1.isSuccess(exit$2)) return exit$2.value;
|
|
95075
|
-
return yield* require_Schema$1.failCause(exit$2.cause);
|
|
95076
|
-
});
|
|
95077
|
-
const withMetrics = require_Schema$1.dual(2, withMetricsImpl);
|
|
95078
|
-
const providerMetricAttributes = (provider, extra) => compactMetricAttributes({
|
|
95079
|
-
provider,
|
|
95080
|
-
...extra
|
|
95081
|
-
});
|
|
95082
|
-
const providerTurnMetricAttributes = (input) => {
|
|
95083
|
-
const modelFamily = normalizeModelMetricLabel(input.model);
|
|
95084
|
-
return compactMetricAttributes({
|
|
95085
|
-
provider: input.provider,
|
|
95086
|
-
...modelFamily ? { modelFamily } : {},
|
|
95087
|
-
...input.extra
|
|
95088
|
-
});
|
|
95089
|
-
};
|
|
95090
|
-
//#endregion
|
|
95091
95311
|
//#region src/observability/RpcInstrumentation.ts
|
|
95092
95312
|
const annotateRpcSpan = (method, traceAttributes) => require_Schema$1.annotateCurrentSpan({
|
|
95093
95313
|
"rpc.method": method,
|
|
@@ -96856,6 +97076,7 @@ const registerCloudRuntimeForReplicaHydration = require_Schema$1.gen(function* (
|
|
|
96856
97076
|
credentialEpoch,
|
|
96857
97077
|
activeTurnCount: 0,
|
|
96858
97078
|
activeSessionCount: 0,
|
|
97079
|
+
acceptingTurns: false,
|
|
96859
97080
|
...forgeGitCommit !== void 0 ? { forgeGitCommit } : {},
|
|
96860
97081
|
forgeServerVersion: installedForgeServerVersion
|
|
96861
97082
|
}),
|
|
@@ -96892,6 +97113,128 @@ const hydrateCloudRuntimeReplica = require_Schema$1.gen(function* () {
|
|
|
96892
97113
|
return yield* hydrateRuntimeReplica({ expectedRuntimeId: grant.runtimeId }, dependencies);
|
|
96893
97114
|
});
|
|
96894
97115
|
//#endregion
|
|
97116
|
+
//#region src/runtimeDrain/RuntimeDrainState.ts
|
|
97117
|
+
/**
|
|
97118
|
+
* The positive facts this process must observe before it can claim a turn.
|
|
97119
|
+
*
|
|
97120
|
+
* Every entry is required, so adding one here is the whole change: the
|
|
97121
|
+
* derivation below reads this list rather than naming fields, and the record
|
|
97122
|
+
* it indexes cannot be built with a member missing.
|
|
97123
|
+
*/
|
|
97124
|
+
const RUNTIME_EXECUTION_PRECONDITIONS = ["orchestrationEngine", "providerLayer"];
|
|
97125
|
+
/**
|
|
97126
|
+
* The single definition of the accepting-turns fact.
|
|
97127
|
+
*
|
|
97128
|
+
* Exported so test stubs of this service derive it exactly as the live state
|
|
97129
|
+
* does. A stub that recomputed it by hand could disagree with production and
|
|
97130
|
+
* still pass.
|
|
97131
|
+
*/
|
|
97132
|
+
function deriveAcceptingTurns(input) {
|
|
97133
|
+
return RUNTIME_EXECUTION_PRECONDITIONS.every((precondition) => input.preconditions[precondition]) && !input.draining && !input.shutdownRequested;
|
|
97134
|
+
}
|
|
97135
|
+
const initialState = {
|
|
97136
|
+
activeTurns: /* @__PURE__ */ new Set(),
|
|
97137
|
+
activeTurnCount: 0,
|
|
97138
|
+
activeSessionCount: 0,
|
|
97139
|
+
draining: false,
|
|
97140
|
+
drainReason: null,
|
|
97141
|
+
drainTargetImageRef: null,
|
|
97142
|
+
drainTargetImageVersion: null,
|
|
97143
|
+
drainForceRequired: false,
|
|
97144
|
+
preconditions: {
|
|
97145
|
+
orchestrationEngine: false,
|
|
97146
|
+
providerLayer: false
|
|
97147
|
+
},
|
|
97148
|
+
shutdownRequested: false
|
|
97149
|
+
};
|
|
97150
|
+
function snapshotFromState(state) {
|
|
97151
|
+
return {
|
|
97152
|
+
activeTurnCount: state.activeTurnCount,
|
|
97153
|
+
activeSessionCount: state.activeSessionCount,
|
|
97154
|
+
draining: state.draining,
|
|
97155
|
+
drainReason: state.drainReason,
|
|
97156
|
+
drainTargetImageRef: state.drainTargetImageRef,
|
|
97157
|
+
drainTargetImageVersion: state.drainTargetImageVersion,
|
|
97158
|
+
drainForceRequired: state.drainForceRequired,
|
|
97159
|
+
acceptingTurns: deriveAcceptingTurns(state)
|
|
97160
|
+
};
|
|
97161
|
+
}
|
|
97162
|
+
function turnKey(input) {
|
|
97163
|
+
return `${input.threadId}:${input.turnId ?? "unknown"}`;
|
|
97164
|
+
}
|
|
97165
|
+
function normalizeCount(count) {
|
|
97166
|
+
return Number.isFinite(count) ? Math.max(0, Math.floor(count)) : 0;
|
|
97167
|
+
}
|
|
97168
|
+
const makeRuntimeDrainState = require_Schema$1.gen(function* () {
|
|
97169
|
+
const stateRef = yield* require_HttpServer.make$3(initialState);
|
|
97170
|
+
const update = (f) => require_HttpServer.updateAndGet(stateRef, f).pipe(require_Schema$1.map(snapshotFromState));
|
|
97171
|
+
return {
|
|
97172
|
+
beginTurn: (input) => update((state) => {
|
|
97173
|
+
const activeTurns = new Set(state.activeTurns);
|
|
97174
|
+
activeTurns.add(turnKey(input));
|
|
97175
|
+
return {
|
|
97176
|
+
...state,
|
|
97177
|
+
activeTurns,
|
|
97178
|
+
activeTurnCount: activeTurns.size
|
|
97179
|
+
};
|
|
97180
|
+
}),
|
|
97181
|
+
completeTurn: (input) => update((state) => {
|
|
97182
|
+
const activeTurns = new Set(state.activeTurns);
|
|
97183
|
+
activeTurns.delete(turnKey(input));
|
|
97184
|
+
return {
|
|
97185
|
+
...state,
|
|
97186
|
+
activeTurns,
|
|
97187
|
+
activeTurnCount: activeTurns.size
|
|
97188
|
+
};
|
|
97189
|
+
}),
|
|
97190
|
+
clearActiveTurns: update((state) => ({
|
|
97191
|
+
...state,
|
|
97192
|
+
activeTurns: /* @__PURE__ */ new Set(),
|
|
97193
|
+
activeTurnCount: 0
|
|
97194
|
+
})),
|
|
97195
|
+
setActiveSessionCount: (count) => update((state) => ({
|
|
97196
|
+
...state,
|
|
97197
|
+
activeSessionCount: normalizeCount(count)
|
|
97198
|
+
})),
|
|
97199
|
+
reconcileProviderSessions: (sessions) => update((state) => {
|
|
97200
|
+
const activeSessions = sessions.filter((session) => session.status !== "closed");
|
|
97201
|
+
const activeTurns = new Set(activeSessions.flatMap((session) => session.activeTurnId === void 0 ? [] : [turnKey({
|
|
97202
|
+
threadId: session.threadId,
|
|
97203
|
+
turnId: session.activeTurnId
|
|
97204
|
+
})]));
|
|
97205
|
+
return {
|
|
97206
|
+
...state,
|
|
97207
|
+
activeTurns,
|
|
97208
|
+
activeTurnCount: activeTurns.size,
|
|
97209
|
+
activeSessionCount: activeSessions.length
|
|
97210
|
+
};
|
|
97211
|
+
}),
|
|
97212
|
+
applyControlPlaneState: (input) => update((state) => ({
|
|
97213
|
+
...state,
|
|
97214
|
+
draining: input.draining ?? state.draining,
|
|
97215
|
+
drainReason: input.drainReason ?? state.drainReason,
|
|
97216
|
+
drainTargetImageRef: input.drainTargetImageRef ?? state.drainTargetImageRef,
|
|
97217
|
+
drainTargetImageVersion: input.drainTargetImageVersion ?? state.drainTargetImageVersion,
|
|
97218
|
+
drainForceRequired: input.drainForceRequired ?? state.drainForceRequired
|
|
97219
|
+
})),
|
|
97220
|
+
markExecutionPrecondition: (precondition) => update((state) => ({
|
|
97221
|
+
...state,
|
|
97222
|
+
preconditions: {
|
|
97223
|
+
...state.preconditions,
|
|
97224
|
+
[precondition]: true
|
|
97225
|
+
}
|
|
97226
|
+
})),
|
|
97227
|
+
requestShutdown: update((state) => ({
|
|
97228
|
+
...state,
|
|
97229
|
+
shutdownRequested: true
|
|
97230
|
+
})),
|
|
97231
|
+
snapshot: require_HttpServer.get$1(stateRef).pipe(require_Schema$1.map(snapshotFromState)),
|
|
97232
|
+
isDraining: require_HttpServer.get$1(stateRef).pipe(require_Schema$1.map((state) => state.draining))
|
|
97233
|
+
};
|
|
97234
|
+
});
|
|
97235
|
+
var RuntimeDrainState = class extends require_Schema$1.Service()("forge/runtimeDrain/RuntimeDrainState") {};
|
|
97236
|
+
const RuntimeDrainStateLive = require_Schema$1.effect(RuntimeDrainState, makeRuntimeDrainState);
|
|
97237
|
+
//#endregion
|
|
96895
97238
|
//#region src/persistence/Services/LocalAutomations.ts
|
|
96896
97239
|
const LocalAutomationStatus = require_Schema$1.Literals([
|
|
96897
97240
|
"active",
|
|
@@ -98299,6 +98642,28 @@ function serializeWorktreeLaunchActivity(activity) {
|
|
|
98299
98642
|
function decodeWorktreeLaunchActivityKind(kind) {
|
|
98300
98643
|
return isCmmdRuntimeWorktreeLaunchActivityKind(kind) ? kind : null;
|
|
98301
98644
|
}
|
|
98645
|
+
function planStepsOf(activity) {
|
|
98646
|
+
const decoded = decodeCmmdRuntimePlanActivity(encodeCmmdRuntimePlanActivityPayload(activity.kind, activity.payload));
|
|
98647
|
+
return decoded !== null && decoded.plan.length > 0 ? decoded.plan : null;
|
|
98648
|
+
}
|
|
98649
|
+
function serializePlanActivity(activity) {
|
|
98650
|
+
if (activity.kind !== "turn.plan.updated") return null;
|
|
98651
|
+
const plan = planStepsOf(activity);
|
|
98652
|
+
if (plan === null) return null;
|
|
98653
|
+
const completed = plan.filter((step) => step.status === "completed").length;
|
|
98654
|
+
return {
|
|
98655
|
+
sourceSequence: null,
|
|
98656
|
+
event: {
|
|
98657
|
+
eventId: `activity:${activity.id}`,
|
|
98658
|
+
occurredAt: canonicalRuntimeEventTimestamp(activity.createdAt),
|
|
98659
|
+
...eventTurn(activity.turnId),
|
|
98660
|
+
kind: "tool_call",
|
|
98661
|
+
summary: `Plan: ${completed} of ${plan.length} steps done`,
|
|
98662
|
+
status: "completed",
|
|
98663
|
+
payload: encodeCmmdRuntimePlanActivityPayload(activity.kind, activity.payload)
|
|
98664
|
+
}
|
|
98665
|
+
};
|
|
98666
|
+
}
|
|
98302
98667
|
function isReplicatedFailureActivity(activity) {
|
|
98303
98668
|
return activity.kind === "runtime.error" || activity.kind.startsWith("provider.") && activity.kind.endsWith(".failed");
|
|
98304
98669
|
}
|
|
@@ -98683,6 +99048,10 @@ function serializeRuntimeThreadEvents(thread) {
|
|
|
98683
99048
|
const event = serializeWorktreeLaunchActivity(activity);
|
|
98684
99049
|
return event === null ? [] : [event];
|
|
98685
99050
|
});
|
|
99051
|
+
const planActivities = thread.activities.flatMap((activity) => {
|
|
99052
|
+
const event = serializePlanActivity(activity);
|
|
99053
|
+
return event === null ? [] : [event];
|
|
99054
|
+
});
|
|
98686
99055
|
const recordedTurns = serializeRecordedTurns(thread);
|
|
98687
99056
|
const textGenerations = serializeTextGenerations(thread);
|
|
98688
99057
|
return [
|
|
@@ -98690,6 +99059,7 @@ function serializeRuntimeThreadEvents(thread) {
|
|
|
98690
99059
|
...replicaActivities,
|
|
98691
99060
|
...toolActivities,
|
|
98692
99061
|
...worktreeLaunchActivities,
|
|
99062
|
+
...planActivities,
|
|
98693
99063
|
...failureActivities,
|
|
98694
99064
|
...recordedTurns,
|
|
98695
99065
|
...textGenerations
|
|
@@ -100501,6 +100871,30 @@ const makeCommandGate = require_Schema$1.gen(function* () {
|
|
|
100501
100871
|
})
|
|
100502
100872
|
};
|
|
100503
100873
|
});
|
|
100874
|
+
/**
|
|
100875
|
+
* Settle the command gate for a finished startup, and report whether commands
|
|
100876
|
+
* are now accepted.
|
|
100877
|
+
*
|
|
100878
|
+
* The success branch is the moment the orchestration engine can take work, so
|
|
100879
|
+
* it is where the engine half of the accepting-turns fact is marked. A failed
|
|
100880
|
+
* startup accepts nothing and must leave the fact untouched: absent must not
|
|
100881
|
+
* read as healthy.
|
|
100882
|
+
*/
|
|
100883
|
+
const settleCommandReadiness = (input) => require_Schema$1.gen(function* () {
|
|
100884
|
+
if (require_Schema$1.isFailure(input.startupExit)) {
|
|
100885
|
+
const error = new ServerRuntimeStartupError({
|
|
100886
|
+
message: startupFailureMessage(input.startupExit.cause),
|
|
100887
|
+
cause: input.startupExit.cause
|
|
100888
|
+
});
|
|
100889
|
+
yield* require_Schema$1.logError("server runtime startup failed", { cause: describeStartupFailure(input.startupExit.cause) });
|
|
100890
|
+
yield* input.commandGate.failCommandReady(error);
|
|
100891
|
+
return false;
|
|
100892
|
+
}
|
|
100893
|
+
yield* require_Schema$1.logDebug("Accepting commands");
|
|
100894
|
+
yield* input.commandGate.signalCommandReady;
|
|
100895
|
+
yield* input.drainState.markExecutionPrecondition("orchestrationEngine");
|
|
100896
|
+
return true;
|
|
100897
|
+
});
|
|
100504
100898
|
const launchStartupHeartbeat = require_Schema$1.gen(function* () {
|
|
100505
100899
|
const analytics = yield* AnalyticsService;
|
|
100506
100900
|
const { threadCount, projectCount } = yield* (yield* ProjectionSnapshotQuery).getCounts().pipe(require_Schema$1.catch_((cause) => require_Schema$1.logWarning("failed to gather startup projection counts for telemetry", { cause }).pipe(require_Schema$1.as({
|
|
@@ -100682,6 +101076,7 @@ const makeServerRuntimeStartup = require_Schema$1.gen(function* () {
|
|
|
100682
101076
|
const serverSettings = yield* ServerSettingsService;
|
|
100683
101077
|
const serverEnvironment = yield* ServerEnvironment;
|
|
100684
101078
|
const usage = yield* UsageService;
|
|
101079
|
+
const drainState = yield* RuntimeDrainState;
|
|
100685
101080
|
const commandGate = yield* makeCommandGate;
|
|
100686
101081
|
const httpListening = yield* require_Schema$1.make$4();
|
|
100687
101082
|
const reactorScope = yield* require_Schema$1.make$3("sequential");
|
|
@@ -100764,18 +101159,11 @@ const makeServerRuntimeStartup = require_Schema$1.gen(function* () {
|
|
|
100764
101159
|
root: true
|
|
100765
101160
|
}));
|
|
100766
101161
|
yield* require_Schema$1.forkScoped(require_Schema$1.gen(function* () {
|
|
100767
|
-
|
|
100768
|
-
|
|
100769
|
-
|
|
100770
|
-
|
|
100771
|
-
|
|
100772
|
-
});
|
|
100773
|
-
yield* require_Schema$1.logError("server runtime startup failed", { cause: describeStartupFailure(startupExit.cause) });
|
|
100774
|
-
yield* commandGate.failCommandReady(error);
|
|
100775
|
-
return;
|
|
100776
|
-
}
|
|
100777
|
-
yield* require_Schema$1.logDebug("Accepting commands");
|
|
100778
|
-
yield* commandGate.signalCommandReady;
|
|
101162
|
+
if (!(yield* settleCommandReadiness({
|
|
101163
|
+
startupExit: yield* require_Schema$1.exit(startup),
|
|
101164
|
+
commandGate,
|
|
101165
|
+
drainState
|
|
101166
|
+
}))) return;
|
|
100779
101167
|
yield* require_Schema$1.logDebug("startup phase: starting the usage scan warm-up");
|
|
100780
101168
|
yield* require_Schema$1.forkScoped(runUsageScanWarmup({ readSummary: usage.readSummary }));
|
|
100781
101169
|
yield* require_Schema$1.logDebug("startup phase: waiting for http listener");
|
|
@@ -153387,7 +153775,9 @@ var CodexAppServerManager = class extends node_events.EventEmitter {
|
|
|
153387
153775
|
scheduleProviderEgressTokenRefresh(context, delayMs) {
|
|
153388
153776
|
if (context.tokenRefreshTimer) clearTimeout(context.tokenRefreshTimer);
|
|
153389
153777
|
const tokenRefreshTimer = setTimeout(() => {
|
|
153390
|
-
this.handleProviderEgressTokenRefresh(context.session.threadId).catch(() =>
|
|
153778
|
+
this.handleProviderEgressTokenRefresh(context.session.threadId).catch((error) => {
|
|
153779
|
+
this.emitErrorEvent(context, "session/tokenRefreshFailed", error instanceof Error ? error.message : String(error));
|
|
153780
|
+
});
|
|
153391
153781
|
}, delayMs);
|
|
153392
153782
|
tokenRefreshTimer.unref?.();
|
|
153393
153783
|
context.tokenRefreshTimer = tokenRefreshTimer;
|
|
@@ -290741,93 +291131,6 @@ async function maybeRefreshRuntimeProvisioningGrant(input) {
|
|
|
290741
291131
|
return "refreshed";
|
|
290742
291132
|
}
|
|
290743
291133
|
//#endregion
|
|
290744
|
-
//#region src/runtimeDrain/RuntimeDrainState.ts
|
|
290745
|
-
const initialState = {
|
|
290746
|
-
activeTurns: /* @__PURE__ */ new Set(),
|
|
290747
|
-
activeTurnCount: 0,
|
|
290748
|
-
activeSessionCount: 0,
|
|
290749
|
-
draining: false,
|
|
290750
|
-
drainReason: null,
|
|
290751
|
-
drainTargetImageRef: null,
|
|
290752
|
-
drainTargetImageVersion: null,
|
|
290753
|
-
drainForceRequired: false
|
|
290754
|
-
};
|
|
290755
|
-
function snapshotFromState(state) {
|
|
290756
|
-
return {
|
|
290757
|
-
activeTurnCount: state.activeTurnCount,
|
|
290758
|
-
activeSessionCount: state.activeSessionCount,
|
|
290759
|
-
draining: state.draining,
|
|
290760
|
-
drainReason: state.drainReason,
|
|
290761
|
-
drainTargetImageRef: state.drainTargetImageRef,
|
|
290762
|
-
drainTargetImageVersion: state.drainTargetImageVersion,
|
|
290763
|
-
drainForceRequired: state.drainForceRequired
|
|
290764
|
-
};
|
|
290765
|
-
}
|
|
290766
|
-
function turnKey(input) {
|
|
290767
|
-
return `${input.threadId}:${input.turnId ?? "unknown"}`;
|
|
290768
|
-
}
|
|
290769
|
-
function normalizeCount(count) {
|
|
290770
|
-
return Number.isFinite(count) ? Math.max(0, Math.floor(count)) : 0;
|
|
290771
|
-
}
|
|
290772
|
-
const makeRuntimeDrainState = require_Schema$1.gen(function* () {
|
|
290773
|
-
const stateRef = yield* require_HttpServer.make$3(initialState);
|
|
290774
|
-
const update = (f) => require_HttpServer.updateAndGet(stateRef, f).pipe(require_Schema$1.map(snapshotFromState));
|
|
290775
|
-
return {
|
|
290776
|
-
beginTurn: (input) => update((state) => {
|
|
290777
|
-
const activeTurns = new Set(state.activeTurns);
|
|
290778
|
-
activeTurns.add(turnKey(input));
|
|
290779
|
-
return {
|
|
290780
|
-
...state,
|
|
290781
|
-
activeTurns,
|
|
290782
|
-
activeTurnCount: activeTurns.size
|
|
290783
|
-
};
|
|
290784
|
-
}),
|
|
290785
|
-
completeTurn: (input) => update((state) => {
|
|
290786
|
-
const activeTurns = new Set(state.activeTurns);
|
|
290787
|
-
activeTurns.delete(turnKey(input));
|
|
290788
|
-
return {
|
|
290789
|
-
...state,
|
|
290790
|
-
activeTurns,
|
|
290791
|
-
activeTurnCount: activeTurns.size
|
|
290792
|
-
};
|
|
290793
|
-
}),
|
|
290794
|
-
clearActiveTurns: update((state) => ({
|
|
290795
|
-
...state,
|
|
290796
|
-
activeTurns: /* @__PURE__ */ new Set(),
|
|
290797
|
-
activeTurnCount: 0
|
|
290798
|
-
})),
|
|
290799
|
-
setActiveSessionCount: (count) => update((state) => ({
|
|
290800
|
-
...state,
|
|
290801
|
-
activeSessionCount: normalizeCount(count)
|
|
290802
|
-
})),
|
|
290803
|
-
reconcileProviderSessions: (sessions) => update((state) => {
|
|
290804
|
-
const activeSessions = sessions.filter((session) => session.status !== "closed");
|
|
290805
|
-
const activeTurns = new Set(activeSessions.flatMap((session) => session.activeTurnId === void 0 ? [] : [turnKey({
|
|
290806
|
-
threadId: session.threadId,
|
|
290807
|
-
turnId: session.activeTurnId
|
|
290808
|
-
})]));
|
|
290809
|
-
return {
|
|
290810
|
-
...state,
|
|
290811
|
-
activeTurns,
|
|
290812
|
-
activeTurnCount: activeTurns.size,
|
|
290813
|
-
activeSessionCount: activeSessions.length
|
|
290814
|
-
};
|
|
290815
|
-
}),
|
|
290816
|
-
applyControlPlaneState: (input) => update((state) => ({
|
|
290817
|
-
...state,
|
|
290818
|
-
draining: input.draining ?? state.draining,
|
|
290819
|
-
drainReason: input.drainReason ?? state.drainReason,
|
|
290820
|
-
drainTargetImageRef: input.drainTargetImageRef ?? state.drainTargetImageRef,
|
|
290821
|
-
drainTargetImageVersion: input.drainTargetImageVersion ?? state.drainTargetImageVersion,
|
|
290822
|
-
drainForceRequired: input.drainForceRequired ?? state.drainForceRequired
|
|
290823
|
-
})),
|
|
290824
|
-
snapshot: require_HttpServer.get$1(stateRef).pipe(require_Schema$1.map(snapshotFromState)),
|
|
290825
|
-
isDraining: require_HttpServer.get$1(stateRef).pipe(require_Schema$1.map((state) => state.draining))
|
|
290826
|
-
};
|
|
290827
|
-
});
|
|
290828
|
-
var RuntimeDrainState = class extends require_Schema$1.Service()("forge/runtimeDrain/RuntimeDrainState") {};
|
|
290829
|
-
const RuntimeDrainStateLive = require_Schema$1.effect(RuntimeDrainState, makeRuntimeDrainState);
|
|
290830
|
-
//#endregion
|
|
290831
291134
|
//#region src/runtimeDrain/RuntimeDrainReporter.ts
|
|
290832
291135
|
const HEARTBEAT_INTERVAL = require_Schema$1.seconds(30);
|
|
290833
291136
|
const HEARTBEAT_TICK_TIMEOUT = require_Schema$1.seconds(60);
|
|
@@ -290885,6 +291188,7 @@ const postRuntimeHeartbeat = (config, snapshot) => require_Schema$1.promise(asyn
|
|
|
290885
291188
|
...config,
|
|
290886
291189
|
activeTurnCount: snapshot.activeTurnCount,
|
|
290887
291190
|
activeSessionCount: snapshot.activeSessionCount,
|
|
291191
|
+
acceptingTurns: snapshot.acceptingTurns,
|
|
290888
291192
|
...forgeGitCommit !== void 0 ? { forgeGitCommit } : {},
|
|
290889
291193
|
forgeServerVersion: installedForgeServerVersion
|
|
290890
291194
|
});
|
|
@@ -290993,6 +291297,7 @@ const makeRuntimeDrainReporter = require_Schema$1.gen(function* () {
|
|
|
290993
291297
|
work: reportOnce,
|
|
290994
291298
|
interval: HEARTBEAT_INTERVAL
|
|
290995
291299
|
}));
|
|
291300
|
+
yield* require_Schema$1.addFinalizer(() => drainState.requestShutdown);
|
|
290996
291301
|
})
|
|
290997
291302
|
};
|
|
290998
291303
|
});
|
|
@@ -291203,6 +291508,7 @@ function decodeCodexRateLimitWindows(raw) {
|
|
|
291203
291508
|
function publicProviderRuntimeError(message) {
|
|
291204
291509
|
return sanitizePublicProviderText(message, { fallback: DEFAULT_PUBLIC_PROVIDER_ERROR });
|
|
291205
291510
|
}
|
|
291511
|
+
const processDomainEvent = (_event) => require_Schema$1.void_;
|
|
291206
291512
|
function isAssistantTextDeltaEvent(event) {
|
|
291207
291513
|
return event.type === "content.delta" && event.payload.streamKind === "assistant_text";
|
|
291208
291514
|
}
|
|
@@ -291998,7 +292304,6 @@ const make$9 = require_Schema$1.fn("make")(function* () {
|
|
|
291998
292304
|
yield* runtimeDrainReporter.reportOnce;
|
|
291999
292305
|
}
|
|
292000
292306
|
});
|
|
292001
|
-
const processDomainEvent = (_event) => require_Schema$1.void_;
|
|
292002
292307
|
const processInput = (input) => input.source === "runtime" ? processRuntimeEvent(input.event) : processDomainEvent(input.event);
|
|
292003
292308
|
const processInputSafely = (input) => processInput(input).pipe(require_Schema$1.catchCause((cause) => {
|
|
292004
292309
|
if (require_Schema$1.hasInterruptsOnly(cause)) return require_Schema$1.failCause(cause);
|
|
@@ -292049,6 +292354,7 @@ const make$9 = require_Schema$1.fn("make")(function* () {
|
|
|
292049
292354
|
return {
|
|
292050
292355
|
start: require_Schema$1.fn("start")(function* () {
|
|
292051
292356
|
yield* reconcileOrphanedRunningSessions();
|
|
292357
|
+
yield* runtimeDrainState.markExecutionPrecondition("providerLayer");
|
|
292052
292358
|
yield* runtimeDrainReporter.start;
|
|
292053
292359
|
yield* require_Schema$1.forkScoped(require_Path.runForEach(providerService.streamEvents, (event) => enqueueInput({
|
|
292054
292360
|
source: "runtime",
|
|
@@ -292288,6 +292594,8 @@ const HANDLED_TURN_START_KEY_MAX = 1e4;
|
|
|
292288
292594
|
const HANDLED_TURN_START_KEY_TTL = require_Schema$1.minutes(30);
|
|
292289
292595
|
const DEFAULT_RUNTIME_MODE = "full-access";
|
|
292290
292596
|
const DEFAULT_THREAD_TITLE = "New thread";
|
|
292597
|
+
const isProviderValidationError = require_Schema$1.is(ProviderValidationError);
|
|
292598
|
+
const isProviderKind = require_Schema$1.is(ProviderKind);
|
|
292291
292599
|
function isPathInsideRoot(candidatePath, rootPath) {
|
|
292292
292600
|
let resolvedCandidate;
|
|
292293
292601
|
let resolvedRoot;
|
|
@@ -292324,6 +292632,38 @@ function resolveExistingWorkspaceCwd(input) {
|
|
|
292324
292632
|
function publicProviderFailureDetail(detail) {
|
|
292325
292633
|
return sanitizePublicProviderText(detail, { fallback: "CMMD is temporarily unavailable. Check the workspace AI connection and retry." }) ?? "CMMD is temporarily unavailable. Check the workspace AI connection and retry.";
|
|
292326
292634
|
}
|
|
292635
|
+
/**
|
|
292636
|
+
* The failure detail a transcript shows, judged on the text and not the envelope.
|
|
292637
|
+
*
|
|
292638
|
+
* Forge writes its own validation copy, so `ProviderValidationError.issue` is
|
|
292639
|
+
* not raw provider output. Every envelope around it hides it, each in its own
|
|
292640
|
+
* way: `Cause.pretty` prints the error tag, and the sanitizer counts
|
|
292641
|
+
* "ProviderValidationError" as a provider leak, so a validation failure
|
|
292642
|
+
* rendered through `Cause.pretty` tripped the guard on its own wrapper. The
|
|
292643
|
+
* `message` getter spells the same tag out in prose. On 2026-09-16 the first of
|
|
292644
|
+
* those replaced "Reconnect the account and try again" with "CMMD is
|
|
292645
|
+
* temporarily unavailable" (#3337).
|
|
292646
|
+
*
|
|
292647
|
+
* The issue still goes through the sanitizer. `ProviderService` builds some
|
|
292648
|
+
* issues from a schema formatter, which echoes the decoded payload, so this is a
|
|
292649
|
+
* narrower input to the same guard rather than a way around it.
|
|
292650
|
+
*/
|
|
292651
|
+
function publicProviderFailureDetailFromError(error) {
|
|
292652
|
+
if (isProviderValidationError(error)) return publicProviderFailureDetail(error.issue);
|
|
292653
|
+
return publicProviderFailureDetail(error instanceof Error ? error.message : String(error));
|
|
292654
|
+
}
|
|
292655
|
+
/**
|
|
292656
|
+
* The same judgement for a failure that arrives as a cause.
|
|
292657
|
+
*
|
|
292658
|
+
* Only the validation branch delegates. A cause carries what a bare error does
|
|
292659
|
+
* not: defects, interrupts, and more than one failure, all of which
|
|
292660
|
+
* `Cause.pretty` renders and `.message` would drop. Squashing every failure into
|
|
292661
|
+
* its message to reach one shared line would lose that.
|
|
292662
|
+
*/
|
|
292663
|
+
function publicProviderFailureDetailFromCause(cause) {
|
|
292664
|
+
const error = require_Schema$1.squash(cause);
|
|
292665
|
+
return isProviderValidationError(error) ? publicProviderFailureDetailFromError(error) : publicProviderFailureDetail(require_Schema$1.pretty(cause));
|
|
292666
|
+
}
|
|
292327
292667
|
function canReplaceThreadTitle(currentTitle, titleSeed) {
|
|
292328
292668
|
const trimmedCurrentTitle = currentTitle.trim();
|
|
292329
292669
|
if (trimmedCurrentTitle === DEFAULT_THREAD_TITLE) return true;
|
|
@@ -292479,7 +292819,7 @@ const make$8 = require_Schema$1.gen(function* () {
|
|
|
292479
292819
|
const thread = readModel.threads.find((entry) => entry.id === threadId);
|
|
292480
292820
|
if (!thread) return yield* require_Schema$1.die(/* @__PURE__ */ new Error(`Thread '${threadId}' was not found in read model.`));
|
|
292481
292821
|
const desiredRuntimeMode = thread.runtimeMode;
|
|
292482
|
-
const currentProvider = thread.session?.status !== "stopped" &&
|
|
292822
|
+
const currentProvider = thread.session?.status !== "stopped" && isProviderKind(thread.session?.providerName) ? thread.session.providerName : void 0;
|
|
292483
292823
|
const rawRequestedModelSelection = options?.modelSelection;
|
|
292484
292824
|
const threadProvider = currentProvider ?? thread.modelSelection.provider;
|
|
292485
292825
|
const isStaleRequestedProvider = rawRequestedModelSelection !== void 0 && rawRequestedModelSelection.provider !== threadProvider;
|
|
@@ -292807,7 +293147,7 @@ const make$8 = require_Schema$1.gen(function* () {
|
|
|
292807
293147
|
summary: "Provider turn start failed",
|
|
292808
293148
|
detail: `User message '${event.payload.messageId}' was not found for turn start request.`,
|
|
292809
293149
|
turnId: null,
|
|
292810
|
-
createdAt:
|
|
293150
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
292811
293151
|
});
|
|
292812
293152
|
return;
|
|
292813
293153
|
}
|
|
@@ -292858,9 +293198,9 @@ const make$8 = require_Schema$1.gen(function* () {
|
|
|
292858
293198
|
threadId: event.payload.threadId,
|
|
292859
293199
|
kind: "provider.turn.start.failed",
|
|
292860
293200
|
summary: "Provider turn start failed",
|
|
292861
|
-
detail:
|
|
293201
|
+
detail: publicProviderFailureDetailFromCause(cause),
|
|
292862
293202
|
turnId: null,
|
|
292863
|
-
createdAt:
|
|
293203
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
292864
293204
|
})));
|
|
292865
293205
|
});
|
|
292866
293206
|
const processTurnInterruptRequested = require_Schema$1.fn("processTurnInterruptRequested")(function* (event) {
|
|
@@ -292874,7 +293214,14 @@ const make$8 = require_Schema$1.gen(function* () {
|
|
|
292874
293214
|
turnId: event.payload.turnId ?? null,
|
|
292875
293215
|
createdAt: event.payload.createdAt
|
|
292876
293216
|
});
|
|
292877
|
-
yield* providerService.interruptTurn({ threadId: event.payload.threadId })
|
|
293217
|
+
yield* providerService.interruptTurn({ threadId: event.payload.threadId }).pipe(require_Schema$1.catchCause((cause) => appendProviderFailureActivity({
|
|
293218
|
+
threadId: event.payload.threadId,
|
|
293219
|
+
kind: "provider.turn.interrupt.failed",
|
|
293220
|
+
summary: "Provider turn interrupt failed",
|
|
293221
|
+
detail: publicProviderFailureDetail(require_Schema$1.pretty(cause)),
|
|
293222
|
+
turnId: event.payload.turnId ?? null,
|
|
293223
|
+
createdAt: event.payload.createdAt
|
|
293224
|
+
})));
|
|
292878
293225
|
});
|
|
292879
293226
|
const processApprovalResponseRequested = require_Schema$1.fn("processApprovalResponseRequested")(function* (event) {
|
|
292880
293227
|
const staged = peekThreadContinuationSession(event.commandId);
|
|
@@ -292911,7 +293258,7 @@ const make$8 = require_Schema$1.gen(function* () {
|
|
|
292911
293258
|
threadId: event.payload.threadId,
|
|
292912
293259
|
kind: "provider.approval.respond.failed",
|
|
292913
293260
|
summary: "Provider approval response failed",
|
|
292914
|
-
detail: isUnknownPendingApprovalRequestError(cause) ? stalePendingRequestDetail("approval", event.payload.requestId) :
|
|
293261
|
+
detail: isUnknownPendingApprovalRequestError(cause) ? stalePendingRequestDetail("approval", event.payload.requestId) : publicProviderFailureDetailFromCause(cause),
|
|
292915
293262
|
turnId: null,
|
|
292916
293263
|
createdAt: event.payload.createdAt,
|
|
292917
293264
|
requestId: event.payload.requestId
|
|
@@ -292954,7 +293301,7 @@ const make$8 = require_Schema$1.gen(function* () {
|
|
|
292954
293301
|
threadId: event.payload.threadId,
|
|
292955
293302
|
kind: "provider.user-input.respond.failed",
|
|
292956
293303
|
summary: "Provider user input response failed",
|
|
292957
|
-
detail: isUnknownPendingUserInputRequestError(cause) ? stalePendingRequestDetail("user-input", event.payload.requestId) :
|
|
293304
|
+
detail: isUnknownPendingUserInputRequestError(cause) ? stalePendingRequestDetail("user-input", event.payload.requestId) : publicProviderFailureDetailFromCause(cause),
|
|
292958
293305
|
turnId: null,
|
|
292959
293306
|
createdAt: event.payload.createdAt,
|
|
292960
293307
|
requestId: event.payload.requestId
|
|
@@ -292967,8 +293314,7 @@ const make$8 = require_Schema$1.gen(function* () {
|
|
|
292967
293314
|
yield* providerService.stopSession({
|
|
292968
293315
|
threadId: thread.id,
|
|
292969
293316
|
...event.payload.preserveResumeState === true ? { preserveResumeState: true } : {}
|
|
292970
|
-
})
|
|
292971
|
-
yield* setThreadSession({
|
|
293317
|
+
}).pipe(require_Schema$1.tap(() => setThreadSession({
|
|
292972
293318
|
threadId: thread.id,
|
|
292973
293319
|
session: {
|
|
292974
293320
|
threadId: thread.id,
|
|
@@ -292980,7 +293326,14 @@ const make$8 = require_Schema$1.gen(function* () {
|
|
|
292980
293326
|
updatedAt: now
|
|
292981
293327
|
},
|
|
292982
293328
|
createdAt: now
|
|
292983
|
-
})
|
|
293329
|
+
})), require_Schema$1.catchCause((cause) => appendProviderFailureActivity({
|
|
293330
|
+
threadId: event.payload.threadId,
|
|
293331
|
+
kind: "provider.session.stop.failed",
|
|
293332
|
+
summary: "Provider session stop failed",
|
|
293333
|
+
detail: publicProviderFailureDetail(require_Schema$1.pretty(cause)),
|
|
293334
|
+
turnId: null,
|
|
293335
|
+
createdAt: now
|
|
293336
|
+
})));
|
|
292984
293337
|
});
|
|
292985
293338
|
const processDomainEvent = require_Schema$1.fn("processDomainEvent")(function* (event) {
|
|
292986
293339
|
yield* require_Schema$1.annotateCurrentSpan({
|
|
@@ -293075,7 +293428,7 @@ const make$8 = require_Schema$1.gen(function* () {
|
|
|
293075
293428
|
threadId: event.payload.threadId,
|
|
293076
293429
|
kind: "provider.turn.start.failed",
|
|
293077
293430
|
summary: "Provider turn start cleanup failed",
|
|
293078
|
-
detail:
|
|
293431
|
+
detail: publicProviderFailureDetailFromError(cause),
|
|
293079
293432
|
turnId: null,
|
|
293080
293433
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
293081
293434
|
})
|
|
@@ -298543,7 +298896,7 @@ function resolveBuildCommitFromEnv(env) {
|
|
|
298543
298896
|
* environment descriptor down instead of reporting an honest "unknown".
|
|
298544
298897
|
*/
|
|
298545
298898
|
function readBakedBuildCommit() {
|
|
298546
|
-
return "
|
|
298899
|
+
return "b06001f4e16f7a336e9108920f9250b366862f3d";
|
|
298547
298900
|
}
|
|
298548
298901
|
async function resolveServerBuildCommit(input) {
|
|
298549
298902
|
if (isFullCommitSha(input.baked)) return input.baked;
|
|
@@ -309967,6 +310320,33 @@ registerProxyRoute({
|
|
|
309967
310320
|
cmmdPath: "/api/projects/campaigns/:id",
|
|
309968
310321
|
orgIdSource: "none"
|
|
309969
310322
|
});
|
|
310323
|
+
/**
|
|
310324
|
+
* Apple App Store guideline 5.1.1(v): an app that supports account creation
|
|
310325
|
+
* or sign-in must let the user start account deletion from inside the app.
|
|
310326
|
+
* CMMD owns the account, so this proxies to its existing deactivation route.
|
|
310327
|
+
*
|
|
310328
|
+
* `cmmdPath` is `/api/settings/delete-account`, not a `/api/forge/context/*`
|
|
310329
|
+
* route: CMMD never built a forge-context-scoped deletion endpoint. It is
|
|
310330
|
+
* still reachable through the same owner JWT this gateway already resolves
|
|
310331
|
+
* per session: CMMD's `optionalJwtAuth` runs ahead of every `/api/*` route
|
|
310332
|
+
* (not only forge-context ones), so the same Bearer that reaches
|
|
310333
|
+
* `/api/cmmd/bootstrap` also authenticates here.
|
|
310334
|
+
*
|
|
310335
|
+
* CMMD's route soft-deletes: it flips the user to `active: false` and
|
|
310336
|
+
* `lifecycleState: 'deactivated'`, revokes CMMD's own refresh tokens, and
|
|
310337
|
+
* destroys its session. It does not purge data on this call. The Forge
|
|
310338
|
+
* client is responsible for the rest: revoking the Forge session
|
|
310339
|
+
* (`/api/auth/logout`) and clearing local state, the same as a manual
|
|
310340
|
+
* sign-out.
|
|
310341
|
+
*/
|
|
310342
|
+
registerProxyRoute({
|
|
310343
|
+
forgePath: "/api/cmmd/settings/delete-account",
|
|
310344
|
+
method: "DELETE",
|
|
310345
|
+
cmmdPath: "/api/settings/delete-account",
|
|
310346
|
+
orgIdSource: "none",
|
|
310347
|
+
responseShape: "unwrapData",
|
|
310348
|
+
requestBody: "none"
|
|
310349
|
+
});
|
|
309970
310350
|
registerProxyRoute({
|
|
309971
310351
|
forgePath: "/api/cmmd/bootstrap",
|
|
309972
310352
|
method: "GET",
|
|
@@ -322006,7 +322386,7 @@ const PlatformServicesLive = require_Schema$1.unwrap(require_Schema$1.gen(functi
|
|
|
322006
322386
|
}));
|
|
322007
322387
|
const RuntimeReplicationLayerLive = RuntimeReplicationLive.pipe(require_Schema$1.provideMerge(RuntimeReplicationClientLive), require_Schema$1.provideMerge(RuntimeReplicationOutboxLive), require_Schema$1.provideMerge(ActiveHourMeterLive.pipe(require_Schema$1.provide$1(RuntimeReplicationOutboxLive))));
|
|
322008
322388
|
const RuntimeDrainLayerLive = RuntimeDrainReporterLive.pipe(require_Schema$1.provideMerge(RuntimeDrainStateLive));
|
|
322009
|
-
const RuntimeAwareProviderReactorsLive = require_Schema$1.mergeAll(ProviderRuntimeIngestionLive, ProviderCommandReactorLive).pipe(require_Schema$1.provide$1(RuntimeDrainLayerLive), require_Schema$1.provide$1(ClaudeUsageTelemetryLive));
|
|
322389
|
+
const RuntimeAwareProviderReactorsLive = require_Schema$1.mergeAll(ProviderRuntimeIngestionLive, ProviderCommandReactorLive).pipe(require_Schema$1.provide$1(RuntimeDrainLayerLive), require_Schema$1.provideMerge(RuntimeDrainStateLive), require_Schema$1.provide$1(ClaudeUsageTelemetryLive));
|
|
322010
322390
|
const PipelineWorkerCoordinatorLayerLive = PipelineWorkerCoordinatorLive.pipe(require_Schema$1.provideMerge(PipelineRunClientLive));
|
|
322011
322391
|
const AgentProtocolReactorLayerLive = AgentProtocolReactorLive.pipe(require_Schema$1.provideMerge(PipelineRunStoreLive));
|
|
322012
322392
|
const PipelineRunCoordinatorLayerLive = PipelineRunCoordinatorLive.pipe(require_Schema$1.provideMerge(PipelineProviderAuthorityInstallerLive), require_Schema$1.provideMerge(PipelineChangeInspectorLive), require_Schema$1.provideMerge(PipelineContextArtifactStoreLive), require_Schema$1.provideMerge(PipelineModelPolicyLive), require_Schema$1.provideMerge(PipelineRunClientLive), require_Schema$1.provideMerge(PipelineRunStoreLive), require_Schema$1.provideMerge(PipelineRunWorkspaceAllocatorLive), require_Schema$1.provideMerge(PipelineStagePolicyLive), require_Schema$1.provideMerge(PipelineWorkerCoordinatorLayerLive));
|