@cmmd-center/forge 0.13.123 → 0.13.125

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin.cjs CHANGED
@@ -30767,7 +30767,7 @@ function frameClassByte(frameClass) {
30767
30767
  if (frameClass === "application") return Uint8Array.of(1);
30768
30768
  return Uint8Array.of(2);
30769
30769
  }
30770
- function encodeBase64Url$1(value) {
30770
+ function encodeBase64Url$2(value) {
30771
30771
  let output = "";
30772
30772
  for (let index = 0; index < value.byteLength; index += 3) {
30773
30773
  const first = value[index] ?? 0;
@@ -30797,7 +30797,7 @@ function decodeBase64Url$1(value) {
30797
30797
  outputIndex += 1;
30798
30798
  }
30799
30799
  }
30800
- if (encodeBase64Url$1(output) !== value) throw new RelayPayloadChannelFailure("channel_authentication_failed", "Encrypted relay frame has a non-canonical base64url encoding.");
30800
+ if (encodeBase64Url$2(output) !== value) throw new RelayPayloadChannelFailure("channel_authentication_failed", "Encrypted relay frame has a non-canonical base64url encoding.");
30801
30801
  return output;
30802
30802
  }
30803
30803
  function isLowOrderX25519PublicKey(value) {
@@ -30836,7 +30836,7 @@ async function createRelayPayloadBinding(input, digestProvider = defaultDigestPr
30836
30836
  };
30837
30837
  }
30838
30838
  function relayPayloadTicketDigestBase64Url(binding) {
30839
- return encodeBase64Url$1(binding.ticketDigest);
30839
+ return encodeBase64Url$2(binding.ticketDigest);
30840
30840
  }
30841
30841
  function relayPayloadInfo(binding) {
30842
30842
  return concat([
@@ -30873,7 +30873,7 @@ async function generateRelayEndpointKeyPair(randomSource = defaultRandomSource)
30873
30873
  }
30874
30874
  async function serializeRelayEndpointPublicKey(publicKey) {
30875
30875
  try {
30876
- return encodeBase64Url$1(bytes(await suite.kem.serializePublicKey(publicKey)));
30876
+ return encodeBase64Url$2(bytes(await suite.kem.serializePublicKey(publicKey)));
30877
30877
  } catch (error) {
30878
30878
  throw new RelayPayloadChannelFailure("endpoint_key_invalid", error instanceof Error ? error.message : "Endpoint public-key serialization failed.");
30879
30879
  }
@@ -30928,7 +30928,7 @@ var HpkeRelayPayloadSender = class {
30928
30928
  constructor(binding, context) {
30929
30929
  this.binding = binding;
30930
30930
  this.context = context;
30931
- this.encapsulatedKey = encodeBase64Url$1(bytes(context.enc));
30931
+ this.encapsulatedKey = encodeBase64Url$2(bytes(context.enc));
30932
30932
  }
30933
30933
  seal(input) {
30934
30934
  return this.queue.run(async () => {
@@ -30958,7 +30958,7 @@ var HpkeRelayPayloadSender = class {
30958
30958
  direction: this.binding.direction,
30959
30959
  frameClass: input.frameClass,
30960
30960
  sequence,
30961
- ciphertext: encodeBase64Url$1(ciphertext)
30961
+ ciphertext: encodeBase64Url$2(ciphertext)
30962
30962
  };
30963
30963
  });
30964
30964
  }
@@ -66337,7 +66337,7 @@ function normalizeNumberish(value) {
66337
66337
  }
66338
66338
  //#endregion
66339
66339
  //#region package.json
66340
- var version$1 = "0.13.123";
66340
+ var version$1 = "0.13.125";
66341
66341
  //#endregion
66342
66342
  //#region src/sentry.ts
66343
66343
  const SERVER_APP_NAME = "forge-server";
@@ -71414,6 +71414,19 @@ function mintCmmdShortLivedToken(grantToken) {
71414
71414
  });
71415
71415
  }
71416
71416
  /**
71417
+ * The redemption request body. `popPublicKeyPem` is the server's PoP identity
71418
+ * (forge#3534): presented when bound sessions are enabled so CMMD stamps the
71419
+ * returned JWT with this server's key (`cnf.jkt`), omitted otherwise.
71420
+ */
71421
+ function buildSessionGrantRedemptionBody(grantToken, popPublicKeyPem) {
71422
+ return {
71423
+ grant_type: "forge_session_grant",
71424
+ grant_token: grantToken,
71425
+ client_id: "cmmd-forge-web",
71426
+ ...popPublicKeyPem ? { pop_public_key: popPublicKeyPem } : {}
71427
+ };
71428
+ }
71429
+ /**
71417
71430
  * Redeem a durable CMMD session grant for a fresh credential set.
71418
71431
  *
71419
71432
  * The grant is CMMD's designed recovery path for exactly the case a rotating
@@ -71425,15 +71438,11 @@ function mintCmmdShortLivedToken(grantToken) {
71425
71438
  * Returns the new MCP PAT alongside the JWT/refresh pair, because CMMD mints a
71426
71439
  * fresh PAT on redemption and the old one is not carried over.
71427
71440
  */
71428
- function redeemCmmdSessionGrant(grantToken) {
71441
+ function redeemCmmdSessionGrant(grantToken, popPublicKeyPem) {
71429
71442
  return fetch(new URL("/api/mcp-server/oauth/token", resolveCommandAppUrl()).toString(), {
71430
71443
  method: "POST",
71431
71444
  headers: { "Content-Type": "application/json" },
71432
- body: JSON.stringify({
71433
- grant_type: "forge_session_grant",
71434
- grant_token: grantToken,
71435
- client_id: "cmmd-forge-web"
71436
- })
71445
+ body: JSON.stringify(buildSessionGrantRedemptionBody(grantToken, popPublicKeyPem))
71437
71446
  }).then(async (response) => {
71438
71447
  if (!response.ok) return null;
71439
71448
  const payload = await response.json();
@@ -71504,6 +71513,140 @@ async function readOAuthErrorCode(response) {
71504
71513
  }
71505
71514
  }
71506
71515
  //#endregion
71516
+ //#region ../../packages/shared/src/cmmdSessionPop.ts
71517
+ /**
71518
+ * CMMD session proof-of-possession client protocol (forge#3517).
71519
+ *
71520
+ * A CMMD session issued to a Forge client can be bound to the client's Ed25519
71521
+ * device key: the public key travels with the login (`pop_public_key`), CMMD
71522
+ * stamps its thumbprint into the token (`cnf.jkt`), and every authenticated
71523
+ * request must then carry a detached Ed25519 signature over a canonical
71524
+ * request binding (method + path + timestamp + nonce). A stolen bearer token
71525
+ * alone is unusable.
71526
+ *
71527
+ * This module is the client half of the scheme CMMD verifies in
71528
+ * `server/services/auth/session-pop-binding.ts`. The protocol deliberately
71529
+ * reuses CMMD's existing crypto shapes rather than inventing a new scheme: the
71530
+ * thumbprint is the same sha256-over-SPKI-DER base64url digest as the forge
71531
+ * device registry and the desktop relay identity, and the signature covers
71532
+ * `<purpose>.<base64url payload>`, the forge relay challenge shape, with
71533
+ * Ed25519. It is not a DPoP port: proofs are plain headers, not JWTs.
71534
+ */
71535
+ const HEADER_KEY = "x-cmmd-pop-key";
71536
+ const HEADER_INPUT = "x-cmmd-pop-input";
71537
+ const HEADER_SIGNATURE = "x-cmmd-pop-signature";
71538
+ const CMMD_SESSION_POP_PURPOSE = "cmmd-session-pop-v1";
71539
+ function encodeBase64Url$1(bytes) {
71540
+ let binary = "";
71541
+ for (const byte of bytes) binary += String.fromCharCode(byte);
71542
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/u, "");
71543
+ }
71544
+ function buildCmmdSessionPopSigningInput(payload) {
71545
+ return `${CMMD_SESSION_POP_PURPOSE}.${encodeBase64Url$1(new TextEncoder().encode(JSON.stringify(payload)))}`;
71546
+ }
71547
+ function randomNonce() {
71548
+ const bytes = new Uint8Array(16);
71549
+ crypto.getRandomValues(bytes);
71550
+ return encodeBase64Url$1(bytes);
71551
+ }
71552
+ /**
71553
+ * Build the three proof headers for one request. Each call produces a fresh
71554
+ * nonce; callers must not reuse the returned headers across attempts
71555
+ * (retries included), because CMMD rejects replayed nonces.
71556
+ */
71557
+ async function buildCmmdSessionPopProofHeaders(input) {
71558
+ const payload = {
71559
+ version: 1,
71560
+ htm: input.method.toUpperCase(),
71561
+ htu: input.path,
71562
+ ts: input.nowSeconds ?? Math.floor(Date.now() / 1e3),
71563
+ nonce: input.nonce ?? randomNonce()
71564
+ };
71565
+ const signingInput = buildCmmdSessionPopSigningInput(payload);
71566
+ const signature = await input.signer.sign(signingInput);
71567
+ const spkiDer = decodePemSpkiDer(input.signer.publicKeyPem);
71568
+ return {
71569
+ [HEADER_KEY]: encodeBase64Url$1(spkiDer),
71570
+ [HEADER_INPUT]: encodeBase64Url$1(new TextEncoder().encode(JSON.stringify(payload))),
71571
+ [HEADER_SIGNATURE]: encodeBase64Url$1(signature)
71572
+ };
71573
+ }
71574
+ function decodePemSpkiDer(pem) {
71575
+ const base64 = pem.replace("-----BEGIN PUBLIC KEY-----", "").replace("-----END PUBLIC KEY-----", "").replace(/\s+/gu, "").replace(/-/g, "+").replace(/_/g, "/");
71576
+ const padded = base64 + "=".repeat((4 - base64.length % 4) % 4);
71577
+ const binary = atob(padded);
71578
+ const bytes = new Uint8Array(binary.length);
71579
+ for (let index = 0; index < binary.length; index += 1) bytes[index] = binary.charCodeAt(index);
71580
+ return bytes;
71581
+ }
71582
+ //#endregion
71583
+ //#region src/cmmd/cmmdSessionPopServer.ts
71584
+ /**
71585
+ * The Forge server's own CMMD session proof-of-possession identity (forge#3534,
71586
+ * D3): the server holds an Ed25519 key, presents its SPKI PEM as
71587
+ * `pop_public_key` when it redeems a CMMD session grant, and signs every
71588
+ * CMMD-origin REST call it makes with detached proofs, so a stolen bearer JWT
71589
+ * alone is unusable. CMMD verifies the scheme in
71590
+ * `server/services/auth/session-pop-binding.ts`.
71591
+ *
71592
+ * Rollout order (docs/forge-cmmd-auth-lanes.md): CMMD deploys first; Forge
71593
+ * flips `FORGE_CMMD_SESSION_POP_ENABLED` afterwards; CMMD's
71594
+ * `JWT_REQUIRE_BOUND_SESSIONS=true` is the contract phase. While the flag is
71595
+ * off this module produces no keys and no headers, and CMMD treats tokens as
71596
+ * plain bearers.
71597
+ *
71598
+ * The identity lives in memory for the process lifetime. After a restart the
71599
+ * server mints a new identity; CMMD then refuses proofs from the old one, and
71600
+ * the JWT resolver's recovery ladder re-mints the affected credentials. The
71601
+ * persistence duty (a stable identity across restarts) lands with the flag
71602
+ * rollout, not with this plumbing.
71603
+ */
71604
+ const ENABLED_FLAG = "FORGE_CMMD_SESSION_POP_ENABLED";
71605
+ /** Enables session proofs only when the rollout flag is exactly "true". */
71606
+ function isCmmdSessionPopEnabled() {
71607
+ return process.env[ENABLED_FLAG] === "true";
71608
+ }
71609
+ let cachedSigner = null;
71610
+ /** Creates an in-memory Ed25519 identity with a public SPKI PEM and a detached signer. */
71611
+ function createServerSigner() {
71612
+ const { publicKey, privateKey } = (0, node_crypto.generateKeyPairSync)("ed25519");
71613
+ const exported = publicKey.export({
71614
+ type: "spki",
71615
+ format: "pem"
71616
+ });
71617
+ return {
71618
+ publicKeyPem: typeof exported === "string" ? exported : exported.toString("utf8"),
71619
+ sign: async (signingInput) => new Uint8Array((0, node_crypto.sign)(null, Buffer.from(signingInput, "utf8"), privateKey))
71620
+ };
71621
+ }
71622
+ /**
71623
+ * The server's PoP identity, created on first use under the flag and stable
71624
+ * for the process lifetime. Null while the flag is off.
71625
+ */
71626
+ function resolveCmmdSessionPopSigner() {
71627
+ if (!isCmmdSessionPopEnabled()) return null;
71628
+ cachedSigner ??= createServerSigner();
71629
+ return cachedSigner;
71630
+ }
71631
+ /** The `pop_public_key` value to present at issuance, or null while disabled. */
71632
+ function cmmdSessionPopPublicKey() {
71633
+ return resolveCmmdSessionPopSigner()?.publicKeyPem ?? null;
71634
+ }
71635
+ /**
71636
+ * The three proof headers for one CMMD-origin request, or no headers while
71637
+ * disabled. Each call carries a fresh nonce; never reuse the result across
71638
+ * attempts, because CMMD rejects replayed nonces.
71639
+ */
71640
+ async function cmmdSessionPopRequestHeaders(input) {
71641
+ const signer = resolveCmmdSessionPopSigner();
71642
+ if (!signer) return {};
71643
+ return buildCmmdSessionPopProofHeaders({
71644
+ signer,
71645
+ method: input.method,
71646
+ path: input.path
71647
+ });
71648
+ }
71649
+ //#endregion
71507
71650
  //#region src/command/cmmdTokenMintLane.ts
71508
71651
  /**
71509
71652
  * The CMMD token-mint lane (forge#3518, expand phase).
@@ -71756,7 +71899,7 @@ function tryGrantRedemption(sessionId, context) {
71756
71899
  return require_Schema$1.gen(function* () {
71757
71900
  yield* logCmmdJwtRung(context, "grant-redemption", "attempted", "redeeming this session's durable CMMD session grant");
71758
71901
  yield* recordCmmdCredentialRefreshMetric("grant-redemption", "attempted");
71759
- const redeemed = yield* require_Schema$1.promise(() => redeemCmmdSessionGrant(grantToken)).pipe(require_Schema$1.orElseSucceed(() => null));
71902
+ const redeemed = yield* require_Schema$1.promise(() => redeemCmmdSessionGrant(grantToken, cmmdSessionPopPublicKey())).pipe(require_Schema$1.orElseSucceed(() => null));
71760
71903
  const accessToken = usableCmmdUserJwt(redeemed?.accessToken);
71761
71904
  if (!accessToken) {
71762
71905
  yield* logCmmdJwtRung(context, "grant-redemption", "failed", "session grant redemption did not return a usable user access JWT");
@@ -72045,11 +72188,25 @@ async function requireCmmdProxySuccess(response, signal) {
72045
72188
  * Uses the stored JWT (set after OAuth auth-code flow with post-update CMMD)
72046
72189
  * to make authenticated REST calls on behalf of the user. A missing delegated
72047
72190
  * JWT is an authentication-required state, not a CMMD availability failure.
72191
+ *
72192
+ * Every request this module sends can carry the server's session
72193
+ * proof-of-possession headers (forge#3534): while
72194
+ * `FORGE_CMMD_SESSION_POP_ENABLED` is true, `authHeaders` attaches detached
72195
+ * Ed25519 proofs over each request's method and path, which CMMD requires for
72196
+ * tokens bound with `cnf.jkt` and ignores otherwise. Each call gets a fresh
72197
+ * nonce, so retries re-sign rather than replay.
72048
72198
  */
72049
- function authHeaders(jwt, orgId) {
72199
+ /** Builds owner JWT and optional organization headers with fresh, flag-gated session proofs. */
72200
+ async function authHeaders(jwt, orgId, method, path) {
72050
72201
  const headers = { Authorization: `Bearer ${jwt}` };
72051
72202
  if (orgId) headers["X-Organization-ID"] = orgId;
72052
- return headers;
72203
+ return {
72204
+ ...headers,
72205
+ ...await cmmdSessionPopRequestHeaders({
72206
+ method,
72207
+ path
72208
+ })
72209
+ };
72053
72210
  }
72054
72211
  async function fetchResponse(url, init, options) {
72055
72212
  try {
@@ -72061,18 +72218,20 @@ async function fetchResponse(url, init, options) {
72061
72218
  rethrowCmmdProxyTimeout(error, options?.signal);
72062
72219
  }
72063
72220
  }
72221
+ /** Fetches a CMMD JSON resource with optional query parameters and caller cancellation. */
72064
72222
  async function proxyGet(jwt, path, searchParams, orgId, options) {
72065
72223
  const cmmdBase = resolveCommandAppUrl();
72066
72224
  const url = new URL(path, cmmdBase);
72067
72225
  if (searchParams) for (const [k, v] of Object.entries(searchParams)) url.searchParams.set(k, v);
72068
- return handleCmmdProxyResponse(await fetchResponse(url.toString(), { headers: authHeaders(jwt, orgId) }, options), options?.signal);
72226
+ return handleCmmdProxyResponse(await fetchResponse(url.toString(), { headers: await authHeaders(jwt, orgId, "GET", path) }, options), options?.signal);
72069
72227
  }
72228
+ /** Posts JSON to CMMD on the owner JWT lane and decodes the response or upstream error. */
72070
72229
  async function proxyPost(jwt, path, body, orgId, options) {
72071
72230
  const cmmdBase = resolveCommandAppUrl();
72072
72231
  return handleCmmdProxyResponse(await fetchResponse(new URL(path, cmmdBase).toString(), {
72073
72232
  method: "POST",
72074
72233
  headers: {
72075
- ...authHeaders(jwt, orgId),
72234
+ ...await authHeaders(jwt, orgId, "POST", path),
72076
72235
  "Content-Type": "application/json"
72077
72236
  },
72078
72237
  body: JSON.stringify(body)
@@ -72086,44 +72245,49 @@ async function responseWithMetadata(response, signal) {
72086
72245
  retryAfter: response.headers.get("retry-after")
72087
72246
  };
72088
72247
  }
72248
+ /** Fetches a CMMD resource while preserving status, Location, and Retry-After metadata. */
72089
72249
  async function proxyGetWithMetadata(jwt, path, orgId, options) {
72090
- return responseWithMetadata(await fetchResponse(new URL(path, resolveCommandAppUrl()).toString(), { headers: authHeaders(jwt, orgId) }, options), options?.signal);
72250
+ return responseWithMetadata(await fetchResponse(new URL(path, resolveCommandAppUrl()).toString(), { headers: await authHeaders(jwt, orgId, "GET", path) }, options), options?.signal);
72091
72251
  }
72252
+ /** Posts JSON to CMMD while preserving status, Location, and Retry-After metadata. */
72092
72253
  async function proxyPostWithMetadata(jwt, path, body, orgId, options) {
72093
72254
  const cmmdBase = resolveCommandAppUrl();
72094
72255
  return responseWithMetadata(await fetchResponse(new URL(path, cmmdBase).toString(), {
72095
72256
  method: "POST",
72096
72257
  headers: {
72097
- ...authHeaders(jwt, orgId),
72258
+ ...await authHeaders(jwt, orgId, "POST", path),
72098
72259
  "Content-Type": "application/json"
72099
72260
  },
72100
72261
  body: JSON.stringify(body)
72101
72262
  }, options), options?.signal);
72102
72263
  }
72264
+ /** Applies a JSON patch request to CMMD using the owner JWT and optional organization. */
72103
72265
  async function proxyPatch(jwt, path, body, orgId) {
72104
72266
  const cmmdBase = resolveCommandAppUrl();
72105
72267
  const url = new URL(path, cmmdBase);
72106
72268
  return handleCmmdProxyResponse(await fetch(url.toString(), {
72107
72269
  method: "PATCH",
72108
72270
  headers: {
72109
- ...authHeaders(jwt, orgId),
72271
+ ...await authHeaders(jwt, orgId, "PATCH", path),
72110
72272
  "Content-Type": "application/json"
72111
72273
  },
72112
72274
  body: JSON.stringify(body)
72113
72275
  }));
72114
72276
  }
72277
+ /** Sends a JSON replacement request to CMMD and decodes its response or upstream error. */
72115
72278
  async function proxyPut(jwt, path, body, orgId) {
72116
72279
  const cmmdBase = resolveCommandAppUrl();
72117
72280
  const url = new URL(path, cmmdBase);
72118
72281
  return handleCmmdProxyResponse(await fetch(url.toString(), {
72119
72282
  method: "PUT",
72120
72283
  headers: {
72121
- ...authHeaders(jwt, orgId),
72284
+ ...await authHeaders(jwt, orgId, "PUT", path),
72122
72285
  "Content-Type": "application/json"
72123
72286
  },
72124
72287
  body: JSON.stringify(body)
72125
72288
  }));
72126
72289
  }
72290
+ /** Deletes a CMMD resource with optional query parameters and JSON body; 204 returns undefined. */
72127
72291
  async function proxyDelete(jwt, path, searchParams, orgId, body) {
72128
72292
  const cmmdBase = resolveCommandAppUrl();
72129
72293
  const url = new URL(path, cmmdBase);
@@ -72131,7 +72295,7 @@ async function proxyDelete(jwt, path, searchParams, orgId, body) {
72131
72295
  const response = await fetch(url.toString(), {
72132
72296
  method: "DELETE",
72133
72297
  headers: {
72134
- ...authHeaders(jwt, orgId),
72298
+ ...await authHeaders(jwt, orgId, "DELETE", path),
72135
72299
  ...body === void 0 ? {} : { "Content-Type": "application/json" }
72136
72300
  },
72137
72301
  ...body === void 0 ? {} : { body: JSON.stringify(body) }
@@ -72139,13 +72303,14 @@ async function proxyDelete(jwt, path, searchParams, orgId, body) {
72139
72303
  if (!response.ok && response.status !== 204) await requireCmmdProxySuccess(response);
72140
72304
  return response.status === 204 ? void 0 : handleCmmdProxyResponse(response);
72141
72305
  }
72306
+ /** Forwards multipart bytes to CMMD, preserving the caller's content type and boundary. */
72142
72307
  async function proxyMultipart(jwt, path, body, contentType, orgId) {
72143
72308
  const cmmdBase = resolveCommandAppUrl();
72144
72309
  const url = new URL(path, cmmdBase);
72145
72310
  return handleCmmdProxyResponse(await fetch(url.toString(), {
72146
72311
  method: "POST",
72147
72312
  headers: {
72148
- ...authHeaders(jwt, orgId),
72313
+ ...await authHeaders(jwt, orgId, "POST", path),
72149
72314
  "Content-Type": contentType
72150
72315
  },
72151
72316
  body
@@ -300407,7 +300572,7 @@ function resolveBuildCommitFromEnv(env) {
300407
300572
  * environment descriptor down instead of reporting an honest "unknown".
300408
300573
  */
300409
300574
  function readBakedBuildCommit() {
300410
- return "36ad9a06120f61eef3931979fa6c199d3c862efb";
300575
+ return "2b217d6b85f7c98cf77e2a23bce2ef8102d3a0a5";
300411
300576
  }
300412
300577
  async function resolveServerBuildCommit(input) {
300413
300578
  if (isFullCommitSha(input.baked)) return input.baked;
@@ -313335,6 +313500,44 @@ const cmmdUpdateProjectAgentMemberAvatarRouteLayer = registerProxyRoute({
313335
313500
  responseShape: "unwrapData"
313336
313501
  });
313337
313502
  //#endregion
313503
+ //#region src/command/cmmdPushProxyRoutes.ts
313504
+ /**
313505
+ * The signed-in phone's push registration, forwarded to CMMD's push
313506
+ * device-token API on the owner's stored CMMD JWT (forge#3534).
313507
+ *
313508
+ * CMMD owns push delivery: the `device_push_tokens` table, the Expo transport,
313509
+ * and the `mobile_push_v1` delivery flag are all CMMD-side, and its
313510
+ * registration API lives at `/api/push`, not under `/api/forge/context`. The
313511
+ * mobile push delivery spec (docs/specs/2026-09-09-mobile-push-delivery.md,
313512
+ * stage 2) recommends reusing that API over adding a forge-context doorway
313513
+ * first: the Forge server already holds the phone's CMMD credential, and the
313514
+ * registry prologue here provides the same session auth, CMMD-connection
313515
+ * gate, and `CMMD_AUTH_REQUIRED` mapping every `/api/cmmd` route gets. The
313516
+ * deny-listed legacy owner control paths are untouched. If review wants a
313517
+ * forge-context doorway first, these two routes are the only call sites to
313518
+ * repoint.
313519
+ *
313520
+ * `orgIdSource` is `none` (the organization comes from the JWT, like the
313521
+ * settings and device-registry routes): a phone registers against its default
313522
+ * organization and has no workspace context to pass.
313523
+ */
313524
+ const cmmdRegisterMobilePushDeviceRouteLayer = registerProxyRoute({
313525
+ forgePath: "/api/cmmd/mobile/push/registration",
313526
+ method: "POST",
313527
+ cmmdPath: "/api/push/device-tokens",
313528
+ orgIdSource: "none",
313529
+ responseShape: "unwrapData",
313530
+ successStatus: 201
313531
+ });
313532
+ const cmmdDeleteMobilePushDeviceRouteLayer = registerProxyRoute({
313533
+ forgePath: "/api/cmmd/mobile/push/registration",
313534
+ method: "DELETE",
313535
+ cmmdPath: "/api/push/device-tokens",
313536
+ orgIdSource: "none",
313537
+ responseShape: "unwrapData",
313538
+ requestBody: "json"
313539
+ });
313540
+ //#endregion
313338
313541
  //#region src/command/runtimeProviderAuthorityUpgradeModel.ts
313339
313542
  const AUTHORITY_UPGRADE_OPERATION_KEYS = new Set([
313340
313543
  "operationId",
@@ -315066,9 +315269,17 @@ const RuntimeReplicationLive = require_Schema$1.effect(RuntimeReplication, requi
315066
315269
  concurrency: 1,
315067
315270
  discard: true
315068
315271
  });
315272
+ const retryStuckThreadStreams = (streamKeys) => runtimeId ? require_Schema$1.forEach(streamKeys, (streamKey) => outbox.resetStuckThreadGeneration({
315273
+ runtimeId,
315274
+ streamKey
315275
+ }).pipe(require_Schema$1.flatMap((reset) => reset ? enqueueThread(threadIdFromStreamKey(streamKey)) : require_Schema$1.void_)), {
315276
+ concurrency: 1,
315277
+ discard: true
315278
+ }) : require_Schema$1.void_;
315069
315279
  return RuntimeReplication.of({
315070
315280
  start,
315071
- retryReprojectionPending
315281
+ retryReprojectionPending,
315282
+ retryStuckThreadStreams
315072
315283
  });
315073
315284
  }));
315074
315285
  //#endregion
@@ -315415,6 +315626,31 @@ const THREAD_STREAM_PAYLOAD_HASH_MISMATCH_CODE = "THREAD_STREAM_PAYLOAD_HASH_MIS
315415
315626
  */
315416
315627
  const THREAD_STREAM_REMOTE_CONFLICT_REPROJECTION_PENDING_CODE = "THREAD_STREAM_REMOTE_CONFLICT_REPROJECTION_PENDING";
315417
315628
  /**
315629
+ * Terminal park code for a thread-events reset `refusedResetIsStuck` judges
315630
+ * genuinely stuck: the exact canonical reset shape was already sent once
315631
+ * under this generation and CMMD refused it again with zero acknowledged
315632
+ * progress (forge#3635). Before this code existed, that case fell through to
315633
+ * `failGeneric`, which recorded the raw `THREAD_STREAM_PAYLOAD_CONFLICT` /
315634
+ * `THREAD_STREAM_HEAD_MISMATCH` code -- a code neither
315635
+ * `readReprojectionPendingThreadStreamKeys` nor
315636
+ * `MANUALLY_RECOVERABLE_BLOCKED_CODES` selects, so the manual retry endpoint
315637
+ * could never reach the row.
315638
+ *
315639
+ * Deliberately excluded from `CLAIMABLE_BLOCKED_CODES`,
315640
+ * `STARTUP_RECOVERABLE_BLOCKED_CODES`, and `MANUALLY_RECOVERABLE_BLOCKED_CODES`:
315641
+ * a plain status flip back to `pending` would resend the exact batch CMMD
315642
+ * already refused twice. `enqueueThread` also leaves a row parked under this
315643
+ * code alone on new domain events and the heartbeat (see the stuck check
315644
+ * inside `enqueueThread` below) instead of re-projecting it back to `pending`
315645
+ * the way it does for every other generation, so a stuck row only clears once
315646
+ * the operator retry endpoint calls `RuntimeReplicationOutboxShape`'s
315647
+ * `resetStuckThreadGeneration` (which mints a fresh, never-before-sent repair
315648
+ * generation before re-projecting) or
315649
+ * a genuinely new generation id supersedes it (e.g. the thread archives and
315650
+ * gets a `:final:` id).
315651
+ */
315652
+ const THREAD_STREAM_REMOTE_CONFLICT_STUCK_CODE = "THREAD_STREAM_REMOTE_CONFLICT_STUCK";
315653
+ /**
315418
315654
  * Whether a refused batch is the exact canonical reset shape (`fromSequence
315419
315655
  * === 1`, empty previous head, deterministic content) under a generation the
315420
315656
  * local cursor already holds with zero acknowledged progress -- i.e. this
@@ -315692,6 +315928,23 @@ const readReprojectionPendingThreadStreamKeys = require_Schema$1.gen(function* (
315692
315928
  AND last_error_code = ${THREAD_STREAM_REMOTE_CONFLICT_REPROJECTION_PENDING_CODE}
315693
315929
  `).map((row) => row.streamKey);
315694
315930
  }).pipe(require_Schema$1.orDie);
315931
+ /**
315932
+ * Thread streams parked under THREAD_STREAM_REMOTE_CONFLICT_STUCK_CODE, for the
315933
+ * manual `/api/runtime-replication/retry` endpoint (forge#3635). Deliberately absent
315934
+ * from MANUALLY_RECOVERABLE_BLOCKED_CODES for the same reason
315935
+ * `readReprojectionPendingThreadStreamKeys` is: a plain status flip back to `pending`
315936
+ * would resend the exact reset CMMD already refused twice. `http.ts`'s retry handler
315937
+ * passes these to `RuntimeReplication`'s `retryStuckThreadStreams`, which calls
315938
+ * `resetStuckThreadGeneration` for each of these before re-projecting, so the retry
315939
+ * always sends a fresh, never-before-refused generation.
315940
+ */
315941
+ const readStuckThreadStreamKeys = require_Schema$1.gen(function* () {
315942
+ return (yield* (yield* require_SqlError.SqlClient)`
315943
+ SELECT stream_key AS "streamKey" FROM runtime_replication_outbox
315944
+ WHERE operation = 'thread-events' AND status = 'blocked'
315945
+ AND last_error_code = ${THREAD_STREAM_REMOTE_CONFLICT_STUCK_CODE}
315946
+ `).map((row) => row.streamKey);
315947
+ }).pipe(require_Schema$1.orDie);
315695
315948
  const RuntimeReplicationOutboxLive = require_Schema$1.effect(RuntimeReplicationOutbox, require_Schema$1.gen(function* () {
315696
315949
  const sql = yield* require_SqlError.SqlClient;
315697
315950
  const upsertPayload = (input) => {
@@ -315912,6 +316165,12 @@ const RuntimeReplicationOutboxLive = require_Schema$1.effect(RuntimeReplicationO
315912
316165
  now
315913
316166
  }).pipe(require_Schema$1.orDie);
315914
316167
  };
316168
+ const isThreadStreamParkedStuck = (input) => sql`
316169
+ SELECT runtime_id AS "runtimeId" FROM runtime_replication_outbox
316170
+ WHERE runtime_id = ${input.runtimeId} AND stream_key = ${input.streamKey}
316171
+ AND operation = 'thread-events' AND status = 'blocked'
316172
+ AND last_error_code = ${THREAD_STREAM_REMOTE_CONFLICT_STUCK_CODE}
316173
+ `.pipe(require_Schema$1.map((rows) => rows.length === 1));
315915
316174
  const enqueueThread = (input) => {
315916
316175
  const now = (/* @__PURE__ */ new Date()).toISOString();
315917
316176
  const baseGenerationId = runtimeThreadGenerationId(input.runtimeId, input.streamKey);
@@ -315920,6 +316179,7 @@ const RuntimeReplicationOutboxLive = require_Schema$1.effect(RuntimeReplicationO
315920
316179
  const previousActiveGeneration = activeRuntimeThreadGenerationId(baseGenerationId, previousCursor?.generationId);
315921
316180
  const generationId = input.historyFinalized ? runtimeThreadFinalGenerationId(input.runtimeId, input.streamKey, input.events) : previousActiveGeneration;
315922
316181
  const replacesGeneration = previousCursor !== void 0 && previousCursor.generationId !== generationId;
316182
+ if (!replacesGeneration && (yield* isThreadStreamParkedStuck(input))) return;
315923
316183
  yield* initializeThreadCursor({
315924
316184
  runtimeId: input.runtimeId,
315925
316185
  streamKey: input.streamKey,
@@ -316221,12 +316481,16 @@ const RuntimeReplicationOutboxLive = require_Schema$1.effect(RuntimeReplicationO
316221
316481
  })).pipe(require_Schema$1.orDie);
316222
316482
  /**
316223
316483
  * Recovers from a CMMD-reported thread stream conflict (see
316224
- * THREAD_STREAM_REMOTE_CONFLICT_CODES). Returns `null` when this item is
316225
- * not eligible (its payload does not decode, or `refusedResetIsStuck`
316226
- * says the exact reset shape already failed once -- in which case the
316227
- * caller falls back to blocking) and `false` when the row was superseded
316228
- * before this could apply, mirroring `fail`'s own supersession signal.
316229
- * Otherwise replaces the local cursor with a brand-new repair generation
316484
+ * THREAD_STREAM_REMOTE_CONFLICT_CODES). Returns `null` only when this
316485
+ * item's payload does not decode, in which case the caller falls back to
316486
+ * `failGeneric`. When `refusedResetIsStuck` says the exact reset shape
316487
+ * already failed once with zero progress, parks the row under
316488
+ * `THREAD_STREAM_REMOTE_CONFLICT_STUCK_CODE` directly (see that code's
316489
+ * doc comment) and returns `true`/`false` the same way the normal repair
316490
+ * path below does -- never `null` -- so the caller never falls through to
316491
+ * `failGeneric`'s raw conflict code (forge#3635). `false` means the row
316492
+ * was superseded before this could apply, mirroring `fail`'s own
316493
+ * supersession signal. Otherwise replaces the local cursor with a brand-new repair generation
316230
316494
  * from sequence 1, empty previous head -- the shape CMMD's reset rule
316231
316495
  * accepts unconditionally -- and parks the row blocked under
316232
316496
  * `THREAD_STREAM_REMOTE_CONFLICT_REPROJECTION_PENDING_CODE`, deferring the
@@ -316245,13 +316509,30 @@ const RuntimeReplicationOutboxLive = require_Schema$1.effect(RuntimeReplicationO
316245
316509
  runtimeId: item.runtimeId,
316246
316510
  streamKey: item.streamKey
316247
316511
  });
316512
+ const now = (/* @__PURE__ */ new Date()).toISOString();
316248
316513
  if (refusedResetIsStuck({
316249
316514
  baseGenerationId,
316250
316515
  refusedGenerationId: parsedBatch.generationId,
316251
316516
  refusedFromSequence: parsedBatch.fromSequence,
316252
316517
  cursor
316253
- })) return null;
316254
- const now = (/* @__PURE__ */ new Date()).toISOString();
316518
+ })) {
316519
+ if ((yield* sql`
316520
+ UPDATE runtime_replication_outbox SET
316521
+ status = 'blocked', next_attempt_at = '9999-12-31T23:59:59.999Z',
316522
+ last_error_code = ${"THREAD_STREAM_REMOTE_CONFLICT_STUCK"},
316523
+ last_error = ${`Runtime replication conflict (${failure.code}) refused a thread-events reset that had already been refused once with zero acknowledged progress under this generation. Parked as stuck rather than resent; use the manual retry endpoint to reset it to a fresh generation.`}, updated_at = ${now}
316524
+ WHERE runtime_id = ${item.runtimeId} AND stream_key = ${item.streamKey}
316525
+ AND payload_hash = ${item.payloadHash}
316526
+ RETURNING runtime_id AS "runtimeId"
316527
+ `).length !== 1) return false;
316528
+ yield* require_Schema$1.logWarning("Runtime replication parked a thread-stream repair as stuck after its reset was refused with zero progress.", {
316529
+ runtimeId: item.runtimeId,
316530
+ streamKey: item.streamKey,
316531
+ errorCode: failure.code,
316532
+ refusedGenerationId: parsedBatch.generationId
316533
+ });
316534
+ return true;
316535
+ }
316255
316536
  const repairGenerationId = `${baseGenerationId}:repair:${node_crypto.randomUUID()}`;
316256
316537
  const message = `Runtime replication conflict (${failure.code}) refused a thread-events batch; deferring to a full-history re-projection under a new repair generation.`;
316257
316538
  if (!(yield* sql.withTransaction(require_Schema$1.gen(function* () {
@@ -316319,6 +316600,30 @@ const RuntimeReplicationOutboxLive = require_Schema$1.effect(RuntimeReplicationO
316319
316600
  AND status = 'blocked'
316320
316601
  AND last_error_code = 'RUNTIME_REVOKED'
316321
316602
  `.pipe(require_Schema$1.asVoid, require_Schema$1.orDie);
316603
+ const resetStuckThreadGeneration = (input) => {
316604
+ const now = (/* @__PURE__ */ new Date()).toISOString();
316605
+ const repairGenerationId = `${runtimeThreadGenerationId(input.runtimeId, input.streamKey)}:repair:${node_crypto.randomUUID()}`;
316606
+ const message = "Runtime replication operator retry reset a stuck thread-stream repair to a new generation.";
316607
+ return sql.withTransaction(require_Schema$1.gen(function* () {
316608
+ if ((yield* sql`
316609
+ UPDATE runtime_replication_outbox SET
316610
+ status = 'blocked', next_attempt_at = '9999-12-31T23:59:59.999Z',
316611
+ last_error_code = ${"THREAD_STREAM_REMOTE_CONFLICT_REPROJECTION_PENDING"},
316612
+ last_error = ${message}, updated_at = ${now}
316613
+ WHERE runtime_id = ${input.runtimeId} AND stream_key = ${input.streamKey}
316614
+ AND operation = 'thread-events'
316615
+ AND last_error_code = ${"THREAD_STREAM_REMOTE_CONFLICT_STUCK"}
316616
+ RETURNING runtime_id AS "runtimeId"
316617
+ `).length !== 1) return false;
316618
+ yield* replaceThreadCursor({
316619
+ runtimeId: input.runtimeId,
316620
+ streamKey: input.streamKey,
316621
+ generationId: repairGenerationId,
316622
+ now
316623
+ });
316624
+ return true;
316625
+ })).pipe(require_Schema$1.orDie);
316626
+ };
316322
316627
  const getStatus = () => readRuntimeReplicationOutboxStatus.pipe(require_Schema$1.provideService(require_SqlError.SqlClient, sql));
316323
316628
  const getDiagnostics = () => require_Schema$1.gen(function* () {
316324
316629
  const [diagnostics] = decodeDiagnostics(yield* sql`
@@ -316349,6 +316654,7 @@ const RuntimeReplicationOutboxLive = require_Schema$1.effect(RuntimeReplicationO
316349
316654
  acknowledge,
316350
316655
  fail,
316351
316656
  retryBlocked,
316657
+ resetStuckThreadGeneration,
316352
316658
  recover,
316353
316659
  recoverLegacyRevokedInventory,
316354
316660
  getStatus,
@@ -316481,10 +316787,14 @@ const retryHandler = require_Schema$1.gen(function* () {
316481
316787
  const replication = yield* require_Schema$1.serviceOption(RuntimeReplication);
316482
316788
  const requeued = yield* retryBlockedRuntimeReplicationOutbox;
316483
316789
  const reprojectionPendingStreamKeys = yield* readReprojectionPendingThreadStreamKeys;
316484
- if (require_Schema$1.isSome(replication)) yield* replication.value.retryReprojectionPending(reprojectionPendingStreamKeys);
316790
+ const stuckStreamKeys = yield* readStuckThreadStreamKeys;
316791
+ if (require_Schema$1.isSome(replication)) {
316792
+ yield* replication.value.retryReprojectionPending(reprojectionPendingStreamKeys);
316793
+ yield* replication.value.retryStuckThreadStreams(stuckStreamKeys);
316794
+ }
316485
316795
  const status = yield* readRuntimeReplicationOutboxStatus;
316486
316796
  return require_HttpServer.jsonUnsafe({
316487
- requeued: requeued + (require_Schema$1.isSome(replication) ? reprojectionPendingStreamKeys.length : 0),
316797
+ requeued: requeued + (require_Schema$1.isSome(replication) ? reprojectionPendingStreamKeys.length + stuckStreamKeys.length : 0),
316488
316798
  ...responseFromStatus(status)
316489
316799
  });
316490
316800
  }).pipe(require_Schema$1.catchTag("AuthError", respondToAuthError));
@@ -324847,7 +325157,7 @@ const MiscRuntimeLayerLive = require_Schema$1.mergeAll(AnalyticsServiceLayerLive
324847
325157
  const RuntimeDependenciesWithoutPullRequestsLive = ReactorLayerLive.pipe(require_Schema$1.provideMerge(CheckpointingLayerLive), require_Schema$1.provideMerge(GitLayerLive), require_Schema$1.provideMerge(OrchestrationLayerLive), require_Schema$1.provideMerge(ProviderLayerLive), require_Schema$1.provideMerge(TerminalLayerLive), require_Schema$1.provideMerge(AgentBrowserManagerLive), require_Schema$1.provideMerge(require_Schema$1.mergeAll(ThreadDevRuntimeLive, DevTunnelLive.pipe(require_Schema$1.provide$1(ThreadDevRuntimeLive)))), require_Schema$1.provideMerge(PersistenceLayerLive), require_Schema$1.provideMerge(KeybindingsLive), require_Schema$1.provideMerge(ProviderRegistryLive), require_Schema$1.provideMerge(require_Schema$1.mergeAll(ServerSettingsLive, UsageServiceLive.pipe(require_Schema$1.provide$1(ServerSettingsLive), require_Schema$1.provide$1(UsageSessionLookupLive), require_Schema$1.provide$1(UsageRecordedSourceLive.pipe(require_Schema$1.provide$1(OrchestrationLayerLive), require_Schema$1.provide$1(RuntimeReplicationOutboxLive), require_Schema$1.provide$1(ProviderSessionRuntimeRepositoryLive), require_Schema$1.provide$1(TextGenerationSessionRepositoryLive)))))), require_Schema$1.provideMerge(WorkspaceLayerLive), require_Schema$1.provideMerge(WorkspaceReadinessStateLive), require_Schema$1.provideMerge(ProjectFaviconResolverLive), require_Schema$1.provideMerge(RepositoryIdentityResolverLive), require_Schema$1.provideMerge(ServerEnvironmentLive), require_Schema$1.provideMerge(AuthLayerLive), require_Schema$1.provideMerge(ServerSecretStoreLayerLive), require_Schema$1.provideMerge(require_Schema$1.mergeAll(CloudRedisCoordinationLive, CloudStateSyncLive.pipe(require_Schema$1.provide$1(PersistenceLayerLive)))), require_Schema$1.provideMerge(MiscRuntimeLayerLive));
324848
325158
  const RuntimeDependenciesLive = pullRequestServiceFactoryLayer.pipe(require_Schema$1.provideMerge(RuntimeDependenciesWithoutPullRequestsLive), require_Schema$1.provideMerge(cmmdProjectIdentityResolverLive.pipe(require_Schema$1.provide$1(RuntimeDependenciesWithoutPullRequestsLive))), require_Schema$1.provideMerge(pullRequestProviderRuntimeLive));
324849
325159
  const RuntimeServicesLive = ServerRuntimeStartupLive.pipe(require_Schema$1.provideMerge(RuntimeDependenciesLive));
324850
- const makeRoutesLayer = require_Schema$1.mergeAll(attachmentUploadRouteLayer, authBearerBootstrapRouteLayer, authBootstrapRouteLayer, authCommandBearerBootstrapRouteLayer, authCommandBootstrapRouteLayer, authCmmdEmbedExchangeRouteLayer, authOAuthTokenExchangeRouteLayer, authWebSocketTicketRouteLayer, authCmmdOAuthDeviceRouteLayer, authCmmdOAuthTokenRouteLayer, authCmmdPasswordTokenRouteLayer, authClientsRevokeOthersRouteLayer, authClientsRevokeRouteLayer, authClientsRouteLayer, authLogoutRouteLayer, authPairingLinksRevokeRouteLayer, authPairingLinksRouteLayer, authPairingCredentialRouteLayer, authSessionRenewRouteLayer, authSessionRouteLayer, authWebSocketTokenRouteLayer, authWebLoginRouteLayer, authWebCallbackRouteLayer, cloudOwnerSessionRedeemRouteLayer, cloudOwnerSessionRevokeRouteLayer, desktopLocalWebBridgePublishRouteLayer, desktopLocalWebBridgeBootstrapRouteLayer, desktopRelayControlPlaneRouteLayer, apiDocsHtmlRouteLayer, apiDocsOpenApiRouteLayer, pulseSignalStateListRouteLayer, pulseSignalStateUpsertRouteLayer, cmmdProfileRouteLayer, ...cmmdProxyRouteLayers, cmmdWorkIntakeRouteLayer, cmmdWsTokenRouteLayer, cmmdGetProjectCommentsRouteLayer, cmmdAddProjectCommentRouteLayer, cmmdUpdateProjectRouteLayer, cmmdUploadTaskAttachmentRouteLayer, cmmdUpdateTaskCommentRouteLayer, cmmdListWorkspaceMembersRouteLayer, cmmdAddProjectMemberRouteLayer, cmmdUpdateProjectAgentMemberAvatarRouteLayer, runtimeReplicationStatusRouteLayer, cmmdRefreshProviderUsageRouteLayer, cmmdForgeCloudProjectsListRouteLayer, cmmdForgeCloudProjectsEventsRouteLayer, cmmdForgeEnvironmentsEventsRouteLayer, cmmdForgeRuntimesEnsureRouteLayer, cmmdForgeRuntimesConnectRouteLayer, ownerRuntimeCodexReadinessRouteLayer, cmmdForgeRuntimesStatusRouteLayer, cmmdForgeRuntimesStartRouteLayer, cmmdForgeRuntimesStopRouteLayer, cmmdForgeRuntimesRecycleRouteLayer, cmmdForgeRuntimesUpdateCommitRouteLayer, cmmdForgeRuntimesDestroyRouteLayer, mobileProviderCatalogRouteLayer, attachmentsRouteLayer, orchestrationDispatchRouteLayer, orchestrationCmmdWorkRunEventRouteLayer, orchestrationAutomationStartThreadRouteLayer, orchestrationAutomationRebindRouteLayer, orchestrationAutomationTerminalReconcileRouteLayer, mobileGitRunStackedActionRouteLayer, pullRequestDiffRouteLayer, orchestrationSnapshotRouteLayer, orchestrationThreadSnapshotRouteLayer, 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, runtimeFilesystemHealthRouteLayer, claudeNativeGenerationProofRouteLayer, claudeUsageRouteLayer, codexRuntimeProviderReadinessRouteLayer, runtimeDiagnosticsRouteLayer, cloudFoldersRouteLayer, cloudProjectCreateRouteLayer, gitUrlCloneRouteLayer, websocketRpcRouteLayer).pipe(require_Schema$1.provide$1(browserApiCorsLayer));
325160
+ const makeRoutesLayer = require_Schema$1.mergeAll(attachmentUploadRouteLayer, authBearerBootstrapRouteLayer, authBootstrapRouteLayer, authCommandBearerBootstrapRouteLayer, authCommandBootstrapRouteLayer, authCmmdEmbedExchangeRouteLayer, authOAuthTokenExchangeRouteLayer, authWebSocketTicketRouteLayer, authCmmdOAuthDeviceRouteLayer, authCmmdOAuthTokenRouteLayer, authCmmdPasswordTokenRouteLayer, authClientsRevokeOthersRouteLayer, authClientsRevokeRouteLayer, authClientsRouteLayer, authLogoutRouteLayer, authPairingLinksRevokeRouteLayer, authPairingLinksRouteLayer, authPairingCredentialRouteLayer, authSessionRenewRouteLayer, authSessionRouteLayer, authWebSocketTokenRouteLayer, authWebLoginRouteLayer, authWebCallbackRouteLayer, cloudOwnerSessionRedeemRouteLayer, cloudOwnerSessionRevokeRouteLayer, desktopLocalWebBridgePublishRouteLayer, desktopLocalWebBridgeBootstrapRouteLayer, desktopRelayControlPlaneRouteLayer, apiDocsHtmlRouteLayer, apiDocsOpenApiRouteLayer, pulseSignalStateListRouteLayer, pulseSignalStateUpsertRouteLayer, cmmdProfileRouteLayer, ...cmmdProxyRouteLayers, cmmdWorkIntakeRouteLayer, cmmdWsTokenRouteLayer, cmmdGetProjectCommentsRouteLayer, cmmdAddProjectCommentRouteLayer, cmmdUpdateProjectRouteLayer, cmmdUploadTaskAttachmentRouteLayer, cmmdUpdateTaskCommentRouteLayer, cmmdListWorkspaceMembersRouteLayer, cmmdAddProjectMemberRouteLayer, cmmdUpdateProjectAgentMemberAvatarRouteLayer, runtimeReplicationStatusRouteLayer, cmmdRefreshProviderUsageRouteLayer, cmmdForgeCloudProjectsListRouteLayer, cmmdForgeCloudProjectsEventsRouteLayer, cmmdForgeEnvironmentsEventsRouteLayer, cmmdForgeRuntimesEnsureRouteLayer, cmmdForgeRuntimesConnectRouteLayer, ownerRuntimeCodexReadinessRouteLayer, cmmdRegisterMobilePushDeviceRouteLayer, cmmdDeleteMobilePushDeviceRouteLayer, cmmdForgeRuntimesStatusRouteLayer, cmmdForgeRuntimesStartRouteLayer, cmmdForgeRuntimesStopRouteLayer, cmmdForgeRuntimesRecycleRouteLayer, cmmdForgeRuntimesUpdateCommitRouteLayer, cmmdForgeRuntimesDestroyRouteLayer, mobileProviderCatalogRouteLayer, attachmentsRouteLayer, orchestrationDispatchRouteLayer, orchestrationCmmdWorkRunEventRouteLayer, orchestrationAutomationStartThreadRouteLayer, orchestrationAutomationRebindRouteLayer, orchestrationAutomationTerminalReconcileRouteLayer, mobileGitRunStackedActionRouteLayer, pullRequestDiffRouteLayer, orchestrationSnapshotRouteLayer, orchestrationThreadSnapshotRouteLayer, 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, runtimeFilesystemHealthRouteLayer, claudeNativeGenerationProofRouteLayer, claudeUsageRouteLayer, codexRuntimeProviderReadinessRouteLayer, runtimeDiagnosticsRouteLayer, cloudFoldersRouteLayer, cloudProjectCreateRouteLayer, gitUrlCloneRouteLayer, websocketRpcRouteLayer).pipe(require_Schema$1.provide$1(browserApiCorsLayer));
324851
325161
  const makeServerLayer = require_Schema$1.unwrap(require_Schema$1.gen(function* () {
324852
325162
  const config = yield* ServerConfig;
324853
325163
  fixPath({ preferProcessPath: config.forgeCmmdRuntimeMode === true });