@cmmd-center/forge 0.10.5 → 0.10.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (22) hide show
  1. package/dist/bin.cjs +1294 -795
  2. package/dist/bin.mjs +1293 -792
  3. package/dist/client/assets/{CanvasPanel-Dr4I7MnM.js → CanvasPanel-ECmvVI7T.js} +2 -2
  4. package/dist/client/assets/{CompositeItem-Cj6_oAlz.js → CompositeItem-8hzrVacr.js} +2 -2
  5. package/dist/client/assets/{DiffPanel-CsMWXFsK.js → DiffPanel-BqOO3dsl.js} +3 -3
  6. package/dist/client/assets/{DiffPanel.logic-Cyp3p58B.js → DiffPanel.logic-Bzm8oiCr.js} +2 -2
  7. package/dist/client/assets/DiffPanelShell-DVVw1mR3.js +2531 -0
  8. package/dist/client/assets/{DiffWorkerPoolProvider-DOF7ypo1.js → DiffWorkerPoolProvider-BsMgSHbg.js} +8 -8
  9. package/dist/client/assets/{PullRequestCodePanel-BuK0wrXE.js → PullRequestCodePanel-DNrNrubs.js} +3 -3
  10. package/dist/client/assets/{Virtualizer-CQJMsfKa.js → Virtualizer-RRV_x18w.js} +2 -2
  11. package/dist/client/assets/{canvasStateStore-DncdOQ4J.js → canvasStateStore-3EN8RaUf.js} +2 -2
  12. package/dist/client/assets/{cmmdAuthRedirect-DWiMDVzN.js → cmmdAuthRedirect-DwPtzhq9.js} +2 -2
  13. package/dist/client/assets/index-D22UpSjv.css +1 -0
  14. package/dist/client/assets/{index-C6vF1RSl.js → index-DCVtRkq1.js} +56 -56
  15. package/dist/client/assets/{src-CtyKlVph.js → src-DZBONdiY.js} +2 -2
  16. package/dist/client/assets/{toggle-pTm2fPLg.js → toggle-mQ7UG7Dd.js} +2 -2
  17. package/dist/client/assets/{useTriggerFocusGuards-B4Ejoaox.js → useTriggerFocusGuards-BUEnX8xa.js} +2 -2
  18. package/dist/client/index.html +11 -11
  19. package/dist/forge-build.json +1 -1
  20. package/package.json +1 -1
  21. package/dist/client/assets/DiffPanelShell-h78vZ6dX.js +0 -2531
  22. package/dist/client/assets/index-T36rURmx.css +0 -1
package/dist/bin.mjs CHANGED
@@ -24231,6 +24231,7 @@ const UsageBucket = Struct({
24231
24231
  costSource: UsageCostSource,
24232
24232
  records: NonNegativeInt,
24233
24233
  unpricedRecords: NonNegativeInt,
24234
+ unreportedRecords: optional$4(NonNegativeInt),
24234
24235
  sessions: NonNegativeInt,
24235
24236
  runtimeId: optional$4(TrimmedNonEmptyString),
24236
24237
  origin: optional$4(UsageBucketOrigin),
@@ -65120,7 +65121,7 @@ function normalizeNumberish(value) {
65120
65121
  }
65121
65122
  //#endregion
65122
65123
  //#region package.json
65123
- var version$1 = "0.10.5";
65124
+ var version$1 = "0.10.7";
65124
65125
  //#endregion
65125
65126
  //#region src/sentry.ts
65126
65127
  const SERVER_APP_NAME = "forge-server";
@@ -67888,6 +67889,15 @@ function parsePersistedServerObservabilitySettings(raw) {
67888
67889
  * @module ServerConfig
67889
67890
  */
67890
67891
  const DEFAULT_PORT = 13773;
67892
+ /**
67893
+ * Where a managed cloud runtime keeps the user's checkouts when
67894
+ * FORGE_CLOUD_PROJECTS_ROOT is not set. CMMD seeds every sprite checkout under
67895
+ * /projects (forge-guest-layout.ts on the CMMD side) and passes that value in
67896
+ * the Service env, so this default only matters for a server started without
67897
+ * it. It used to be a path under the Fly-era mounted volume; on a sprite the
67898
+ * two repos disagreed and every local-checkout turn was refused (FOR-36484).
67899
+ */
67900
+ const DEFAULT_CLOUD_PROJECTS_ROOT = "/projects";
67891
67901
  const RuntimeMode = Literals(["web", "desktop"]);
67892
67902
  Literals(["browser", "headless"]);
67893
67903
  const deriveServerPaths = fn$1(function* (baseDir, _devUrl, _mode) {
@@ -68013,7 +68023,7 @@ var ServerConfig = class ServerConfig extends Service$1()("forge/config/ServerCo
68013
68023
  forgeCodexHomePath: void 0,
68014
68024
  forgeClaudeConfigPath: void 0,
68015
68025
  forgeApexBaseUrl: void 0,
68016
- cloudProjectsRoot: "/data/Projects",
68026
+ cloudProjectsRoot: DEFAULT_CLOUD_PROJECTS_ROOT,
68017
68027
  ...overrides
68018
68028
  };
68019
68029
  }));
@@ -70017,6 +70027,14 @@ function invalidateCachedCmmdWorkIntakeForIdentity(identityKey) {
70017
70027
  *
70018
70028
  * Bespoke routes (MCP/PAT transport, hybrid fallback, multipart) stay in
70019
70029
  * http.ts and are NOT migrated here.
70030
+ *
70031
+ * A second, narrower entry point — `registerProxyHandler` / `ProxyHandlerRoute`
70032
+ * — covers routes whose middle (request parsing, the actual gateway call,
70033
+ * success shaping) cannot be expressed by the five `ProxyRoute` fields above,
70034
+ * while still sharing the same prologue: session auth, the CMMD-connection
70035
+ * gate, and the same `buildProxyErrorResponse` error mapping plus
70036
+ * `clearUnrecoverableCmmdAuthForSession` on an auth failure. See the type doc
70037
+ * below for the exact contract.
70020
70038
  */
70021
70039
  /** Substitutes ":paramName" tokens in a path template from a params record. */
70022
70040
  function substitutePath(template, params) {
@@ -70066,6 +70084,29 @@ function buildProxyErrorResponse(error) {
70066
70084
  }
70067
70085
  return jsonUnsafe({ error: "CMMD REST request failed." }, { status: 502 });
70068
70086
  }
70087
+ /**
70088
+ * Clears every unrecoverable CMMD credential tied to this session, logging a
70089
+ * warning rather than failing the request if the clear itself errors — a
70090
+ * session that already has no usable credential must still get its 401,
70091
+ * not a 500 from a failed best-effort cleanup.
70092
+ */
70093
+ function clearCmmdAuthAfterFailure(sessionId) {
70094
+ return clearUnrecoverableCmmdAuthForSession(sessionId).pipe(catch_((error) => logWarning$1("Failed to clear unrecoverable CMMD auth after CMMD auth failure.", {
70095
+ cause: error,
70096
+ sessionId
70097
+ })));
70098
+ }
70099
+ /**
70100
+ * The single "no usable CMMD credential" response: clears whatever
70101
+ * unrecoverable auth state this session is holding, then returns the
70102
+ * canonical `CMMD_AUTH_REQUIRED` body. Every prologue path that decides the
70103
+ * session has no way to reach CMMD — a missing PAT, a JWT that fails to
70104
+ * resolve, a bespoke gate elsewhere in http.ts — emits this same response so
70105
+ * the Shell only ever has one `CMMD_AUTH_REQUIRED` body to branch on.
70106
+ */
70107
+ function respondCmmdConnectionRequired(sessionId) {
70108
+ return clearCmmdAuthAfterFailure(sessionId).pipe(as$3(buildProxyErrorResponse(new CmmdProxyAuthenticationRequiredError("CMMD connection required. Reconnect CMMD to continue."))));
70109
+ }
70069
70110
  async function dispatchToProxy(method, jwt, cmmdPath, rawBody, orgId, searchParams) {
70070
70111
  return cmmdGateway.request({
70071
70112
  method,
@@ -70096,12 +70137,27 @@ function buildProxySearchParams(input) {
70096
70137
  return Object.keys(result).length > 0 ? result : void 0;
70097
70138
  }
70098
70139
  const _registeredRoutes = [];
70099
- /**
70100
- * Generates an Effect HttpRouter layer for the given route.
70101
- * The returned layer registers one handler at forgePath.
70102
- */
70103
- function registerProxyRoute(route) {
70104
- _registeredRoutes.push(route);
70140
+ const _registeredLayers = [];
70141
+ /**
70142
+ * Layers produced by every registerProxyRoute call so far, in registration
70143
+ * order. Callers that want only the routes registered by their own module
70144
+ * should snapshot `.length` before their own registerProxyRoute calls run and
70145
+ * slice from that index — see command/http.ts's `cmmdProxyRouteLayers`.
70146
+ *
70147
+ * Typed via `ReturnType<typeof buildProxyRouteLayer>` (not `HttpRouter.add`
70148
+ * directly, and not `registerProxyRoute` itself — that would be circular
70149
+ * since registerProxyRoute pushes onto this same array): `buildProxyRouteLayer`
70150
+ * takes a concrete, non-generic `ProxyRoute` argument and never references
70151
+ * this array, so its return type is fully resolved independently. Referencing
70152
+ * the generic `HttpRouter.add` on its own instead collapses its unresolved E/R
70153
+ * type parameters to `unknown`, which then leaks into makeRoutesLayer's
70154
+ * requirements channel everywhere this array is spread.
70155
+ */
70156
+ function registeredProxyRouteLayers() {
70157
+ return Object.freeze([..._registeredLayers]);
70158
+ }
70159
+ /** Builds the Effect HttpRouter layer for one route, with no registry side effects. */
70160
+ function buildProxyRouteLayer(route) {
70105
70161
  const handler = gen(function* () {
70106
70162
  const req = yield* HttpServerRequest;
70107
70163
  const session = yield* (yield* ServerAuth).authenticateHttpRequest(req);
@@ -70124,23 +70180,14 @@ function registerProxyRoute(route) {
70124
70180
  forceRefresh
70125
70181
  });
70126
70182
  const jwt = yield* resolveJwt();
70127
- if (!jwt) {
70128
- yield* clearUnrecoverableCmmdAuthForSession(session.sessionId).pipe(catch_((error) => logWarning$1("Failed to clear unrecoverable CMMD auth after missing JWT.", {
70129
- cause: error,
70130
- sessionId: session.sessionId
70131
- })));
70132
- return buildProxyErrorResponse(new CmmdProxyAuthenticationRequiredError("CMMD connection required. Reconnect CMMD to continue."));
70133
- }
70183
+ if (!jwt) return yield* respondCmmdConnectionRequired(session.sessionId);
70134
70184
  let outcome = yield* promise(() => runProxy(() => dispatchToProxy(route.method, jwt, cmmdPath, rawBody, orgId, searchParams)));
70135
70185
  if (!outcome.ok && outcome.error instanceof CmmdProxyAuthError) {
70136
70186
  const refreshedJwt = yield* resolveJwt(true);
70137
70187
  if (refreshedJwt && refreshedJwt !== jwt) outcome = yield* promise(() => runProxy(() => dispatchToProxy(route.method, refreshedJwt, cmmdPath, rawBody, orgId, searchParams)));
70138
70188
  }
70139
70189
  if (!outcome.ok) {
70140
- if (outcome.error instanceof CmmdProxyAuthError || outcome.error instanceof CmmdProxyAuthenticationRequiredError) yield* clearUnrecoverableCmmdAuthForSession(session.sessionId).pipe(catch_((error) => logWarning$1("Failed to clear unrecoverable CMMD auth after REST 401.", {
70141
- cause: error,
70142
- sessionId: session.sessionId
70143
- })));
70190
+ if (outcome.error instanceof CmmdProxyAuthError || outcome.error instanceof CmmdProxyAuthenticationRequiredError) yield* clearCmmdAuthAfterFailure(session.sessionId);
70144
70191
  return buildProxyErrorResponse(outcome.error);
70145
70192
  }
70146
70193
  const payload = route.responseShape === "passthrough" ? outcome.value : unwrapEnvelope$1(outcome.value);
@@ -70150,6 +70197,59 @@ function registerProxyRoute(route) {
70150
70197
  }).pipe(catchTag("AuthError", (error) => respondToAuthError(error)));
70151
70198
  return add$1(route.method, route.forgePath, handler);
70152
70199
  }
70200
+ /**
70201
+ * Generates an Effect HttpRouter layer for the given route and records it in
70202
+ * the registry (for auditing / tests, and so command/http.ts's
70203
+ * `cmmdProxyRouteLayers` can pick it up). The returned layer registers one
70204
+ * handler at forgePath.
70205
+ */
70206
+ function registerProxyRoute(route) {
70207
+ _registeredRoutes.push(route);
70208
+ const layer = buildProxyRouteLayer(route);
70209
+ _registeredLayers.push(layer);
70210
+ return layer;
70211
+ }
70212
+ /**
70213
+ * Builds the bare handler Effect for one handler route (no `HttpRouter.add`
70214
+ * wrapping, no registry side effects) — exposed on its own so tests can
70215
+ * exercise it the same way they exercise every other bespoke handler in
70216
+ * http.ts: providing `HttpServerRequest` / `ServerAuth` directly and running
70217
+ * the Effect, without standing up a router.
70218
+ */
70219
+ function buildProxyHandlerEffect(route) {
70220
+ return gen(function* () {
70221
+ const req = yield* HttpServerRequest;
70222
+ const session = yield* (yield* ServerAuth).authenticateHttpRequest(req);
70223
+ if (!readCommandAccessTokenForSession(session.sessionId)) return yield* respondCmmdConnectionRequired(session.sessionId);
70224
+ const parsed = yield* route.parse(req);
70225
+ if (!parsed.ok) return jsonUnsafe(parsed.body, { status: parsed.status });
70226
+ const result$4 = yield* route.run(parsed.value, { session }).pipe(result);
70227
+ if (isFailure$1(result$4)) {
70228
+ const error = result$4.failure;
70229
+ if (error instanceof CmmdProxyAuthError || error instanceof CmmdProxyAuthenticationRequiredError) yield* clearCmmdAuthAfterFailure(session.sessionId);
70230
+ return buildProxyErrorResponse(error);
70231
+ }
70232
+ return jsonUnsafe(result$4.success.body, { status: result$4.success.status });
70233
+ }).pipe(catchTag("AuthError", (error) => respondToAuthError(error)));
70234
+ }
70235
+ const _registeredHandlerRoutes = [];
70236
+ /**
70237
+ * Builds the handler Effect for one route, mounts it via `HttpRouter.add` and
70238
+ * records that layer in the same registry `registerProxyRoute` uses (so
70239
+ * command/http.ts's `cmmdProxyRouteLayers` picks it up without a separate
70240
+ * mount list) — then returns the bare handler Effect rather than the layer,
70241
+ * so the caller can keep a single `__xHandlerForTests`-style export that
70242
+ * doubles as both the thing under test and the thing that gets mounted.
70243
+ */
70244
+ function registerProxyHandler(route) {
70245
+ _registeredHandlerRoutes.push({
70246
+ method: route.method,
70247
+ forgePath: route.forgePath
70248
+ });
70249
+ const handler = buildProxyHandlerEffect(route);
70250
+ _registeredLayers.push(add$1(route.method, route.forgePath, handler));
70251
+ return handler;
70252
+ }
70153
70253
  //#endregion
70154
70254
  //#region src/connect/credentialRefresh.ts
70155
70255
  async function refreshConnectCredential(deps) {
@@ -92262,6 +92362,172 @@ function classifyRuntimeReplicationHttpFailure(failure) {
92262
92362
  };
92263
92363
  }
92264
92364
  //#endregion
92365
+ //#region src/runtimeReplication/runtimeLane.ts
92366
+ /**
92367
+ * Read a grant-lane response the way the gateway reads an owner-lane one: a
92368
+ * non-2xx becomes a `CmmdProxyRequestError` carrying the status and CMMD's
92369
+ * error code, so a caller can classify either lane's failure with one rule.
92370
+ */
92371
+ async function parseRuntimeLaneResponse(response) {
92372
+ const text = await response.text();
92373
+ let body = null;
92374
+ if (text) try {
92375
+ body = JSON.parse(text);
92376
+ } catch {
92377
+ body = null;
92378
+ }
92379
+ if (!response.ok) {
92380
+ const code = readRuntimeReplicationErrorCode(body);
92381
+ throw new CmmdProxyRequestError(`CMMD runtime replication failed (${response.status})`, response.status, null, code ? { code } : null);
92382
+ }
92383
+ if (body === null) throw new Error("CMMD runtime replication returned an empty or invalid JSON response.");
92384
+ return body;
92385
+ }
92386
+ /**
92387
+ * One request on whichever lane the runtime holds. The caller has already
92388
+ * built the path for `lane.kind`; this only decides the transport and the
92389
+ * credential header, and normalises failures to the gateway's error classes.
92390
+ */
92391
+ async function requestOnRuntimeLane(lane, request, transport = {}) {
92392
+ if (lane.kind === "owner-session") return (transport.gateway ?? cmmdGateway).request({
92393
+ method: request.method,
92394
+ jwt: lane.jwt,
92395
+ path: request.path,
92396
+ ...request.body === void 0 ? {} : { body: request.body }
92397
+ });
92398
+ return parseRuntimeLaneResponse(await (transport.fetchImpl ?? fetch)(new URL(request.path, `${lane.controlPlaneUrl}/`), {
92399
+ method: request.method,
92400
+ headers: {
92401
+ authorization: `Bearer ${lane.grantToken}`,
92402
+ accept: "application/json",
92403
+ ...request.body === void 0 ? {} : { "content-type": "application/json" }
92404
+ },
92405
+ ...request.body === void 0 ? {} : { body: JSON.stringify(request.body) },
92406
+ ...request.signal === void 0 ? {} : { signal: request.signal }
92407
+ }));
92408
+ }
92409
+ function mapRuntimeReplicationClientError(error, operation) {
92410
+ if (error instanceof CmmdProxyAuthError) return new RuntimeReplicationClientError({
92411
+ kind: "auth",
92412
+ code: "CMMD_AUTH_REQUIRED",
92413
+ detail: error.message
92414
+ });
92415
+ if (error instanceof CmmdProxyAuthenticationRequiredError) return new RuntimeReplicationClientError({
92416
+ kind: "auth",
92417
+ code: "CMMD_AUTH_REQUIRED",
92418
+ detail: error.message
92419
+ });
92420
+ if (error instanceof CmmdProxyPermissionError) return new RuntimeReplicationClientError({
92421
+ kind: "permanent",
92422
+ code: "CMMD_PERMISSION_DENIED",
92423
+ detail: error.message
92424
+ });
92425
+ if (error instanceof CmmdProxyRequestError) return new RuntimeReplicationClientError(classifyRuntimeReplicationHttpFailure({
92426
+ status: error.status,
92427
+ body: error.body,
92428
+ detail: error.detail ?? error.message,
92429
+ ...operation ? { operation } : {}
92430
+ }));
92431
+ return new RuntimeReplicationClientError({
92432
+ kind: "retryable",
92433
+ code: "CMMD_UNAVAILABLE",
92434
+ detail: error instanceof Error ? error.message : String(error)
92435
+ });
92436
+ }
92437
+ //#endregion
92438
+ //#region src/runtimeReplication/lifecycleIntentClient.ts
92439
+ /**
92440
+ * The runtime half of a lifecycle intent: a settle or un-settle a person asked
92441
+ * for while this runtime was offline, held by CMMD until the runtime lists it,
92442
+ * applies it through its own orchestration, and acknowledges it.
92443
+ *
92444
+ * Both lanes carry the same envelope (pinned equal in the contracts package),
92445
+ * so one client serves the desktop's owner-session lane and the cloud
92446
+ * runtime's grant lane; only the path family differs.
92447
+ */
92448
+ const LIFECYCLE_INTENT_TIMEOUT = "10 seconds";
92449
+ const LifecycleIntentListEnvelope = Struct({ data: Struct({ intents: ArraySchema(Struct({
92450
+ runtimeId: String$1,
92451
+ threadId: String$1,
92452
+ action: Literals(["settle", "unsettle"]),
92453
+ requestedAt: String$1
92454
+ })) }) });
92455
+ const LifecycleIntentAcknowledgementEnvelope = Struct({ data: Struct({ acknowledged: Number$1 }) });
92456
+ const decodeListEnvelope = decodeUnknownSync(LifecycleIntentListEnvelope);
92457
+ const decodeAcknowledgementEnvelope = decodeUnknownSync(LifecycleIntentAcknowledgementEnvelope);
92458
+ function decodeLifecycleIntentListResponse(response) {
92459
+ return decodeListEnvelope(response).data;
92460
+ }
92461
+ function decodeLifecycleIntentAcknowledgementResponse(response) {
92462
+ return decodeAcknowledgementEnvelope(response).data;
92463
+ }
92464
+ /**
92465
+ * Ids arrive from runtime rows, not constrained to path-safe characters, so
92466
+ * they are encoded the way every other runtime-lane path builder encodes them.
92467
+ */
92468
+ function lifecycleIntentPath(lane, operation) {
92469
+ const base = `/api/forge/context/${lane.kind === "grant" ? "runtime-replication" : "devices"}/runtimes/${encodeURIComponent(lane.runtimeId)}/thread-lifecycle-intents`;
92470
+ return operation === "ack" ? `${base}/ack` : base;
92471
+ }
92472
+ function timedOut(operation) {
92473
+ return new RuntimeReplicationClientError({
92474
+ kind: "retryable",
92475
+ code: "CMMD_TIMEOUT",
92476
+ detail: `CMMD lifecycle intent ${operation} timed out.`
92477
+ });
92478
+ }
92479
+ function decodeOrFail(response, decode, label) {
92480
+ return try_({
92481
+ try: () => decode(response),
92482
+ catch: (cause) => new RuntimeReplicationClientError({
92483
+ kind: "permanent",
92484
+ code: "CMMD_PROTOCOL_INVALID_RESPONSE",
92485
+ detail: `CMMD returned an invalid lifecycle intent ${label}: ${cause instanceof Error ? cause.message : String(cause)}`
92486
+ })
92487
+ });
92488
+ }
92489
+ /**
92490
+ * Every pending intent for this runtime, or an empty list.
92491
+ *
92492
+ * 404 is an ordinary answer, not a failure: a CMMD that predates the route
92493
+ * has nothing pending for anyone, and a runtime it has not registered yet has
92494
+ * nothing pending either. Every other non-2xx is a typed error -- a signed-out
92495
+ * owner (auth) is the caller's to skip, an outage is the next tick's to retry.
92496
+ */
92497
+ function listPendingLifecycleIntents(lane, transport) {
92498
+ return tryPromise({
92499
+ try: (signal) => requestOnRuntimeLane(lane, {
92500
+ method: "GET",
92501
+ path: lifecycleIntentPath(lane, "list"),
92502
+ signal
92503
+ }, transport),
92504
+ catch: (cause) => cause instanceof CmmdProxyRequestError && cause.status === 404 ? null : mapRuntimeReplicationClientError(cause)
92505
+ }).pipe(catch_((cause) => cause === null ? succeed(null) : fail(cause)), flatMap((response) => response === null ? succeed([]) : decodeOrFail(response, decodeLifecycleIntentListResponse, "list").pipe(map$3((list) => list.intents))), timeoutOrElse({
92506
+ duration: LIFECYCLE_INTENT_TIMEOUT,
92507
+ orElse: () => fail(timedOut("list"))
92508
+ }));
92509
+ }
92510
+ /**
92511
+ * Tell CMMD which intents were applied (or deliberately skipped), by thread
92512
+ * and requested time. CMMD drops only an intent whose requested time matches,
92513
+ * so a newer request recorded while this one was being applied survives.
92514
+ */
92515
+ function acknowledgeLifecycleIntents(lane, intents, transport) {
92516
+ const body = { intents };
92517
+ return tryPromise({
92518
+ try: (signal) => requestOnRuntimeLane(lane, {
92519
+ method: "POST",
92520
+ path: lifecycleIntentPath(lane, "ack"),
92521
+ body,
92522
+ signal
92523
+ }, transport),
92524
+ catch: mapRuntimeReplicationClientError
92525
+ }).pipe(flatMap((response) => decodeOrFail(response, decodeLifecycleIntentAcknowledgementResponse, "acknowledgement")), timeoutOrElse({
92526
+ duration: LIFECYCLE_INTENT_TIMEOUT,
92527
+ orElse: () => fail(timedOut("ack"))
92528
+ }));
92529
+ }
92530
+ //#endregion
92265
92531
  //#region src/runtimeReplication/runtimeReplicationGrantPolicy.ts
92266
92532
  /**
92267
92533
  * Chooses which CMMD grant a replication send should use: the in-memory
@@ -92357,26 +92623,11 @@ function runtimeReplicationDevicePath(input) {
92357
92623
  const threadId = input.streamKey.slice(7);
92358
92624
  return `${devicePath}/threads/${encodeURIComponent(threadId)}/events`;
92359
92625
  }
92360
- async function parseRuntimeReplicationResponse(response) {
92361
- const text = await response.text();
92362
- let body = null;
92363
- if (text) try {
92364
- body = JSON.parse(text);
92365
- } catch {
92366
- body = null;
92367
- }
92368
- if (!response.ok) {
92369
- const code = readRuntimeReplicationErrorCode(body);
92370
- throw new CmmdProxyRequestError(`CMMD runtime replication failed (${response.status})`, response.status, null, code ? { code } : null);
92371
- }
92372
- if (body === null) throw new Error("CMMD runtime replication returned an empty or invalid JSON response.");
92373
- return body;
92374
- }
92375
92626
  async function requestRuntimeReplicationWithGrant(input, fetchImpl = fetch) {
92376
92627
  const abortController = new AbortController();
92377
92628
  const timeout = setTimeout(() => abortController.abort(), RUNTIME_REPLICATION_TIMEOUT_MS);
92378
92629
  try {
92379
- return await parseRuntimeReplicationResponse(await fetchImpl(new URL(runtimeReplicationGrantPath(input), `${input.controlPlaneUrl}/`), {
92630
+ return await parseRuntimeLaneResponse(await fetchImpl(new URL(runtimeReplicationGrantPath(input), `${input.controlPlaneUrl}/`), {
92380
92631
  method: input.operation === "inventory" ? "PUT" : "POST",
92381
92632
  headers: {
92382
92633
  authorization: `Bearer ${input.grantToken}`,
@@ -92389,34 +92640,6 @@ async function requestRuntimeReplicationWithGrant(input, fetchImpl = fetch) {
92389
92640
  clearTimeout(timeout);
92390
92641
  }
92391
92642
  }
92392
- function mapRuntimeReplicationClientError(error, operation) {
92393
- if (error instanceof CmmdProxyAuthError) return new RuntimeReplicationClientError({
92394
- kind: "auth",
92395
- code: "CMMD_AUTH_REQUIRED",
92396
- detail: error.message
92397
- });
92398
- if (error instanceof CmmdProxyAuthenticationRequiredError) return new RuntimeReplicationClientError({
92399
- kind: "auth",
92400
- code: "CMMD_AUTH_REQUIRED",
92401
- detail: error.message
92402
- });
92403
- if (error instanceof CmmdProxyPermissionError) return new RuntimeReplicationClientError({
92404
- kind: "permanent",
92405
- code: "CMMD_PERMISSION_DENIED",
92406
- detail: error.message
92407
- });
92408
- if (error instanceof CmmdProxyRequestError) return new RuntimeReplicationClientError(classifyRuntimeReplicationHttpFailure({
92409
- status: error.status,
92410
- body: error.body,
92411
- detail: error.detail ?? error.message,
92412
- ...operation ? { operation } : {}
92413
- }));
92414
- return new RuntimeReplicationClientError({
92415
- kind: "retryable",
92416
- code: "CMMD_UNAVAILABLE",
92417
- detail: error instanceof Error ? error.message : String(error)
92418
- });
92419
- }
92420
92643
  function decodeRuntimeThreadAcknowledgementResponse(response) {
92421
92644
  return decodeThreadAcknowledgement(response).data.acknowledgement;
92422
92645
  }
@@ -92492,9 +92715,12 @@ function replicateWithOwnerSession(sql, input) {
92492
92715
  const jwt = owner.jwt;
92493
92716
  const path = runtimeReplicationDevicePath(input);
92494
92717
  const response = yield* tryPromise({
92495
- try: () => cmmdGateway.request({
92718
+ try: () => requestOnRuntimeLane({
92719
+ kind: "owner-session",
92720
+ runtimeId: input.runtimeId,
92721
+ jwt
92722
+ }, {
92496
92723
  method: input.operation === "inventory" ? "PUT" : "POST",
92497
- jwt,
92498
92724
  path,
92499
92725
  body: input.payload
92500
92726
  }),
@@ -92505,11 +92731,63 @@ function replicateWithOwnerSession(sql, input) {
92505
92731
  return yield* decodeAcknowledgementOrFail(response, decodeRuntimeThreadAcknowledgementResponse, "transcript");
92506
92732
  });
92507
92733
  }
92734
+ /**
92735
+ * The lane this runtime holds right now, resolved per call because both
92736
+ * credentials rotate: the cloud grant is re-read from the control authority,
92737
+ * and the owner session is whichever sign-in is newest on this desktop.
92738
+ */
92739
+ function resolveRuntimeLane(config, sql, input) {
92740
+ return gen(function* () {
92741
+ if (config.forgeCmmdRuntimeMode === true) {
92742
+ const cloudGrant = resolveCloudRuntimeReplicationGrant(config);
92743
+ if (!cloudGrant) return yield* new RuntimeReplicationClientError({
92744
+ kind: "auth",
92745
+ code: "CMMD_RUNTIME_GRANT_REQUIRED",
92746
+ detail: "Cloud runtime replication requires a canonical runtime ID, CMMD URL, and scoped runtime grant."
92747
+ });
92748
+ if (input.runtimeId !== cloudGrant.runtimeId) return yield* new RuntimeReplicationClientError({
92749
+ kind: "permanent",
92750
+ code: "CMMD_RUNTIME_ID_MISMATCH",
92751
+ detail: "The requested runtime does not match this cloud runtime identity."
92752
+ });
92753
+ return {
92754
+ kind: "grant",
92755
+ controlPlaneUrl: cloudGrant.controlPlaneUrl,
92756
+ runtimeId: cloudGrant.runtimeId,
92757
+ grantToken: cloudGrant.grantToken
92758
+ };
92759
+ }
92760
+ const owner = yield* resolveCmmdOwnerSessionCredential(sql, { logPrefix: input.logPrefix });
92761
+ if (owner.kind === "no-session") return yield* new RuntimeReplicationClientError({
92762
+ kind: "auth",
92763
+ code: "CMMD_AUTH_REQUIRED",
92764
+ detail: "CMMD sign-in is required for runtime replication."
92765
+ });
92766
+ if (owner.kind === "no-credential") return yield* new RuntimeReplicationClientError({
92767
+ kind: "auth",
92768
+ code: "CMMD_AUTH_REQUIRED",
92769
+ detail: "CMMD REST credentials are unavailable for runtime replication."
92770
+ });
92771
+ return {
92772
+ kind: "owner-session",
92773
+ runtimeId: input.runtimeId,
92774
+ jwt: owner.jwt
92775
+ };
92776
+ });
92777
+ }
92508
92778
  const RuntimeReplicationClientLive = effect(RuntimeReplicationClient, gen(function* () {
92509
92779
  const sql = yield* SqlClient;
92510
92780
  const config = yield* ServerConfig;
92511
92781
  const send = (input) => config.forgeCmmdRuntimeMode === true ? replicateWithRuntimeGrant(config, input) : replicateWithOwnerSession(sql, input);
92512
- return RuntimeReplicationClient.of({ send });
92782
+ const lane = (runtimeId) => resolveRuntimeLane(config, sql, {
92783
+ runtimeId,
92784
+ logPrefix: "lifecycle-intents"
92785
+ });
92786
+ return RuntimeReplicationClient.of({
92787
+ send,
92788
+ listPendingLifecycleIntents: ({ runtimeId }) => lane(runtimeId).pipe(flatMap((l) => listPendingLifecycleIntents(l))),
92789
+ acknowledgeLifecycleIntents: ({ runtimeId, intents }) => lane(runtimeId).pipe(flatMap((l) => acknowledgeLifecycleIntents(l, intents)))
92790
+ });
92513
92791
  }));
92514
92792
  //#endregion
92515
92793
  //#region src/runtimeReplication/Services/RuntimeReplicationOutbox.ts
@@ -92827,6 +93105,14 @@ function stableReplicaDigest(...values) {
92827
93105
  function replicaHydrationCommandId(runtimeId, generationId, threadId) {
92828
93106
  return CommandId.make("runtime-replica-hydration:" + stableReplicaDigest(runtimeId, generationId, threadId));
92829
93107
  }
93108
+ /**
93109
+ * One id per (runtime, thread, requested time): a restart between dispatch and
93110
+ * acknowledgement re-lists the same intent, and the engine's command receipts
93111
+ * turn the second dispatch into a no-op instead of a second settle.
93112
+ */
93113
+ function lifecycleIntentCommandId(runtimeId, threadId, requestedAt) {
93114
+ return CommandId.make("lifecycle-intent:" + stableReplicaDigest(runtimeId, threadId, requestedAt));
93115
+ }
92830
93116
  //#endregion
92831
93117
  //#region src/runtimeReplication/protocol.ts
92832
93118
  const EMPTY_RUNTIME_THREAD_HEAD_HASH = "sha256:47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU";
@@ -93776,6 +94062,21 @@ function totalTokens(totals) {
93776
94062
  return totals.uncachedInputTokens + totals.cachedInputTokens + totals.cacheCreationTokens + totals.outputTokens;
93777
94063
  }
93778
94064
  /**
94065
+ * What a transcript record's own on-disk facts say it is a row of.
94066
+ *
94067
+ * Reuses exactly the facts `usageDrivers.ts`'s `isForgeAgent` reads to route a
94068
+ * record to the Forge agents lane, minus the "is this one of this
94069
+ * environment's own threads" gate: a Claude sidechain or a Codex subagent
94070
+ * rollout is a Subagent row regardless of which thread (if any) it hangs
94071
+ * under, so a subagent driven from outside Forge is still `subagent`, not a
94072
+ * plain Recorded-turn-shaped `turn`. Exported so the scan cache can recompute
94073
+ * the same value on decode instead of storing it as a redundant column.
94074
+ */
94075
+ function transcriptRecordKind(provider, sidechain, rootSessionId) {
94076
+ if (provider === "claude") return sidechain === true ? "subagent" : "turn";
94077
+ return rootSessionId !== void 0 ? "subagent" : "turn";
94078
+ }
94079
+ /**
93779
94080
  * Cheap substring gate applied before `JSON.parse`.
93780
94081
  *
93781
94082
  * Transcripts are mostly tool output; only a minority of lines carry usage. On
@@ -93844,6 +94145,7 @@ function parseClaudeLine(line, diagnostics) {
93844
94145
  const dedupeKey = claudeDedupeKey(stringAt(messageRecord, "id"), stringAt(record, "requestId"));
93845
94146
  const cost = record["costUSD"];
93846
94147
  const launcher = stringAt(record, "entrypoint");
94148
+ const sidechain = record["isSidechain"] === true;
93847
94149
  return {
93848
94150
  provider: "claude",
93849
94151
  timestampMs,
@@ -93852,8 +94154,9 @@ function parseClaudeLine(line, diagnostics) {
93852
94154
  totals: claudeTokenBuckets(usageRecord) ?? EMPTY_TOTALS,
93853
94155
  reportedCostUsd: typeof cost === "number" && Number.isFinite(cost) ? cost : null,
93854
94156
  dedupeKey,
94157
+ kind: transcriptRecordKind("claude", sidechain, void 0),
93855
94158
  ...launcher === null ? {} : { launcher },
93856
- ...record["isSidechain"] === true ? { sidechain: true } : {}
94159
+ ...sidechain ? { sidechain: true } : {}
93857
94160
  };
93858
94161
  }
93859
94162
  function initialCodexScanState() {
@@ -93970,6 +94273,7 @@ function parseCodexTokenCount(record, payloadRecord, state) {
93970
94273
  totals,
93971
94274
  reportedCostUsd: null,
93972
94275
  dedupeKey: null,
94276
+ kind: transcriptRecordKind("codex", void 0, state.rootSessionId),
93973
94277
  ...codexSessionFields(state)
93974
94278
  };
93975
94279
  }
@@ -94238,7 +94542,8 @@ var UsageAggregator = class {
94238
94542
  origin,
94239
94543
  sync,
94240
94544
  runtimeId,
94241
- driver
94545
+ driver,
94546
+ record.kind
94242
94547
  ].join("\0");
94243
94548
  const existing = this.#buckets.get(key);
94244
94549
  if (existing !== void 0) return existing;
@@ -94276,7 +94581,7 @@ var UsageAggregator = class {
94276
94581
  finish() {
94277
94582
  const buckets = [];
94278
94583
  for (const [key, bucket] of this.#buckets) {
94279
- const [day = "", hourStart = "", provider = "", model = "", origin = "", sync = "", runtimeId = "", driver = ""] = key.split("\0");
94584
+ const [day = "", hourStart = "", provider = "", model = "", origin = "", sync = "", runtimeId = "", driver = "", kind = ""] = key.split("\0");
94280
94585
  buckets.push({
94281
94586
  day,
94282
94587
  ...hourStart === "" ? {} : { hourStart },
@@ -94292,10 +94597,15 @@ var UsageAggregator = class {
94292
94597
  origin,
94293
94598
  ...sync === "" ? {} : { sync },
94294
94599
  ...runtimeId === "" ? {} : { runtimeId },
94295
- ...driver === "" ? {} : { driver }
94600
+ ...driver === "" ? {} : { driver },
94601
+ kind
94296
94602
  });
94297
94603
  }
94298
- buckets.sort((a, b) => bucketSortKey(a).localeCompare(bucketSortKey(b)));
94604
+ buckets.sort((a, b) => {
94605
+ const left = bucketSortKey(a);
94606
+ const right = bucketSortKey(b);
94607
+ return left < right ? -1 : left > right ? 1 : 0;
94608
+ });
94299
94609
  return {
94300
94610
  buckets,
94301
94611
  duplicatesDropped: this.#duplicatesDropped,
@@ -94313,7 +94623,8 @@ function bucketSortKey(bucket) {
94313
94623
  bucket.origin ?? "",
94314
94624
  bucket.sync ?? "",
94315
94625
  bucket.runtimeId ?? "",
94316
- bucket.driver ?? ""
94626
+ bucket.driver ?? "",
94627
+ bucket.kind ?? ""
94317
94628
  ].join("\0");
94318
94629
  }
94319
94630
  /**
@@ -95302,6 +95613,7 @@ function syncOf(sequence, options, threadId, events) {
95302
95613
  return sequence <= cursor.acknowledgedSequence ? "acknowledged" : "pending";
95303
95614
  }
95304
95615
  function recordOf(event, provider, sync, threadId, runtimeId) {
95616
+ const kind = event.usageKind ?? "turn";
95305
95617
  return {
95306
95618
  provider,
95307
95619
  timestampMs: Date.parse(event.occurredAt),
@@ -95310,6 +95622,7 @@ function recordOf(event, provider, sync, threadId, runtimeId) {
95310
95622
  totals: event.usage ?? EMPTY_TOTALS,
95311
95623
  reportedCostUsd: null,
95312
95624
  dedupeKey: `recorded:${threadId}:${event.turnId}:${event.usageKind ?? "turn"}:${event.subagentId ?? ""}:${event.model}`,
95625
+ kind,
95313
95626
  origin: "recorded",
95314
95627
  ...sync === void 0 ? {} : { sync },
95315
95628
  ...runtimeId === void 0 ? {} : { runtimeId },
@@ -96030,6 +96343,22 @@ async function readTranscriptRecords(filePath, provider) {
96030
96343
  //#endregion
96031
96344
  //#region src/usage/usageScanCache.ts
96032
96345
  /**
96346
+ * Durable per-file scan cache.
96347
+ *
96348
+ * Transcripts are append-only and a file that has not changed can never yield
96349
+ * different usage, so parsed records are keyed by `(size, mtime)` and reused.
96350
+ * Without this every server restart re-parses the whole window: seconds for a
96351
+ * 30-day scan, against milliseconds to reload this cache.
96352
+ *
96353
+ * Caching *per file* rather than per day is deliberate. It is timezone
96354
+ * independent, so changing the reporting zone does not invalidate anything, and
96355
+ * it keeps cross-file de-duplication exact: cached entries are de-duplicated
96356
+ * within their own file only, and the aggregator still applies the global
96357
+ * dedupe pass over the small surviving key set.
96358
+ *
96359
+ * @module usageScanCache
96360
+ */
96361
+ /**
96033
96362
  * Bumped whenever cached records could differ from what a fresh parse produces.
96034
96363
  *
96035
96364
  * Version 1 was written before `parseCodexLine` suppressed the parent history a
@@ -96175,6 +96504,7 @@ function decodeRecord(row, provider, tables) {
96175
96504
  },
96176
96505
  reportedCostUsd: finiteNumber(reportedCostUsd),
96177
96506
  dedupeKey: typeof dedupeKey === "string" ? dedupeKey : null,
96507
+ kind: transcriptRecordKind(provider, session.sidechain, session.rootSessionId),
96178
96508
  ...session
96179
96509
  };
96180
96510
  }
@@ -97138,7 +97468,7 @@ const resolveAutoBootstrapWelcomeTargets = gen(function* () {
97138
97468
  /**
97139
97469
  * Cloud-mode project recovery — runs only on cloud execution runtimes.
97140
97470
  * Scans `cloudProjectsRoot` (default
97141
- * /data/Projects) for git-repo subdirectories and registers any not yet in
97471
+ * /projects) for git-repo subdirectories and registers any not yet in
97142
97472
  * the orchestration engine. This is the cloud-mode replacement for the
97143
97473
  * gated `autoBootstrapProjectFromCwd` path: managed runtimes whose volume
97144
97474
  * already holds cloned repos surface them in the sidebar after restart.
@@ -99142,144 +99472,6 @@ function claudeWriteToken(env = process.env) {
99142
99472
  return accessor.read(env);
99143
99473
  }
99144
99474
  //#endregion
99145
- //#region src/usage/providerRateLimits.ts
99146
- /**
99147
- * In-process cache of the latest Claude 5h/7d rate-limit telemetry, decoded
99148
- * from the genuine Claude Agent SDK's own `rate_limit_event` messages
99149
- * (see ClaudeAdapter.ts). This is intentionally NOT a CMMD call site: CMMD
99150
- * must never replay a personal Claude OAuth token against api.anthropic.com
99151
- * from its own backend (see CMMD's personal-claude-delivery.ts) - the only
99152
- * legitimate source for this data is the real in-VM SDK session reporting it
99153
- * as a side effect of a real turn.
99154
- *
99155
- * Snapshots are fenced by the exact non-secret credential-generation hash.
99156
- * A Forge process can outlive an account reconnect, so a process-wide singleton
99157
- * without that fence can leak account A's windows into account B's session.
99158
- * The request-scoped route that reads this
99159
- * cache (apps/server/src/command/http.ts) is what actually forwards it to
99160
- * CMMD, using the request's own authenticated session - a background event
99161
- * pipeline has no such session to reuse safely.
99162
- */
99163
- /**
99164
- * The SDK only ever reports ONE window per event. Only `five_hour` and
99165
- * `seven_day` map to the two windows the Usage page shows; the
99166
- * per-model/overage variants (seven_day_opus, overage, ...) are ignored here
99167
- * on purpose rather than silently overwriting the plain 7-day figure.
99168
- */
99169
- function mapClaudeRateLimitInfo(info) {
99170
- if (typeof info.utilization !== "number" || typeof info.resetsAt !== "number" || !info.status) return null;
99171
- const kind = info.rateLimitType === "five_hour" ? "fiveHour" : info.rateLimitType === "seven_day" ? "sevenDay" : null;
99172
- if (!kind) return null;
99173
- return {
99174
- kind,
99175
- window: {
99176
- usedPercent: Math.round(info.utilization * 100),
99177
- resetsAt: (/* @__PURE__ */ new Date(info.resetsAt * 1e3)).toISOString(),
99178
- status: info.status
99179
- }
99180
- };
99181
- }
99182
- const SEVEN_DAY_MODEL_PREFIX = "seven_day_";
99183
- const SEVEN_DAY_OVERAGE_SUFFIX = "overage_included";
99184
- function capitalizeModelSuffix(suffix) {
99185
- return suffix.length === 0 ? suffix : suffix.charAt(0).toUpperCase() + suffix.slice(1);
99186
- }
99187
- /**
99188
- * Maps a per-model weekly SDKRateLimitInfo (`seven_day_<model>`, e.g.
99189
- * `seven_day_opus`) into a `ProviderUsageModelWindow`. `seven_day_overage_included`
99190
- * is not a per-model window (it reports overage-inclusive quota, not a
99191
- * specific model) and stays ignored here, same as plain `overage`.
99192
- */
99193
- function mapClaudeModelRateLimitInfo(info) {
99194
- if (typeof info.utilization !== "number" || typeof info.resetsAt !== "number" || !info.status) return null;
99195
- if (!info.rateLimitType?.startsWith(SEVEN_DAY_MODEL_PREFIX)) return null;
99196
- const suffix = info.rateLimitType.slice(10);
99197
- if (suffix.length === 0 || suffix === SEVEN_DAY_OVERAGE_SUFFIX) return null;
99198
- return {
99199
- model: capitalizeModelSuffix(suffix),
99200
- window: {
99201
- usedPercent: Math.round(info.utilization * 100),
99202
- resetsAt: (/* @__PURE__ */ new Date(info.resetsAt * 1e3)).toISOString(),
99203
- status: info.status
99204
- }
99205
- };
99206
- }
99207
- const cachedSnapshots = /* @__PURE__ */ new Map();
99208
- let localClaudeGenerationHash = null;
99209
- function setLocalClaudeUsageGeneration(generationId) {
99210
- localClaudeGenerationHash = createHash("sha256").update(generationId).digest("hex");
99211
- }
99212
- function currentClaudeUsageGenerationHash() {
99213
- const value = process.env.FORGE_PERSONAL_CLAUDE_GENERATION_HASH?.trim() ?? "";
99214
- return /^[a-f0-9]{64}$/.test(value) ? value : localClaudeGenerationHash;
99215
- }
99216
- function cacheKeyFor(generationHash, providerAccountId) {
99217
- return providerAccountId ? `${providerAccountId}:${generationHash}` : generationHash;
99218
- }
99219
- /**
99220
- * `observedAt` here is a placeholder, not an observation — it becomes
99221
- * meaningful only once a standard (five_hour/seven_day) window actually
99222
- * lands via `withStandardWindow`, which recomputes it from the retained
99223
- * windows' own observation times. A per-model-only cache (no standard window
99224
- * yet) still carries this placeholder, so callers should treat `observedAt`
99225
- * as trustworthy only once `fiveHour` or `sevenDay` is non-null.
99226
- */
99227
- function emptyCachedSnapshot(observedAt) {
99228
- return {
99229
- fiveHour: null,
99230
- sevenDay: null,
99231
- modelWindowsByModel: {},
99232
- observedAt,
99233
- fiveHourObservedAt: null,
99234
- sevenDayObservedAt: null
99235
- };
99236
- }
99237
- /** Oldest observation among the retained standard windows, so one fresh event cannot mask stale data. */
99238
- function oldestObservedAt(fiveHourObservedAt, sevenDayObservedAt) {
99239
- return [fiveHourObservedAt, sevenDayObservedAt].filter((value) => value !== null).toSorted()[0];
99240
- }
99241
- function withStandardWindow(previous, mapped, observedAt) {
99242
- const isFiveHour = mapped.kind === "fiveHour";
99243
- const fiveHourObservedAt = isFiveHour ? observedAt : previous.fiveHourObservedAt;
99244
- const sevenDayObservedAt = isFiveHour ? previous.sevenDayObservedAt : observedAt;
99245
- return {
99246
- ...previous,
99247
- fiveHour: isFiveHour ? mapped.window : previous.fiveHour,
99248
- sevenDay: isFiveHour ? previous.sevenDay : mapped.window,
99249
- fiveHourObservedAt,
99250
- sevenDayObservedAt,
99251
- observedAt: oldestObservedAt(fiveHourObservedAt, sevenDayObservedAt)
99252
- };
99253
- }
99254
- function withModelWindow(previous, mapped) {
99255
- return {
99256
- ...previous,
99257
- modelWindowsByModel: {
99258
- ...previous.modelWindowsByModel,
99259
- [mapped.model]: mapped.window
99260
- }
99261
- };
99262
- }
99263
- /**
99264
- * Merges a single-window update into the cached snapshot without clobbering
99265
- * the other windows. A per-model weekly report (`seven_day_<model>`) merges
99266
- * into `modelWindowsByModel` keyed by model, leaving every other model and
99267
- * the plain five_hour/seven_day windows untouched.
99268
- */
99269
- function recordClaudeRateLimitTelemetry(info, generationHash = currentClaudeUsageGenerationHash(), providerAccountId) {
99270
- if (generationHash === null) return;
99271
- const cacheKey = cacheKeyFor(generationHash, providerAccountId);
99272
- const observedAt = (/* @__PURE__ */ new Date()).toISOString();
99273
- const previous = cachedSnapshots.get(cacheKey) ?? emptyCachedSnapshot(observedAt);
99274
- const standard = mapClaudeRateLimitInfo(info);
99275
- if (standard) {
99276
- cachedSnapshots.set(cacheKey, withStandardWindow(previous, standard, observedAt));
99277
- return;
99278
- }
99279
- const model = mapClaudeModelRateLimitInfo(info);
99280
- if (model) cachedSnapshots.set(cacheKey, withModelWindow(previous, model));
99281
- }
99282
- //#endregion
99283
99475
  //#region src/providerAuth/ClaudeDeviceAuth.ts
99284
99476
  const AUTHORIZE_URL_PATTERN = /https:\/\/[^\s]*\/oauth\/authorize\?[^\s]+/u;
99285
99477
  const ANSI_ESCAPE_PATTERN$1 = new RegExp(String.raw`\x1B\[[0-?]*[ -/]*[@-~]`, "gu");
@@ -99794,7 +99986,6 @@ async function finalizeClaudeCredentialSync(input) {
99794
99986
  const providerAccountId = extractClaudeProviderAccountId(input.response);
99795
99987
  const credentialGenerationId = extractClaudeCredentialGenerationId(input.response);
99796
99988
  if (providerAccountId === null || credentialGenerationId === null) return null;
99797
- if (input.auth.path === USER_CLAUDE_CREDENTIAL_PATH) setLocalClaudeUsageGeneration(credentialGenerationId);
99798
99989
  return publishClaudeUsageAfterSync({
99799
99990
  auth: input.auth,
99800
99991
  providerAccountId,
@@ -146884,137 +147075,6 @@ const LocalAutomationRepositoryLive = effect(LocalAutomationRepository, gen(func
146884
147075
  */
146885
147076
  var CodexAdapter = class extends Service$1()("forge/provider/Services/CodexAdapter") {};
146886
147077
  //#endregion
146887
- //#region ../../packages/shared/src/model.ts
146888
- /** Check whether a capabilities object includes a given effort value. */
146889
- function hasEffortLevel(caps, value) {
146890
- return caps.reasoningEffortLevels.some((l) => l.value === value);
146891
- }
146892
- /** Return the default effort value for a capabilities object, or null if none. */
146893
- function getDefaultEffort(caps) {
146894
- return caps.reasoningEffortLevels.find((l) => l.isDefault)?.value ?? null;
146895
- }
146896
- /**
146897
- * Resolve a raw effort option against capabilities.
146898
- *
146899
- * Returns the effective effort value — the explicit value if supported and not
146900
- * prompt-injected, otherwise the model's default. Returns `undefined` only
146901
- * when the model has no effort levels at all.
146902
- *
146903
- * Prompt-injected efforts (e.g. "ultrathink") are excluded because they are
146904
- * applied via prompt text, not the effort API parameter.
146905
- */
146906
- function resolveEffort(caps, raw) {
146907
- const defaultValue = getDefaultEffort(caps);
146908
- const trimmed = typeof raw === "string" ? raw.trim() : null;
146909
- if (trimmed && !caps.promptInjectedEffortLevels.includes(trimmed) && hasEffortLevel(caps, trimmed)) return trimmed;
146910
- return defaultValue ?? void 0;
146911
- }
146912
- /** Check whether a capabilities object includes a given context window value. */
146913
- function hasContextWindowOption(caps, value) {
146914
- return caps.contextWindowOptions.some((o) => o.value === value);
146915
- }
146916
- /** Return the default context window value, or `null` if none is defined. */
146917
- function getDefaultContextWindow(caps) {
146918
- return caps.contextWindowOptions.find((o) => o.isDefault)?.value ?? null;
146919
- }
146920
- /**
146921
- * Resolve a raw `contextWindow` option against capabilities.
146922
- *
146923
- * Returns the effective context window value — the explicit value if supported,
146924
- * otherwise the model's default. Returns `undefined` only when the model has
146925
- * no context window options at all.
146926
- *
146927
- * Unlike effort levels (where the API has matching defaults), the context
146928
- * window requires an explicit API suffix (e.g. `[1m]`), so we always preserve
146929
- * the resolved value to avoid ambiguity between "user chose the default" and
146930
- * "not specified".
146931
- */
146932
- function resolveContextWindow(caps, raw) {
146933
- const defaultValue = getDefaultContextWindow(caps);
146934
- if (!raw) return defaultValue ?? void 0;
146935
- return hasContextWindowOption(caps, raw) ? raw : defaultValue ?? void 0;
146936
- }
146937
- function normalizeCodexModelOptionsWithCapabilities(caps, modelOptions) {
146938
- const reasoningEffort = resolveEffort(caps, modelOptions?.reasoningEffort);
146939
- const fastMode = caps.supportsFastMode ? modelOptions?.fastMode : void 0;
146940
- const nextOptions = {
146941
- ...reasoningEffort ? { reasoningEffort } : {},
146942
- ...fastMode !== void 0 ? { fastMode } : {}
146943
- };
146944
- return Object.keys(nextOptions).length > 0 ? nextOptions : void 0;
146945
- }
146946
- function normalizeClaudeModelOptionsWithCapabilities(caps, modelOptions) {
146947
- const effort = resolveEffort(caps, modelOptions?.effort);
146948
- const thinking = caps.supportsThinkingToggle ? modelOptions?.thinking : void 0;
146949
- const fastMode = caps.supportsFastMode ? modelOptions?.fastMode : void 0;
146950
- const contextWindow = resolveContextWindow(caps, modelOptions?.contextWindow);
146951
- const nextOptions = {
146952
- ...thinking !== void 0 ? { thinking } : {},
146953
- ...effort ? { effort } : {},
146954
- ...fastMode !== void 0 ? { fastMode } : {},
146955
- ...contextWindow !== void 0 ? { contextWindow } : {}
146956
- };
146957
- return Object.keys(nextOptions).length > 0 ? nextOptions : void 0;
146958
- }
146959
- function normalizeModelSlug(model, provider = "codex") {
146960
- if (typeof model !== "string") return null;
146961
- const trimmed = model.trim();
146962
- if (!trimmed) return null;
146963
- const aliases = MODEL_SLUG_ALIASES_BY_PROVIDER[provider];
146964
- const aliased = Object.prototype.hasOwnProperty.call(aliases, trimmed) ? aliases[trimmed] : void 0;
146965
- return typeof aliased === "string" ? aliased : trimmed;
146966
- }
146967
- /** Trim a string, returning null for empty/missing values. */
146968
- function trimOrNull(value) {
146969
- if (typeof value !== "string") return null;
146970
- return value.trim() || null;
146971
- }
146972
- /**
146973
- * Resolve the actual API model identifier from a model selection.
146974
- *
146975
- * Provider-aware: each provider can map `contextWindow` (or other options)
146976
- * to whatever the API requires — a model-id suffix, a separate parameter, etc.
146977
- * The canonical slug stored in the selection stays unchanged so the
146978
- * capabilities system keeps working.
146979
- *
146980
- * Expects `contextWindow` to already be resolved (via `resolveContextWindow`)
146981
- * to the effective value, not stripped to `undefined` for defaults.
146982
- */
146983
- function resolveApiModelId(modelSelection) {
146984
- switch (modelSelection.provider) {
146985
- case "claudeAgent": switch (modelSelection.options?.contextWindow) {
146986
- case "1m": return `${modelSelection.model}[1m]`;
146987
- default: return modelSelection.model;
146988
- }
146989
- default: return modelSelection.model;
146990
- }
146991
- }
146992
- function applyClaudePromptEffortPrefix(text, effort) {
146993
- const trimmed = text.trim();
146994
- if (!trimmed) return trimmed;
146995
- if (effort !== "ultrathink") return trimmed;
146996
- if (trimmed.startsWith("Ultrathink:")) return trimmed;
146997
- return `Ultrathink:\n${trimmed}`;
146998
- }
146999
- function getRawProviderOptionSelectionValue(selections, id) {
147000
- return selections?.find((candidate) => candidate.id === id)?.value;
147001
- }
147002
- function getProviderOptionSelectionValue(selections, id) {
147003
- return getRawProviderOptionSelectionValue(selections, id);
147004
- }
147005
- function getProviderOptionStringSelectionValue(selections, id) {
147006
- const value = getProviderOptionSelectionValue(selections, id);
147007
- return typeof value === "string" ? value : void 0;
147008
- }
147009
- function flatProviderOptions(selection) {
147010
- if (!selection) return void 0;
147011
- if (selection.provider !== "cursor" && selection.provider !== "opencode") return void 0;
147012
- return selection.options;
147013
- }
147014
- function getModelSelectionStringOptionValue(selection, id) {
147015
- return getProviderOptionStringSelectionValue(flatProviderOptions(selection), id);
147016
- }
147017
- //#endregion
147018
147078
  //#region src/provider/codexCliVersion.ts
147019
147079
  const CODEX_VERSION_PATTERN = /\bv?(\d+\.\d+(?:\.\d+)?(?:-[0-9A-Za-z.-]+)?)\b/;
147020
147080
  const MINIMUM_CODEX_CLI_VERSION = "0.37.0";
@@ -147669,6 +147729,213 @@ async function probeCodexDiscovery(input) {
147669
147729
  });
147670
147730
  }
147671
147731
  //#endregion
147732
+ //#region ../../packages/shared/src/model.ts
147733
+ /** Check whether a capabilities object includes a given effort value. */
147734
+ function hasEffortLevel(caps, value) {
147735
+ return caps.reasoningEffortLevels.some((l) => l.value === value);
147736
+ }
147737
+ /** Return the default effort value for a capabilities object, or null if none. */
147738
+ function getDefaultEffort(caps) {
147739
+ return caps.reasoningEffortLevels.find((l) => l.isDefault)?.value ?? null;
147740
+ }
147741
+ /**
147742
+ * Resolve a raw effort option against capabilities.
147743
+ *
147744
+ * Returns the effective effort value — the explicit value if supported and not
147745
+ * prompt-injected, otherwise the model's default. Returns `undefined` only
147746
+ * when the model has no effort levels at all.
147747
+ *
147748
+ * Prompt-injected efforts (e.g. "ultrathink") are excluded because they are
147749
+ * applied via prompt text, not the effort API parameter.
147750
+ */
147751
+ function resolveEffort(caps, raw) {
147752
+ const defaultValue = getDefaultEffort(caps);
147753
+ const trimmed = typeof raw === "string" ? raw.trim() : null;
147754
+ if (trimmed && !caps.promptInjectedEffortLevels.includes(trimmed) && hasEffortLevel(caps, trimmed)) return trimmed;
147755
+ return defaultValue ?? void 0;
147756
+ }
147757
+ /** Check whether a capabilities object includes a given context window value. */
147758
+ function hasContextWindowOption(caps, value) {
147759
+ return caps.contextWindowOptions.some((o) => o.value === value);
147760
+ }
147761
+ /** Return the default context window value, or `null` if none is defined. */
147762
+ function getDefaultContextWindow(caps) {
147763
+ return caps.contextWindowOptions.find((o) => o.isDefault)?.value ?? null;
147764
+ }
147765
+ /**
147766
+ * Resolve a raw `contextWindow` option against capabilities.
147767
+ *
147768
+ * Returns the effective context window value — the explicit value if supported,
147769
+ * otherwise the model's default. Returns `undefined` only when the model has
147770
+ * no context window options at all.
147771
+ *
147772
+ * Unlike effort levels (where the API has matching defaults), the context
147773
+ * window requires an explicit API suffix (e.g. `[1m]`), so we always preserve
147774
+ * the resolved value to avoid ambiguity between "user chose the default" and
147775
+ * "not specified".
147776
+ */
147777
+ function resolveContextWindow(caps, raw) {
147778
+ const defaultValue = getDefaultContextWindow(caps);
147779
+ if (!raw) return defaultValue ?? void 0;
147780
+ return hasContextWindowOption(caps, raw) ? raw : defaultValue ?? void 0;
147781
+ }
147782
+ function normalizeCodexModelOptionsWithCapabilities(caps, modelOptions) {
147783
+ const reasoningEffort = resolveEffort(caps, modelOptions?.reasoningEffort);
147784
+ const fastMode = caps.supportsFastMode ? modelOptions?.fastMode : void 0;
147785
+ const nextOptions = {
147786
+ ...reasoningEffort ? { reasoningEffort } : {},
147787
+ ...fastMode !== void 0 ? { fastMode } : {}
147788
+ };
147789
+ return Object.keys(nextOptions).length > 0 ? nextOptions : void 0;
147790
+ }
147791
+ function normalizeClaudeModelOptionsWithCapabilities(caps, modelOptions) {
147792
+ const effort = resolveEffort(caps, modelOptions?.effort);
147793
+ const thinking = caps.supportsThinkingToggle ? modelOptions?.thinking : void 0;
147794
+ const fastMode = caps.supportsFastMode ? modelOptions?.fastMode : void 0;
147795
+ const contextWindow = resolveContextWindow(caps, modelOptions?.contextWindow);
147796
+ const nextOptions = {
147797
+ ...thinking !== void 0 ? { thinking } : {},
147798
+ ...effort ? { effort } : {},
147799
+ ...fastMode !== void 0 ? { fastMode } : {},
147800
+ ...contextWindow !== void 0 ? { contextWindow } : {}
147801
+ };
147802
+ return Object.keys(nextOptions).length > 0 ? nextOptions : void 0;
147803
+ }
147804
+ function normalizeModelSlug(model, provider = "codex") {
147805
+ if (typeof model !== "string") return null;
147806
+ const trimmed = model.trim();
147807
+ if (!trimmed) return null;
147808
+ const aliases = MODEL_SLUG_ALIASES_BY_PROVIDER[provider];
147809
+ const aliased = Object.prototype.hasOwnProperty.call(aliases, trimmed) ? aliases[trimmed] : void 0;
147810
+ return typeof aliased === "string" ? aliased : trimmed;
147811
+ }
147812
+ /** Trim a string, returning null for empty/missing values. */
147813
+ function trimOrNull(value) {
147814
+ if (typeof value !== "string") return null;
147815
+ return value.trim() || null;
147816
+ }
147817
+ /**
147818
+ * Resolve the actual API model identifier from a model selection.
147819
+ *
147820
+ * Provider-aware: each provider can map `contextWindow` (or other options)
147821
+ * to whatever the API requires — a model-id suffix, a separate parameter, etc.
147822
+ * The canonical slug stored in the selection stays unchanged so the
147823
+ * capabilities system keeps working.
147824
+ *
147825
+ * Expects `contextWindow` to already be resolved (via `resolveContextWindow`)
147826
+ * to the effective value, not stripped to `undefined` for defaults.
147827
+ */
147828
+ function resolveApiModelId(modelSelection) {
147829
+ switch (modelSelection.provider) {
147830
+ case "claudeAgent": switch (modelSelection.options?.contextWindow) {
147831
+ case "1m": return `${modelSelection.model}[1m]`;
147832
+ default: return modelSelection.model;
147833
+ }
147834
+ default: return modelSelection.model;
147835
+ }
147836
+ }
147837
+ function applyClaudePromptEffortPrefix(text, effort) {
147838
+ const trimmed = text.trim();
147839
+ if (!trimmed) return trimmed;
147840
+ if (effort !== "ultrathink") return trimmed;
147841
+ if (trimmed.startsWith("Ultrathink:")) return trimmed;
147842
+ return `Ultrathink:\n${trimmed}`;
147843
+ }
147844
+ function getRawProviderOptionSelectionValue(selections, id) {
147845
+ return selections?.find((candidate) => candidate.id === id)?.value;
147846
+ }
147847
+ function getProviderOptionSelectionValue(selections, id) {
147848
+ return getRawProviderOptionSelectionValue(selections, id);
147849
+ }
147850
+ function getProviderOptionStringSelectionValue(selections, id) {
147851
+ const value = getProviderOptionSelectionValue(selections, id);
147852
+ return typeof value === "string" ? value : void 0;
147853
+ }
147854
+ function flatProviderOptions(selection) {
147855
+ if (!selection) return void 0;
147856
+ if (selection.provider !== "cursor" && selection.provider !== "opencode") return void 0;
147857
+ return selection.options;
147858
+ }
147859
+ function getModelSelectionStringOptionValue(selection, id) {
147860
+ return getProviderOptionStringSelectionValue(flatProviderOptions(selection), id);
147861
+ }
147862
+ function acceptableModelSlug(value) {
147863
+ const trimmed = value?.trim();
147864
+ if (!trimmed || trimmed.length > 120) return;
147865
+ return trimmed;
147866
+ }
147867
+ /**
147868
+ * Order the credential's model scope: selected model first, then the catalog,
147869
+ * deduplicated and capped.
147870
+ *
147871
+ * Returns `undefined` when there is no catalog to widen to, which is the signal
147872
+ * to send the old single-model body. A slug CMMD would refuse is dropped rather
147873
+ * than sent, because one bad entry 400s the whole mint and takes the session
147874
+ * with it.
147875
+ */
147876
+ function providerEgressModelScope(model, models) {
147877
+ const catalog = (models ?? []).map(acceptableModelSlug).filter((slug) => slug !== void 0);
147878
+ if (catalog.length === 0) return;
147879
+ const selected = acceptableModelSlug(model);
147880
+ const ordered = new Set(selected ? [selected] : []);
147881
+ for (const slug of catalog) {
147882
+ if (ordered.size >= 32) break;
147883
+ ordered.add(slug);
147884
+ }
147885
+ return [...ordered];
147886
+ }
147887
+ //#endregion
147888
+ //#region src/provider/codexCredentialModelScope.ts
147889
+ /**
147890
+ * Which Codex models one workspace egress credential has to cover.
147891
+ *
147892
+ * FOR-36501: the credential was scoped to the model the user picked, and the
147893
+ * Codex app-server holds one credential for the whole process. A turn on
147894
+ * gpt-6-astra that called `spawn_agent` with gpt-5.6-terra therefore lost the
147895
+ * child to a 401 before it spent a token. The subagent model is the model's own
147896
+ * choice in the tool arguments, so Forge cannot predict it and has to scope the
147897
+ * credential to the catalog a spawn can pick from.
147898
+ *
147899
+ * The catalog is the built-in Codex list, which is what the picker offers. It
147900
+ * includes the Spark model even though only a Pro account may call it: the
147901
+ * account snapshot is not resolved at issue time in workspace mode, and CMMD
147902
+ * still decides per call which models the account may use, so a slug in the
147903
+ * scope is permission to ask, never permission to spend.
147904
+ */
147905
+ /**
147906
+ * Normalize a Codex model slug to the one the app-server and the mint route use.
147907
+ *
147908
+ * Lives here rather than in codexAppServerManager.ts so the catalog builder can
147909
+ * use it without importing the manager back. The manager re-exports it, which is
147910
+ * where every existing caller still reads it from.
147911
+ */
147912
+ function normalizeCodexModelSlug(model, preferredId) {
147913
+ const normalized = normalizeModelSlug(model);
147914
+ if (!normalized) return;
147915
+ if (preferredId?.endsWith("-codex") && preferredId !== normalized) return preferredId;
147916
+ return normalized;
147917
+ }
147918
+ /** The model a proxy token is minted for when the thread names none. */
147919
+ function resolveCodexProviderProxyTokenModel(model) {
147920
+ const displaySlug = model?.trim().toLowerCase().replace(/\s+/g, "-");
147921
+ return normalizeCodexModelSlug(displaySlug) ?? "gpt-6-astra";
147922
+ }
147923
+ /** Every built-in Codex slug a `spawn_agent` call can name. */
147924
+ function codexCredentialModelCatalog() {
147925
+ return CODEX_BUILT_IN_MODELS.map((model) => normalizeCodexModelSlug(model.slug) ?? model.slug);
147926
+ }
147927
+ /**
147928
+ * The `models` list to mint a Codex session credential with.
147929
+ *
147930
+ * `undefined` means the catalog is unknown, and the caller then sends `model`
147931
+ * alone, exactly as before this card. That is the only safe answer: an empty
147932
+ * list would narrow the credential rather than widen it.
147933
+ */
147934
+ function buildCodexCredentialModelScope(input) {
147935
+ const catalog = (input.catalogModels ?? codexCredentialModelCatalog()).map((slug) => normalizeCodexModelSlug(slug) ?? slug).filter((slug) => slug.trim().length > 0);
147936
+ return providerEgressModelScope(input.selectedModel, catalog);
147937
+ }
147938
+ //#endregion
147672
147939
  //#region src/egress/providerDeliveryReceipt.ts
147673
147940
  const PROVIDER_ACCOUNT_IDENTITY$2 = /^pai_v1_[A-Za-z0-9_-]{43}$/;
147674
147941
  const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
@@ -147920,6 +148187,21 @@ function runtimeProviderEgressBaseUrl(provider, controlPlaneUrl) {
147920
148187
  anthropic: "/api/provider-egress/anthropic"
147921
148188
  }[provider]}`;
147922
148189
  }
148190
+ /**
148191
+ * The model fields of a mint body.
148192
+ *
148193
+ * `model` stays the single selected model, which is what CMMD runs its
148194
+ * post-mint constraint check on. `models` appears only when the caller knows a
148195
+ * catalog, so a caller that does not know one sends exactly the body it sent
148196
+ * before FOR-36501.
148197
+ */
148198
+ function providerEgressModelBodyFields(input) {
148199
+ const scope = providerEgressModelScope(input.model, input.models);
148200
+ return {
148201
+ ...input.model ? { model: input.model } : {},
148202
+ ...scope ? { models: scope } : {}
148203
+ };
148204
+ }
147923
148205
  const issueProviderEgressToken = (input) => issueProviderEgressCredential(input).pipe(map$3((credential) => credential.token));
147924
148206
  const issueProviderEgressCredential = (input) => tryPromise({
147925
148207
  try: async () => {
@@ -147943,7 +148225,7 @@ async function issueCmmdRuntimeProviderEgressCredential(input) {
147943
148225
  token: runtimeGrantToken,
147944
148226
  body: JSON.stringify({
147945
148227
  provider: input.provider,
147946
- ...input.model ? { model: input.model } : {},
148228
+ ...providerEgressModelBodyFields(input),
147947
148229
  ...input.provider === "openai" && input.providerAccountId ? { provider_account_id: input.providerAccountId } : {}
147948
148230
  })
147949
148231
  });
@@ -148059,7 +148341,7 @@ function issueCmmdLocalUserProviderEgressCredential(input) {
148059
148341
  },
148060
148342
  body: JSON.stringify({
148061
148343
  provider: input.provider,
148062
- ...input.model ? { model: input.model } : {},
148344
+ ...providerEgressModelBodyFields(input),
148063
148345
  ...input.provider === "openai" && input.providerAccountId ? { provider_account_id: input.providerAccountId } : {},
148064
148346
  client: "local-desktop",
148065
148347
  sessionId,
@@ -148442,16 +148724,6 @@ function mapCodexRuntimeMode(runtimeMode) {
148442
148724
  async function killChildTree(child) {
148443
148725
  await killCodexChildProcess(child);
148444
148726
  }
148445
- function normalizeCodexModelSlug(model, preferredId) {
148446
- const normalized = normalizeModelSlug(model);
148447
- if (!normalized) return;
148448
- if (preferredId?.endsWith("-codex") && preferredId !== normalized) return preferredId;
148449
- return normalized;
148450
- }
148451
- function resolveCodexProviderProxyTokenModel(model) {
148452
- const displaySlug = model?.trim().toLowerCase().replace(/\s+/g, "-");
148453
- return normalizeCodexModelSlug(displaySlug) ?? "gpt-6-astra";
148454
- }
148455
148727
  function buildCodexCollaborationMode(input) {
148456
148728
  if (input.interactionMode === void 0) return;
148457
148729
  const model = normalizeCodexModelSlug(input.model) ?? "gpt-6-astra";
@@ -149002,9 +149274,11 @@ var CodexAppServerManager = class extends EventEmitter$1 {
149002
149274
  const proxyConfig = getOpenAiProviderEgressProxyConfig({ allowLocalUser: true });
149003
149275
  if (proxyConfig.mode === "disabled") return null;
149004
149276
  if (proxyConfig.mode === "misconfigured") throw new ProviderEgressTokenError({ message: proxyConfig.message });
149277
+ const models = buildCodexCredentialModelScope({ selectedModel: input.model });
149005
149278
  return await runPromise(issueProviderEgressCredential({
149006
149279
  provider: "openai",
149007
149280
  model: input.model,
149281
+ ...models ? { models } : {},
149008
149282
  threadId: input.threadId,
149009
149283
  ...input.providerAccountId ? { providerAccountId: input.providerAccountId } : {}
149010
149284
  }));
@@ -149397,13 +149671,40 @@ var CodexAppServerManager = class extends EventEmitter$1 {
149397
149671
  if (!providerConversationId) return;
149398
149672
  return context.collabReceiverTurns.get(providerConversationId);
149399
149673
  }
149674
+ /**
149675
+ * The child threads one thread item says the turn spawned.
149676
+ *
149677
+ * Two item shapes name a child, and which one arrives depends on the Codex
149678
+ * build. `CollabAgentToolCallThreadItem` lists `receiverThreadIds`, which
149679
+ * "in case of spawn operation ... corresponds to the newly spawned agent".
149680
+ * `SubAgentActivityThreadItem` names a single `agentThreadId` and is what a
149681
+ * `spawn_agent` call reports on codex-cli 0.152/0.153: measured on the
149682
+ * packaged desktop on 2026-09-06, the spawn arrived as `SubAgentActivity`
149683
+ * (`kind: started`) and the only collab tool call that followed was the
149684
+ * `wait`, whose `receiverThreadIds` was empty. Reading only the collab item
149685
+ * left the child unmapped, so its spend was published as a second turn row
149686
+ * under the child's own turn id instead of a subagent row under the parent's.
149687
+ *
149688
+ * `SubAgentActivityThreadItem` has no `model` field, so a `completed` report
149689
+ * for a child a collab call already named must not blank the model out; the
149690
+ * caller's `model ?? known` merge is what keeps it.
149691
+ */
149692
+ readSpawnedThreadIds(item, itemType) {
149693
+ if (itemType === "subAgentActivity") {
149694
+ const agentThreadId = this.readString(item, "agentThreadId");
149695
+ return agentThreadId ? [agentThreadId] : [];
149696
+ }
149697
+ if (itemType !== "collabAgentToolCall") return [];
149698
+ return this.readArray(item, "receiverThreadIds")?.map((value) => typeof value === "string" ? value : null).filter((value) => value !== null) ?? [];
149699
+ }
149400
149700
  rememberCollabReceiverTurns(context, params, parentTurnId) {
149401
149701
  if (!parentTurnId) return;
149402
149702
  const payload = this.readObject(params);
149403
149703
  const item = this.readObject(payload, "item") ?? payload;
149404
- if ((this.readString(item, "type") ?? this.readString(item, "kind")) !== "collabAgentToolCall") return;
149704
+ const itemType = this.readString(item, "type") ?? this.readString(item, "kind");
149705
+ const receiverThreadIds = this.readSpawnedThreadIds(item, itemType);
149706
+ if (receiverThreadIds.length === 0) return;
149405
149707
  const model = this.readString(item, "model");
149406
- const receiverThreadIds = this.readArray(item, "receiverThreadIds")?.map((value) => typeof value === "string" ? value : null).filter((value) => value !== null) ?? [];
149407
149708
  for (const receiverThreadId of receiverThreadIds) {
149408
149709
  const known = context.collabReceiverTurns.get(receiverThreadId)?.model;
149409
149710
  const resolved = model ?? known;
@@ -149419,8 +149720,8 @@ var CodexAppServerManager = class extends EventEmitter$1 {
149419
149720
  * Codex reports a child thread's tokens on the parent's own connection:
149420
149721
  * `ThreadTokenUsageUpdatedNotification` requires `threadId` and `turnId` and
149421
149722
  * names the child thread for a child, and `Thread.parentThreadId` is "only
149422
- * set if this thread is a subagent" (codex 0.144.6 app-server protocol
149423
- * schema). Every other child notification is suppressed so it cannot replace
149723
+ * set if this thread is a subagent" (still true of the codex-cli 0.153
149724
+ * app-server protocol schema). Every other child notification is suppressed so it cannot replace
149424
149725
  * the parent turn; this one is not, because the tokens belong on the ledger.
149425
149726
  * The method is Forge's own rather than the protocol's, because the payload
149426
149727
  * carries what the Usage row needs rather than what the notification held.
@@ -207164,36 +207465,23 @@ function mapCodexThreadNameUpdatedEvent(event, canonicalThreadId, payload) {
207164
207465
  }
207165
207466
  }];
207166
207467
  }
207167
- /** One provider call's spend, from Codex's `last_token_usage`. */
207168
- function codexTurnUsageDelta(value) {
207169
- const usage = asObject$2(value);
207170
- return codexUsageBuckets(usage?.last_token_usage ?? usage?.last, "call-delta");
207171
- }
207172
207468
  /**
207173
- * One Codex token report in Forge's disjoint buckets. Codex reports
207174
- * `input_tokens` inclusive of the cached and cache-write portions, so the
207175
- * uncached bucket is the remainder; reasoning is reported inside output and is
207176
- * surfaced separately without being added again. Mirrors `parseCodexLine` in
207469
+ * One provider call's spend, from Codex's `last_token_usage`. Reads the
207470
+ * buckets via `codexTokenBuckets`, the shared home of the Claude/Codex
207471
+ * disjointness rule (providerTokenBuckets.ts): Codex reports `input_tokens`
207472
+ * inclusive of the cached and cache-write portions, so the uncached bucket is
207473
+ * the remainder, and reasoning is reported inside output and surfaced
207474
+ * separately without being added again. Mirrors `parseCodexLine` in
207177
207475
  * usage/usageTranscripts.ts so a Recorded turn and a scanned transcript agree
207178
207476
  * on the same numbers.
207179
207477
  */
207180
- function codexUsageBuckets(value, scope) {
207181
- const lastUsage = asObject$2(value);
207182
- if (!lastUsage) return void 0;
207183
- const int = (key, alt) => Math.max(0, Math.trunc(asNumber(lastUsage[key]) ?? asNumber(lastUsage[alt]) ?? 0));
207184
- const inputTokens = int("input_tokens", "inputTokens");
207185
- const cachedInputTokens = int("cached_input_tokens", "cachedInputTokens");
207186
- const cacheCreationTokens = int("cache_write_input_tokens", "cacheWriteInputTokens");
207187
- const outputTokens = int("output_tokens", "outputTokens");
207188
- if (inputTokens + cachedInputTokens + cacheCreationTokens + outputTokens === 0) return void 0;
207189
- return {
207190
- scope,
207191
- uncachedInputTokens: Math.max(0, inputTokens - cachedInputTokens - cacheCreationTokens),
207192
- cachedInputTokens,
207193
- cacheCreationTokens,
207194
- outputTokens,
207195
- reasoningTokens: Math.min(outputTokens, int("reasoning_output_tokens", "reasoningOutputTokens"))
207196
- };
207478
+ function codexTurnUsageDelta(value) {
207479
+ const usage = asObject$2(value);
207480
+ const buckets = codexTokenBuckets(usage?.last_token_usage ?? usage?.last);
207481
+ return buckets ? {
207482
+ scope: "call-delta",
207483
+ ...buckets
207484
+ } : void 0;
207197
207485
  }
207198
207486
  function mapCodexThreadTokenUsageEvent(event, canonicalThreadId, payload) {
207199
207487
  const tokenUsage = asObject$2(payload?.tokenUsage);
@@ -207216,11 +207504,14 @@ function mapCodexThreadTokenUsageEvent(event, canonicalThreadId, payload) {
207216
207504
  *
207217
207505
  * The source is the live app-server protocol, not a rollout read: Codex sends
207218
207506
  * `thread/tokenUsage/updated` for a child thread on the parent's own
207219
- * connection (0.144.6 schema: `ThreadTokenUsageUpdatedNotification` requires
207220
- * `threadId` and `turnId`, `Thread.parentThreadId` is set only for a subagent,
207221
- * and `CollabAgentToolCallThreadItem` names `receiverThreadIds` and the
207222
- * spawned agent's `model`), and `codexAppServerManager` already tracked those
207223
- * child threads to route their notifications onto the parent turn.
207507
+ * connection (`ThreadTokenUsageUpdatedNotification` requires `threadId` and
207508
+ * `turnId`, and `Thread.parentThreadId` is set only for a subagent), and
207509
+ * `codexAppServerManager` already tracked those child threads to route their
207510
+ * notifications onto the parent turn. It learns a child from whichever item
207511
+ * the running Codex build uses to announce a spawn: the
207512
+ * `receiverThreadIds` of a `CollabAgentToolCallThreadItem`, which also names
207513
+ * the spawned agent's `model`, or the `agentThreadId` of a
207514
+ * `SubAgentActivityThreadItem`, which names no model.
207224
207515
  *
207225
207516
  * The row carries no context-meter snapshot and no `turnUsage`: the parent's
207226
207517
  * own row is never re-summed with its children. It carries the call's delta
@@ -207882,6 +208173,7 @@ const DEFAULT_PUBLIC_PROVIDER_ERROR = "CMMD is temporarily unavailable. Check th
207882
208173
  function categorizePublicProviderError(message) {
207883
208174
  if (!message) return null;
207884
208175
  const m = message.toLowerCase();
208176
+ if (/\bforge_provider_model_not_allowed\b/.test(m) || /\bnot\s+scoped\s+to\s+the\s+requested\s+model\b/.test(m)) return "The workspace AI credential does not cover the model this turn asked for. Retry, or pick that model for the thread.";
207885
208177
  if (/\bmodel\b[\s\S]*\b(not\s+(found|available|supported)|does\s+not\s+exist|unsupported|invalid|unknown)\b/.test(m) || /\b(unsupported|unknown|invalid)\b[\s\S]*\bmodel\b/.test(m) || /\b(model_not_found|invalid_model|model_not_supported)\b/.test(m)) return "The selected model isn't available right now. Pick a different model and retry.";
207886
208178
  if (/\b(rate[\s-]?limit|too\s+many\s+requests|quota|insufficient_quota)\b/.test(m) || /\b429\b/.test(m)) return "The AI service is rate-limited or out of quota. Wait a moment and retry.";
207887
208179
  if (/\b(unauthorized|forbidden|authentication\s+(failed|error|required)|invalid\s+api\s+key|expired\s+(token|credential))\b/.test(m) || /\b40[13]\b/.test(m)) return "Workspace AI authentication failed. Reconnect the workspace and retry.";
@@ -208102,7 +208394,8 @@ const CODE_BY_UPSTREAM_REASON$1 = {
208102
208394
  credential_expired_refreshing: "CREDENTIAL_EXPIRED_REFRESHING",
208103
208395
  credential_reconnect_required: "CREDENTIAL_RECONNECT_REQUIRED",
208104
208396
  credential_not_connected: "CREDENTIAL_RECONNECT_REQUIRED",
208105
- credential_generation_not_applied: "CREDENTIAL_GENERATION_NOT_APPLIED"
208397
+ credential_generation_not_applied: "CREDENTIAL_GENERATION_NOT_APPLIED",
208398
+ runtime_unavailable: "RUNTIME_UNAVAILABLE"
208106
208399
  };
208107
208400
  const CLAUDE_NATIVE_CREDENTIAL_UNUSABLE_COPY = "The delivered Claude credential is unavailable or unusable in this runtime.";
208108
208401
  /**
@@ -208165,10 +208458,17 @@ function claudeNativeCredentialUnusableMessage() {
208165
208458
  * CMMD writes this marker when it activates a personal Claude subscription
208166
208459
  * inside a running sprite. Activation always happens after boot, so a
208167
208460
  * boot-time env var alone cannot reflect it (FOR-36249).
208461
+ *
208462
+ * CMMD names the file in the Service env (FORGE_PERSONAL_CLAUDE_MARKER_PATH).
208463
+ * Without that, the marker sits directly under FORGE_HOME, which is the same
208464
+ * guest home CMMD derives every sprite path from. A server with neither has no
208465
+ * sprite home to look in, and a desktop never has a marker, so it reads none.
208168
208466
  */
208169
- const PERSONAL_CLAUDE_IN_VM_MARKER_PATH = "/data/.forge-personal-claude-in-vm";
208467
+ const PERSONAL_CLAUDE_IN_VM_MARKER_NAME = ".forge-personal-claude-in-vm";
208170
208468
  function markerPath(env) {
208171
- return env.FORGE_PERSONAL_CLAUDE_MARKER_PATH || PERSONAL_CLAUDE_IN_VM_MARKER_PATH;
208469
+ if (env.FORGE_PERSONAL_CLAUDE_MARKER_PATH) return env.FORGE_PERSONAL_CLAUDE_MARKER_PATH;
208470
+ if (env.FORGE_HOME) return join(env.FORGE_HOME, PERSONAL_CLAUDE_IN_VM_MARKER_NAME);
208471
+ return null;
208172
208472
  }
208173
208473
  /**
208174
208474
  * True when this runtime should offer the personal Claude subscription lane.
@@ -208181,8 +208481,10 @@ function markerPath(env) {
208181
208481
  */
208182
208482
  function personalClaudeInVmEnabled(env = process.env) {
208183
208483
  if (env.FORGE_PERSONAL_CLAUDE_IN_VM === "true") return true;
208484
+ const marker = markerPath(env);
208485
+ if (!marker) return false;
208184
208486
  try {
208185
- return existsSync(markerPath(env));
208487
+ return existsSync(marker);
208186
208488
  } catch {
208187
208489
  return false;
208188
208490
  }
@@ -209720,9 +210022,6 @@ function buildClaudeSessionContext(input) {
209720
210022
  query: input.queryRuntime,
209721
210023
  streamFiber: void 0,
209722
210024
  startedAt: input.startedAt,
209723
- recordsPersonalUsageTelemetry: input.recordsPersonalUsageTelemetry,
209724
- personalUsageGenerationHash: input.personalUsageGenerationHash,
209725
- personalUsageProviderAccountId: input.personalUsageProviderAccountId,
209726
210025
  basePermissionMode: input.permissionMode,
209727
210026
  resumeSessionId: input.sessionId,
209728
210027
  pendingApprovals: input.pendingApprovals,
@@ -210080,26 +210379,18 @@ function finiteNumberFieldOrZero(usage, key) {
210080
210379
  }
210081
210380
  /**
210082
210381
  * The whole turn's spend from the SDK result message, cache split intact.
210083
- * Claude reports `input_tokens` exclusive of the cached and cache-creation
210084
- * portions, so the buckets are already disjoint. Claude does not report
210085
- * reasoning separately.
210382
+ * Reads the buckets via `claudeTokenBuckets`, the shared home of the
210383
+ * Claude/Codex disjointness rule (providerTokenBuckets.ts): Claude reports
210384
+ * `input_tokens` exclusive of the cached and cache-creation portions, so the
210385
+ * buckets are already disjoint, and Claude does not report reasoning
210386
+ * separately.
210086
210387
  */
210087
210388
  function claudeTurnUsageTotal(value) {
210088
- const usage = asClaudeUsageRecord(value);
210089
- if (!usage) return void 0;
210090
- const uncachedInputTokens = finiteNumberFieldOrZero(usage, "input_tokens");
210091
- const cachedInputTokens = finiteNumberFieldOrZero(usage, "cache_read_input_tokens");
210092
- const cacheCreationTokens = finiteNumberFieldOrZero(usage, "cache_creation_input_tokens");
210093
- const outputTokens = finiteNumberFieldOrZero(usage, "output_tokens");
210094
- if (uncachedInputTokens + cachedInputTokens + cacheCreationTokens + outputTokens <= 0) return;
210095
- return {
210389
+ const buckets = claudeTokenBuckets(value);
210390
+ return buckets ? {
210096
210391
  scope: "turn-total",
210097
- uncachedInputTokens: Math.trunc(uncachedInputTokens),
210098
- cachedInputTokens: Math.trunc(cachedInputTokens),
210099
- cacheCreationTokens: Math.trunc(cacheCreationTokens),
210100
- outputTokens: Math.trunc(outputTokens),
210101
- reasoningTokens: 0
210102
- };
210392
+ ...buckets
210393
+ } : void 0;
210103
210394
  }
210104
210395
  const EMPTY_MODEL_USAGE_BUCKETS = {
210105
210396
  uncachedInputTokens: 0,
@@ -210112,20 +210403,14 @@ function bucketsTotal(buckets) {
210112
210403
  return buckets.uncachedInputTokens + buckets.cachedInputTokens + buckets.cacheCreationTokens + buckets.outputTokens;
210113
210404
  }
210114
210405
  /**
210115
- * One `ModelUsage` entry as buckets. `ModelUsage` names its fields in
210116
- * camelCase, unlike `result.usage`, so this cannot share `claudeTurnUsageTotal`.
210117
- * Claude reports `inputTokens` exclusive of the cached and cache-creation
210118
- * portions, so the buckets are already disjoint, and it reports no reasoning.
210406
+ * One `ModelUsage` entry as buckets, via `claudeTokenBuckets`. `ModelUsage`
210407
+ * names its fields in camelCase, unlike `result.usage`, but `claudeTokenBuckets`
210408
+ * already reads both spellings. Claude reports `inputTokens` exclusive of the
210409
+ * cached and cache-creation portions, so the buckets are already disjoint, and
210410
+ * it reports no reasoning.
210119
210411
  */
210120
210412
  function claudeModelUsageBuckets(usage) {
210121
- const record = usage;
210122
- return {
210123
- uncachedInputTokens: Math.trunc(finiteNumberFieldOrZero(record, "inputTokens")),
210124
- cachedInputTokens: Math.trunc(finiteNumberFieldOrZero(record, "cacheReadInputTokens")),
210125
- cacheCreationTokens: Math.trunc(finiteNumberFieldOrZero(record, "cacheCreationInputTokens")),
210126
- outputTokens: Math.trunc(finiteNumberFieldOrZero(record, "outputTokens")),
210127
- reasoningTokens: 0
210128
- };
210413
+ return claudeTokenBuckets(usage) ?? EMPTY_MODEL_USAGE_BUCKETS;
210129
210414
  }
210130
210415
  /**
210131
210416
  * What each model spent during THIS turn, from the SDK's per-model totals.
@@ -211468,7 +211753,6 @@ const makeClaudeAdapter = fn$1("makeClaudeAdapter")(function* (options) {
211468
211753
  return;
211469
211754
  }
211470
211755
  if (message.type === "rate_limit_event") {
211471
- if (context.recordsPersonalUsageTelemetry) recordClaudeRateLimitTelemetry(message.rate_limit_info, context.personalUsageGenerationHash, context.personalUsageProviderAccountId);
211472
211756
  yield* offerRuntimeEvent({
211473
211757
  ...base,
211474
211758
  type: "account.rate-limits.updated",
@@ -211966,10 +212250,7 @@ const makeClaudeAdapter = fn$1("makeClaudeAdapter")(function* (options) {
211966
212250
  inFlightTools,
211967
212251
  resumeSessionAt: resumeState?.resumeSessionAt,
211968
212252
  effectiveApiModelId: modelConfig.effectiveApiModelId,
211969
- effectiveEffort: modelConfig.effectiveEffort,
211970
- recordsPersonalUsageTelemetry: sessionProvider === PROVIDER$11 && modelConfig.endpointProfile === void 0 && providerProxyCredential === null && !claudeSettings.anthropicBaseUrl && !claudeSettings.anthropicApiKey,
211971
- personalUsageGenerationHash: currentClaudeUsageGenerationHash(),
211972
- personalUsageProviderAccountId: modelConfig.modelSelection?.provider === "claudeAgent" ? modelConfig.modelSelection.providerAccountId : void 0
212253
+ effectiveEffort: modelConfig.effectiveEffort
211973
212254
  });
211974
212255
  yield* set$2(contextRef, context$4);
211975
212256
  sessions.set(threadId, context$4);
@@ -226762,7 +227043,8 @@ const CLAUDE_READINESS_COPY = {
226762
227043
  failed: "Claude native runtime setup could not be applied. Reconnect Claude in Settings.",
226763
227044
  invalid: "Claude native runtime readiness is no longer valid. Reconnect Claude in Settings.",
226764
227045
  unavailable: "Claude native runtime readiness could not be verified.",
226765
- generationMismatch: "Claude native runtime generation does not match CMMD readiness."
227046
+ generationMismatch: "Claude native runtime generation does not match CMMD readiness.",
227047
+ environmentUnavailable: "This Environment is not running, so Claude cannot run on it. Restart the Environment, then try again."
226766
227048
  };
226767
227049
  var ClaudeRuntimeReadinessError = class extends Error {
226768
227050
  constructor(safeIssue, retryable = false, retryProfile = "default") {
@@ -226832,6 +227114,7 @@ async function withReadinessRetry(attempt) {
226832
227114
  */
226833
227115
  function readinessReasonIssue(readiness) {
226834
227116
  const code = claudeReadinessReasonCode(readiness.reason);
227117
+ if (code === "RUNTIME_UNAVAILABLE") return CLAUDE_READINESS_COPY.environmentUnavailable;
226835
227118
  if (code === "CREDENTIAL_RECONNECT_REQUIRED") return CLAUDE_READINESS_COPY.invalid;
226836
227119
  if (code === "CREDENTIAL_GENERATION_NOT_APPLIED") return CLAUDE_READINESS_COPY.applying;
226837
227120
  if (code !== "CREDENTIAL_EXPIRED_REFRESHING") return null;
@@ -226842,6 +227125,10 @@ function readinessReasonIssue(readiness) {
226842
227125
  function isCredentialRefreshInFlight(readiness) {
226843
227126
  return claudeReadinessReasonCode(readiness.reason) === "CREDENTIAL_EXPIRED_REFRESHING";
226844
227127
  }
227128
+ /** True when CMMD says the runtime itself cannot take a delivery (CMMD-36473). */
227129
+ function isRuntimeUnavailable(readiness) {
227130
+ return claudeReadinessReasonCode(readiness.reason) === "RUNTIME_UNAVAILABLE";
227131
+ }
226845
227132
  function readinessFailureIssue(readiness) {
226846
227133
  const reasonIssue = readinessReasonIssue(readiness);
226847
227134
  if (reasonIssue !== null) return reasonIssue;
@@ -226881,11 +227168,12 @@ function verifiedClaudeDeliveryBinding(readiness, authority) {
226881
227168
  function appliedClaudeGeneration(readiness) {
226882
227169
  if (readiness.connected !== true || readiness.deliveryStatus !== "applied" || readiness.nativeExecutable !== true || typeof readiness.generationId !== "string" || readiness.generationId.trim().length === 0) {
226883
227170
  const refreshing = isCredentialRefreshInFlight(readiness);
226884
- throw new ClaudeRuntimeReadinessError(readinessFailureIssue(readiness), refreshing || [
227171
+ const retryable = !isRuntimeUnavailable(readiness) && (refreshing || [
226885
227172
  "pending",
226886
227173
  "claimed",
226887
227174
  "activating"
226888
- ].includes(readiness.deliveryStatus), refreshing ? "credentialRefresh" : "default");
227175
+ ].includes(readiness.deliveryStatus));
227176
+ throw new ClaudeRuntimeReadinessError(readinessFailureIssue(readiness), retryable, refreshing ? "credentialRefresh" : "default");
226889
227177
  }
226890
227178
  return readiness.generationId;
226891
227179
  }
@@ -228039,15 +228327,15 @@ const collectOutput = fn$1("collectOutput")(function* (input, stream, maxOutputB
228039
228327
  /**
228040
228328
  * Adds a `safe.directory` exception to a git child environment.
228041
228329
  *
228042
- * Forge runs git against workspaces on a mounted volume (`/data/Projects/...` on
228043
- * Fly). A volume mount replaces the build-time ownership of its mountpoint, so a
228330
+ * Forge runs git against workspaces on a mounted volume (`<cloudProjectsRoot>/...`
228331
+ * on Fly). A volume mount replaces the build-time ownership of its mountpoint, so a
228044
228332
  * repository there can be owned by a uid other than the server's, and git then
228045
228333
  * refuses EVERY command against it with "detected dubious ownership" — the
228046
228334
  * FORGE-2T failure in `CheckpointStore.captureCheckpoint`.
228047
228335
  *
228048
228336
  * The exception has to be `*`, verified against git 2.43:
228049
228337
  * - git compares `safe.directory` entries literally, so a prefix such as
228050
- * `/data/Projects/*` does not match the repository at all.
228338
+ * `/projects/*` does not match the repository at all.
228051
228339
  * - the value must name the DISCOVERED REPOSITORY ROOT, which is an ancestor of
228052
228340
  * `cwd` whenever a command runs from a subdirectory. Resolving that root means
228053
228341
  * asking git, which is the command being refused.
@@ -284169,6 +284457,27 @@ const makeRuntimeDrainReporter = gen(function* () {
284169
284457
  var RuntimeDrainReporter = class extends Service$1()("forge/runtimeDrain/RuntimeDrainReporter") {};
284170
284458
  const RuntimeDrainReporterLive = effect(RuntimeDrainReporter, makeRuntimeDrainReporter);
284171
284459
  //#endregion
284460
+ //#region src/usage/providerRateLimits.ts
284461
+ /**
284462
+ * The SDK only ever reports ONE window per event. Only `five_hour` and
284463
+ * `seven_day` map to the two windows the Usage page shows; the
284464
+ * per-model/overage variants (seven_day_opus, overage, ...) are ignored here
284465
+ * on purpose rather than silently overwriting the plain 7-day figure.
284466
+ */
284467
+ function mapClaudeRateLimitInfo(info) {
284468
+ if (typeof info.utilization !== "number" || typeof info.resetsAt !== "number" || !info.status) return null;
284469
+ const kind = info.rateLimitType === "five_hour" ? "fiveHour" : info.rateLimitType === "seven_day" ? "sevenDay" : null;
284470
+ if (!kind) return null;
284471
+ return {
284472
+ kind,
284473
+ window: {
284474
+ usedPercent: Math.round(info.utilization * 100),
284475
+ resetsAt: (/* @__PURE__ */ new Date(info.resetsAt * 1e3)).toISOString(),
284476
+ status: info.status
284477
+ }
284478
+ };
284479
+ }
284480
+ //#endregion
284172
284481
  //#region src/orchestration/Layers/ProviderRuntimeIngestion.ts
284173
284482
  const providerTurnKey = (threadId, turnId) => `${threadId}:${turnId}`;
284174
284483
  const providerCommandId = (event, tag) => CommandId.make(`provider:${event.eventId}:${tag}:${crypto.randomUUID()}`);
@@ -290891,7 +291200,7 @@ const ServerLoggerLive = gen(function* () {
290891
291200
  * Observed live on a Forge Cloud sprite (2026-07-25): the browser opens
290892
291201
  * `wss://<sprite>.sprites.app/ws?routeKey=…&runtimeTicket=<JWT>`, and the HTTP
290893
291202
  * instrumentation records `url.full` / `url.query` verbatim. The ticket then
290894
- * lands in `/data/userdata/logs/server.trace.ndjson` at mode 644 — readable by
291203
+ * lands in `<FORGE_HOME>/userdata/logs/server.trace.ndjson` at mode 644 — readable by
290895
291204
  * the same user the agent runs as — and the URL also crosses fly.io's edge,
290896
291205
  * where infrastructure we do not control may log it.
290897
291206
  *
@@ -291183,7 +291492,7 @@ function resolveBuildCommitFromEnv(env) {
291183
291492
  * environment descriptor down instead of reporting an honest "unknown".
291184
291493
  */
291185
291494
  function readBakedBuildCommit() {
291186
- return "3a8f4c1280c7611f1850f146a6792e13b754bb4b";
291495
+ return "9e352ae66ea610fd1916726270fce8a1ab138a3b";
291187
291496
  }
291188
291497
  async function resolveServerBuildCommit(input) {
291189
291498
  if (isFullCommitSha(input.baked)) return input.baked;
@@ -299172,16 +299481,6 @@ function describeDispatchCause(cause) {
299172
299481
  if (deepest === void 0 || deepest.length <= DISPATCH_CAUSE_DETAIL_LIMIT) return deepest;
299173
299482
  return `${deepest.slice(0, DISPATCH_CAUSE_DETAIL_LIMIT)}...`;
299174
299483
  }
299175
- /**
299176
- * Where automation-created projects live when the caller does not say.
299177
- *
299178
- * This is the documented default of the `cloudProjectsRoot` setting
299179
- * (FORGE_CLOUD_PROJECTS_ROOT, see cli.ts) and exists only for direct callers
299180
- * such as tests. Every HTTP route passes the CONFIGURED value instead: reading
299181
- * the default here is what made a runtime configured with any other root create
299182
- * its automation projects in a directory nothing else read.
299183
- */
299184
- const DEFAULT_CLOUD_PROJECTS_ROOT = "/data/Projects";
299185
299484
  const respondToOrchestrationHttpError = (error) => gen(function* () {
299186
299485
  if (error._tag === "OrchestrationGetSnapshotError") {
299187
299486
  yield* logError("orchestration http route failed", {
@@ -300376,6 +300675,7 @@ function resolveWsUrl(baseUrl) {
300376
300675
  const callCmmdTool = legacyCmmdToolBridge.callTool;
300377
300676
  const extractMcpToolText = legacyCmmdToolBridge.extractText;
300378
300677
  const isCmmdMcpAuthError = legacyCmmdToolBridge.isAuthError;
300678
+ const __cmmdProxyRouteLayersStartIndex = registeredProxyRouteLayers().length;
300379
300679
  /**
300380
300680
  * CMMD-side path for the PROJECT-keyed Forge Cloud catalog. Shared by the list
300381
300681
  * proxy, the SSE poll-and-emit proxy, and the register/unregister proxies so the
@@ -300385,8 +300685,9 @@ const CMMD_CLOUD_PROJECTS_PATH = "/api/forge/context/cloud-projects";
300385
300685
  const CMMD_RUNTIMES_PATH = "/api/forge/context/runtimes";
300386
300686
  /**
300387
300687
  * Authenticate the browser session and resolve the CMMD JWT to forward
300388
- * upstream. Returns null when no token could be resolved, which every caller
300389
- * turns into a CMMD_AUTH_REQUIRED response.
300688
+ * upstream. `jwt` is null when none could be resolved, which every caller
300689
+ * turns into `respondCmmdConnectionRequired(session.sessionId)` — the same
300690
+ * unified `CMMD_AUTH_REQUIRED` body and auth-clear the registry uses.
300390
300691
  *
300391
300692
  * Shared so the auth preamble is written once rather than once per proxy route.
300392
300693
  */
@@ -300394,11 +300695,14 @@ function makeCmmdProxyAccessTokenEffect(logPrefix) {
300394
300695
  return gen(function* () {
300395
300696
  const request = yield* HttpServerRequest;
300396
300697
  const session = yield* (yield* ServerAuth).authenticateHttpRequest(request);
300397
- return yield* resolveCmmdJwtForSession({
300398
- sessionId: session.sessionId,
300399
- subject: session.subject,
300400
- logPrefix
300401
- });
300698
+ return {
300699
+ session,
300700
+ jwt: yield* resolveCmmdJwtForSession({
300701
+ sessionId: session.sessionId,
300702
+ subject: session.subject,
300703
+ logPrefix
300704
+ })
300705
+ };
300402
300706
  });
300403
300707
  }
300404
300708
  var WorkIntakeSnapshotReadError = class extends TaggedErrorClass()("WorkIntakeSnapshotReadError", {
@@ -300478,32 +300782,19 @@ const cmmdProfileRouteLayer = add$1("GET", "/api/cmmd/profile", gen(function* ()
300478
300782
  * `resolution`/`sinceTime`/`untilTime` when the page is drawing hours, which is
300479
300783
  * what lets CMMD cut hour buckets rather than only days.
300480
300784
  */
300481
- const cmmdUsageSummaryRouteLayer = registerProxyRoute({
300785
+ registerProxyRoute({
300482
300786
  forgePath: "/api/cmmd/usage/summary",
300483
300787
  method: "GET",
300484
300788
  cmmdPath: "/api/forge/context/usage/summary",
300485
300789
  orgIdSource: "none"
300486
300790
  });
300487
- /**
300488
- * The workspace's CMMD plan: entitlements, the current period, and how much of
300489
- * each metered allowance is left. This is subscription consumption, which is a
300490
- * different question from the API-equivalent estimate the usage summary above
300491
- * computes from transcripts.
300492
- *
300493
- * `orgIdSource` is `query` (FOR-36406): a plan belongs to an organization, and
300494
- * without one CMMD answers for the user's default organization, which is their
300495
- * personal space rather than the workspace their Environment runs in. The web
300496
- * passes the Environment's organization as `?orgId=` and the registry turns it
300497
- * into `X-Organization-ID`; without it CMMD still answers, for the default.
300498
- */
300499
- const cmmdBillingRouteLayer = registerProxyRoute({
300791
+ registerProxyRoute({
300500
300792
  forgePath: "/api/cmmd/billing",
300501
300793
  method: "GET",
300502
300794
  cmmdPath: "/api/forge/context/billing",
300503
300795
  orgIdSource: "query"
300504
300796
  });
300505
- /** Per-day consumption across that period, so the remaining figure gets a shape. */
300506
- const cmmdBillingSeriesRouteLayer = registerProxyRoute({
300797
+ registerProxyRoute({
300507
300798
  forgePath: "/api/cmmd/billing/series",
300508
300799
  method: "GET",
300509
300800
  cmmdPath: "/api/forge/context/billing/series",
@@ -300541,6 +300832,15 @@ function runCmmdRestProxy(session, proxy, dependencies = {}) {
300541
300832
  });
300542
300833
  }
300543
300834
  /**
300835
+ * Adapts `runCmmdRestProxy`'s `{ ok, value | error }` outcome into a
300836
+ * `ProxyHandlerRoute.run` result: the shared shape every converted handler's
300837
+ * `run` uses so it stays the three or so lines of the actual gateway call
300838
+ * plus response shaping, with resolve-and-retry left to `runCmmdRestProxy`.
300839
+ */
300840
+ function runCmmdRestProxyAsHandlerResult(session, proxy, shape) {
300841
+ return runCmmdRestProxy(session, proxy).pipe(flatMap((outcome) => outcome.ok ? succeed(shape(outcome.value)) : fail(outcome.error)));
300842
+ }
300843
+ /**
300544
300844
  * Forge-context REST responses wrap their payload in `{ data, meta, pagination? }`
300545
300845
  * (see CMMD `sendForgeEnvelope`). Unwrap to the bare payload so handler response
300546
300846
  * shapes match what the web client expected from the prior MCP text path.
@@ -300704,22 +301004,34 @@ function buildCreateBrainDocumentInput(payload) {
300704
301004
  ...payload.tags && payload.tags.length > 0 ? { tags: payload.tags } : {}
300705
301005
  };
300706
301006
  }
300707
- const cmmdCreateBrainDocRouteLayer = add$1("POST", "/api/cmmd/brain-docs", gen(function* () {
300708
- const request = yield* HttpServerRequest;
300709
- const session = yield* (yield* ServerAuth).authenticateHttpRequest(request);
300710
- if (!readCommandAccessTokenForSession(session.sessionId)) return jsonUnsafe({ error: "CMMD account not connected. Log in via the connections panel." }, { status: 401 });
300711
- const payload = parseBrainDocPayload(yield* request.json);
300712
- if (!payload) return jsonUnsafe({ error: "Invalid request: title (1-500 chars) and content (1-100k chars) are required." }, { status: 400 });
300713
- const restOutcome = yield* runCmmdRestProxy(session, (jwt) => cmmdGateway.createBrainDocument({
301007
+ function parseCreateBrainDocRequest(request) {
301008
+ return request.json.pipe(orElseSucceed(() => null), map$3((rawBody) => {
301009
+ const payload = parseBrainDocPayload(rawBody);
301010
+ return payload ? {
301011
+ ok: true,
301012
+ value: payload
301013
+ } : {
301014
+ ok: false,
301015
+ status: 400,
301016
+ body: { error: "Invalid request: title (1-500 chars) and content (1-100k chars) are required." }
301017
+ };
301018
+ }));
301019
+ }
301020
+ registerProxyHandler({
301021
+ forgePath: "/api/cmmd/brain-docs",
301022
+ method: "POST",
301023
+ parse: parseCreateBrainDocRequest,
301024
+ run: (payload, { session }) => runCmmdRestProxyAsHandlerResult(session, (jwt) => cmmdGateway.createBrainDocument({
300714
301025
  jwt,
300715
301026
  document: buildCreateBrainDocumentInput(payload)
300716
- }));
300717
- if (restOutcome.ok) return jsonUnsafe({
300718
- success: true,
300719
- doc: unwrapForgeEnvelope(restOutcome.value)
300720
- }, { status: 201 });
300721
- return buildProxyErrorResponse(restOutcome.error);
300722
- }).pipe(catchTag("AuthError", (error) => respondToAuthError(error))));
301027
+ }), (value) => ({
301028
+ status: 201,
301029
+ body: {
301030
+ success: true,
301031
+ doc: unwrapForgeEnvelope(value)
301032
+ }
301033
+ }))
301034
+ });
300723
301035
  function normalizeOptionalNullableString(value, options) {
300724
301036
  if (value === void 0) return void 0;
300725
301037
  if (value === null) return null;
@@ -300773,46 +301085,77 @@ function buildUpdateTaskToolInput(payload) {
300773
301085
  ...payload.labels !== void 0 ? { tags: payload.labels } : {}
300774
301086
  };
300775
301087
  }
300776
- const updateCmmdTaskHandler = gen(function* () {
300777
- const request = yield* HttpServerRequest;
300778
- const session = yield* (yield* ServerAuth).authenticateHttpRequest(request);
300779
- if (!readCommandAccessTokenForSession(session.sessionId)) return jsonUnsafe({ error: "CMMD account not connected. Log in via the connections panel." }, { status: 401 });
300780
- const payload = parseUpdateTaskPayload(yield* request.json);
300781
- if (!payload) return jsonUnsafe({ error: "Invalid request: taskId is required and at least one update field must be provided." }, { status: 400 });
301088
+ function parseUpdateCmmdTaskRequest(request) {
301089
+ return request.json.pipe(orElseSucceed(() => null), map$3((rawBody) => {
301090
+ const payload = parseUpdateTaskPayload(rawBody);
301091
+ return payload ? {
301092
+ ok: true,
301093
+ value: payload
301094
+ } : {
301095
+ ok: false,
301096
+ status: 400,
301097
+ body: { error: "Invalid request: taskId is required and at least one update field must be provided." }
301098
+ };
301099
+ }));
301100
+ }
301101
+ function runUpdateCmmdTask(payload, { session }) {
300782
301102
  const { taskId, ...patch } = buildUpdateTaskToolInput(payload);
300783
- const restOutcome = yield* runCmmdRestProxy(session, (jwt) => cmmdGateway.updateTask({
301103
+ return runCmmdRestProxyAsHandlerResult(session, (jwt) => cmmdGateway.updateTask({
300784
301104
  jwt,
300785
301105
  taskId: String(taskId),
300786
301106
  patch
300787
- }));
300788
- if (restOutcome.ok) {
301107
+ }), (value) => {
300789
301108
  invalidateCachedCmmdWorkIntakeForSession(session.sessionId);
300790
- return jsonUnsafe({
300791
- success: true,
300792
- details: unwrapForgeEnvelope(restOutcome.value)
300793
- }, { status: 200 });
300794
- }
300795
- return buildProxyErrorResponse(restOutcome.error);
300796
- }).pipe(catchTag("AuthError", (error) => respondToAuthError(error)));
300797
- const cmmdUpdateTaskRouteLayer = add$1("POST", "/api/cmmd/tasks/update", updateCmmdTaskHandler);
300798
- const commandUpdateTaskRouteLayer = add$1("POST", "/api/command/tasks/update", updateCmmdTaskHandler);
300799
- const cmmdAddTaskCommentRouteLayer = add$1("POST", "/api/cmmd/tasks/comment", gen(function* () {
300800
- const request = yield* HttpServerRequest;
300801
- const session = yield* (yield* ServerAuth).authenticateHttpRequest(request);
300802
- const payload = parseTaskCommentPayload(yield* request.json);
300803
- if (!payload) return jsonUnsafe({ error: "taskId and content (max 2000 chars) are required." }, { status: 400 });
300804
- if (!readCommandAccessTokenForSession(session.sessionId)) return jsonUnsafe({ error: "CMMD account not connected. Log in via the connections panel." }, { status: 401 });
300805
- const restOutcome = yield* runCmmdRestProxy(session, (jwt) => cmmdGateway.addTaskComment({
301109
+ return {
301110
+ status: 200,
301111
+ body: {
301112
+ success: true,
301113
+ details: unwrapForgeEnvelope(value)
301114
+ }
301115
+ };
301116
+ });
301117
+ }
301118
+ registerProxyHandler({
301119
+ forgePath: "/api/cmmd/tasks/update",
301120
+ method: "POST",
301121
+ parse: parseUpdateCmmdTaskRequest,
301122
+ run: runUpdateCmmdTask
301123
+ });
301124
+ registerProxyHandler({
301125
+ forgePath: "/api/command/tasks/update",
301126
+ method: "POST",
301127
+ parse: parseUpdateCmmdTaskRequest,
301128
+ run: runUpdateCmmdTask
301129
+ });
301130
+ function parseAddCmmdTaskCommentRequest(request) {
301131
+ return request.json.pipe(orElseSucceed(() => null), map$3((rawBody) => {
301132
+ const payload = parseTaskCommentPayload(rawBody);
301133
+ return payload ? {
301134
+ ok: true,
301135
+ value: payload
301136
+ } : {
301137
+ ok: false,
301138
+ status: 400,
301139
+ body: { error: "taskId and content (max 2000 chars) are required." }
301140
+ };
301141
+ }));
301142
+ }
301143
+ registerProxyHandler({
301144
+ forgePath: "/api/cmmd/tasks/comment",
301145
+ method: "POST",
301146
+ parse: parseAddCmmdTaskCommentRequest,
301147
+ run: (payload, { session }) => runCmmdRestProxyAsHandlerResult(session, (jwt) => cmmdGateway.addTaskComment({
300806
301148
  jwt,
300807
301149
  taskId: payload.taskId,
300808
301150
  content: payload.content
300809
- }));
300810
- if (restOutcome.ok) return jsonUnsafe({
300811
- success: true,
300812
- details: unwrapForgeEnvelope(restOutcome.value)
300813
- }, { status: 201 });
300814
- return buildProxyErrorResponse(restOutcome.error);
300815
- }).pipe(catchTag("AuthError", (error) => respondToAuthError(error))));
301151
+ }), (value) => ({
301152
+ status: 201,
301153
+ body: {
301154
+ success: true,
301155
+ details: unwrapForgeEnvelope(value)
301156
+ }
301157
+ }))
301158
+ });
300816
301159
  function parseTaskCommentPayload(body) {
300817
301160
  if (typeof body !== "object" || body === null) return null;
300818
301161
  const b = body;
@@ -300841,23 +301184,38 @@ function normalizeTaskSearchParams(url) {
300841
301184
  limit: Math.min(Number(url.searchParams.get("limit") ?? "20"), 50)
300842
301185
  };
300843
301186
  }
300844
- const cmmdSearchTasksRouteLayer = add$1("GET", "/api/cmmd/tasks/search", gen(function* () {
300845
- const request = yield* HttpServerRequest;
300846
- const accessToken = readCommandAccessTokenForSession((yield* (yield* ServerAuth).authenticateHttpRequest(request)).sessionId);
300847
- if (!accessToken) return jsonUnsafe({ error: "CMMD account not connected. Log in via the connections panel." }, { status: 401 });
300848
- const search = normalizeTaskSearchParams(new URL(request.url, "http://localhost"));
300849
- if (!search) return jsonUnsafe({
300850
- tasks: [],
300851
- total: 0
300852
- }, { status: 200 });
300853
- return jsonUnsafe(parseJsonObjectText(extractMcpToolText(yield* promise(() => callCmmdTool(accessToken, "search_tasks", {
301187
+ function parseSearchCmmdTasksRequest(request) {
301188
+ return sync$1(() => ({
301189
+ ok: true,
301190
+ value: normalizeTaskSearchParams(new URL(request.url, "http://localhost"))
301191
+ }));
301192
+ }
301193
+ function runSearchCmmdTasks(search, { session }) {
301194
+ if (!search) return succeed({
301195
+ status: 200,
301196
+ body: {
301197
+ tasks: [],
301198
+ total: 0
301199
+ }
301200
+ });
301201
+ const accessToken = readCommandAccessTokenForSession(session.sessionId) ?? "";
301202
+ return promise(() => callCmmdTool(accessToken, "search_tasks", {
300854
301203
  query: search.query,
300855
301204
  limit: search.limit
300856
- })))) ?? {
300857
- tasks: [],
300858
- total: 0
300859
- }, { status: 200 });
300860
- }).pipe(catchTag("AuthError", (error) => respondToAuthError(error))));
301205
+ })).pipe(map$3((result) => ({
301206
+ status: 200,
301207
+ body: parseJsonObjectText(extractMcpToolText(result)) ?? {
301208
+ tasks: [],
301209
+ total: 0
301210
+ }
301211
+ })));
301212
+ }
301213
+ registerProxyHandler({
301214
+ forgePath: "/api/cmmd/tasks/search",
301215
+ method: "GET",
301216
+ parse: parseSearchCmmdTasksRequest,
301217
+ run: runSearchCmmdTasks
301218
+ });
300861
301219
  function parseJsonObjectText(text) {
300862
301220
  if (!text) return null;
300863
301221
  try {
@@ -300871,23 +301229,47 @@ function parsePositiveIntegerId(value) {
300871
301229
  const numericId = Number(value);
300872
301230
  return Number.isInteger(numericId) && numericId > 0 ? numericId : null;
300873
301231
  }
300874
- const cmmdGetTaskRouteLayer = add$1("GET", "/api/cmmd/tasks/:id", gen(function* () {
300875
- const request = yield* HttpServerRequest;
300876
- const session = yield* (yield* ServerAuth).authenticateHttpRequest(request);
300877
- if (!readCommandAccessTokenForSession(session.sessionId)) return jsonUnsafe({ error: "CMMD account not connected. Log in via the connections panel." }, { status: 401 });
300878
- const taskId = extractIdFromPath(new URL(request.url, "http://localhost").pathname, 1);
300879
- if (!taskId) return jsonUnsafe({ error: "Task ID is required." }, { status: 400 });
300880
- const numericId = parsePositiveIntegerId(taskId);
300881
- if (!numericId) return jsonUnsafe({ error: "Invalid task ID." }, { status: 400 });
300882
- const restOutcome = yield* runCmmdRestProxy(session, (jwt) => cmmdGateway.getTask({
301232
+ function parseGetCmmdTaskRequest(request) {
301233
+ return sync$1(() => {
301234
+ const taskId = extractIdFromPath(new URL(request.url, "http://localhost").pathname, 1);
301235
+ if (!taskId) return {
301236
+ ok: false,
301237
+ status: 400,
301238
+ body: { error: "Task ID is required." }
301239
+ };
301240
+ const numericId = parsePositiveIntegerId(taskId);
301241
+ if (!numericId) return {
301242
+ ok: false,
301243
+ status: 400,
301244
+ body: { error: "Invalid task ID." }
301245
+ };
301246
+ return {
301247
+ ok: true,
301248
+ value: numericId
301249
+ };
301250
+ });
301251
+ }
301252
+ function runGetCmmdTask(numericId, { session }) {
301253
+ return runCmmdRestProxyAsHandlerResult(session, (jwt) => cmmdGateway.getTask({
300883
301254
  jwt,
300884
301255
  taskId: String(numericId)
300885
- }));
300886
- if (!restOutcome.ok) return buildProxyErrorResponse(restOutcome.error);
300887
- const task = unwrapForgeEnvelope(restOutcome.value);
300888
- if (task === null || task === void 0) return jsonUnsafe({ error: "Task not found." }, { status: 404 });
300889
- return jsonUnsafe(task, { status: 200 });
300890
- }).pipe(catchTag("AuthError", (error) => respondToAuthError(error))));
301256
+ }), (value) => {
301257
+ const task = unwrapForgeEnvelope(value);
301258
+ return task === null || task === void 0 ? {
301259
+ status: 404,
301260
+ body: { error: "Task not found." }
301261
+ } : {
301262
+ status: 200,
301263
+ body: task
301264
+ };
301265
+ });
301266
+ }
301267
+ registerProxyHandler({
301268
+ forgePath: "/api/cmmd/tasks/:id",
301269
+ method: "GET",
301270
+ parse: parseGetCmmdTaskRequest,
301271
+ run: runGetCmmdTask
301272
+ });
300891
301273
  function extractIdFromPath(pathname, fromEnd) {
300892
301274
  const parts = pathname.split("/").filter(Boolean);
300893
301275
  return parts[parts.length - fromEnd];
@@ -300899,22 +301281,37 @@ function decodePathSegment(segment) {
300899
301281
  return null;
300900
301282
  }
300901
301283
  }
300902
- const cmmdGetTaskCommentsRouteLayer = add$1("GET", "/api/cmmd/tasks/:id/comments", gen(function* () {
300903
- const request = yield* HttpServerRequest;
300904
- const session = yield* (yield* ServerAuth).authenticateHttpRequest(request);
300905
- const taskId = extractIdFromPath(new URL(request.url, "http://localhost").pathname, 2);
300906
- if (!taskId) return jsonUnsafe({ error: "Task ID is required." }, { status: 400 });
300907
- if (!readCommandAccessTokenForSession(session.sessionId)) return jsonUnsafe({ error: "CMMD account not connected. Log in via the connections panel." }, { status: 401 });
300908
- const restOutcome = yield* runCmmdRestProxy(session, (jwt) => cmmdGateway.listTaskComments({
301284
+ function parseGetCmmdTaskCommentsRequest(request) {
301285
+ return sync$1(() => {
301286
+ const taskId = extractIdFromPath(new URL(request.url, "http://localhost").pathname, 2);
301287
+ return taskId ? {
301288
+ ok: true,
301289
+ value: taskId
301290
+ } : {
301291
+ ok: false,
301292
+ status: 400,
301293
+ body: { error: "Task ID is required." }
301294
+ };
301295
+ });
301296
+ }
301297
+ function runGetCmmdTaskComments(taskId, { session }) {
301298
+ return runCmmdRestProxyAsHandlerResult(session, (jwt) => cmmdGateway.listTaskComments({
300909
301299
  jwt,
300910
301300
  taskId
300911
- }));
300912
- if (restOutcome.ok) {
300913
- const data = unwrapForgeEnvelope(restOutcome.value);
300914
- return jsonUnsafe({ comments: Array.isArray(data) ? data : [] }, { status: 200 });
300915
- }
300916
- return buildProxyErrorResponse(restOutcome.error);
300917
- }).pipe(catchTag("AuthError", (error) => respondToAuthError(error))));
301301
+ }), (value) => {
301302
+ const data = unwrapForgeEnvelope(value);
301303
+ return {
301304
+ status: 200,
301305
+ body: { comments: Array.isArray(data) ? data : [] }
301306
+ };
301307
+ });
301308
+ }
301309
+ registerProxyHandler({
301310
+ forgePath: "/api/cmmd/tasks/:id/comments",
301311
+ method: "GET",
301312
+ parse: parseGetCmmdTaskCommentsRequest,
301313
+ run: runGetCmmdTaskComments
301314
+ });
300918
301315
  function normalizeCommentList(value) {
300919
301316
  if (Array.isArray(value)) return value;
300920
301317
  if (!value || typeof value !== "object") return [];
@@ -301020,55 +301417,54 @@ const cmmdUpdateProjectRouteLayer = add$1("PATCH", "/api/cmmd/projects/:id", gen
301020
301417
  project: outcome.value
301021
301418
  }, { status: 200 });
301022
301419
  }).pipe(catchTag("AuthError", (error) => respondToAuthError(error))));
301023
- const cmmdGetProjectRepositoryRouteLayer = registerProxyRoute({
301420
+ registerProxyRoute({
301024
301421
  forgePath: "/api/cmmd/projects/:id/repository",
301025
301422
  method: "GET",
301026
301423
  cmmdPath: "/api/forge/context/projects/:id/repository",
301027
301424
  orgIdSource: "none",
301028
301425
  responseShape: "unwrapData"
301029
301426
  });
301030
- /** Canonical repository identity; unlike the singular route above, this is not execution-link state. */
301031
- const cmmdListProjectRepositoriesRouteLayer = registerProxyRoute({
301427
+ registerProxyRoute({
301032
301428
  forgePath: "/api/cmmd/projects/:projectId/repositories",
301033
301429
  method: "GET",
301034
301430
  cmmdPath: "/api/forge/context/projects/:projectId/repositories",
301035
301431
  orgIdSource: "none",
301036
301432
  responseShape: "unwrapData"
301037
301433
  });
301038
- const cmmdGetOrgMembersRouteLayer = registerProxyRoute({
301434
+ registerProxyRoute({
301039
301435
  forgePath: "/api/cmmd/organizations/:id/members",
301040
301436
  method: "GET",
301041
301437
  cmmdPath: "/api/organizations/:id/members",
301042
301438
  orgIdSource: "none",
301043
301439
  responseShape: "unwrapData"
301044
301440
  });
301045
- const cmmdSimHostsRouteLayer = registerProxyRoute({
301441
+ registerProxyRoute({
301046
301442
  forgePath: "/api/cmmd/sim-host/hosts",
301047
301443
  method: "GET",
301048
301444
  cmmdPath: "/api/forge/context/sim-host/hosts",
301049
301445
  responseShape: "unwrapData"
301050
301446
  });
301051
- const cmmdSimLeaseReadRouteLayer = registerProxyRoute({
301447
+ registerProxyRoute({
301052
301448
  forgePath: "/api/cmmd/sim-host/leases",
301053
301449
  method: "GET",
301054
301450
  cmmdPath: "/api/forge/context/sim-host/leases",
301055
301451
  responseShape: "unwrapData"
301056
301452
  });
301057
- const cmmdSimLeaseClaimRouteLayer = registerProxyRoute({
301453
+ registerProxyRoute({
301058
301454
  forgePath: "/api/cmmd/sim-host/leases",
301059
301455
  method: "POST",
301060
301456
  cmmdPath: "/api/forge/context/sim-host/leases",
301061
301457
  responseShape: "unwrapData",
301062
301458
  successStatus: 200
301063
301459
  });
301064
- const cmmdSimLeaseReleaseRouteLayer = registerProxyRoute({
301460
+ registerProxyRoute({
301065
301461
  forgePath: "/api/cmmd/sim-host/leases/:leaseId/release",
301066
301462
  method: "POST",
301067
301463
  cmmdPath: "/api/forge/context/sim-host/leases/:leaseId/release",
301068
301464
  responseShape: "unwrapData",
301069
301465
  successStatus: 200
301070
301466
  });
301071
- const cmmdSimLeaseRenewRouteLayer = registerProxyRoute({
301467
+ registerProxyRoute({
301072
301468
  forgePath: "/api/cmmd/sim-host/leases/:leaseId/renew",
301073
301469
  method: "POST",
301074
301470
  cmmdPath: "/api/forge/context/sim-host/leases/:leaseId/renew",
@@ -301092,7 +301488,7 @@ function getMultipartContentType(headers) {
301092
301488
  const contentType = headers["content-type"] ?? "";
301093
301489
  return contentType.includes("multipart/form-data") ? contentType : null;
301094
301490
  }
301095
- const cmmdGetTaskAttachmentsRouteLayer = registerProxyRoute({
301491
+ registerProxyRoute({
301096
301492
  forgePath: "/api/cmmd/tasks/:id/attachments",
301097
301493
  method: "GET",
301098
301494
  cmmdPath: "/api/forge/context/tasks/:id/attachments",
@@ -301127,150 +301523,150 @@ const cmmdUpdateTaskCommentRouteLayer = add$1("PATCH", "/api/cmmd/tasks/:taskId/
301127
301523
  ...outcome.value
301128
301524
  }, { status: 200 });
301129
301525
  }).pipe(catchTag("AuthError", (error) => respondToAuthError(error))));
301130
- const cmmdDeleteTaskCommentRouteLayer = registerProxyRoute({
301526
+ registerProxyRoute({
301131
301527
  forgePath: "/api/cmmd/tasks/:taskId/comments/:commentId",
301132
301528
  method: "DELETE",
301133
301529
  cmmdPath: "/api/forge/context/tasks/:taskId/comments/:commentId",
301134
301530
  orgIdSource: "none",
301135
301531
  requestBody: "json"
301136
301532
  });
301137
- const cmmdListProjectAgentMembersRouteLayer = registerProxyRoute({
301533
+ registerProxyRoute({
301138
301534
  forgePath: "/api/cmmd/projects/:projectId/agent-members",
301139
301535
  method: "GET",
301140
301536
  cmmdPath: "/api/forge/context/projects/:projectId/agent-members",
301141
301537
  orgIdSource: "none",
301142
301538
  responseShape: "unwrapData"
301143
301539
  });
301144
- const cmmdCreateProjectAgentMemberRouteLayer = registerProxyRoute({
301540
+ registerProxyRoute({
301145
301541
  forgePath: "/api/cmmd/projects/:projectId/agent-members",
301146
301542
  method: "POST",
301147
301543
  cmmdPath: "/api/forge/context/projects/:projectId/agent-members",
301148
301544
  orgIdSource: "none",
301149
301545
  responseShape: "unwrapData"
301150
301546
  });
301151
- const cmmdGetProjectAgentMemberRouteLayer = registerProxyRoute({
301547
+ registerProxyRoute({
301152
301548
  forgePath: "/api/cmmd/projects/:projectId/agent-members/:memberId",
301153
301549
  method: "GET",
301154
301550
  cmmdPath: "/api/forge/context/projects/:projectId/agent-members/:memberId",
301155
301551
  orgIdSource: "none",
301156
301552
  responseShape: "unwrapData"
301157
301553
  });
301158
- const cmmdRenameProjectAgentMemberRouteLayer = registerProxyRoute({
301554
+ registerProxyRoute({
301159
301555
  forgePath: "/api/cmmd/projects/:projectId/agent-members/:memberId",
301160
301556
  method: "PATCH",
301161
301557
  cmmdPath: "/api/forge/context/projects/:projectId/agent-members/:memberId",
301162
301558
  orgIdSource: "none",
301163
301559
  responseShape: "unwrapData"
301164
301560
  });
301165
- const cmmdRetireProjectAgentMemberRouteLayer = registerProxyRoute({
301561
+ registerProxyRoute({
301166
301562
  forgePath: "/api/cmmd/projects/:projectId/agent-members/:memberId/retire",
301167
301563
  method: "POST",
301168
301564
  cmmdPath: "/api/forge/context/projects/:projectId/agent-members/:memberId/retire",
301169
301565
  orgIdSource: "none",
301170
301566
  responseShape: "unwrapData"
301171
301567
  });
301172
- const cmmdListProjectAgentMemberInstancesRouteLayer = registerProxyRoute({
301568
+ registerProxyRoute({
301173
301569
  forgePath: "/api/cmmd/projects/:projectId/agent-members/:memberId/instances",
301174
301570
  method: "GET",
301175
301571
  cmmdPath: "/api/forge/context/projects/:projectId/agent-members/:memberId/instances",
301176
301572
  orgIdSource: "none",
301177
301573
  responseShape: "unwrapData"
301178
301574
  });
301179
- const cmmdPreviewProjectAgentMemberConsolidationRouteLayer = registerProxyRoute({
301575
+ registerProxyRoute({
301180
301576
  forgePath: "/api/cmmd/projects/:projectId/agent-members/consolidation/preview",
301181
301577
  method: "POST",
301182
301578
  cmmdPath: "/api/forge/context/projects/:projectId/agent-members/consolidation/preview",
301183
301579
  orgIdSource: "none",
301184
301580
  responseShape: "unwrapData"
301185
301581
  });
301186
- const cmmdApplyProjectAgentMemberConsolidationRouteLayer = registerProxyRoute({
301582
+ registerProxyRoute({
301187
301583
  forgePath: "/api/cmmd/projects/:projectId/agent-members/consolidation/apply",
301188
301584
  method: "POST",
301189
301585
  cmmdPath: "/api/forge/context/projects/:projectId/agent-members/consolidation/apply",
301190
301586
  orgIdSource: "none",
301191
301587
  responseShape: "unwrapData"
301192
301588
  });
301193
- const cmmdPutProjectTaskAssignmentRouteLayer = registerProxyRoute({
301589
+ registerProxyRoute({
301194
301590
  forgePath: "/api/cmmd/projects/:projectId/tasks/:taskId/assignment",
301195
301591
  method: "PUT",
301196
301592
  cmmdPath: "/api/forge/context/projects/:projectId/tasks/:taskId/assignment",
301197
301593
  orgIdSource: "none",
301198
301594
  responseShape: "unwrapData"
301199
301595
  });
301200
- const cmmdListTasksRouteLayer = registerProxyRoute({
301596
+ registerProxyRoute({
301201
301597
  forgePath: "/api/cmmd/tasks",
301202
301598
  method: "GET",
301203
301599
  cmmdPath: "/api/forge/context/tasks"
301204
301600
  });
301205
- const cmmdCreateTaskRouteLayer = registerProxyRoute({
301601
+ registerProxyRoute({
301206
301602
  forgePath: "/api/cmmd/tasks",
301207
301603
  method: "POST",
301208
301604
  cmmdPath: "/api/forge/context/tasks"
301209
301605
  });
301210
- const cmmdArchiveTaskRouteLayer = registerProxyRoute({
301606
+ registerProxyRoute({
301211
301607
  forgePath: "/api/cmmd/tasks/:id/archive",
301212
301608
  method: "POST",
301213
301609
  cmmdPath: "/api/forge/context/tasks/:id/archive",
301214
301610
  orgIdSource: "none"
301215
301611
  });
301216
- const cmmdUnarchiveTaskRouteLayer = registerProxyRoute({
301612
+ registerProxyRoute({
301217
301613
  forgePath: "/api/cmmd/tasks/:id/unarchive",
301218
301614
  method: "POST",
301219
301615
  cmmdPath: "/api/forge/context/tasks/:id/unarchive",
301220
301616
  orgIdSource: "none"
301221
301617
  });
301222
- const cmmdListSavedViewsRouteLayer = registerProxyRoute({
301618
+ registerProxyRoute({
301223
301619
  forgePath: "/api/cmmd/saved-views",
301224
301620
  method: "GET",
301225
301621
  cmmdPath: "/api/forge/context/saved-views",
301226
301622
  orgIdSource: "none"
301227
301623
  });
301228
- const cmmdCreateSavedViewRouteLayer = registerProxyRoute({
301624
+ registerProxyRoute({
301229
301625
  forgePath: "/api/cmmd/saved-views",
301230
301626
  method: "POST",
301231
301627
  cmmdPath: "/api/forge/context/saved-views",
301232
301628
  orgIdSource: "none",
301233
301629
  successStatus: 201
301234
301630
  });
301235
- const cmmdImportSavedViewRouteLayer = registerProxyRoute({
301631
+ registerProxyRoute({
301236
301632
  forgePath: "/api/cmmd/saved-views/import",
301237
301633
  method: "POST",
301238
301634
  cmmdPath: "/api/forge/context/saved-views/import",
301239
301635
  orgIdSource: "none"
301240
301636
  });
301241
- const cmmdUpdateSavedViewRouteLayer = registerProxyRoute({
301637
+ registerProxyRoute({
301242
301638
  forgePath: "/api/cmmd/saved-views/:viewId",
301243
301639
  method: "PATCH",
301244
301640
  cmmdPath: "/api/forge/context/saved-views/:viewId",
301245
301641
  orgIdSource: "none"
301246
301642
  });
301247
- const cmmdDeleteSavedViewRouteLayer = registerProxyRoute({
301643
+ registerProxyRoute({
301248
301644
  forgePath: "/api/cmmd/saved-views/:viewId",
301249
301645
  method: "DELETE",
301250
301646
  cmmdPath: "/api/forge/context/saved-views/:viewId",
301251
301647
  orgIdSource: "none",
301252
301648
  forwardSearchParams: true
301253
301649
  });
301254
- const cmmdListProjectsRouteLayer = registerProxyRoute({
301650
+ registerProxyRoute({
301255
301651
  forgePath: "/api/cmmd/projects",
301256
301652
  method: "GET",
301257
301653
  cmmdPath: "/api/forge/context/projects",
301258
301654
  responseShape: "passthrough"
301259
301655
  });
301260
- const cmmdGetProjectRouteLayer = registerProxyRoute({
301656
+ registerProxyRoute({
301261
301657
  forgePath: "/api/cmmd/projects/:id",
301262
301658
  method: "GET",
301263
301659
  cmmdPath: "/api/forge/context/projects/:id",
301264
301660
  orgIdSource: "none",
301265
301661
  responseShape: "passthrough"
301266
301662
  });
301267
- const cmmdCreateProjectRouteLayer = registerProxyRoute({
301663
+ registerProxyRoute({
301268
301664
  forgePath: "/api/cmmd/projects",
301269
301665
  method: "POST",
301270
301666
  cmmdPath: "/api/projects",
301271
301667
  responseShape: "passthrough"
301272
301668
  });
301273
- const cmmdDeleteProjectRouteLayer = registerProxyRoute({
301669
+ registerProxyRoute({
301274
301670
  forgePath: "/api/cmmd/projects/:id",
301275
301671
  method: "DELETE",
301276
301672
  cmmdPath: "/api/forge/context/projects/:id",
@@ -301278,78 +301674,78 @@ const cmmdDeleteProjectRouteLayer = registerProxyRoute({
301278
301674
  fixedSearchParams: { soft: "false" },
301279
301675
  workIntakeInvalidation: "always"
301280
301676
  });
301281
- const cmmdMoveProjectRouteLayer = registerProxyRoute({
301677
+ registerProxyRoute({
301282
301678
  forgePath: "/api/cmmd/projects/:id/move",
301283
301679
  method: "POST",
301284
301680
  cmmdPath: "/api/forge/context/projects/:id/move",
301285
301681
  orgIdSource: "none",
301286
301682
  responseShape: "unwrapData"
301287
301683
  });
301288
- const cmmdGetProjectMembersRouteLayer = registerProxyRoute({
301684
+ registerProxyRoute({
301289
301685
  forgePath: "/api/cmmd/projects/:id/members",
301290
301686
  method: "GET",
301291
301687
  cmmdPath: "/api/forge/context/projects/:id/team"
301292
301688
  });
301293
- const cmmdGetProjectMilestonesRouteLayer = registerProxyRoute({
301689
+ registerProxyRoute({
301294
301690
  forgePath: "/api/cmmd/projects/:id/milestones",
301295
301691
  method: "GET",
301296
301692
  cmmdPath: "/api/forge/context/projects/:id/milestones"
301297
301693
  });
301298
- const cmmdCreateProjectMilestoneRouteLayer = registerProxyRoute({
301694
+ registerProxyRoute({
301299
301695
  forgePath: "/api/cmmd/projects/:id/milestones",
301300
301696
  method: "POST",
301301
301697
  cmmdPath: "/api/forge/context/projects/:id/milestones",
301302
301698
  orgIdSource: "none",
301303
301699
  responseShape: "unwrapData"
301304
301700
  });
301305
- const cmmdUpdateProjectMilestoneRouteLayer = registerProxyRoute({
301701
+ registerProxyRoute({
301306
301702
  forgePath: "/api/cmmd/projects/:id/milestones/:milestoneId",
301307
301703
  method: "PATCH",
301308
301704
  cmmdPath: "/api/forge/context/projects/:id/milestones/:milestoneId",
301309
301705
  orgIdSource: "none",
301310
301706
  responseShape: "unwrapData"
301311
301707
  });
301312
- const cmmdDeleteProjectMilestoneRouteLayer = registerProxyRoute({
301708
+ registerProxyRoute({
301313
301709
  forgePath: "/api/cmmd/projects/:id/milestones/:milestoneId",
301314
301710
  method: "DELETE",
301315
301711
  cmmdPath: "/api/forge/context/projects/:id/milestones/:milestoneId",
301316
301712
  orgIdSource: "none"
301317
301713
  });
301318
- const cmmdGetProjectUpdatesRouteLayer = registerProxyRoute({
301714
+ registerProxyRoute({
301319
301715
  forgePath: "/api/cmmd/projects/:id/updates",
301320
301716
  method: "GET",
301321
301717
  cmmdPath: "/api/forge/context/projects/:id/updates",
301322
301718
  orgIdSource: "none",
301323
301719
  responseShape: "passthrough"
301324
301720
  });
301325
- const cmmdCreateProjectUpdateRouteLayer = registerProxyRoute({
301721
+ registerProxyRoute({
301326
301722
  forgePath: "/api/cmmd/projects/:id/updates",
301327
301723
  method: "POST",
301328
301724
  cmmdPath: "/api/forge/context/projects/:id/updates",
301329
301725
  orgIdSource: "none",
301330
301726
  responseShape: "unwrapData"
301331
301727
  });
301332
- const cmmdUpdateProjectUpdateRouteLayer = registerProxyRoute({
301728
+ registerProxyRoute({
301333
301729
  forgePath: "/api/cmmd/projects/:id/updates/:updateId",
301334
301730
  method: "PATCH",
301335
301731
  cmmdPath: "/api/forge/context/projects/:id/updates/:updateId",
301336
301732
  orgIdSource: "none",
301337
301733
  responseShape: "unwrapData"
301338
301734
  });
301339
- const cmmdDeleteProjectUpdateRouteLayer = registerProxyRoute({
301735
+ registerProxyRoute({
301340
301736
  forgePath: "/api/cmmd/projects/:id/updates/:updateId",
301341
301737
  method: "DELETE",
301342
301738
  cmmdPath: "/api/forge/context/projects/:id/updates/:updateId",
301343
301739
  orgIdSource: "none"
301344
301740
  });
301345
- const cmmdImproveProjectContentRouteLayer = registerProxyRoute({
301741
+ registerProxyRoute({
301346
301742
  forgePath: "/api/cmmd/projects/:id/content/readability",
301347
301743
  method: "POST",
301348
301744
  cmmdPath: "/api/forge/context/projects/:id/content/readability",
301349
301745
  orgIdSource: "none",
301350
301746
  responseShape: "unwrapData"
301351
301747
  });
301352
- const cmmdCreateProjectTaskDraftRouteLayer = registerProxyRoute({
301748
+ registerProxyRoute({
301353
301749
  forgePath: "/api/cmmd/projects/:projectId/task-drafts",
301354
301750
  method: "POST",
301355
301751
  cmmdPath: "/api/forge/context/projects/:projectId/task-drafts",
@@ -301357,7 +301753,7 @@ const cmmdCreateProjectTaskDraftRouteLayer = registerProxyRoute({
301357
301753
  responseShape: "unwrapData",
301358
301754
  successStatus: 201
301359
301755
  });
301360
- const cmmdGetProjectTaskDraftRouteLayer = registerProxyRoute({
301756
+ registerProxyRoute({
301361
301757
  forgePath: "/api/cmmd/projects/:projectId/task-drafts/:draftId",
301362
301758
  method: "GET",
301363
301759
  cmmdPath: "/api/forge/context/projects/:projectId/task-drafts/:draftId",
@@ -301365,7 +301761,7 @@ const cmmdGetProjectTaskDraftRouteLayer = registerProxyRoute({
301365
301761
  responseShape: "unwrapData",
301366
301762
  successStatus: 200
301367
301763
  });
301368
- const cmmdUpdateProjectTaskDraftRouteLayer = registerProxyRoute({
301764
+ registerProxyRoute({
301369
301765
  forgePath: "/api/cmmd/projects/:projectId/task-drafts/:draftId",
301370
301766
  method: "PATCH",
301371
301767
  cmmdPath: "/api/forge/context/projects/:projectId/task-drafts/:draftId",
@@ -301373,7 +301769,7 @@ const cmmdUpdateProjectTaskDraftRouteLayer = registerProxyRoute({
301373
301769
  responseShape: "unwrapData",
301374
301770
  successStatus: 200
301375
301771
  });
301376
- const cmmdPreviewProjectTaskDraftRouteLayer = registerProxyRoute({
301772
+ registerProxyRoute({
301377
301773
  forgePath: "/api/cmmd/projects/:projectId/task-drafts/:draftId/preview",
301378
301774
  method: "POST",
301379
301775
  cmmdPath: "/api/forge/context/projects/:projectId/task-drafts/:draftId/preview",
@@ -301381,7 +301777,7 @@ const cmmdPreviewProjectTaskDraftRouteLayer = registerProxyRoute({
301381
301777
  responseShape: "unwrapData",
301382
301778
  successStatus: 200
301383
301779
  });
301384
- const cmmdCommitProjectTaskDraftRouteLayer = registerProxyRoute({
301780
+ registerProxyRoute({
301385
301781
  forgePath: "/api/cmmd/projects/:projectId/task-drafts/:draftId/commit",
301386
301782
  method: "POST",
301387
301783
  cmmdPath: "/api/forge/context/projects/:projectId/task-drafts/:draftId/commit",
@@ -301389,7 +301785,7 @@ const cmmdCommitProjectTaskDraftRouteLayer = registerProxyRoute({
301389
301785
  responseShape: "unwrapData",
301390
301786
  successStatus: 200
301391
301787
  });
301392
- const cmmdDiscardProjectTaskDraftRouteLayer = registerProxyRoute({
301788
+ registerProxyRoute({
301393
301789
  forgePath: "/api/cmmd/projects/:projectId/task-drafts/:draftId/discard",
301394
301790
  method: "POST",
301395
301791
  cmmdPath: "/api/forge/context/projects/:projectId/task-drafts/:draftId/discard",
@@ -301397,352 +301793,352 @@ const cmmdDiscardProjectTaskDraftRouteLayer = registerProxyRoute({
301397
301793
  responseShape: "unwrapData",
301398
301794
  successStatus: 200
301399
301795
  });
301400
- const cmmdGetProjectLeadPlanRouteLayer = registerProxyRoute({
301796
+ registerProxyRoute({
301401
301797
  forgePath: "/api/cmmd/projects/:projectId/project-lead/plan",
301402
301798
  method: "GET",
301403
301799
  cmmdPath: "/api/forge/context/projects/:projectId/project-lead/plan",
301404
301800
  orgIdSource: "none"
301405
301801
  });
301406
- const cmmdActivateProjectLeadAuthorityRouteLayer = registerProxyRoute({
301802
+ registerProxyRoute({
301407
301803
  forgePath: "/api/cmmd/projects/:projectId/project-lead/authority/activate",
301408
301804
  method: "POST",
301409
301805
  cmmdPath: "/api/forge/context/projects/:projectId/project-lead/authority/activate",
301410
301806
  orgIdSource: "none",
301411
301807
  responseShape: "unwrapData"
301412
301808
  });
301413
- const cmmdGetProjectLeadReadinessRouteLayer = registerProxyRoute({
301809
+ registerProxyRoute({
301414
301810
  forgePath: "/api/cmmd/projects/:projectId/project-lead/readiness",
301415
301811
  method: "GET",
301416
301812
  cmmdPath: "/api/forge/context/projects/:projectId/project-lead/readiness",
301417
301813
  orgIdSource: "none"
301418
301814
  });
301419
- const cmmdGetProjectLeadCapabilitiesRouteLayer = registerProxyRoute({
301815
+ registerProxyRoute({
301420
301816
  forgePath: "/api/cmmd/projects/:projectId/project-lead/capabilities",
301421
301817
  method: "GET",
301422
301818
  cmmdPath: "/api/forge/context/projects/:projectId/project-lead/capabilities",
301423
301819
  orgIdSource: "none"
301424
301820
  });
301425
- const cmmdGetProjectLeadSummaryRouteLayer = registerProxyRoute({
301821
+ registerProxyRoute({
301426
301822
  forgePath: "/api/cmmd/projects/:projectId/project-lead/summary",
301427
301823
  method: "GET",
301428
301824
  cmmdPath: "/api/forge/context/projects/:projectId/project-lead/summary",
301429
301825
  orgIdSource: "none"
301430
301826
  });
301431
- const cmmdGetProjectLeadDetailRouteLayer = registerProxyRoute({
301827
+ registerProxyRoute({
301432
301828
  forgePath: "/api/cmmd/projects/:projectId/project-lead/detail",
301433
301829
  method: "GET",
301434
301830
  cmmdPath: "/api/forge/context/projects/:projectId/project-lead/detail",
301435
301831
  orgIdSource: "none"
301436
301832
  });
301437
- const cmmdGetProjectLeadBriefingRouteLayer = registerProxyRoute({
301833
+ registerProxyRoute({
301438
301834
  forgePath: "/api/cmmd/projects/:projectId/project-lead/briefing",
301439
301835
  method: "GET",
301440
301836
  cmmdPath: "/api/forge/context/projects/:projectId/project-lead/briefing",
301441
301837
  orgIdSource: "none"
301442
301838
  });
301443
- const cmmdListProjectLeadEventsRouteLayer = registerProxyRoute({
301839
+ registerProxyRoute({
301444
301840
  forgePath: "/api/cmmd/projects/:projectId/project-lead/events",
301445
301841
  method: "GET",
301446
301842
  cmmdPath: "/api/forge/context/projects/:projectId/project-lead/events",
301447
301843
  orgIdSource: "none"
301448
301844
  });
301449
- const cmmdExplainProjectLeadRouteLayer = registerProxyRoute({
301845
+ registerProxyRoute({
301450
301846
  forgePath: "/api/cmmd/projects/:projectId/project-lead/explain",
301451
301847
  method: "GET",
301452
301848
  cmmdPath: "/api/forge/context/projects/:projectId/project-lead/explain",
301453
301849
  orgIdSource: "none"
301454
301850
  });
301455
- const cmmdPauseProjectLeadRouteLayer = registerProxyRoute({
301851
+ registerProxyRoute({
301456
301852
  forgePath: "/api/cmmd/projects/:projectId/project-lead/pause",
301457
301853
  method: "POST",
301458
301854
  cmmdPath: "/api/forge/context/projects/:projectId/project-lead/pause",
301459
301855
  orgIdSource: "none"
301460
301856
  });
301461
- const cmmdResumeProjectLeadRouteLayer = registerProxyRoute({
301857
+ registerProxyRoute({
301462
301858
  forgePath: "/api/cmmd/projects/:projectId/project-lead/resume",
301463
301859
  method: "POST",
301464
301860
  cmmdPath: "/api/forge/context/projects/:projectId/project-lead/resume",
301465
301861
  orgIdSource: "none"
301466
301862
  });
301467
- const cmmdReserveProjectLeadTaskRouteLayer = registerProxyRoute({
301863
+ registerProxyRoute({
301468
301864
  forgePath: "/api/cmmd/projects/:projectId/project-lead/tasks/:taskId/reservations",
301469
301865
  method: "POST",
301470
301866
  cmmdPath: "/api/forge/context/projects/:projectId/project-lead/tasks/:taskId/reservations",
301471
301867
  orgIdSource: "none"
301472
301868
  });
301473
- const cmmdReleaseProjectLeadReservationRouteLayer = registerProxyRoute({
301869
+ registerProxyRoute({
301474
301870
  forgePath: "/api/cmmd/projects/:projectId/project-lead/reservations/:reservationId/release",
301475
301871
  method: "POST",
301476
301872
  cmmdPath: "/api/forge/context/projects/:projectId/project-lead/reservations/:reservationId/release",
301477
301873
  orgIdSource: "none"
301478
301874
  });
301479
- const cmmdReconcileProjectLeadRouteLayer = registerProxyRoute({
301875
+ registerProxyRoute({
301480
301876
  forgePath: "/api/cmmd/projects/:projectId/project-lead/reconcile",
301481
301877
  method: "POST",
301482
301878
  cmmdPath: "/api/forge/context/projects/:projectId/project-lead/reconcile",
301483
301879
  orgIdSource: "none"
301484
301880
  });
301485
- const cmmdResolveProjectLeadAttentionRouteLayer = registerProxyRoute({
301881
+ registerProxyRoute({
301486
301882
  forgePath: "/api/cmmd/projects/:projectId/project-lead/attention/:attentionId/resolve",
301487
301883
  method: "POST",
301488
301884
  cmmdPath: "/api/forge/context/projects/:projectId/project-lead/attention/:attentionId/resolve",
301489
301885
  orgIdSource: "none"
301490
301886
  });
301491
- const cmmdClaimProjectLeadControllerRouteLayer = registerProxyRoute({
301887
+ registerProxyRoute({
301492
301888
  forgePath: "/api/cmmd/projects/:projectId/project-lead/controller/claim",
301493
301889
  method: "POST",
301494
301890
  cmmdPath: "/api/forge/context/projects/:projectId/project-lead/controller/claim",
301495
301891
  orgIdSource: "none"
301496
301892
  });
301497
- const cmmdRenewProjectLeadControllerClaimRouteLayer = registerProxyRoute({
301893
+ registerProxyRoute({
301498
301894
  forgePath: "/api/cmmd/projects/:projectId/project-lead/controller/claim/renew",
301499
301895
  method: "POST",
301500
301896
  cmmdPath: "/api/forge/context/projects/:projectId/project-lead/controller/claim/renew",
301501
301897
  orgIdSource: "none"
301502
301898
  });
301503
- const cmmdYieldProjectLeadControllerClaimRouteLayer = registerProxyRoute({
301899
+ registerProxyRoute({
301504
301900
  forgePath: "/api/cmmd/projects/:projectId/project-lead/controller/claim/yield",
301505
301901
  method: "POST",
301506
301902
  cmmdPath: "/api/forge/context/projects/:projectId/project-lead/controller/claim/yield",
301507
301903
  orgIdSource: "none"
301508
301904
  });
301509
- const cmmdAcknowledgeProjectLeadControllerEventRouteLayer = registerProxyRoute({
301905
+ registerProxyRoute({
301510
301906
  forgePath: "/api/cmmd/projects/:projectId/project-lead/controller/events/:eventId/acknowledge",
301511
301907
  method: "POST",
301512
301908
  cmmdPath: "/api/forge/context/projects/:projectId/project-lead/controller/events/:eventId/acknowledge",
301513
301909
  orgIdSource: "none"
301514
301910
  });
301515
- const cmmdRecordProjectLeadControllerDecisionRouteLayer = registerProxyRoute({
301911
+ registerProxyRoute({
301516
301912
  forgePath: "/api/cmmd/projects/:projectId/project-lead/controller/decisions",
301517
301913
  method: "POST",
301518
301914
  cmmdPath: "/api/forge/context/projects/:projectId/project-lead/controller/decisions",
301519
301915
  orgIdSource: "none"
301520
301916
  });
301521
- const cmmdListForgeAutomationPresetsRouteLayer = registerProxyRoute({
301917
+ registerProxyRoute({
301522
301918
  forgePath: "/api/cmmd/automations/presets",
301523
301919
  method: "GET",
301524
301920
  cmmdPath: "/api/forge/context/automations/presets",
301525
301921
  orgIdSource: "none",
301526
301922
  responseShape: "unwrapData"
301527
301923
  });
301528
- const cmmdListUserForgeAutomationRulesRouteLayer = registerProxyRoute({
301924
+ registerProxyRoute({
301529
301925
  forgePath: "/api/cmmd/automations/user/rules",
301530
301926
  method: "GET",
301531
301927
  cmmdPath: "/api/forge/context/automations/user/rules",
301532
301928
  orgIdSource: "none",
301533
301929
  responseShape: "unwrapData"
301534
301930
  });
301535
- const cmmdCreateUserForgeAutomationRuleRouteLayer = registerProxyRoute({
301931
+ registerProxyRoute({
301536
301932
  forgePath: "/api/cmmd/automations/user/rules",
301537
301933
  method: "POST",
301538
301934
  cmmdPath: "/api/forge/context/automations/user/rules",
301539
301935
  orgIdSource: "none",
301540
301936
  responseShape: "unwrapData"
301541
301937
  });
301542
- const cmmdUpdateUserForgeAutomationRuleRouteLayer = registerProxyRoute({
301938
+ registerProxyRoute({
301543
301939
  forgePath: "/api/cmmd/automations/user/rules/:ruleId",
301544
301940
  method: "PATCH",
301545
301941
  cmmdPath: "/api/forge/context/automations/user/rules/:ruleId",
301546
301942
  orgIdSource: "none",
301547
301943
  responseShape: "unwrapData"
301548
301944
  });
301549
- const cmmdListUserForgeAutomationRunsRouteLayer = registerProxyRoute({
301945
+ registerProxyRoute({
301550
301946
  forgePath: "/api/cmmd/automations/user/rules/:ruleId/runs",
301551
301947
  method: "GET",
301552
301948
  cmmdPath: "/api/forge/context/automations/user/rules/:ruleId/runs",
301553
301949
  orgIdSource: "none",
301554
301950
  responseShape: "unwrapData"
301555
301951
  });
301556
- const cmmdStartUserForgeAutomationRunRouteLayer = registerProxyRoute({
301952
+ registerProxyRoute({
301557
301953
  forgePath: "/api/cmmd/automations/user/rules/:ruleId/runs",
301558
301954
  method: "POST",
301559
301955
  cmmdPath: "/api/forge/context/automations/user/rules/:ruleId/runs",
301560
301956
  orgIdSource: "none",
301561
301957
  responseShape: "unwrapData"
301562
301958
  });
301563
- const cmmdListForgeAutomationRulesRouteLayer = registerProxyRoute({
301959
+ registerProxyRoute({
301564
301960
  forgePath: "/api/cmmd/automations/projects/:projectId/rules",
301565
301961
  method: "GET",
301566
301962
  cmmdPath: "/api/forge/context/automations/projects/:projectId/rules",
301567
301963
  orgIdSource: "query",
301568
301964
  responseShape: "unwrapData"
301569
301965
  });
301570
- const cmmdCreateForgeAutomationRuleRouteLayer = registerProxyRoute({
301966
+ registerProxyRoute({
301571
301967
  forgePath: "/api/cmmd/automations/projects/:projectId/rules",
301572
301968
  method: "POST",
301573
301969
  cmmdPath: "/api/forge/context/automations/projects/:projectId/rules",
301574
301970
  orgIdSource: "query",
301575
301971
  responseShape: "unwrapData"
301576
301972
  });
301577
- const cmmdUpdateForgeAutomationRuleRouteLayer = registerProxyRoute({
301973
+ registerProxyRoute({
301578
301974
  forgePath: "/api/cmmd/automations/projects/:projectId/rules/:ruleId",
301579
301975
  method: "PATCH",
301580
301976
  cmmdPath: "/api/forge/context/automations/projects/:projectId/rules/:ruleId",
301581
301977
  orgIdSource: "query",
301582
301978
  responseShape: "unwrapData"
301583
301979
  });
301584
- const cmmdListForgeAutomationRunsRouteLayer = registerProxyRoute({
301980
+ registerProxyRoute({
301585
301981
  forgePath: "/api/cmmd/automations/projects/:projectId/runs",
301586
301982
  method: "GET",
301587
301983
  cmmdPath: "/api/forge/context/automations/projects/:projectId/runs",
301588
301984
  orgIdSource: "query",
301589
301985
  responseShape: "unwrapData"
301590
301986
  });
301591
- const cmmdStartForgeAutomationRunRouteLayer = registerProxyRoute({
301987
+ registerProxyRoute({
301592
301988
  forgePath: "/api/cmmd/automations/projects/:projectId/tasks/:taskId/runs",
301593
301989
  method: "POST",
301594
301990
  cmmdPath: "/api/forge/context/automations/projects/:projectId/tasks/:taskId/runs",
301595
301991
  orgIdSource: "query",
301596
301992
  responseShape: "unwrapData"
301597
301993
  });
301598
- const cmmdGetForgeAutomationRunRouteLayer = registerProxyRoute({
301994
+ registerProxyRoute({
301599
301995
  forgePath: "/api/cmmd/automations/runs/:runId",
301600
301996
  method: "GET",
301601
301997
  cmmdPath: "/api/forge/context/automations/runs/:runId",
301602
301998
  orgIdSource: "query",
301603
301999
  responseShape: "unwrapData"
301604
302000
  });
301605
- const cmmdRetryForgeAutomationRunRouteLayer = registerProxyRoute({
302001
+ registerProxyRoute({
301606
302002
  forgePath: "/api/cmmd/automations/runs/:runId/retry",
301607
302003
  method: "POST",
301608
302004
  cmmdPath: "/api/forge/context/automations/runs/:runId/retry",
301609
302005
  orgIdSource: "query",
301610
302006
  responseShape: "unwrapData"
301611
302007
  });
301612
- const cmmdCancelForgeAutomationRunRouteLayer = registerProxyRoute({
302008
+ registerProxyRoute({
301613
302009
  forgePath: "/api/cmmd/automations/runs/:runId/cancel",
301614
302010
  method: "POST",
301615
302011
  cmmdPath: "/api/forge/context/automations/runs/:runId/cancel",
301616
302012
  orgIdSource: "query",
301617
302013
  responseShape: "unwrapData"
301618
302014
  });
301619
- const cmmdApproveForgeAutomationEscalationRouteLayer = registerProxyRoute({
302015
+ registerProxyRoute({
301620
302016
  forgePath: "/api/cmmd/automations/runs/:runId/escalations/approve",
301621
302017
  method: "POST",
301622
302018
  cmmdPath: "/api/forge/context/automations/runs/:runId/escalations/approve",
301623
302019
  orgIdSource: "query",
301624
302020
  responseShape: "unwrapData"
301625
302021
  });
301626
- const cmmdRejectForgeAutomationEscalationRouteLayer = registerProxyRoute({
302022
+ registerProxyRoute({
301627
302023
  forgePath: "/api/cmmd/automations/runs/:runId/escalations/reject",
301628
302024
  method: "POST",
301629
302025
  cmmdPath: "/api/forge/context/automations/runs/:runId/escalations/reject",
301630
302026
  orgIdSource: "query",
301631
302027
  responseShape: "unwrapData"
301632
302028
  });
301633
- const cmmdListProjectBoardRouteLayer = registerProxyRoute({
302029
+ registerProxyRoute({
301634
302030
  forgePath: "/api/cmmd/projects/:id/board",
301635
302031
  method: "GET",
301636
302032
  cmmdPath: "/api/forge/context/projects/:id/board",
301637
302033
  orgIdSource: "none",
301638
302034
  responseShape: "unwrapData"
301639
302035
  });
301640
- const cmmdGetProjectTaskWorkflowRouteLayer = registerProxyRoute({
302036
+ registerProxyRoute({
301641
302037
  forgePath: "/api/cmmd/projects/:id/task-workflow",
301642
302038
  method: "GET",
301643
302039
  cmmdPath: "/api/forge/context/projects/:id/task-workflow",
301644
302040
  orgIdSource: "none",
301645
302041
  responseShape: "unwrapData"
301646
302042
  });
301647
- const cmmdUpdateProjectTaskWorkflowRouteLayer = registerProxyRoute({
302043
+ registerProxyRoute({
301648
302044
  forgePath: "/api/cmmd/projects/:id/task-workflow",
301649
302045
  method: "PUT",
301650
302046
  cmmdPath: "/api/forge/context/projects/:id/task-workflow",
301651
302047
  orgIdSource: "none",
301652
302048
  responseShape: "unwrapData"
301653
302049
  });
301654
- const cmmdCreateProjectBoardTaskRouteLayer = registerProxyRoute({
302050
+ registerProxyRoute({
301655
302051
  forgePath: "/api/cmmd/projects/:id/board",
301656
302052
  method: "POST",
301657
302053
  cmmdPath: "/api/forge/context/projects/:id/board",
301658
302054
  orgIdSource: "none",
301659
302055
  responseShape: "unwrapData"
301660
302056
  });
301661
- const cmmdUpdateProjectBoardTaskRouteLayer = registerProxyRoute({
302057
+ registerProxyRoute({
301662
302058
  forgePath: "/api/cmmd/projects/:id/board/:taskId",
301663
302059
  method: "PATCH",
301664
302060
  cmmdPath: "/api/forge/context/projects/:id/board/:taskId",
301665
302061
  orgIdSource: "none",
301666
302062
  responseShape: "unwrapData"
301667
302063
  });
301668
- const cmmdUpdateProjectBoardTaskStatusRouteLayer = registerProxyRoute({
302064
+ registerProxyRoute({
301669
302065
  forgePath: "/api/cmmd/projects/:id/board/:taskId/status",
301670
302066
  method: "PATCH",
301671
302067
  cmmdPath: "/api/forge/context/projects/:id/board/:taskId/status",
301672
302068
  orgIdSource: "none",
301673
302069
  responseShape: "unwrapData"
301674
302070
  });
301675
- const cmmdListTaskExecutionOptionsRouteLayer = registerProxyRoute({
302071
+ registerProxyRoute({
301676
302072
  forgePath: "/api/cmmd/projects/:id/board/:taskId/execution-options",
301677
302073
  method: "GET",
301678
302074
  cmmdPath: "/api/forge/context/projects/:id/board/:taskId/execution-options",
301679
302075
  orgIdSource: "none",
301680
302076
  responseShape: "unwrapData"
301681
302077
  });
301682
- const cmmdCreateTaskWorkSessionRouteLayer = registerProxyRoute({
302078
+ registerProxyRoute({
301683
302079
  forgePath: "/api/cmmd/projects/:id/board/:taskId/work-sessions",
301684
302080
  method: "POST",
301685
302081
  cmmdPath: "/api/forge/context/projects/:id/board/:taskId/work-sessions",
301686
302082
  orgIdSource: "none",
301687
302083
  responseShape: "unwrapData"
301688
302084
  });
301689
- const cmmdListProjectWorkSessionsRouteLayer = registerProxyRoute({
302085
+ registerProxyRoute({
301690
302086
  forgePath: "/api/cmmd/projects/:id/work-sessions",
301691
302087
  method: "GET",
301692
302088
  cmmdPath: "/api/forge/context/projects/:id/work-sessions",
301693
302089
  orgIdSource: "none",
301694
302090
  responseShape: "unwrapData"
301695
302091
  });
301696
- const cmmdGetWorkSessionRouteLayer = registerProxyRoute({
302092
+ registerProxyRoute({
301697
302093
  forgePath: "/api/cmmd/work-sessions/:workSessionId",
301698
302094
  method: "GET",
301699
302095
  cmmdPath: "/api/forge/context/work-sessions/:workSessionId",
301700
302096
  orgIdSource: "none",
301701
302097
  responseShape: "unwrapData"
301702
302098
  });
301703
- const cmmdUpdateWorkSessionRouteLayer = registerProxyRoute({
302099
+ registerProxyRoute({
301704
302100
  forgePath: "/api/cmmd/work-sessions/:workSessionId",
301705
302101
  method: "PATCH",
301706
302102
  cmmdPath: "/api/forge/context/work-sessions/:workSessionId",
301707
302103
  orgIdSource: "none",
301708
302104
  responseShape: "unwrapData"
301709
302105
  });
301710
- const cmmdAttachWorkSessionThreadRouteLayer = registerProxyRoute({
302106
+ registerProxyRoute({
301711
302107
  forgePath: "/api/cmmd/work-sessions/:workSessionId/threads",
301712
302108
  method: "POST",
301713
302109
  cmmdPath: "/api/forge/context/work-sessions/:workSessionId/threads",
301714
302110
  orgIdSource: "none",
301715
302111
  responseShape: "unwrapData"
301716
302112
  });
301717
- const cmmdListTaskConversationsRouteLayer = registerProxyRoute({
302113
+ registerProxyRoute({
301718
302114
  forgePath: "/api/cmmd/tasks/:taskId/conversations",
301719
302115
  method: "GET",
301720
302116
  cmmdPath: "/api/forge/context/tasks/:taskId/conversations",
301721
302117
  orgIdSource: "none",
301722
302118
  responseShape: "unwrapData"
301723
302119
  });
301724
- const cmmdLinkTaskConversationRouteLayer = registerProxyRoute({
302120
+ registerProxyRoute({
301725
302121
  forgePath: "/api/cmmd/tasks/:taskId/conversations",
301726
302122
  method: "POST",
301727
302123
  cmmdPath: "/api/forge/context/tasks/:taskId/conversations",
301728
302124
  orgIdSource: "none",
301729
302125
  responseShape: "unwrapData"
301730
302126
  });
301731
- const cmmdGetTaskHistoryRouteLayer = registerProxyRoute({
302127
+ registerProxyRoute({
301732
302128
  forgePath: "/api/cmmd/tasks/:taskId/history",
301733
302129
  method: "GET",
301734
302130
  cmmdPath: "/api/forge/context/tasks/:taskId/history",
301735
302131
  orgIdSource: "none",
301736
302132
  responseShape: "unwrapData"
301737
302133
  });
301738
- const cmmdUpsertTaskPullRequestRouteLayer = registerProxyRoute({
302134
+ registerProxyRoute({
301739
302135
  forgePath: "/api/cmmd/tasks/:taskId/pull-requests",
301740
302136
  method: "PUT",
301741
302137
  cmmdPath: "/api/forge/context/tasks/:taskId/pull-requests",
301742
302138
  orgIdSource: "none",
301743
302139
  responseShape: "unwrapData"
301744
302140
  });
301745
- const cmmdPullRequestRouteLayers = [
302141
+ for (const path of [
301746
302142
  "list",
301747
302143
  "list-stats",
301748
302144
  "detail",
@@ -301760,70 +302156,70 @@ const cmmdPullRequestRouteLayers = [
301760
302156
  "thread/resolution",
301761
302157
  "reviewers",
301762
302158
  "reaction"
301763
- ].map((path) => registerProxyRoute({
302159
+ ]) registerProxyRoute({
301764
302160
  forgePath: `/api/cmmd/pull-requests/${path}`,
301765
302161
  method: "POST",
301766
302162
  cmmdPath: `/api/forge/context/pull-requests/${path}`,
301767
302163
  orgIdSource: "none",
301768
302164
  responseShape: "unwrapData"
301769
- }));
301770
- const cmmdGetTaskConversationRouteLayer = registerProxyRoute({
302165
+ });
302166
+ registerProxyRoute({
301771
302167
  forgePath: "/api/cmmd/tasks/:taskId/conversations/:conversationId",
301772
302168
  method: "GET",
301773
302169
  cmmdPath: "/api/forge/context/tasks/:taskId/conversations/:conversationId",
301774
302170
  orgIdSource: "none",
301775
302171
  responseShape: "unwrapData"
301776
302172
  });
301777
- const cmmdSpawnForgeThreadFromBoardTaskRouteLayer = registerProxyRoute({
302173
+ registerProxyRoute({
301778
302174
  forgePath: "/api/cmmd/projects/:id/board/:taskId/spawn-forge-thread",
301779
302175
  method: "POST",
301780
302176
  cmmdPath: "/api/forge/context/projects/:id/board/:taskId/spawn-forge-thread",
301781
302177
  orgIdSource: "none",
301782
302178
  responseShape: "unwrapData"
301783
302179
  });
301784
- const cmmdListCenterBoardRouteLayer = registerProxyRoute({
302180
+ registerProxyRoute({
301785
302181
  forgePath: "/api/cmmd/work-items/board",
301786
302182
  method: "GET",
301787
302183
  cmmdPath: "/api/forge/context/work-items/board",
301788
302184
  orgIdSource: "none",
301789
302185
  responseShape: "unwrapData"
301790
302186
  });
301791
- const cmmdCreateCenterBoardTaskRouteLayer = registerProxyRoute({
302187
+ registerProxyRoute({
301792
302188
  forgePath: "/api/cmmd/work-items/board",
301793
302189
  method: "POST",
301794
302190
  cmmdPath: "/api/forge/context/work-items/board",
301795
302191
  orgIdSource: "none",
301796
302192
  responseShape: "unwrapData"
301797
302193
  });
301798
- const cmmdCreateFeedbackRouteLayer = registerProxyRoute({
302194
+ registerProxyRoute({
301799
302195
  forgePath: "/api/cmmd/feedback",
301800
302196
  method: "POST",
301801
302197
  cmmdPath: "/api/forge/context/feedback",
301802
302198
  orgIdSource: "none",
301803
302199
  responseShape: "unwrapData"
301804
302200
  });
301805
- const cmmdUpdateCenterBoardTaskRouteLayer = registerProxyRoute({
302201
+ registerProxyRoute({
301806
302202
  forgePath: "/api/cmmd/work-items/board/:taskId",
301807
302203
  method: "PATCH",
301808
302204
  cmmdPath: "/api/forge/context/work-items/board/:taskId",
301809
302205
  orgIdSource: "none",
301810
302206
  responseShape: "unwrapData"
301811
302207
  });
301812
- const cmmdMoveCenterBoardTaskRouteLayer = registerProxyRoute({
302208
+ registerProxyRoute({
301813
302209
  forgePath: "/api/cmmd/work-items/board/:taskId/move",
301814
302210
  method: "PATCH",
301815
302211
  cmmdPath: "/api/forge/context/work-items/board/:taskId/move",
301816
302212
  orgIdSource: "none",
301817
302213
  responseShape: "unwrapData"
301818
302214
  });
301819
- const cmmdMoveProjectBoardTaskRouteLayer = registerProxyRoute({
302215
+ registerProxyRoute({
301820
302216
  forgePath: "/api/cmmd/projects/:projectId/board/:taskId/move",
301821
302217
  method: "PATCH",
301822
302218
  cmmdPath: "/api/forge/context/projects/:projectId/board/:taskId/move",
301823
302219
  orgIdSource: "none",
301824
302220
  responseShape: "unwrapData"
301825
302221
  });
301826
- const cmmdArchiveProjectBoardTaskRouteLayer = registerProxyRoute({
302222
+ registerProxyRoute({
301827
302223
  forgePath: "/api/cmmd/projects/:projectId/board/:taskId/archive",
301828
302224
  method: "POST",
301829
302225
  cmmdPath: "/api/forge/context/projects/:projectId/board/:taskId/archive",
@@ -301831,7 +302227,7 @@ const cmmdArchiveProjectBoardTaskRouteLayer = registerProxyRoute({
301831
302227
  responseShape: "unwrapData",
301832
302228
  requestBody: "none"
301833
302229
  });
301834
- const cmmdUnarchiveProjectBoardTaskRouteLayer = registerProxyRoute({
302230
+ registerProxyRoute({
301835
302231
  forgePath: "/api/cmmd/projects/:projectId/board/:taskId/unarchive",
301836
302232
  method: "POST",
301837
302233
  cmmdPath: "/api/forge/context/projects/:projectId/board/:taskId/unarchive",
@@ -301839,7 +302235,7 @@ const cmmdUnarchiveProjectBoardTaskRouteLayer = registerProxyRoute({
301839
302235
  responseShape: "unwrapData",
301840
302236
  requestBody: "none"
301841
302237
  });
301842
- const cmmdArchiveCenterBoardTaskRouteLayer = registerProxyRoute({
302238
+ registerProxyRoute({
301843
302239
  forgePath: "/api/cmmd/work-items/board/:taskId/archive",
301844
302240
  method: "POST",
301845
302241
  cmmdPath: "/api/forge/context/work-items/board/:taskId/archive",
@@ -301847,7 +302243,7 @@ const cmmdArchiveCenterBoardTaskRouteLayer = registerProxyRoute({
301847
302243
  responseShape: "unwrapData",
301848
302244
  requestBody: "none"
301849
302245
  });
301850
- const cmmdUnarchiveCenterBoardTaskRouteLayer = registerProxyRoute({
302246
+ registerProxyRoute({
301851
302247
  forgePath: "/api/cmmd/work-items/board/:taskId/unarchive",
301852
302248
  method: "POST",
301853
302249
  cmmdPath: "/api/forge/context/work-items/board/:taskId/unarchive",
@@ -301855,109 +302251,109 @@ const cmmdUnarchiveCenterBoardTaskRouteLayer = registerProxyRoute({
301855
302251
  responseShape: "unwrapData",
301856
302252
  requestBody: "none"
301857
302253
  });
301858
- const cmmdListCampaignsRouteLayer = registerProxyRoute({
302254
+ registerProxyRoute({
301859
302255
  forgePath: "/api/cmmd/campaigns",
301860
302256
  method: "GET",
301861
302257
  cmmdPath: "/api/forge/context/campaigns",
301862
302258
  orgIdSource: "none",
301863
302259
  responseShape: "passthrough"
301864
302260
  });
301865
- const cmmdGetCampaignRouteLayer = registerProxyRoute({
302261
+ registerProxyRoute({
301866
302262
  forgePath: "/api/cmmd/campaigns/:id",
301867
302263
  method: "GET",
301868
302264
  cmmdPath: "/api/forge/context/campaigns/:id",
301869
302265
  orgIdSource: "none",
301870
302266
  responseShape: "passthrough"
301871
302267
  });
301872
- const cmmdCreateCampaignRouteLayer = registerProxyRoute({
302268
+ registerProxyRoute({
301873
302269
  forgePath: "/api/cmmd/campaigns",
301874
302270
  method: "POST",
301875
302271
  cmmdPath: "/api/projects/campaigns",
301876
302272
  responseShape: "passthrough"
301877
302273
  });
301878
- const cmmdUpdateCampaignRouteLayer = registerProxyRoute({
302274
+ registerProxyRoute({
301879
302275
  forgePath: "/api/cmmd/campaigns/:id",
301880
302276
  method: "PUT",
301881
302277
  cmmdPath: "/api/projects/campaigns/:id",
301882
302278
  responseShape: "passthrough"
301883
302279
  });
301884
- const cmmdDeleteCampaignRouteLayer = registerProxyRoute({
302280
+ registerProxyRoute({
301885
302281
  forgePath: "/api/cmmd/campaigns/:id",
301886
302282
  method: "DELETE",
301887
302283
  cmmdPath: "/api/projects/campaigns/:id",
301888
302284
  orgIdSource: "none"
301889
302285
  });
301890
- const cmmdBootstrapRouteLayer = registerProxyRoute({
302286
+ registerProxyRoute({
301891
302287
  forgePath: "/api/cmmd/bootstrap",
301892
302288
  method: "GET",
301893
302289
  cmmdPath: "/api/forge/context/bootstrap",
301894
302290
  orgIdSource: "none",
301895
302291
  responseShape: "passthrough"
301896
302292
  });
301897
- const cmmdGetAccountPreferencesRouteLayer = registerProxyRoute({
302293
+ registerProxyRoute({
301898
302294
  forgePath: "/api/cmmd/account/preferences",
301899
302295
  method: "GET",
301900
302296
  cmmdPath: "/api/forge/context/account/preferences",
301901
302297
  orgIdSource: "none",
301902
302298
  responseShape: "unwrapData"
301903
302299
  });
301904
- const cmmdUpdateAccountPreferencesRouteLayer = registerProxyRoute({
302300
+ registerProxyRoute({
301905
302301
  forgePath: "/api/cmmd/account/preferences",
301906
302302
  method: "PATCH",
301907
302303
  cmmdPath: "/api/forge/context/account/preferences",
301908
302304
  orgIdSource: "none",
301909
302305
  responseShape: "unwrapData"
301910
302306
  });
301911
- const cmmdGetOrgProviderPolicyRouteLayer = registerProxyRoute({
302307
+ registerProxyRoute({
301912
302308
  forgePath: "/api/cmmd/org/provider-policy",
301913
302309
  method: "GET",
301914
302310
  cmmdPath: "/api/forge/context/org/provider-policy",
301915
302311
  orgIdSource: "none",
301916
302312
  responseShape: "unwrapData"
301917
302313
  });
301918
- const cmmdListChatsRouteLayer = registerProxyRoute({
302314
+ registerProxyRoute({
301919
302315
  forgePath: "/api/cmmd/chats",
301920
302316
  method: "GET",
301921
302317
  cmmdPath: "/api/forge/context/chats",
301922
302318
  orgIdSource: "none",
301923
302319
  responseShape: "unwrapData"
301924
302320
  });
301925
- const cmmdGetChatRouteLayer = registerProxyRoute({
302321
+ registerProxyRoute({
301926
302322
  forgePath: "/api/cmmd/chats/:threadId",
301927
302323
  method: "GET",
301928
302324
  cmmdPath: "/api/forge/context/chats/:threadId",
301929
302325
  orgIdSource: "none",
301930
302326
  responseShape: "unwrapData"
301931
302327
  });
301932
- const cmmdListDevicesRouteLayer = registerProxyRoute({
302328
+ registerProxyRoute({
301933
302329
  forgePath: "/api/cmmd/devices",
301934
302330
  method: "GET",
301935
302331
  cmmdPath: "/api/forge/context/devices",
301936
302332
  orgIdSource: "none",
301937
302333
  responseShape: "unwrapData"
301938
302334
  });
301939
- const cmmdRegisterDeviceRouteLayer = registerProxyRoute({
302335
+ registerProxyRoute({
301940
302336
  forgePath: "/api/cmmd/devices/register",
301941
302337
  method: "POST",
301942
302338
  cmmdPath: "/api/forge/context/devices/register",
301943
302339
  orgIdSource: "none",
301944
302340
  responseShape: "unwrapData"
301945
302341
  });
301946
- const cmmdHeartbeatRuntimeRouteLayer = registerProxyRoute({
302342
+ registerProxyRoute({
301947
302343
  forgePath: "/api/cmmd/devices/runtimes/:runtimeId/heartbeat",
301948
302344
  method: "POST",
301949
302345
  cmmdPath: "/api/forge/context/devices/runtimes/:runtimeId/heartbeat",
301950
302346
  orgIdSource: "none",
301951
302347
  responseShape: "unwrapData"
301952
302348
  });
301953
- const cmmdGrantRuntimeAccessRouteLayer = registerProxyRoute({
302349
+ registerProxyRoute({
301954
302350
  forgePath: "/api/cmmd/devices/runtimes/:runtimeId/access-grants",
301955
302351
  method: "POST",
301956
302352
  cmmdPath: "/api/forge/context/devices/runtimes/:runtimeId/access-grants",
301957
302353
  orgIdSource: "none",
301958
302354
  responseShape: "unwrapData"
301959
302355
  });
301960
- const cmmdRevokeRuntimeAccessRouteLayer = registerProxyRoute({
302356
+ registerProxyRoute({
301961
302357
  forgePath: "/api/cmmd/devices/runtimes/:runtimeId/access-grants/:grantId/revoke",
301962
302358
  method: "POST",
301963
302359
  cmmdPath: "/api/forge/context/devices/runtimes/:runtimeId/access-grants/:grantId/revoke",
@@ -301965,46 +302361,60 @@ const cmmdRevokeRuntimeAccessRouteLayer = registerProxyRoute({
301965
302361
  responseShape: "unwrapData",
301966
302362
  successStatus: 200
301967
302363
  });
301968
- const cmmdCreateRelayControlRouteLayer = registerProxyRoute({
302364
+ registerProxyRoute({
301969
302365
  forgePath: "/api/cmmd/devices/runtimes/:runtimeId/relay-routes",
301970
302366
  method: "POST",
301971
302367
  cmmdPath: "/api/forge/context/devices/runtimes/:runtimeId/relay-routes",
301972
302368
  orgIdSource: "none",
301973
302369
  responseShape: "unwrapData"
301974
302370
  });
301975
- const cmmdCreateRelayActionGrantRouteLayer = registerProxyRoute({
302371
+ registerProxyRoute({
301976
302372
  forgePath: "/api/cmmd/devices/runtimes/:runtimeId/relay-action-grants",
301977
302373
  method: "POST",
301978
302374
  cmmdPath: "/api/forge/context/devices/runtimes/:runtimeId/relay-action-grants",
301979
302375
  orgIdSource: "none",
301980
302376
  responseShape: "unwrapData"
301981
302377
  });
301982
- const cmmdReplaceRuntimeInventoryRouteLayer = registerProxyRoute({
302378
+ registerProxyRoute({
301983
302379
  forgePath: "/api/cmmd/devices/runtimes/:runtimeId/inventory",
301984
302380
  method: "PUT",
301985
302381
  cmmdPath: "/api/forge/context/devices/runtimes/:runtimeId/inventory",
301986
302382
  orgIdSource: "none",
301987
302383
  responseShape: "unwrapData"
301988
302384
  });
301989
- const cmmdListRuntimeInventoryRouteLayer = registerProxyRoute({
302385
+ registerProxyRoute({
301990
302386
  forgePath: "/api/cmmd/runtime-inventory",
301991
302387
  method: "GET",
301992
302388
  cmmdPath: "/api/forge/context/runtime-inventory",
301993
302389
  orgIdSource: "none",
301994
302390
  responseShape: "unwrapData"
301995
302391
  });
302392
+ registerProxyRoute({
302393
+ forgePath: "/api/cmmd/threads/:runtimeId/:threadId/lifecycle-intent",
302394
+ method: "PUT",
302395
+ cmmdPath: "/api/forge/context/threads/:runtimeId/:threadId/lifecycle-intent",
302396
+ orgIdSource: "none",
302397
+ requestBody: "json",
302398
+ responseShape: "unwrapData"
302399
+ });
302400
+ registerProxyRoute({
302401
+ forgePath: "/api/cmmd/threads/:runtimeId/:threadId/lifecycle-intent",
302402
+ method: "DELETE",
302403
+ cmmdPath: "/api/forge/context/threads/:runtimeId/:threadId/lifecycle-intent",
302404
+ orgIdSource: "none"
302405
+ });
301996
302406
  /**
301997
302407
  * Owner-scoped, bounded control-plane observation. This is intentionally
301998
302408
  * separate from the runtime inventory publisher and never wakes a runtime.
301999
302409
  */
302000
- const cmmdGetRuntimeDiagnosticsRouteLayer = registerProxyRoute({
302410
+ registerProxyRoute({
302001
302411
  forgePath: "/api/cmmd/runtime-diagnostics/v2/runtimes/:runtimeId",
302002
302412
  method: "GET",
302003
302413
  cmmdPath: "/api/forge/context/runtime-diagnostics/v2/runtimes/:runtimeId",
302004
302414
  orgIdSource: "none",
302005
302415
  responseShape: "unwrapData"
302006
302416
  });
302007
- const cmmdProvisionAuthRuntimeRouteLayer = registerProxyRoute({
302417
+ registerProxyRoute({
302008
302418
  forgePath: "/api/cmmd/auth-runtime",
302009
302419
  method: "POST",
302010
302420
  cmmdPath: "/api/forge/context/auth-runtime",
@@ -302012,21 +302422,21 @@ const cmmdProvisionAuthRuntimeRouteLayer = registerProxyRoute({
302012
302422
  responseShape: "unwrapData",
302013
302423
  requestBody: "none"
302014
302424
  });
302015
- const cmmdGetAuthRuntimeRouteLayer = registerProxyRoute({
302425
+ registerProxyRoute({
302016
302426
  forgePath: "/api/cmmd/auth-runtime",
302017
302427
  method: "GET",
302018
302428
  cmmdPath: "/api/forge/context/auth-runtime",
302019
302429
  orgIdSource: "none",
302020
302430
  responseShape: "unwrapData"
302021
302431
  });
302022
- const cmmdDestroyAuthRuntimeRouteLayer = registerProxyRoute({
302432
+ registerProxyRoute({
302023
302433
  forgePath: "/api/cmmd/auth-runtime",
302024
302434
  method: "DELETE",
302025
302435
  cmmdPath: "/api/forge/context/auth-runtime",
302026
302436
  orgIdSource: "none",
302027
302437
  responseShape: "unwrapData"
302028
302438
  });
302029
- const cmmdConnectAuthRuntimeRouteLayer = registerProxyRoute({
302439
+ registerProxyRoute({
302030
302440
  forgePath: "/api/cmmd/auth-runtime/connect",
302031
302441
  method: "POST",
302032
302442
  cmmdPath: "/api/forge/context/auth-runtime/connect",
@@ -302034,14 +302444,14 @@ const cmmdConnectAuthRuntimeRouteLayer = registerProxyRoute({
302034
302444
  responseShape: "unwrapData",
302035
302445
  requestBody: "none"
302036
302446
  });
302037
- const cmmdGetProviderAccountsRouteLayer = registerProxyRoute({
302447
+ registerProxyRoute({
302038
302448
  forgePath: "/api/cmmd/providers/accounts",
302039
302449
  method: "GET",
302040
302450
  cmmdPath: "/api/forge/context/providers/accounts",
302041
302451
  orgIdSource: "none",
302042
302452
  responseShape: "unwrapData"
302043
302453
  });
302044
- const cmmdDeleteProviderAccountRouteLayer = registerProxyRoute({
302454
+ registerProxyRoute({
302045
302455
  forgePath: "/api/cmmd/providers/accounts/:id",
302046
302456
  method: "DELETE",
302047
302457
  cmmdPath: "/api/forge/context/providers/accounts/:id",
@@ -302049,23 +302459,29 @@ const cmmdDeleteProviderAccountRouteLayer = registerProxyRoute({
302049
302459
  responseShape: "unwrapData",
302050
302460
  requestBody: "none"
302051
302461
  });
302052
- const cmmdSetProviderAccountDefaultRouteLayer = registerProxyRoute({
302462
+ registerProxyRoute({
302053
302463
  forgePath: "/api/cmmd/providers/accounts/default",
302054
302464
  method: "PUT",
302055
302465
  cmmdPath: "/api/forge/context/providers/accounts/default",
302056
302466
  orgIdSource: "none",
302057
302467
  responseShape: "unwrapData"
302058
302468
  });
302059
- const cmmdGetProviderUsageRouteLayer = add$1("GET", "/api/cmmd/providers/usage", gen(function* () {
302060
- const request = yield* HttpServerRequest;
302061
- const outcome = yield* runCmmdRestProxy(yield* (yield* ServerAuth).authenticateHttpRequest(request), (jwt) => cmmdGateway.request({
302469
+ registerProxyHandler({
302470
+ forgePath: "/api/cmmd/providers/usage",
302471
+ method: "GET",
302472
+ parse: () => succeed({
302473
+ ok: true,
302474
+ value: void 0
302475
+ }),
302476
+ run: (_parsed, { session }) => runCmmdRestProxyAsHandlerResult(session, (jwt) => cmmdGateway.request({
302062
302477
  method: "GET",
302063
302478
  jwt,
302064
302479
  path: "/api/forge/context/providers/usage"
302065
- }));
302066
- if (!outcome.ok) return buildProxyErrorResponse(outcome.error);
302067
- return jsonUnsafe(unwrapForgeEnvelope(outcome.value), { status: 200 });
302068
- }).pipe(catchTag("AuthError", (error) => respondToAuthError(error))));
302480
+ }), (value) => ({
302481
+ status: 200,
302482
+ body: unwrapForgeEnvelope(value)
302483
+ }))
302484
+ });
302069
302485
  function parseProviderUsageRefreshInput(rawBody) {
302070
302486
  if (rawBody === null || typeof rawBody !== "object") return null;
302071
302487
  const body = rawBody;
@@ -302147,56 +302563,56 @@ function makeRefreshProviderUsageHandler(dependencies = {}) {
302147
302563
  }).pipe(catchTag("AuthError", (error) => respondToAuthError(error)));
302148
302564
  }
302149
302565
  const cmmdRefreshProviderUsageRouteLayer = add$1("POST", "/api/cmmd/providers/usage/refresh", makeRefreshProviderUsageHandler());
302150
- const cmmdGetUserCodexCredentialRouteLayer = registerProxyRoute({
302566
+ registerProxyRoute({
302151
302567
  forgePath: "/api/cmmd/providers/codex/credential",
302152
302568
  method: "GET",
302153
302569
  cmmdPath: "/api/forge/context/providers/codex/credential",
302154
302570
  orgIdSource: "none",
302155
302571
  responseShape: "unwrapData"
302156
302572
  });
302157
- const cmmdDeleteUserCodexCredentialRouteLayer = registerProxyRoute({
302573
+ registerProxyRoute({
302158
302574
  forgePath: "/api/cmmd/providers/codex/credential",
302159
302575
  method: "DELETE",
302160
302576
  cmmdPath: "/api/forge/context/providers/codex/credential",
302161
302577
  orgIdSource: "none",
302162
302578
  responseShape: "unwrapData"
302163
302579
  });
302164
- const cmmdGetUserClaudeCredentialRouteLayer = registerProxyRoute({
302580
+ registerProxyRoute({
302165
302581
  forgePath: "/api/cmmd/providers/claude/credential",
302166
302582
  method: "GET",
302167
302583
  cmmdPath: "/api/forge/context/providers/claude/credential",
302168
302584
  orgIdSource: "none",
302169
302585
  responseShape: "unwrapData"
302170
302586
  });
302171
- const cmmdDeleteUserClaudeCredentialRouteLayer = registerProxyRoute({
302587
+ registerProxyRoute({
302172
302588
  forgePath: "/api/cmmd/providers/claude/credential",
302173
302589
  method: "DELETE",
302174
302590
  cmmdPath: "/api/forge/context/providers/claude/credential",
302175
302591
  orgIdSource: "none",
302176
302592
  responseShape: "unwrapData"
302177
302593
  });
302178
- const cmmdGetClaudeRuntimeReadinessRouteLayer = registerProxyRoute({
302594
+ registerProxyRoute({
302179
302595
  forgePath: "/api/cmmd/providers/claude/runtime-readiness/:runtimeId",
302180
302596
  method: "GET",
302181
302597
  cmmdPath: "/api/forge/context/providers/claude/runtime-readiness/:runtimeId",
302182
302598
  orgIdSource: "none",
302183
302599
  responseShape: "unwrapData"
302184
302600
  });
302185
- const cmmdAppendRuntimeThreadEventsRouteLayer = registerProxyRoute({
302601
+ registerProxyRoute({
302186
302602
  forgePath: "/api/cmmd/devices/runtimes/:runtimeId/threads/:threadId/events",
302187
302603
  method: "POST",
302188
302604
  cmmdPath: "/api/forge/context/devices/runtimes/:runtimeId/threads/:threadId/events",
302189
302605
  orgIdSource: "none",
302190
302606
  responseShape: "unwrapData"
302191
302607
  });
302192
- const cmmdGetRuntimeThreadReplicaRouteLayer = registerProxyRoute({
302608
+ registerProxyRoute({
302193
302609
  forgePath: "/api/cmmd/threads/:runtimeId/:threadId",
302194
302610
  method: "GET",
302195
302611
  cmmdPath: "/api/forge/context/threads/:runtimeId/:threadId",
302196
302612
  orgIdSource: "none",
302197
302613
  responseShape: "unwrapData"
302198
302614
  });
302199
- const cmmdRenameDeviceRouteLayer = registerProxyRoute({
302615
+ registerProxyRoute({
302200
302616
  forgePath: "/api/cmmd/devices/:deviceId/rename",
302201
302617
  method: "POST",
302202
302618
  cmmdPath: "/api/forge/context/devices/:deviceId/rename",
@@ -302212,7 +302628,7 @@ const cmmdRenameDeviceRouteLayer = registerProxyRoute({
302212
302628
  * the status and the code reach the browser unchanged, which is what lets the
302213
302629
  * rename field say something specific instead of "something went wrong".
302214
302630
  */
302215
- const cmmdRenameForgeRuntimeRouteLayer = registerProxyRoute({
302631
+ registerProxyRoute({
302216
302632
  forgePath: "/api/cmmd/forge-runtimes/:runtimeId/rename",
302217
302633
  method: "POST",
302218
302634
  cmmdPath: "/api/forge/context/runtimes/:runtimeId/rename",
@@ -302220,7 +302636,7 @@ const cmmdRenameForgeRuntimeRouteLayer = registerProxyRoute({
302220
302636
  responseShape: "unwrapData",
302221
302637
  successStatus: 200
302222
302638
  });
302223
- const cmmdRevokeDeviceRouteLayer = registerProxyRoute({
302639
+ registerProxyRoute({
302224
302640
  forgePath: "/api/cmmd/devices/:deviceId/revoke",
302225
302641
  method: "POST",
302226
302642
  cmmdPath: "/api/forge/context/devices/:deviceId/revoke",
@@ -302229,24 +302645,21 @@ const cmmdRevokeDeviceRouteLayer = registerProxyRoute({
302229
302645
  requestBody: "none",
302230
302646
  successStatus: 200
302231
302647
  });
302232
- const cmmdListConnectorsRouteLayer = registerProxyRoute({
302648
+ registerProxyRoute({
302233
302649
  forgePath: "/api/cmmd/connectors",
302234
302650
  method: "GET",
302235
302651
  cmmdPath: "/api/forge/context/connectors",
302236
302652
  orgIdSource: "none"
302237
302653
  });
302238
- const cmmdInstallConnectorRouteLayer = registerProxyRoute({
302654
+ registerProxyRoute({
302239
302655
  forgePath: "/api/cmmd/connectors/:connectorId/install",
302240
302656
  method: "POST",
302241
302657
  cmmdPath: "/api/forge/context/connectors/:connectorId/install",
302242
302658
  orgIdSource: "none"
302243
302659
  });
302244
302660
  const cmmdForgeCloudProjectsListRouteLayer = add$1("GET", "/api/cmmd/forge-cloud-projects", gen(function* () {
302245
- const accessToken = yield* makeCmmdProxyAccessTokenEffect("forge-cloud-projects");
302246
- if (!accessToken) return buildCmmdAuthErrorResponse({
302247
- code: "CMMD_AUTH_REQUIRED",
302248
- message: "CMMD authentication is required. Sign in again to continue."
302249
- });
302661
+ const { session, jwt: accessToken } = yield* makeCmmdProxyAccessTokenEffect("forge-cloud-projects");
302662
+ if (!accessToken) return yield* respondCmmdConnectionRequired(session.sessionId);
302250
302663
  const upstreamUrl = `${resolveCommandAppUrl()}${CMMD_CLOUD_PROJECTS_PATH}`;
302251
302664
  const upstreamOrError = yield* fetchCmmdUpstreamWithRetry(() => fetch(upstreamUrl, { headers: {
302252
302665
  Authorization: `Bearer ${accessToken}`,
@@ -302257,10 +302670,7 @@ const cmmdForgeCloudProjectsListRouteLayer = add$1("GET", "/api/cmmd/forge-cloud
302257
302670
  code: "CMMD_UNAVAILABLE"
302258
302671
  }, { status: 503 });
302259
302672
  const upstream = upstreamOrError.res;
302260
- if (upstream.status === 401 || upstream.status === 403) return buildCmmdAuthErrorResponse({
302261
- code: "CMMD_AUTH_REQUIRED",
302262
- message: "CMMD authentication expired. Sign in again to continue."
302263
- });
302673
+ if (upstream.status === 401 || upstream.status === 403) return yield* respondCmmdConnectionRequired(session.sessionId);
302264
302674
  const bodyOrError = yield* tryPromise(() => upstream.text()).pipe(map$3((text) => ({
302265
302675
  ok: true,
302266
302676
  text
@@ -302282,35 +302692,35 @@ const cmmdForgeCloudProjectsListRouteLayer = add$1("GET", "/api/cmmd/forge-cloud
302282
302692
  headers: { "content-type": "application/json" }
302283
302693
  });
302284
302694
  }).pipe(catchTag("AuthError", (error) => respondToAuthError(error))));
302285
- const cmmdForgeCloudProjectRegisterRouteLayer = registerProxyRoute({
302695
+ registerProxyRoute({
302286
302696
  forgePath: "/api/cmmd/forge-cloud-projects",
302287
302697
  method: "POST",
302288
302698
  cmmdPath: CMMD_CLOUD_PROJECTS_PATH,
302289
302699
  orgIdSource: "none",
302290
302700
  responseShape: "unwrapData"
302291
302701
  });
302292
- const cmmdForgeCloudProjectUnregisterRouteLayer = registerProxyRoute({
302702
+ registerProxyRoute({
302293
302703
  forgePath: "/api/cmmd/forge-cloud-projects/:projectId",
302294
302704
  method: "DELETE",
302295
302705
  cmmdPath: `${CMMD_CLOUD_PROJECTS_PATH}/:projectId`,
302296
302706
  orgIdSource: "none",
302297
302707
  responseShape: "unwrapData"
302298
302708
  });
302299
- const cmmdForgeCloudProjectLifecyclePreflightRouteLayer = registerProxyRoute({
302709
+ registerProxyRoute({
302300
302710
  forgePath: "/api/cmmd/forge-cloud-projects/:projectId/lifecycle-preflight",
302301
302711
  method: "GET",
302302
302712
  cmmdPath: `${CMMD_CLOUD_PROJECTS_PATH}/:projectId/lifecycle-preflight`,
302303
302713
  orgIdSource: "none",
302304
302714
  responseShape: "unwrapData"
302305
302715
  });
302306
- const cmmdForgeCloudProjectRemovalPreviewRouteLayer = registerProxyRoute({
302716
+ registerProxyRoute({
302307
302717
  forgePath: "/api/cmmd/forge-cloud-projects/:projectId/removal-preview",
302308
302718
  method: "GET",
302309
302719
  cmmdPath: `${CMMD_CLOUD_PROJECTS_PATH}/:projectId/removal-preview`,
302310
302720
  orgIdSource: "none",
302311
302721
  responseShape: "unwrapData"
302312
302722
  });
302313
- const cmmdForgeCloudProjectRemovalRouteLayer = registerProxyRoute({
302723
+ registerProxyRoute({
302314
302724
  forgePath: "/api/cmmd/forge-cloud-projects/:projectId/removal",
302315
302725
  method: "POST",
302316
302726
  cmmdPath: `${CMMD_CLOUD_PROJECTS_PATH}/:projectId/removal`,
@@ -302319,7 +302729,7 @@ const cmmdForgeCloudProjectRemovalRouteLayer = registerProxyRoute({
302319
302729
  successStatus: 202,
302320
302730
  workIntakeInvalidation: "completedPermanentRemoval"
302321
302731
  });
302322
- const cmmdForgeCloudProjectRemovalReceiptRouteLayer = registerProxyRoute({
302732
+ registerProxyRoute({
302323
302733
  forgePath: "/api/cmmd/forge-cloud-project-removals/:operationId",
302324
302734
  method: "GET",
302325
302735
  cmmdPath: `${CMMD_CLOUD_PROJECTS_PATH}/removals/:operationId`,
@@ -302383,11 +302793,8 @@ function makeFetchCloudProjectsFrameEffect(upstreamUrl, accessToken) {
302383
302793
  })).pipe(catch_(() => succeed(null)));
302384
302794
  }
302385
302795
  const cmmdForgeCloudProjectsEventsRouteLayer = add$1("GET", "/api/cmmd/forge-cloud-projects/events", gen(function* () {
302386
- const accessToken = yield* makeCmmdProxyAccessTokenEffect("forge-cloud-projects/events");
302387
- if (!accessToken) return buildCmmdAuthErrorResponse({
302388
- code: "CMMD_AUTH_REQUIRED",
302389
- message: "CMMD authentication is required. Sign in again to continue."
302390
- });
302796
+ const { session, jwt: accessToken } = yield* makeCmmdProxyAccessTokenEffect("forge-cloud-projects/events");
302797
+ if (!accessToken) return yield* respondCmmdConnectionRequired(session.sessionId);
302391
302798
  const fetchCloudProjectsFrame = makeFetchCloudProjectsFrameEffect(`${resolveCommandAppUrl()}${CMMD_CLOUD_PROJECTS_PATH}`, accessToken);
302392
302799
  const dataStream = concat$2(fromEffect(fetchCloudProjectsFrame), tick(FORGE_RUNTIMES_POLL_INTERVAL).pipe(mapEffect$1(() => fetchCloudProjectsFrame))).pipe(filter$2((frame) => frame !== null));
302393
302800
  const keepaliveStream = tick(FORGE_RUNTIMES_KEEPALIVE_INTERVAL).pipe(map$7(() => FORGE_RUNTIMES_KEEPALIVE_FRAME));
@@ -302459,11 +302866,8 @@ function fetchCmmdUpstreamWithRetry(send, policy = "idempotent") {
302459
302866
  }
302460
302867
  const cmmdForgeRuntimesEnsureRouteLayer = add$1("POST", "/api/cmmd/forge-runtimes/ensure", gen(function* () {
302461
302868
  const request = yield* HttpServerRequest;
302462
- const accessToken = yield* makeCmmdProxyAccessTokenEffect("forge-runtimes/ensure");
302463
- if (!accessToken) return buildCmmdAuthErrorResponse({
302464
- code: "CMMD_AUTH_REQUIRED",
302465
- message: "CMMD authentication is required. Sign in again to continue."
302466
- });
302869
+ const { session, jwt: accessToken } = yield* makeCmmdProxyAccessTokenEffect("forge-runtimes/ensure");
302870
+ if (!accessToken) return yield* respondCmmdConnectionRequired(session.sessionId);
302467
302871
  const scopedBody = splitCmmdRuntimeOrganizationScope(yield* request.json.pipe(catch_(() => succeed({}))));
302468
302872
  if (!scopedBody) return jsonUnsafe({ error: "A valid organizationId is required when organization scope is provided." }, { status: 400 });
302469
302873
  const upstreamUrl = `${resolveCommandAppUrl()}/api/forge/context/runtimes/ensure`;
@@ -302482,10 +302886,7 @@ const cmmdForgeRuntimesEnsureRouteLayer = add$1("POST", "/api/cmmd/forge-runtime
302482
302886
  code: "CMMD_UNAVAILABLE"
302483
302887
  }, { status: 503 });
302484
302888
  const upstream = upstreamOrError.res;
302485
- if (upstream.status === 401 || upstream.status === 403) return buildCmmdAuthErrorResponse({
302486
- code: "CMMD_AUTH_REQUIRED",
302487
- message: "CMMD authentication expired. Sign in again to continue."
302488
- });
302889
+ if (upstream.status === 401 || upstream.status === 403) return yield* respondCmmdConnectionRequired(session.sessionId);
302489
302890
  const bodyOrError = yield* tryPromise(() => upstream.text()).pipe(map$3((text) => ({
302490
302891
  ok: true,
302491
302892
  text
@@ -302509,11 +302910,8 @@ const cmmdForgeRuntimesEnsureRouteLayer = add$1("POST", "/api/cmmd/forge-runtime
302509
302910
  }).pipe(catchTag("AuthError", (error) => respondToAuthError(error))));
302510
302911
  const cmmdForgeRuntimesConnectRouteLayer = add$1("POST", "/api/cmmd/forge-runtimes/:runtimeId/connect", gen(function* () {
302511
302912
  const request = yield* HttpServerRequest;
302512
- const accessToken = yield* makeCmmdProxyAccessTokenEffect("forge-runtimes/connect");
302513
- if (!accessToken) return buildCmmdAuthErrorResponse({
302514
- code: "CMMD_AUTH_REQUIRED",
302515
- message: "CMMD authentication is required. Sign in again to continue."
302516
- });
302913
+ const { session, jwt: accessToken } = yield* makeCmmdProxyAccessTokenEffect("forge-runtimes/connect");
302914
+ if (!accessToken) return yield* respondCmmdConnectionRequired(session.sessionId);
302517
302915
  const runtimeId = extractIdFromPath(new URL(request.url, "http://localhost").pathname, 2);
302518
302916
  if (!runtimeId) return jsonUnsafe({ error: "Runtime ID is required." }, { status: 400 });
302519
302917
  const scopedBody = splitCmmdRuntimeOrganizationScope(yield* request.json.pipe(catch_(() => succeed({}))));
@@ -302534,10 +302932,7 @@ const cmmdForgeRuntimesConnectRouteLayer = add$1("POST", "/api/cmmd/forge-runtim
302534
302932
  code: "CMMD_UNAVAILABLE"
302535
302933
  }, { status: 503 });
302536
302934
  const upstream = upstreamOrError.res;
302537
- if (upstream.status === 401 || upstream.status === 403) return buildCmmdAuthErrorResponse({
302538
- code: "CMMD_AUTH_REQUIRED",
302539
- message: "CMMD authentication expired. Sign in again to continue."
302540
- });
302935
+ if (upstream.status === 401 || upstream.status === 403) return yield* respondCmmdConnectionRequired(session.sessionId);
302541
302936
  const bodyOrError = yield* tryPromise(() => upstream.text()).pipe(map$3((text) => ({
302542
302937
  ok: true,
302543
302938
  text
@@ -302561,11 +302956,8 @@ const cmmdForgeRuntimesConnectRouteLayer = add$1("POST", "/api/cmmd/forge-runtim
302561
302956
  }).pipe(catchTag("AuthError", (error) => respondToAuthError(error))));
302562
302957
  const cmmdForgeRuntimesStatusRouteLayer = add$1("GET", "/api/cmmd/forge-runtimes/:runtimeId/status", gen(function* () {
302563
302958
  const request = yield* HttpServerRequest;
302564
- const accessToken = yield* makeCmmdProxyAccessTokenEffect("forge-runtimes/status");
302565
- if (!accessToken) return buildCmmdAuthErrorResponse({
302566
- code: "CMMD_AUTH_REQUIRED",
302567
- message: "CMMD authentication is required. Sign in again to continue."
302568
- });
302959
+ const { session, jwt: accessToken } = yield* makeCmmdProxyAccessTokenEffect("forge-runtimes/status");
302960
+ if (!accessToken) return yield* respondCmmdConnectionRequired(session.sessionId);
302569
302961
  const runtimeId = extractIdFromPath(new URL(request.url, "http://localhost").pathname, 2);
302570
302962
  if (!runtimeId) return jsonUnsafe({ error: "Runtime ID is required." }, { status: 400 });
302571
302963
  const upstreamUrl = `${resolveCommandAppUrl()}/api/forge/context/runtimes/${encodeURIComponent(runtimeId)}/status`;
@@ -302581,10 +302973,7 @@ const cmmdForgeRuntimesStatusRouteLayer = add$1("GET", "/api/cmmd/forge-runtimes
302581
302973
  code: "CMMD_UNAVAILABLE"
302582
302974
  }, { status: 503 });
302583
302975
  const upstream = upstreamOrError.res;
302584
- if (upstream.status === 401 || upstream.status === 403) return buildCmmdAuthErrorResponse({
302585
- code: "CMMD_AUTH_REQUIRED",
302586
- message: "CMMD authentication expired. Sign in again to continue."
302587
- });
302976
+ if (upstream.status === 401 || upstream.status === 403) return yield* respondCmmdConnectionRequired(session.sessionId);
302588
302977
  const bodyOrError = yield* tryPromise(() => upstream.text()).pipe(map$3((text) => ({
302589
302978
  ok: true,
302590
302979
  text
@@ -302615,10 +303004,7 @@ function makeCmmdForgeRuntimesLifecycleHandler(action) {
302615
303004
  subject: session.subject,
302616
303005
  logPrefix: `forge-runtimes/${action}`
302617
303006
  });
302618
- if (!accessToken) return buildCmmdAuthErrorResponse({
302619
- code: "CMMD_AUTH_REQUIRED",
302620
- message: "CMMD authentication is required. Sign in again to continue."
302621
- });
303007
+ if (!accessToken) return yield* respondCmmdConnectionRequired(session.sessionId);
302622
303008
  const runtimeId = extractIdFromPath(new URL(request.url, "http://localhost").pathname, 2);
302623
303009
  if (!runtimeId) return jsonUnsafe({ error: "Runtime ID is required." }, { status: 400 });
302624
303010
  const scopedBody = splitCmmdRuntimeOrganizationScope(yield* request.json.pipe(catch_(() => succeed({}))));
@@ -302639,10 +303025,7 @@ function makeCmmdForgeRuntimesLifecycleHandler(action) {
302639
303025
  code: "CMMD_UNAVAILABLE"
302640
303026
  }, { status: 503 });
302641
303027
  const upstream = upstreamOrError.res;
302642
- if (upstream.status === 401 || upstream.status === 403) return buildCmmdAuthErrorResponse({
302643
- code: "CMMD_AUTH_REQUIRED",
302644
- message: "CMMD authentication expired. Sign in again to continue."
302645
- });
303028
+ if (upstream.status === 401 || upstream.status === 403) return yield* respondCmmdConnectionRequired(session.sessionId);
302646
303029
  const bodyOrError = yield* tryPromise(() => upstream.text()).pipe(map$3((text) => ({
302647
303030
  ok: true,
302648
303031
  text
@@ -302675,11 +303058,8 @@ const cmmdForgeRuntimesRecycleRouteLayer = add$1("POST", "/api/cmmd/forge-runtim
302675
303058
  const cmmdForgeRuntimesUpdateCommitRouteLayer = add$1("POST", "/api/cmmd/forge-runtimes/:runtimeId/update-commit", __cmmdForgeRuntimesUpdateCommitHandlerForTests);
302676
303059
  const cmmdForgeRuntimesDestroyRouteLayer = add$1("POST", "/api/cmmd/forge-runtimes/:runtimeId/destroy", gen(function* () {
302677
303060
  const request = yield* HttpServerRequest;
302678
- const accessToken = yield* makeCmmdProxyAccessTokenEffect("forge-runtimes/destroy");
302679
- if (!accessToken) return buildCmmdAuthErrorResponse({
302680
- code: "CMMD_AUTH_REQUIRED",
302681
- message: "CMMD authentication is required. Sign in again to continue."
302682
- });
303061
+ const { session, jwt: accessToken } = yield* makeCmmdProxyAccessTokenEffect("forge-runtimes/destroy");
303062
+ if (!accessToken) return yield* respondCmmdConnectionRequired(session.sessionId);
302683
303063
  const runtimeId = extractIdFromPath(new URL(request.url, "http://localhost").pathname, 2);
302684
303064
  if (!runtimeId) return jsonUnsafe({ error: "Runtime ID is required." }, { status: 400 });
302685
303065
  const scopedBody = splitCmmdRuntimeOrganizationScope(yield* request.json.pipe(catch_(() => succeed({}))));
@@ -302700,10 +303080,7 @@ const cmmdForgeRuntimesDestroyRouteLayer = add$1("POST", "/api/cmmd/forge-runtim
302700
303080
  code: "CMMD_UNAVAILABLE"
302701
303081
  }, { status: 503 });
302702
303082
  const upstream = upstreamOrError.res;
302703
- if (upstream.status === 401 || upstream.status === 403) return buildCmmdAuthErrorResponse({
302704
- code: "CMMD_AUTH_REQUIRED",
302705
- message: "CMMD authentication expired. Sign in again to continue."
302706
- });
303083
+ if (upstream.status === 401 || upstream.status === 403) return yield* respondCmmdConnectionRequired(session.sessionId);
302707
303084
  const bodyOrError = yield* tryPromise(() => upstream.text()).pipe(map$3((text) => ({
302708
303085
  ok: true,
302709
303086
  text
@@ -302725,6 +303102,7 @@ const cmmdForgeRuntimesDestroyRouteLayer = add$1("POST", "/api/cmmd/forge-runtim
302725
303102
  headers: { "content-type": "application/json" }
302726
303103
  });
302727
303104
  }).pipe(catchTag("AuthError", (error) => respondToAuthError(error))));
303105
+ const cmmdProxyRouteLayers = registeredProxyRouteLayers().slice(__cmmdProxyRouteLayersStartIndex);
302728
303106
  //#endregion
302729
303107
  //#region src/cmmdData/projectTeamProxyRoutes.ts
302730
303108
  const cmmdListWorkspaceMembersRouteLayer = registerProxyRoute({
@@ -303967,6 +304345,103 @@ function recordRuntimeReplicationOutboxDiagnostics(diagnostics, now = Date.now()
303967
304345
  ]).pipe(asVoid);
303968
304346
  }
303969
304347
  //#endregion
304348
+ //#region src/runtimeReplication/pendingLifecycleIntents.ts
304349
+ /**
304350
+ * The newest moment a person or a turn touched this thread, mirroring the
304351
+ * client's `threadLastActivityAt` over the full thread rather than its shell:
304352
+ * the shell's `latestUserMessageAt` is projected from exactly these messages.
304353
+ */
304354
+ function readModelThreadLastActivityAt(thread) {
304355
+ const candidates = [
304356
+ ...thread.messages.filter((message) => message.role === "user").map((m) => m.createdAt),
304357
+ thread.latestTurn?.requestedAt,
304358
+ thread.latestTurn?.startedAt,
304359
+ thread.latestTurn?.completedAt
304360
+ ];
304361
+ let latest = null;
304362
+ let latestTimestamp = Number.NEGATIVE_INFINITY;
304363
+ for (const candidate of candidates) {
304364
+ if (candidate === null || candidate === void 0) continue;
304365
+ const timestamp = Date.parse(candidate);
304366
+ if (timestamp > latestTimestamp) {
304367
+ latest = candidate;
304368
+ latestTimestamp = timestamp;
304369
+ }
304370
+ }
304371
+ return latest;
304372
+ }
304373
+ function intentIsSpent(thread, intent) {
304374
+ const lastActivityAt = readModelThreadLastActivityAt(thread);
304375
+ if (lastActivityAt === null) return false;
304376
+ const activity = Date.parse(lastActivityAt);
304377
+ const requested = Date.parse(intent.requestedAt);
304378
+ return Number.isFinite(activity) && Number.isFinite(requested) && activity > requested;
304379
+ }
304380
+ function commandFor(runtimeId, intent) {
304381
+ const commandId = lifecycleIntentCommandId(runtimeId, intent.threadId, intent.requestedAt);
304382
+ const threadId = ThreadId.make(intent.threadId);
304383
+ return intent.action === "settle" ? {
304384
+ type: "thread.settle",
304385
+ commandId,
304386
+ threadId,
304387
+ settledOverride: "settled"
304388
+ } : {
304389
+ type: "thread.unsettle",
304390
+ commandId,
304391
+ threadId
304392
+ };
304393
+ }
304394
+ const applyOne = fn$1("applyLifecycleIntent")(function* (runtimeId, intent, dependencies) {
304395
+ const base = {
304396
+ runtimeId,
304397
+ threadId: intent.threadId,
304398
+ action: intent.action,
304399
+ requestedAt: intent.requestedAt
304400
+ };
304401
+ const report = (outcome, detail) => dependencies.log({
304402
+ ...base,
304403
+ outcome,
304404
+ ...detail === void 0 ? {} : { detail }
304405
+ }).pipe(as$3(outcome));
304406
+ const thread = (yield* dependencies.getReadModel()).threads.find((candidate) => candidate.id === intent.threadId);
304407
+ if (thread === void 0) return yield* report("missing-thread");
304408
+ if (intentIsSpent(thread, intent)) return yield* report("spent");
304409
+ return yield* dependencies.dispatch(commandFor(runtimeId, intent)).pipe(flatMap(() => report("applied")), catch_((error) => error._tag === "OrchestrationCommandInvariantError" || error._tag === "OrchestrationCommandPreviouslyRejectedError" ? report("refused", error.detail) : report("failed", error.message)));
304410
+ });
304411
+ /**
304412
+ * One tick: list, apply each, acknowledge everything that got an answer.
304413
+ *
304414
+ * A signed-out owner is not an error to retry into the log every five
304415
+ * minutes; it is a state the desktop leaves when someone signs in, so it is
304416
+ * logged once at info and the tick ends. Any other listing or acknowledgement
304417
+ * failure is returned typed, and the intents stay pending on CMMD.
304418
+ */
304419
+ function applyPendingLifecycleIntents(input, dependencies) {
304420
+ return gen(function* () {
304421
+ const intents = yield* dependencies.listPending();
304422
+ if (intents.length === 0) return;
304423
+ const answered = [];
304424
+ for (const intent of intents) if ((yield* applyOne(input.runtimeId, intent, dependencies)) !== "failed") answered.push({
304425
+ threadId: intent.threadId,
304426
+ requestedAt: intent.requestedAt
304427
+ });
304428
+ if (answered.length === 0) return;
304429
+ yield* dependencies.acknowledge(answered);
304430
+ }).pipe(catch_((error) => error.kind === "auth" ? logInfo("Lifecycle intents skipped: CMMD sign-in is required.", {
304431
+ runtimeId: input.runtimeId,
304432
+ code: error.code
304433
+ }) : fail(error)));
304434
+ }
304435
+ /**
304436
+ * One structured line per intent, so a row that "came back" after a wake can
304437
+ * be explained from the log: applied, refused by the decider, or spent by
304438
+ * newer activity.
304439
+ */
304440
+ function logLifecycleIntentOutcome(outcome) {
304441
+ const message = `Lifecycle intent ${outcome.outcome}.`;
304442
+ return outcome.outcome === "refused" || outcome.outcome === "failed" ? logWarning$1(message, outcome) : logInfo(message, outcome);
304443
+ }
304444
+ //#endregion
303970
304445
  //#region src/runtimeReplication/processOutboxItem.ts
303971
304446
  function publicationMetricAttributes(item, outcome, failure) {
303972
304447
  return {
@@ -304163,6 +304638,31 @@ const RuntimeReplicationLive = effect(RuntimeReplication, gen(function* () {
304163
304638
  }).pipe(asVoid, catchCause((cause) => logError("Runtime replication reconciliation failed.", { cause })));
304164
304639
  const heartbeat = enqueueAll.pipe(repeat(spaced("5 minutes")), forkScoped);
304165
304640
  /**
304641
+ * Settle and un-settle requests a person recorded in CMMD while this
304642
+ * runtime was offline. The first tick runs at once, which is the
304643
+ * startup case (this phase starts after the orchestration reactors);
304644
+ * every heartbeat after that picks up requests made while awake. The
304645
+ * tick handles its own expected failures; the supervisor restarts the
304646
+ * schedule if it ever dies between ticks.
304647
+ */
304648
+ const lifecycleIntents = runSupervisedRepeat({
304649
+ label: "Lifecycle intent applier",
304650
+ work: applyPendingLifecycleIntents({ runtimeId }, {
304651
+ listPending: () => client.listPendingLifecycleIntents({ runtimeId }),
304652
+ acknowledge: (intents) => client.acknowledgeLifecycleIntents({
304653
+ runtimeId,
304654
+ intents
304655
+ }),
304656
+ dispatch: engine.dispatch,
304657
+ getReadModel: engine.getReadModel,
304658
+ log: logLifecycleIntentOutcome
304659
+ }).pipe(catchCause((cause) => logError("Lifecycle intent tick failed.", {
304660
+ cause,
304661
+ runtimeId
304662
+ }))),
304663
+ interval: "5 minutes"
304664
+ }).pipe(forkScoped);
304665
+ /**
304166
304666
  * Closes and reports whatever Active Hour interval is currently open,
304167
304667
  * every 5 minutes -- the same cadence as the inventory heartbeat, not
304168
304668
  * because the two are related, but because it is a reasonable default
@@ -304181,6 +304681,7 @@ const RuntimeReplicationLive = effect(RuntimeReplication, gen(function* () {
304181
304681
  reactor,
304182
304682
  providerRegistry.streamChanges.pipe(debounce$1("250 millis"), mapEffect$1(() => enqueueAll, { concurrency: 1 }), runDrain, forkScoped),
304183
304683
  heartbeat,
304684
+ lifecycleIntents,
304184
304685
  activeHourFlush,
304185
304686
  gen(function* () {
304186
304687
  yield* outbox.recover();
@@ -313581,7 +314082,7 @@ const MiscRuntimeLayerLive = mergeAll(AnalyticsServiceLayerLive, OpenLive, Serve
313581
314082
  const RuntimeDependenciesWithoutPullRequestsLive = ReactorLayerLive.pipe(provideMerge(CheckpointingLayerLive), provideMerge(GitLayerLive), provideMerge(OrchestrationLayerLive), provideMerge(ProviderLayerLive), provideMerge(TerminalLayerLive), provideMerge(AgentBrowserManagerLive), provideMerge(mergeAll(ThreadDevRuntimeLive, DevTunnelLive.pipe(provide$1(ThreadDevRuntimeLive)))), provideMerge(PersistenceLayerLive), provideMerge(KeybindingsLive), provideMerge(ProviderRegistryLive), provideMerge(mergeAll(ServerSettingsLive, UsageServiceLive.pipe(provide$1(ServerSettingsLive), provide$1(UsageSessionLookupLive), provide$1(UsageRecordedSourceLive.pipe(provide$1(OrchestrationLayerLive), provide$1(RuntimeReplicationOutboxLive), provide$1(ProviderSessionRuntimeRepositoryLive), provide$1(TextGenerationSessionRepositoryLive)))))), provideMerge(WorkspaceLayerLive), provideMerge(WorkspaceReadinessStateLive), provideMerge(ProjectFaviconResolverLive), provideMerge(RepositoryIdentityResolverLive), provideMerge(ServerEnvironmentLive), provideMerge(AuthLayerLive), provideMerge(ServerSecretStoreLayerLive), provideMerge(mergeAll(CloudRedisCoordinationLive, CloudStateSyncLive.pipe(provide$1(PersistenceLayerLive)))), provideMerge(MiscRuntimeLayerLive));
313582
314083
  const RuntimeDependenciesLive = pullRequestServiceFactoryLayer.pipe(provideMerge(RuntimeDependenciesWithoutPullRequestsLive), provideMerge(cmmdProjectIdentityResolverLive.pipe(provide$1(RuntimeDependenciesWithoutPullRequestsLive))), provideMerge(pullRequestProviderRuntimeLive));
313583
314084
  const RuntimeServicesLive = ServerRuntimeStartupLive.pipe(provideMerge(RuntimeDependenciesLive));
313584
- const makeRoutesLayer = mergeAll(authBearerBootstrapRouteLayer, authBootstrapRouteLayer, authCommandBearerBootstrapRouteLayer, authCommandBootstrapRouteLayer, authOAuthTokenExchangeRouteLayer, authWebSocketTicketRouteLayer, authCmmdOAuthDeviceRouteLayer, authCmmdOAuthTokenRouteLayer, authCmmdPasswordTokenRouteLayer, authClientsRevokeOthersRouteLayer, authClientsRevokeRouteLayer, authClientsRouteLayer, authLogoutRouteLayer, authPairingLinksRevokeRouteLayer, authPairingLinksRouteLayer, authPairingCredentialRouteLayer, authSessionRouteLayer, authWebSocketTokenRouteLayer, authWebLoginRouteLayer, authWebCallbackRouteLayer, desktopLocalWebBridgePublishRouteLayer, desktopLocalWebBridgeBootstrapRouteLayer, desktopRelayControlPlaneRouteLayer, apiDocsHtmlRouteLayer, apiDocsOpenApiRouteLayer, pulseSignalStateListRouteLayer, pulseSignalStateUpsertRouteLayer, cmmdProfileRouteLayer, cmmdCreateBrainDocRouteLayer, cmmdUpdateTaskRouteLayer, cmmdUpsertTaskPullRequestRouteLayer, ...cmmdPullRequestRouteLayers, cmmdAddTaskCommentRouteLayer, cmmdWorkIntakeRouteLayer, cmmdWsTokenRouteLayer, cmmdSearchTasksRouteLayer, cmmdGetTaskCommentsRouteLayer, cmmdGetProjectCommentsRouteLayer, cmmdAddProjectCommentRouteLayer, cmmdUpdateProjectRouteLayer, cmmdGetOrgMembersRouteLayer, cmmdSimHostsRouteLayer, cmmdSimLeaseReadRouteLayer, cmmdSimLeaseClaimRouteLayer, cmmdSimLeaseReleaseRouteLayer, cmmdSimLeaseRenewRouteLayer, cmmdUploadTaskAttachmentRouteLayer, cmmdGetTaskAttachmentsRouteLayer, cmmdUpdateTaskCommentRouteLayer, cmmdDeleteTaskCommentRouteLayer, cmmdGetProjectRepositoryRouteLayer, cmmdListProjectRepositoriesRouteLayer, cmmdArchiveTaskRouteLayer, cmmdUnarchiveTaskRouteLayer, cmmdListTasksRouteLayer, cmmdCreateTaskRouteLayer, cmmdListCampaignsRouteLayer, cmmdGetCampaignRouteLayer, cmmdCreateCampaignRouteLayer, cmmdUpdateCampaignRouteLayer, cmmdDeleteCampaignRouteLayer, cmmdListSavedViewsRouteLayer, cmmdCreateSavedViewRouteLayer, cmmdImportSavedViewRouteLayer, cmmdUpdateSavedViewRouteLayer, cmmdDeleteSavedViewRouteLayer, cmmdListProjectsRouteLayer, cmmdGetProjectRouteLayer, cmmdCreateProjectRouteLayer, cmmdDeleteProjectRouteLayer, cmmdMoveProjectRouteLayer, cmmdGetProjectMembersRouteLayer, cmmdListWorkspaceMembersRouteLayer, cmmdAddProjectMemberRouteLayer, cmmdGetProjectMilestonesRouteLayer, cmmdCreateProjectMilestoneRouteLayer, cmmdUpdateProjectMilestoneRouteLayer, cmmdDeleteProjectMilestoneRouteLayer, cmmdGetProjectUpdatesRouteLayer, cmmdCreateProjectUpdateRouteLayer, cmmdUpdateProjectUpdateRouteLayer, cmmdDeleteProjectUpdateRouteLayer, cmmdImproveProjectContentRouteLayer, cmmdCreateProjectTaskDraftRouteLayer, cmmdGetProjectTaskDraftRouteLayer, cmmdUpdateProjectTaskDraftRouteLayer, cmmdPreviewProjectTaskDraftRouteLayer, cmmdCommitProjectTaskDraftRouteLayer, cmmdDiscardProjectTaskDraftRouteLayer, cmmdGetProjectLeadPlanRouteLayer, cmmdActivateProjectLeadAuthorityRouteLayer, cmmdGetProjectLeadReadinessRouteLayer, cmmdGetProjectLeadCapabilitiesRouteLayer, cmmdGetProjectLeadSummaryRouteLayer, cmmdGetProjectLeadDetailRouteLayer, cmmdGetProjectLeadBriefingRouteLayer, cmmdListProjectLeadEventsRouteLayer, cmmdExplainProjectLeadRouteLayer, cmmdPauseProjectLeadRouteLayer, cmmdResumeProjectLeadRouteLayer, cmmdReserveProjectLeadTaskRouteLayer, cmmdReleaseProjectLeadReservationRouteLayer, cmmdReconcileProjectLeadRouteLayer, cmmdResolveProjectLeadAttentionRouteLayer, cmmdClaimProjectLeadControllerRouteLayer, cmmdRenewProjectLeadControllerClaimRouteLayer, cmmdYieldProjectLeadControllerClaimRouteLayer, cmmdAcknowledgeProjectLeadControllerEventRouteLayer, cmmdRecordProjectLeadControllerDecisionRouteLayer, cmmdListForgeAutomationPresetsRouteLayer, cmmdListUserForgeAutomationRulesRouteLayer, cmmdCreateUserForgeAutomationRuleRouteLayer, cmmdUpdateUserForgeAutomationRuleRouteLayer, cmmdListUserForgeAutomationRunsRouteLayer, cmmdStartUserForgeAutomationRunRouteLayer, cmmdListForgeAutomationRulesRouteLayer, cmmdCreateForgeAutomationRuleRouteLayer, cmmdUpdateForgeAutomationRuleRouteLayer, cmmdListForgeAutomationRunsRouteLayer, cmmdStartForgeAutomationRunRouteLayer, cmmdGetForgeAutomationRunRouteLayer, cmmdRetryForgeAutomationRunRouteLayer, cmmdCancelForgeAutomationRunRouteLayer, cmmdApproveForgeAutomationEscalationRouteLayer, cmmdRejectForgeAutomationEscalationRouteLayer, cmmdListProjectAgentMembersRouteLayer, cmmdCreateProjectAgentMemberRouteLayer, cmmdGetProjectAgentMemberRouteLayer, cmmdRenameProjectAgentMemberRouteLayer, cmmdRetireProjectAgentMemberRouteLayer, cmmdUpdateProjectAgentMemberAvatarRouteLayer, cmmdListProjectAgentMemberInstancesRouteLayer, cmmdPreviewProjectAgentMemberConsolidationRouteLayer, cmmdApplyProjectAgentMemberConsolidationRouteLayer, cmmdPutProjectTaskAssignmentRouteLayer, cmmdListProjectBoardRouteLayer, cmmdGetProjectTaskWorkflowRouteLayer, cmmdUpdateProjectTaskWorkflowRouteLayer, cmmdCreateProjectBoardTaskRouteLayer, cmmdUpdateProjectBoardTaskRouteLayer, cmmdUpdateProjectBoardTaskStatusRouteLayer, cmmdListTaskExecutionOptionsRouteLayer, cmmdCreateTaskWorkSessionRouteLayer, cmmdListProjectWorkSessionsRouteLayer, cmmdGetWorkSessionRouteLayer, cmmdUpdateWorkSessionRouteLayer, cmmdAttachWorkSessionThreadRouteLayer, cmmdListTaskConversationsRouteLayer, cmmdLinkTaskConversationRouteLayer, cmmdGetTaskHistoryRouteLayer, cmmdGetTaskConversationRouteLayer, cmmdSpawnForgeThreadFromBoardTaskRouteLayer, cmmdListCenterBoardRouteLayer, cmmdCreateCenterBoardTaskRouteLayer, cmmdCreateFeedbackRouteLayer, cmmdUpdateCenterBoardTaskRouteLayer, cmmdMoveCenterBoardTaskRouteLayer, cmmdMoveProjectBoardTaskRouteLayer, cmmdArchiveProjectBoardTaskRouteLayer, cmmdUnarchiveProjectBoardTaskRouteLayer, cmmdArchiveCenterBoardTaskRouteLayer, cmmdUnarchiveCenterBoardTaskRouteLayer, cmmdBootstrapRouteLayer, cmmdGetAccountPreferencesRouteLayer, cmmdUpdateAccountPreferencesRouteLayer, cmmdGetOrgProviderPolicyRouteLayer, cmmdListChatsRouteLayer, cmmdGetChatRouteLayer, cmmdListDevicesRouteLayer, runtimeReplicationStatusRouteLayer, cmmdRegisterDeviceRouteLayer, cmmdHeartbeatRuntimeRouteLayer, cmmdGrantRuntimeAccessRouteLayer, cmmdRevokeRuntimeAccessRouteLayer, cmmdCreateRelayControlRouteLayer, cmmdCreateRelayActionGrantRouteLayer, cmmdReplaceRuntimeInventoryRouteLayer, cmmdListRuntimeInventoryRouteLayer, cmmdGetRuntimeDiagnosticsRouteLayer, cmmdProvisionAuthRuntimeRouteLayer, cmmdGetAuthRuntimeRouteLayer, cmmdDestroyAuthRuntimeRouteLayer, cmmdConnectAuthRuntimeRouteLayer, cmmdGetProviderAccountsRouteLayer, cmmdDeleteProviderAccountRouteLayer, cmmdSetProviderAccountDefaultRouteLayer, cmmdGetProviderUsageRouteLayer, cmmdRefreshProviderUsageRouteLayer, cmmdGetUserCodexCredentialRouteLayer, cmmdDeleteUserCodexCredentialRouteLayer, cmmdGetUserClaudeCredentialRouteLayer, cmmdDeleteUserClaudeCredentialRouteLayer, cmmdGetClaudeRuntimeReadinessRouteLayer, cmmdAppendRuntimeThreadEventsRouteLayer, cmmdGetRuntimeThreadReplicaRouteLayer, cmmdRenameDeviceRouteLayer, cmmdRevokeDeviceRouteLayer, cmmdInstallConnectorRouteLayer, cmmdListConnectorsRouteLayer, cmmdForgeCloudProjectsListRouteLayer, cmmdForgeCloudProjectsEventsRouteLayer, cmmdForgeCloudProjectRegisterRouteLayer, cmmdForgeCloudProjectUnregisterRouteLayer, cmmdForgeCloudProjectLifecyclePreflightRouteLayer, cmmdForgeCloudProjectRemovalRouteLayer, cmmdForgeCloudProjectRemovalPreviewRouteLayer, cmmdForgeCloudProjectRemovalReceiptRouteLayer, cmmdForgeRuntimesEnsureRouteLayer, cmmdForgeRuntimesConnectRouteLayer, ownerRuntimeCodexReadinessRouteLayer, cmmdForgeRuntimesStatusRouteLayer, cmmdForgeRuntimesStartRouteLayer, cmmdForgeRuntimesStopRouteLayer, cmmdForgeRuntimesRecycleRouteLayer, cmmdForgeRuntimesUpdateCommitRouteLayer, cmmdForgeRuntimesDestroyRouteLayer, cmmdRenameForgeRuntimeRouteLayer, cmmdGetTaskRouteLayer, commandUpdateTaskRouteLayer, mobileProviderCatalogRouteLayer, cmmdUsageSummaryRouteLayer, cmmdBillingRouteLayer, cmmdBillingSeriesRouteLayer, attachmentsRouteLayer, orchestrationDispatchRouteLayer, orchestrationCmmdWorkRunEventRouteLayer, orchestrationAutomationStartThreadRouteLayer, orchestrationAutomationRebindRouteLayer, orchestrationAutomationTerminalReconcileRouteLayer, mobileGitRunStackedActionRouteLayer, pullRequestDiffRouteLayer, orchestrationSnapshotRouteLayer, localAutomationListRouteLayer, localAutomationCreateRouteLayer, localAutomationUpdateRouteLayer, localAutomationDeleteRouteLayer, localAutomationRunRouteLayer, otlpTracesProxyRouteLayer, devTunnelProxyRouteLayer, devTunnelLocalPortProxyRouteLayer, projectFaviconRouteLayer, serverEnvironmentRouteLayer, browserWebRtcReadinessRouteLayer, staticAndDevRouteLayer, githubStatusRouteLayer, githubAuthorizeUrlRouteLayer, githubDisconnectRouteLayer, githubReposRouteLayer, githubCloneRouteLayer, githubCloneJobStartRouteLayer, githubCloneJobStatusRouteLayer, githubRefreshCredentialsRouteLayer, githubToolConfirmationApproveRouteLayer, projectLinkGetRouteLayer, projectLinkListRouteLayer, projectLinkSetRouteLayer, projectLinkDeleteRouteLayer, cmmdWorkspacesRouteLayer, cmmdCampaignsRouteLayer, cmmdProjectLinksRouteLayer, cmmdEnsureGitHubProjectContextRouteLayer, cmmdProjectRepositoryEnsureRouteLayer, cmmdProjectsGetRouteLayer, cmmdProjectsCreateRouteLayer, workspaceReadinessRouteLayer, runtimeLivenessRouteLayer, claudeNativeGenerationProofRouteLayer, claudeUsageRouteLayer, codexRuntimeProviderReadinessRouteLayer, runtimeDiagnosticsRouteLayer, cloudFoldersRouteLayer, cloudProjectCreateRouteLayer, gitUrlCloneRouteLayer, websocketRpcRouteLayer).pipe(provide$1(browserApiCorsLayer));
314085
+ const makeRoutesLayer = mergeAll(authBearerBootstrapRouteLayer, authBootstrapRouteLayer, authCommandBearerBootstrapRouteLayer, authCommandBootstrapRouteLayer, authOAuthTokenExchangeRouteLayer, authWebSocketTicketRouteLayer, authCmmdOAuthDeviceRouteLayer, authCmmdOAuthTokenRouteLayer, authCmmdPasswordTokenRouteLayer, authClientsRevokeOthersRouteLayer, authClientsRevokeRouteLayer, authClientsRouteLayer, authLogoutRouteLayer, authPairingLinksRevokeRouteLayer, authPairingLinksRouteLayer, authPairingCredentialRouteLayer, authSessionRouteLayer, authWebSocketTokenRouteLayer, authWebLoginRouteLayer, authWebCallbackRouteLayer, desktopLocalWebBridgePublishRouteLayer, desktopLocalWebBridgeBootstrapRouteLayer, desktopRelayControlPlaneRouteLayer, apiDocsHtmlRouteLayer, apiDocsOpenApiRouteLayer, pulseSignalStateListRouteLayer, pulseSignalStateUpsertRouteLayer, cmmdProfileRouteLayer, ...cmmdProxyRouteLayers, cmmdWorkIntakeRouteLayer, cmmdWsTokenRouteLayer, cmmdGetProjectCommentsRouteLayer, cmmdAddProjectCommentRouteLayer, cmmdUpdateProjectRouteLayer, cmmdUploadTaskAttachmentRouteLayer, cmmdUpdateTaskCommentRouteLayer, cmmdListWorkspaceMembersRouteLayer, cmmdAddProjectMemberRouteLayer, cmmdUpdateProjectAgentMemberAvatarRouteLayer, runtimeReplicationStatusRouteLayer, cmmdRefreshProviderUsageRouteLayer, cmmdForgeCloudProjectsListRouteLayer, cmmdForgeCloudProjectsEventsRouteLayer, cmmdForgeRuntimesEnsureRouteLayer, cmmdForgeRuntimesConnectRouteLayer, ownerRuntimeCodexReadinessRouteLayer, cmmdForgeRuntimesStatusRouteLayer, cmmdForgeRuntimesStartRouteLayer, cmmdForgeRuntimesStopRouteLayer, cmmdForgeRuntimesRecycleRouteLayer, cmmdForgeRuntimesUpdateCommitRouteLayer, cmmdForgeRuntimesDestroyRouteLayer, mobileProviderCatalogRouteLayer, attachmentsRouteLayer, orchestrationDispatchRouteLayer, orchestrationCmmdWorkRunEventRouteLayer, orchestrationAutomationStartThreadRouteLayer, orchestrationAutomationRebindRouteLayer, orchestrationAutomationTerminalReconcileRouteLayer, mobileGitRunStackedActionRouteLayer, pullRequestDiffRouteLayer, orchestrationSnapshotRouteLayer, localAutomationListRouteLayer, localAutomationCreateRouteLayer, localAutomationUpdateRouteLayer, localAutomationDeleteRouteLayer, localAutomationRunRouteLayer, otlpTracesProxyRouteLayer, devTunnelProxyRouteLayer, devTunnelLocalPortProxyRouteLayer, projectFaviconRouteLayer, serverEnvironmentRouteLayer, browserWebRtcReadinessRouteLayer, staticAndDevRouteLayer, githubStatusRouteLayer, githubAuthorizeUrlRouteLayer, githubDisconnectRouteLayer, githubReposRouteLayer, githubCloneRouteLayer, githubCloneJobStartRouteLayer, githubCloneJobStatusRouteLayer, githubRefreshCredentialsRouteLayer, githubToolConfirmationApproveRouteLayer, projectLinkGetRouteLayer, projectLinkListRouteLayer, projectLinkSetRouteLayer, projectLinkDeleteRouteLayer, cmmdWorkspacesRouteLayer, cmmdCampaignsRouteLayer, cmmdProjectLinksRouteLayer, cmmdEnsureGitHubProjectContextRouteLayer, cmmdProjectRepositoryEnsureRouteLayer, cmmdProjectsGetRouteLayer, cmmdProjectsCreateRouteLayer, workspaceReadinessRouteLayer, runtimeLivenessRouteLayer, claudeNativeGenerationProofRouteLayer, claudeUsageRouteLayer, codexRuntimeProviderReadinessRouteLayer, runtimeDiagnosticsRouteLayer, cloudFoldersRouteLayer, cloudProjectCreateRouteLayer, gitUrlCloneRouteLayer, websocketRpcRouteLayer).pipe(provide$1(browserApiCorsLayer));
313585
314086
  const runServer = launch$1(unwrap(gen(function* () {
313586
314087
  const config = yield* ServerConfig;
313587
314088
  fixPath({ preferProcessPath: config.forgeCmmdRuntimeMode === true });
@@ -314093,7 +314594,7 @@ const resolveServerConfig = (flags, cliLogLevel, options) => gen(function* () {
314093
314594
  forgeCodexHomePath: env.forgeCodexHomePath,
314094
314595
  forgeClaudeConfigPath: env.forgeClaudeConfigPath,
314095
314596
  forgeApexBaseUrl: env.forgeApexBaseUrl,
314096
- cloudProjectsRoot: env.cloudProjectsRoot ?? "/data/Projects"
314597
+ cloudProjectsRoot: env.cloudProjectsRoot ?? "/projects"
314097
314598
  };
314098
314599
  if (config.forgeCloudShellMode === true && (!config.forgeCloudOwnerAssertionPublicKey?.trim() || !config.forgeCloudOwnerAssertionKeyId?.trim())) return yield* die$1(/* @__PURE__ */ new Error("FORGE_CMMD_CLOUD_OWNER_ASSERTION_PUBLIC_KEY and FORGE_CMMD_CLOUD_OWNER_ASSERTION_KEY_ID are required in cloud-shell mode; runtime ticket keys are not accepted for Cloud owner assertions."));
314099
314600
  if (config.forgeCloudShellMode === true && !isEd25519PublicKey(config.forgeCloudOwnerAssertionPublicKey ?? "")) return yield* die$1(/* @__PURE__ */ new Error("FORGE_CMMD_CLOUD_OWNER_ASSERTION_PUBLIC_KEY must be a valid Ed25519 public key in cloud-shell mode."));