@cmmd-center/forge 0.13.0 → 0.13.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (20) hide show
  1. package/dist/bin.cjs +409 -134
  2. package/dist/bin.mjs +433 -158
  3. package/dist/client/assets/{CanvasPanel-BUdwnabz.js → CanvasPanel-BrVen-8G.js} +2 -2
  4. package/dist/client/assets/{CompositeItem-BxaZQRyb.js → CompositeItem-BNZfMUvm.js} +2 -2
  5. package/dist/client/assets/{DiffPanel-BOLibNHF.js → DiffPanel-Bh9UFe_U.js} +2 -2
  6. package/dist/client/assets/{DiffPanel.logic-BrRjlJeM.js → DiffPanel.logic-A3r3u_Vr.js} +2 -2
  7. package/dist/client/assets/{DiffPanelShell-CgycIPfE.js → DiffPanelShell-B30xoHOs.js} +3 -3
  8. package/dist/client/assets/{DiffWorkerPoolProvider-jWJpEXVo.js → DiffWorkerPoolProvider-CYkhfTpq.js} +2 -2
  9. package/dist/client/assets/{PullRequestCodePanel-BW7XdaG8.js → PullRequestCodePanel-T32DALQE.js} +2 -2
  10. package/dist/client/assets/{Virtualizer-qjNwH1hl.js → Virtualizer-DbDh3RHG.js} +2 -2
  11. package/dist/client/assets/{canvasStateStore-DDwjZ3AG.js → canvasStateStore-DN5mPB5B.js} +2 -2
  12. package/dist/client/assets/{cmmdAuthRedirect-CPfIOB5Y.js → cmmdAuthRedirect-sqR8W6vY.js} +2 -2
  13. package/dist/client/assets/{index-9clxg-cN.js → index-FpNJGy15.js} +59 -59
  14. package/dist/client/assets/{src-dZ5rHSKC.js → src-CFqnisEM.js} +2 -2
  15. package/dist/client/assets/{toggle-Bn-2EZmB.js → toggle-CLUqZXdO.js} +2 -2
  16. package/dist/client/assets/{useTriggerFocusGuards-DRINKzwL.js → useTriggerFocusGuards-CaUimC-O.js} +2 -2
  17. package/dist/client/index.html +10 -10
  18. package/dist/forge-build.json +1 -1
  19. package/dist/{open-D8mGyWmt.mjs → open-FIgTDosf.mjs} +3 -3
  20. package/package.json +1 -1
package/dist/bin.cjs CHANGED
@@ -16544,7 +16544,7 @@ function makeNetServiceShape(createServer = node_net.createServer) {
16544
16544
  }
16545
16545
  //#endregion
16546
16546
  //#region ../../packages/shared/src/releaseInfo.generated.ts
16547
- const FORGE_RELEASE_VERSION = "0.13.0";
16547
+ const FORGE_RELEASE_VERSION = "0.13.2";
16548
16548
  //#endregion
16549
16549
  //#region ../../packages/shared/src/hostProcess.ts
16550
16550
  /**
@@ -22647,6 +22647,27 @@ const ProviderUnavailableDetail = require_Schema$1.Literals([
22647
22647
  "delivery-pending",
22648
22648
  "reconnect-required"
22649
22649
  ]);
22650
+ /**
22651
+ * Whether the provider CLI honours the credential-directory variable, as this
22652
+ * Environment's probe found. `inconclusive` is a probe that ran and could not
22653
+ * tell. It is not `unsupported`, and it is never reported as `supported`. The
22654
+ * members are CMMD's `forgeRuntimeInventoryCredentialDirectoryAnswers`.
22655
+ */
22656
+ const ProviderCredentialDirectoryAnswer = require_Schema$1.Literals([
22657
+ "supported",
22658
+ "unsupported",
22659
+ "inconclusive"
22660
+ ]);
22661
+ /**
22662
+ * Which Credential Store the provider CLI uses on this Environment: its file,
22663
+ * the operating system's store, or `unknown` when it cannot be read the way
22664
+ * the CLI reads it. The members are CMMD's `forgeRuntimeInventoryCredentialStores`.
22665
+ */
22666
+ const ProviderCredentialStore = require_Schema$1.Literals([
22667
+ "file",
22668
+ "os",
22669
+ "unknown"
22670
+ ]);
22650
22671
  const ServerProviderModel = require_Schema$1.Struct({
22651
22672
  slug: TrimmedNonEmptyString,
22652
22673
  name: TrimmedNonEmptyString,
@@ -22683,6 +22704,8 @@ const ServerProvider = require_Schema$1.Struct({
22683
22704
  availability: require_Schema$1.optional(ProviderAvailability),
22684
22705
  unavailableReason: require_Schema$1.optional(ProviderUnavailableReason),
22685
22706
  unavailableDetail: require_Schema$1.optional(ProviderUnavailableDetail),
22707
+ credentialDirectory: require_Schema$1.optional(ProviderCredentialDirectoryAnswer),
22708
+ credentialStore: require_Schema$1.optional(ProviderCredentialStore),
22686
22709
  slashCommands: require_Schema$1.ArraySchema(ServerProviderSlashCommand).pipe(require_Schema$1.withDecodingDefault(require_Schema$1.succeed([]))),
22687
22710
  skills: require_Schema$1.ArraySchema(ServerProviderSkill).pipe(require_Schema$1.withDecodingDefault(require_Schema$1.succeed([])))
22688
22711
  });
@@ -26721,12 +26744,12 @@ function encodeCmmdRuntimeThreadWorkspaceMetadata(workspace) {
26721
26744
  }
26722
26745
  //#endregion
26723
26746
  //#region ../../packages/contracts/src/cmmdRuntimeToolActivity.ts
26724
- function isRecord$22(value) {
26747
+ function isRecord$23(value) {
26725
26748
  return value !== null && typeof value === "object" && !Array.isArray(value);
26726
26749
  }
26727
26750
  function encodeCmmdRuntimeToolActivityPayload(kind, payload) {
26728
26751
  return {
26729
- ...isRecord$22(payload) ? payload : { sourcePayload: payload },
26752
+ ...isRecord$23(payload) ? payload : { sourcePayload: payload },
26730
26753
  forgeToolActivity: {
26731
26754
  schemaVersion: 1,
26732
26755
  source: "native",
@@ -30726,13 +30749,13 @@ async function completePendingDesktopRelayIdentityRotation(input) {
30726
30749
  }
30727
30750
  //#endregion
30728
30751
  //#region ../../packages/relay-host/src/internal/desktopRelayJws.ts
30729
- function isRecord$21(value) {
30752
+ function isRecord$22(value) {
30730
30753
  return typeof value === "object" && value !== null && !Array.isArray(value);
30731
30754
  }
30732
30755
  function decodeBase64UrlJson$1(value) {
30733
30756
  try {
30734
30757
  const decoded = JSON.parse(Buffer.from(value, "base64url").toString("utf8"));
30735
- return isRecord$21(decoded) ? decoded : null;
30758
+ return isRecord$22(decoded) ? decoded : null;
30736
30759
  } catch {
30737
30760
  return null;
30738
30761
  }
@@ -30886,11 +30909,11 @@ var DesktopRelayControlPlaneError = class extends Error {
30886
30909
  this.name = "DesktopRelayControlPlaneError";
30887
30910
  }
30888
30911
  };
30889
- function isRecord$20(value) {
30912
+ function isRecord$21(value) {
30890
30913
  return typeof value === "object" && value !== null && !Array.isArray(value);
30891
30914
  }
30892
30915
  function parseErrorPayload(value) {
30893
- return isRecord$20(value) ? value : {};
30916
+ return isRecord$21(value) ? value : {};
30894
30917
  }
30895
30918
  function messageFromErrorPayload(payload, fallback) {
30896
30919
  return typeof payload.error === "string" && payload.error.trim().length > 0 ? payload.error.trim() : fallback;
@@ -30988,7 +31011,7 @@ async function postControlPlane(input) {
30988
31011
  const errorPayload = parseErrorPayload(payload);
30989
31012
  throw new DesktopRelayControlPlaneError(typeof errorPayload.code === "string" && errorPayload.code.trim().length > 0 ? errorPayload.code.trim() : `CMMD_HTTP_${response.status}`, messageFromErrorPayload(errorPayload, `CMMD relay request failed (${response.status}).`), response.status === 408 || response.status === 429 || response.status >= 500);
30990
31013
  }
30991
- if (!isRecord$20(payload) || !("data" in payload)) throw new DesktopRelayControlPlaneError("CONTROL_PLANE_INVALID_RESPONSE", "CMMD returned an invalid Forge relay response.", false);
31014
+ if (!isRecord$21(payload) || !("data" in payload)) throw new DesktopRelayControlPlaneError("CONTROL_PLANE_INVALID_RESPONSE", "CMMD returned an invalid Forge relay response.", false);
30992
31015
  return payload.data;
30993
31016
  }
30994
31017
  function resolveRegisteredDevice(input) {
@@ -65841,7 +65864,7 @@ function normalizeNumberish(value) {
65841
65864
  }
65842
65865
  //#endregion
65843
65866
  //#region package.json
65844
- var version$1 = "0.13.0";
65867
+ var version$1 = "0.13.2";
65845
65868
  //#endregion
65846
65869
  //#region src/sentry.ts
65847
65870
  const SERVER_APP_NAME = "forge-server";
@@ -71405,12 +71428,12 @@ function resolveDesktopRelayControlPlaneTarget(path, configuredRuntimeId) {
71405
71428
  code: "RELAY_OPERATION_DENIED"
71406
71429
  };
71407
71430
  }
71408
- function isRecord$19(value) {
71431
+ function isRecord$20(value) {
71409
71432
  return typeof value === "object" && value !== null && !Array.isArray(value);
71410
71433
  }
71411
71434
  function relayControlPlaneBodyMatchesRuntime(path, body, configuredRuntimeId) {
71412
71435
  if (path !== "/api/forge/context/devices/register") return true;
71413
- if (!isRecord$19(body) || !isRecord$19(body.runtime)) return false;
71436
+ if (!isRecord$20(body) || !isRecord$20(body.runtime)) return false;
71414
71437
  return body.runtime.runtimeId === configuredRuntimeId;
71415
71438
  }
71416
71439
  /** Matches the client id `connect login` used, so CMMD accepts the refresh. */
@@ -71425,7 +71448,7 @@ function forbiddenResponse() {
71425
71448
  return errorResponse(403, "RELAY_BRIDGE_FORBIDDEN", "Desktop relay bridge access denied.");
71426
71449
  }
71427
71450
  function relayProxyErrorResponse(error) {
71428
- if (error instanceof CmmdProxyRequestError && isRecord$19(error.body)) {
71451
+ if (error instanceof CmmdProxyRequestError && isRecord$20(error.body)) {
71429
71452
  const code = typeof error.body.code === "string" ? error.body.code : error.code;
71430
71453
  const message = typeof error.body.error === "string" ? error.body.error : error.detail;
71431
71454
  return errorResponse(error.status >= 500 ? 502 : error.status, code, message ?? "CMMD relay coordination failed.");
@@ -93801,7 +93824,7 @@ const REPLICA_THREAD_STATUSES = [
93801
93824
  ];
93802
93825
  //#endregion
93803
93826
  //#region src/runtimeReplication/replicaDecodeModel.ts
93804
- function isRecord$18(value) {
93827
+ function isRecord$19(value) {
93805
93828
  return typeof value === "object" && value !== null && !Array.isArray(value);
93806
93829
  }
93807
93830
  function isNonBlankString(value) {
@@ -93821,7 +93844,7 @@ function nullableInteger(value) {
93821
93844
  return value === null || typeof value === "number" && Number.isSafeInteger(value);
93822
93845
  }
93823
93846
  function unwrapEnvelope(payload, expectedDomain) {
93824
- if (!isRecord$18(payload) || !isRecord$18(payload.meta) || !isRecord$18(payload.data)) return null;
93847
+ if (!isRecord$19(payload) || !isRecord$19(payload.meta) || !isRecord$19(payload.data)) return null;
93825
93848
  const { domain, timestamp, version } = payload.meta;
93826
93849
  if (!isNonBlankString(domain) || expectedDomain !== void 0 && domain !== expectedDomain || version !== "1.0" || !isIsoDateTime(timestamp)) return null;
93827
93850
  return payload.data;
@@ -93834,12 +93857,12 @@ function hasValidRuntimeIdentity(value) {
93834
93857
  ].includes(String(value.runtimeKind)) && typeof value.displayName === "string" && typeof value.status === "string";
93835
93858
  }
93836
93859
  function decodeRuntime$1(value) {
93837
- if (!isRecord$18(value) || !hasValidRuntimeIdentity(value)) return null;
93838
- if (!nullableString(value.endpointUrl) || value.endpointUrl !== null && !URL.canParse(value.endpointUrl) || !nullableInteger(value.deviceId) || !nullableString(value.workspaceRoot) || !nullableString(value.githubRepoFullName) || !(value.lastSeenAt === null || isIsoDateTime(value.lastSeenAt)) || !(value.metadata === null || isRecord$18(value.metadata))) return null;
93860
+ if (!isRecord$19(value) || !hasValidRuntimeIdentity(value)) return null;
93861
+ if (!nullableString(value.endpointUrl) || value.endpointUrl !== null && !URL.canParse(value.endpointUrl) || !nullableInteger(value.deviceId) || !nullableString(value.workspaceRoot) || !nullableString(value.githubRepoFullName) || !(value.lastSeenAt === null || isIsoDateTime(value.lastSeenAt)) || !(value.metadata === null || isRecord$19(value.metadata))) return null;
93839
93862
  return value;
93840
93863
  }
93841
93864
  function decodeProject(value) {
93842
- if (!isRecord$18(value) || !isNonBlankString(value.projectId) || typeof value.title !== "string" || !nullableString(value.githubRepoFullName) || !nullableString(value.branch)) return null;
93865
+ if (!isRecord$19(value) || !isNonBlankString(value.projectId) || typeof value.title !== "string" || !nullableString(value.githubRepoFullName) || !nullableString(value.branch)) return null;
93843
93866
  return {
93844
93867
  projectId: value.projectId,
93845
93868
  title: value.title,
@@ -93848,11 +93871,11 @@ function decodeProject(value) {
93848
93871
  };
93849
93872
  }
93850
93873
  function decodeThread$1(value) {
93851
- if (!isRecord$18(value) || !isNonBlankString(value.threadId) || typeof value.title !== "string" || !isReplicaThreadStatus(value.status) || !nullableString(value.model) || !nullableString(value.branch) || !(value.lastActivityAt === null || isIsoDateTime(value.lastActivityAt))) return null;
93874
+ if (!isRecord$19(value) || !isNonBlankString(value.threadId) || typeof value.title !== "string" || !isReplicaThreadStatus(value.status) || !nullableString(value.model) || !nullableString(value.branch) || !(value.lastActivityAt === null || isIsoDateTime(value.lastActivityAt))) return null;
93852
93875
  return value;
93853
93876
  }
93854
93877
  function decodeSummary(value) {
93855
- if (!isRecord$18(value) || !nullableString(value.conversationId)) return null;
93878
+ if (!isRecord$19(value) || !nullableString(value.conversationId)) return null;
93856
93879
  const project = decodeProject(value.project);
93857
93880
  const thread = decodeThread$1(value.thread);
93858
93881
  return project === null || thread === null ? null : {
@@ -93963,7 +93986,7 @@ function isNonNegativeInt(value) {
93963
93986
  /** `usage` is null for an Unreported turn, otherwise exactly the five buckets. */
93964
93987
  function isValidTurnUsageTokens(value) {
93965
93988
  if (value === null) return true;
93966
- if (!isRecord$18(value)) return false;
93989
+ if (!isRecord$19(value)) return false;
93967
93990
  return turnUsageTokenKeys.every((key) => isNonNegativeInt(value[key])) && Object.keys(value).every((key) => turnUsageTokenKeys.includes(key));
93968
93991
  }
93969
93992
  /** The row itself: no text, no status, and the turn it belongs to. */
@@ -93972,7 +93995,7 @@ function hasValidTurnUsageEnvelope(value) {
93972
93995
  }
93973
93996
  /** What the row records: who ran it, what it spent, and what it says of itself. */
93974
93997
  function hasValidTurnUsageRecord(payload) {
93975
- return isRecord$18(payload) && isNonBlankString(payload.provider) && isNonBlankString(payload.model) && "usage" in payload && isValidTurnUsageTokens(payload.usage) && hasValidTurnUsageAttribution(payload);
93998
+ return isRecord$19(payload) && isNonBlankString(payload.provider) && isNonBlankString(payload.model) && "usage" in payload && isValidTurnUsageTokens(payload.usage) && hasValidTurnUsageAttribution(payload);
93976
93999
  }
93977
94000
  /** A turn_usage row: no text, no status, and its record in `payload`. */
93978
94001
  function hasValidTurnUsagePayload(value) {
@@ -94009,7 +94032,7 @@ function hasValidEventPayload(value) {
94009
94032
  return isNonBlankString(value.text) && value.status === null;
94010
94033
  }
94011
94034
  function decodeEvent$1(value) {
94012
- if (!isRecord$18(value) || !hasValidEventFields(value) || !hasValidEventPayload(value)) return null;
94035
+ if (!isRecord$19(value) || !hasValidEventFields(value) || !hasValidEventPayload(value)) return null;
94013
94036
  return value;
94014
94037
  }
94015
94038
  function decodeEvents(data) {
@@ -94030,11 +94053,11 @@ function decodeReplicaThreadDetail(payload) {
94030
94053
  const thread = decodeThread$1(data.thread);
94031
94054
  const reachability = decodeReachability(data.reachability);
94032
94055
  const events = decodeEvents(data);
94033
- if (runtime === null || project === null || thread === null || reachability === null || events === null || !isRecord$18(data.execution) || typeof data.execution.available !== "boolean" || ![
94056
+ if (runtime === null || project === null || thread === null || reachability === null || events === null || !isRecord$19(data.execution) || typeof data.execution.available !== "boolean" || ![
94034
94057
  null,
94035
94058
  "runtime_offline",
94036
94059
  "runtime_unavailable"
94037
- ].includes(data.execution.reason) || (data.execution.available ? data.execution.reason !== null : data.execution.reason === null) || !isRecord$18(data.replication) || data.replication.protocolVersion !== 2 || !isNonBlankString(data.replication.generationId) || !Number.isSafeInteger(data.replication.acknowledgedSequence) || Number(data.replication.acknowledgedSequence) < 0 || !isNonBlankString(data.replication.headHash)) return null;
94060
+ ].includes(data.execution.reason) || (data.execution.available ? data.execution.reason !== null : data.execution.reason === null) || !isRecord$19(data.replication) || data.replication.protocolVersion !== 2 || !isNonBlankString(data.replication.generationId) || !Number.isSafeInteger(data.replication.acknowledgedSequence) || Number(data.replication.acknowledgedSequence) < 0 || !isNonBlankString(data.replication.headHash)) return null;
94038
94061
  return {
94039
94062
  conversationId: data.conversationId,
94040
94063
  runtime,
@@ -94955,7 +94978,7 @@ function resolveRuntimeReplicationRuntimeId(config) {
94955
94978
  }
94956
94979
  //#endregion
94957
94980
  //#region src/usage/providerTokenBuckets.ts
94958
- function isRecord$17(value) {
94981
+ function isRecord$18(value) {
94959
94982
  return typeof value === "object" && value !== null && !Array.isArray(value);
94960
94983
  }
94961
94984
  function count(record, ...keys) {
@@ -94976,7 +94999,7 @@ function reportedOrNull(tokens) {
94976
94999
  * the app server sends camelCase.
94977
95000
  */
94978
95001
  function codexTokenBuckets(value) {
94979
- if (!isRecord$17(value)) return null;
95002
+ if (!isRecord$18(value)) return null;
94980
95003
  const inputTokens = count(value, "input_tokens", "inputTokens");
94981
95004
  const cachedInputTokens = count(value, "cached_input_tokens", "cachedInputTokens");
94982
95005
  const cacheCreationTokens = count(value, "cache_write_input_tokens", "cacheWriteInputTokens");
@@ -94995,7 +95018,7 @@ function codexTokenBuckets(value) {
94995
95018
  * tokens into output and does not break them out, so reasoning stays zero.
94996
95019
  */
94997
95020
  function claudeTokenBuckets(value) {
94998
- if (!isRecord$17(value)) return null;
95021
+ if (!isRecord$18(value)) return null;
94999
95022
  return reportedOrNull({
95000
95023
  uncachedInputTokens: count(value, "input_tokens", "inputTokens"),
95001
95024
  cachedInputTokens: count(value, "cache_read_input_tokens", "cacheReadInputTokens"),
@@ -95889,6 +95912,20 @@ function publishedAvailability(provider) {
95889
95912
  ...detail === void 0 ? {} : { unavailableDetail: detail }
95890
95913
  };
95891
95914
  }
95915
+ /**
95916
+ * What the Claude CLI said about its credentials, beside the version it said
95917
+ * it for. CMMD keeps each Claude version's answers, so these go on the Claude
95918
+ * entry only. Each is copied only when the snapshot has an answer: absent means
95919
+ * the runtime has not answered yet, and inventing a value would hide that.
95920
+ */
95921
+ function claudeCredentialAnswersToPublish(provider) {
95922
+ if (provider.provider !== "claudeAgent") return {};
95923
+ const { credentialDirectory, credentialStore } = provider;
95924
+ return {
95925
+ ...credentialDirectory === void 0 ? {} : { credentialDirectory },
95926
+ ...credentialStore === void 0 ? {} : { credentialStore }
95927
+ };
95928
+ }
95892
95929
  function serializeProvider(provider) {
95893
95930
  const models = [];
95894
95931
  for (const model of provider.models) {
@@ -95901,7 +95938,8 @@ function serializeProvider(provider) {
95901
95938
  models,
95902
95939
  ...publishedAvailability(provider),
95903
95940
  version: cappedText(provider.version, VERSION_MAX_LENGTH),
95904
- binaryPath: cappedText(provider.auth.provenance?.binaryPath, BINARY_PATH_MAX_LENGTH)
95941
+ binaryPath: cappedText(provider.auth.provenance?.binaryPath, BINARY_PATH_MAX_LENGTH),
95942
+ ...claudeCredentialAnswersToPublish(provider)
95905
95943
  };
95906
95944
  }
95907
95945
  function serializeProviderCatalog(providers) {
@@ -95922,7 +95960,7 @@ const replicaTurnStatuses = new Set([
95922
95960
  "cancelled",
95923
95961
  "interrupted"
95924
95962
  ]);
95925
- function isRecord$16(value) {
95963
+ function isRecord$17(value) {
95926
95964
  return typeof value === "object" && value !== null && !Array.isArray(value);
95927
95965
  }
95928
95966
  function replicaSourceSequence(value) {
@@ -95935,7 +95973,7 @@ function replicaSourceTurn(sourceTurnId) {
95935
95973
  return typeof sourceTurnId === "string" && sourceTurnId.length > 0 ? { turnId: sourceTurnId } : {};
95936
95974
  }
95937
95975
  function replicaActivitySource(activity) {
95938
- if (!activity.kind.startsWith("replica.") || !isRecord$16(activity.payload)) return null;
95976
+ if (!activity.kind.startsWith("replica.") || !isRecord$17(activity.payload)) return null;
95939
95977
  const sourceSequence = replicaSourceSequence(activity.sequence);
95940
95978
  const eventId = replicaSourceEventId(activity.payload.sourceEventId);
95941
95979
  if (sourceSequence === null || eventId === null) return null;
@@ -95948,7 +95986,7 @@ function replicaActivitySource(activity) {
95948
95986
  }
95949
95987
  function replicaSummaryEvent(activity, source) {
95950
95988
  if (activity.kind !== "replica.activity_summary" && activity.kind !== "replica.error_summary") return null;
95951
- const sourceText = isRecord$16(activity.payload) ? activity.payload.text : null;
95989
+ const sourceText = isRecord$17(activity.payload) ? activity.payload.text : null;
95952
95990
  return {
95953
95991
  sourceSequence: source.sourceSequence,
95954
95992
  event: {
@@ -95961,7 +95999,7 @@ function replicaSummaryEvent(activity, source) {
95961
95999
  };
95962
96000
  }
95963
96001
  function replicaTurnEvent(activity, source) {
95964
- const status = isRecord$16(activity.payload) ? activity.payload.status : null;
96002
+ const status = isRecord$17(activity.payload) ? activity.payload.status : null;
95965
96003
  if (activity.kind !== "replica.turn_status" || !replicaTurnStatuses.has(status)) return null;
95966
96004
  return {
95967
96005
  sourceSequence: source.sourceSequence,
@@ -95975,7 +96013,7 @@ function replicaTurnEvent(activity, source) {
95975
96013
  };
95976
96014
  }
95977
96015
  function replicaToolCallEvent(activity, source) {
95978
- if (activity.kind !== "replica.tool_call" || !isRecord$16(activity.payload)) return null;
96016
+ if (activity.kind !== "replica.tool_call" || !isRecord$17(activity.payload)) return null;
95979
96017
  const sourceText = activity.payload.text;
95980
96018
  const status = activity.payload.status;
95981
96019
  if (typeof sourceText !== "string" || typeof status !== "string") return null;
@@ -95993,9 +96031,9 @@ function replicaToolCallEvent(activity, source) {
95993
96031
  };
95994
96032
  }
95995
96033
  function replicaTurnUsageEvent(activity, source) {
95996
- if (activity.kind !== "replica.turn_usage" || !isRecord$16(activity.payload)) return null;
96034
+ if (activity.kind !== "replica.turn_usage" || !isRecord$17(activity.payload)) return null;
95997
96035
  const usage = activity.payload.payload;
95998
- if (!("turnId" in source.turn) || !isRecord$16(usage)) return null;
96036
+ if (!("turnId" in source.turn) || !isRecord$17(usage)) return null;
95999
96037
  const provider = usage.provider;
96000
96038
  const model = usage.model;
96001
96039
  if (typeof provider !== "string" || typeof model !== "string" || !("usage" in usage)) return null;
@@ -96808,9 +96846,9 @@ function isUsageSessionLookupRuntimeNotFound(error) {
96808
96846
  async function isRuntimeNotFoundResponse(response) {
96809
96847
  if (response.status !== 404) return false;
96810
96848
  const body = await response.json().catch(() => null);
96811
- return isRecord$15(body) && body["code"] === "RUNTIME_NOT_FOUND";
96849
+ return isRecord$16(body) && body["code"] === "RUNTIME_NOT_FOUND";
96812
96850
  }
96813
- function isRecord$15(value) {
96851
+ function isRecord$16(value) {
96814
96852
  return typeof value === "object" && value !== null;
96815
96853
  }
96816
96854
  /**
@@ -96822,11 +96860,11 @@ function isRecord$15(value) {
96822
96860
  * no count on the page saying so.
96823
96861
  */
96824
96862
  function decodeHeldSessions(body) {
96825
- const held = isRecord$15(body) && isRecord$15(body["data"]) ? body["data"]["held"] : void 0;
96863
+ const held = isRecord$16(body) && isRecord$16(body["data"]) ? body["data"]["held"] : void 0;
96826
96864
  if (!Array.isArray(held)) throw new Error("The usage session lookup returned an invalid body.");
96827
96865
  return held.map((row) => {
96828
- const providerSessionId = isRecord$15(row) ? row["providerSessionId"] : void 0;
96829
- const runtimeId = isRecord$15(row) ? row["runtimeId"] : void 0;
96866
+ const providerSessionId = isRecord$16(row) ? row["providerSessionId"] : void 0;
96867
+ const runtimeId = isRecord$16(row) ? row["runtimeId"] : void 0;
96830
96868
  if (typeof providerSessionId !== "string" || typeof runtimeId !== "string") throw new Error("The usage session lookup returned an invalid held row.");
96831
96869
  return {
96832
96870
  providerSessionId,
@@ -99622,7 +99660,7 @@ function emptyConfig(source, path) {
99622
99660
  issues: []
99623
99661
  };
99624
99662
  }
99625
- function isRecord$14(value) {
99663
+ function isRecord$15(value) {
99626
99664
  return typeof value === "object" && value !== null && !Array.isArray(value);
99627
99665
  }
99628
99666
  function stringArray(value) {
@@ -99650,7 +99688,7 @@ function terminalsFromValue(value) {
99650
99688
  name: `Terminal ${index + 1}`,
99651
99689
  command: terminal.trim()
99652
99690
  }];
99653
- if (!isRecord$14(terminal)) return [];
99691
+ if (!isRecord$15(terminal)) return [];
99654
99692
  const command = typeof terminal.command === "string" ? terminal.command.trim() : "";
99655
99693
  if (!command) return [];
99656
99694
  return [{
@@ -99689,7 +99727,7 @@ function readConfigFile(source, path) {
99689
99727
  }]
99690
99728
  };
99691
99729
  }
99692
- if (!isRecord$14(parsed)) return {
99730
+ if (!isRecord$15(parsed)) return {
99693
99731
  ...emptyConfig(source, path),
99694
99732
  issues: [{
99695
99733
  severity: "blocked",
@@ -100832,7 +100870,7 @@ const CLAUDE_IDENTITY_KEYS = new Set([
100832
100870
  "credentialGenerationId"
100833
100871
  ]);
100834
100872
  const CLAUDE_IDENTITY_OPTIONAL_KEYS = new Set(["providerAccountIdentity"]);
100835
- function isRecord$13(value) {
100873
+ function isRecord$14(value) {
100836
100874
  return typeof value === "object" && value !== null && !Array.isArray(value);
100837
100875
  }
100838
100876
  function isStrictRfc3339DateTime(value) {
@@ -100861,7 +100899,7 @@ function hasAllowedKeys(value, required, optional) {
100861
100899
  return keys.every((key) => required.has(key) || optional.has(key)) && [...required].every((key) => keys.includes(key));
100862
100900
  }
100863
100901
  function parseDeliveryIdentity(value, provider) {
100864
- if (!isRecord$13(value)) return null;
100902
+ if (!isRecord$14(value)) return null;
100865
100903
  if (provider === "openai") return parseCodexDeliveryIdentity(value);
100866
100904
  if (provider === "anthropic") return parseClaudeDeliveryIdentity(value);
100867
100905
  return null;
@@ -100896,7 +100934,7 @@ function parseClaudeDeliveryIdentity(value) {
100896
100934
  };
100897
100935
  }
100898
100936
  function parseProviderRuntimeDeliveryReceipt(value, expected) {
100899
- if (!isRecord$13(value) || !hasExactKeys$2(value, RECEIPT_KEYS)) return null;
100937
+ if (!isRecord$14(value) || !hasExactKeys$2(value, RECEIPT_KEYS)) return null;
100900
100938
  const identity = parseDeliveryIdentity(value.identity, expected.provider);
100901
100939
  if (!identity || typeof value.receiptId !== "string" || value.receiptId.length === 0 || value.receiptId.length > 256 || value.runtimeId !== expected.runtimeId || value.machineId !== expected.machineId || value.credentialEpoch !== expected.credentialEpoch || !Number.isInteger(value.credentialEpoch) || value.credentialEpoch < 0 || !isStrictRfc3339DateTime(value.issuedAt) || value.expiresAt !== expected.expiresAt || value.expiresAt !== null && !isStrictRfc3339DateTime(value.expiresAt)) return null;
100902
100940
  return {
@@ -100918,8 +100956,8 @@ function providerDeliveryBindingFromReceipt(receipt) {
100918
100956
  };
100919
100957
  }
100920
100958
  function readProviderDeliveryBinding(value) {
100921
- if (!isRecord$13(value) || !hasExactKeys$2(value, BINDING_KEYS)) return null;
100922
- const identityProvider = isRecord$13(value.identity) ? value.identity.provider : void 0;
100959
+ if (!isRecord$14(value) || !hasExactKeys$2(value, BINDING_KEYS)) return null;
100960
+ const identityProvider = isRecord$14(value.identity) ? value.identity.provider : void 0;
100923
100961
  const tokenProvider = identityProvider === "codex" ? "openai" : identityProvider === "claude" ? "anthropic" : null;
100924
100962
  if (!tokenProvider) return null;
100925
100963
  const identity = parseDeliveryIdentity(value.identity, tokenProvider);
@@ -148203,12 +148241,12 @@ function decodeProviderKind(providerName, operation) {
148203
148241
  detail: `Unknown persisted provider '${providerName}'.`
148204
148242
  }));
148205
148243
  }
148206
- function isRecord$12(value) {
148244
+ function isRecord$13(value) {
148207
148245
  return value !== null && typeof value === "object" && !Array.isArray(value);
148208
148246
  }
148209
148247
  function mergeRuntimePayload(existing, next) {
148210
148248
  if (next === void 0) return existing ?? null;
148211
- if (isRecord$12(existing) && isRecord$12(next)) return {
148249
+ if (isRecord$13(existing) && isRecord$13(next)) return {
148212
148250
  ...existing,
148213
148251
  ...next
148214
148252
  };
@@ -150180,7 +150218,7 @@ const PAGINATION_KEYS = new Set([
150180
150218
  "total",
150181
150219
  "hasMore"
150182
150220
  ]);
150183
- function isRecord$11(value) {
150221
+ function isRecord$12(value) {
150184
150222
  return typeof value === "object" && value !== null && !Array.isArray(value);
150185
150223
  }
150186
150224
  function hasOnlyKeys(value, allowed) {
@@ -150193,17 +150231,17 @@ function isRfc3339(value) {
150193
150231
  return typeof value === "string" && RFC3339.test(value) && Number.isFinite(Date.parse(value));
150194
150232
  }
150195
150233
  function isEnvelopeMeta(value) {
150196
- if (!isRecord$11(value) || !hasExactKeys$1(value, META_KEYS)) return false;
150234
+ if (!isRecord$12(value) || !hasExactKeys$1(value, META_KEYS)) return false;
150197
150235
  return typeof value.domain === "string" && value.domain.length > 0 && isRfc3339(value.timestamp) && typeof value.version === "string" && value.version.length > 0;
150198
150236
  }
150199
150237
  function isPagination(value) {
150200
- if (!isRecord$11(value) || !hasExactKeys$1(value, PAGINATION_KEYS)) return false;
150238
+ if (!isRecord$12(value) || !hasExactKeys$1(value, PAGINATION_KEYS)) return false;
150201
150239
  return Number.isInteger(value.page) && value.page >= 0 && Number.isInteger(value.limit) && value.limit >= 0 && Number.isInteger(value.total) && value.total >= 0 && typeof value.hasMore === "boolean";
150202
150240
  }
150203
150241
  function readLocalProviderAccountId(authJson) {
150204
150242
  try {
150205
150243
  const value = JSON.parse(authJson);
150206
- if (!isRecord$11(value) || value.auth_mode !== "chatgpt" || !isRecord$11(value.tokens)) return null;
150244
+ if (!isRecord$12(value) || value.auth_mode !== "chatgpt" || !isRecord$12(value.tokens)) return null;
150207
150245
  const providerAccountId = value.tokens.account_id;
150208
150246
  if (typeof providerAccountId !== "string") return null;
150209
150247
  const normalized = providerAccountId.trim();
@@ -150216,13 +150254,13 @@ function resolveLocalAuthJsonPath(homePath) {
150216
150254
  return (0, node_path.join)(homePath?.trim() || process.env.CODEX_HOME?.trim() || (0, node_path.join)((0, node_os.homedir)(), ".codex"), "auth.json");
150217
150255
  }
150218
150256
  function parseCodexAccountIdentityEnvelope(value) {
150219
- if (!isRecord$11(value) || !hasOnlyKeys(value, ENVELOPE_KEYS)) return null;
150257
+ if (!isRecord$12(value) || !hasOnlyKeys(value, ENVELOPE_KEYS)) return null;
150220
150258
  if (!("data" in value) || !("meta" in value) || !isEnvelopeMeta(value.meta)) return null;
150221
150259
  if (value.pagination !== void 0 && !isPagination(value.pagination)) return null;
150222
150260
  return readCodexAccountIdentity(value.data);
150223
150261
  }
150224
150262
  function readCodexAccountIdentity(value) {
150225
- if (!isRecord$11(value) || !hasExactKeys$1(value, IDENTITY_KEYS)) return null;
150263
+ if (!isRecord$12(value) || !hasExactKeys$1(value, IDENTITY_KEYS)) return null;
150226
150264
  if (value.kind !== "provider_account" || value.provider !== "codex" || typeof value.providerAccountIdentity !== "string" || !PROVIDER_ACCOUNT_IDENTITY$1.test(value.providerAccountIdentity)) return null;
150227
150265
  return {
150228
150266
  kind: "provider_account",
@@ -211407,10 +211445,16 @@ function claudeSubscriptionChildEnv(processEnv, credentialDirectory) {
211407
211445
  * environment with `claudeSubscriptionChildEnv`, the same builder as the turn's
211408
211446
  * personal-subscription branch.
211409
211447
  *
211410
- * `claude auth status` is a pure read. It sends no prompt and leaves
211411
- * `.credentials.json` byte-identical, so probing spends no subscription usage.
211448
+ * `claude auth status` sends no prompt and leaves `.credentials.json`
211449
+ * byte-identical, so probing spends no subscription usage. For Team and
211450
+ * Enterprise accounts the CLI's `auth` preAction schedules a remote-settings
211451
+ * fetch it never awaits, and the command exits before that fetch runs (see the
211452
+ * 2026-09-10 amendment to `docs/adr/cmmd-is-the-only-claude-credential-renewer.md`).
211412
211453
  * It prints JSON on stdout and exits 1 when logged out, so the exit code is not
211413
211454
  * a failure signal and the `loggedIn` field is what gets read.
211455
+ *
211456
+ * Each answer a probe reaches is also kept in `claudeCredentialDirectoryAnswers`
211457
+ * so the provider check can publish it without probing.
211414
211458
  */
211415
211459
  const execFileAsync$3 = (0, node_util.promisify)(node_child_process.execFile);
211416
211460
  const AUTH_STATUS_ARGS = ["auth", "status"];
@@ -211427,8 +211471,7 @@ const PROBE_DIRECTORY_PREFIX = "forge-claude-capability-";
211427
211471
  const VERSION_PATTERN = /\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?/;
211428
211472
  function makeClaudeCredentialDirectoryProbe(deps) {
211429
211473
  const answers = /* @__PURE__ */ new Map();
211430
- const answer = async () => {
211431
- const version = await readVersionSafely(deps);
211474
+ const answerFor = (version) => {
211432
211475
  if (version === null) return runProbe(deps);
211433
211476
  const cached = answers.get(version);
211434
211477
  if (cached) return cached;
@@ -211439,10 +211482,47 @@ function makeClaudeCredentialDirectoryProbe(deps) {
211439
211482
  };
211440
211483
  pending.then((result) => {
211441
211484
  if (result === "inconclusive") forget();
211442
- }, forget);
211485
+ deps.onAnswer?.(version, result);
211486
+ }, () => {
211487
+ forget();
211488
+ deps.onAnswer?.(version, "inconclusive");
211489
+ });
211443
211490
  return pending;
211444
211491
  };
211445
- return { support: require_Schema$1.tryPromise(answer).pipe(require_Schema$1.orElseSucceed(() => "inconclusive")) };
211492
+ return { support: inconclusiveOnFailure(async () => answerFor(await readVersionSafely(deps))) };
211493
+ }
211494
+ /**
211495
+ * The one place a probe failure is handled. A missing binary, a timeout or a
211496
+ * directory that cannot be made all mean the probe could not tell.
211497
+ */
211498
+ function inconclusiveOnFailure(run) {
211499
+ return require_Schema$1.tryPromise(run).pipe(require_Schema$1.orElseSucceed(() => "inconclusive"));
211500
+ }
211501
+ const keyOf = (binaryPath, version) => JSON.stringify([binaryPath, version]);
211502
+ function makeClaudeCredentialDirectoryAnswers() {
211503
+ const answers = /* @__PURE__ */ new Map();
211504
+ const listeners = /* @__PURE__ */ new Set();
211505
+ return {
211506
+ record: (binaryPath, version, answer) => {
211507
+ const key = keyOf(binaryPath, version);
211508
+ if (answers.get(key) === answer) return;
211509
+ answers.set(key, answer);
211510
+ for (const listener of listeners) listener();
211511
+ },
211512
+ answerFor: (binaryPath, version) => answers.get(keyOf(binaryPath, version)),
211513
+ subscribe: (listener) => {
211514
+ listeners.add(listener);
211515
+ return () => {
211516
+ listeners.delete(listener);
211517
+ };
211518
+ }
211519
+ };
211520
+ }
211521
+ /** Every answer a turn-time probe in this process has reached. */
211522
+ const claudeCredentialDirectoryAnswers = makeClaudeCredentialDirectoryAnswers();
211523
+ /** The version in `claude --version` output, the key a probe answer is kept under. */
211524
+ function claudeVersionFromOutput(stdout) {
211525
+ return VERSION_PATTERN.exec(stdout)?.[0] ?? null;
211446
211526
  }
211447
211527
  /**
211448
211528
  * One probe per binary path for the life of the process. A conclusive answer is
@@ -211467,7 +211547,12 @@ function claudeCredentialDirectoryProbeFor(binaryPath) {
211467
211547
  if (!binaryPath) return INCONCLUSIVE_PROBE;
211468
211548
  const existing = probesByBinaryPath.get(binaryPath);
211469
211549
  if (existing) return existing;
211470
- const probe = makeClaudeCredentialDirectoryProbe(claudeCredentialDirectoryProbeDeps(binaryPath));
211550
+ const probe = makeClaudeCredentialDirectoryProbe({
211551
+ ...claudeCredentialDirectoryProbeDeps(binaryPath),
211552
+ onAnswer: (version, answer) => {
211553
+ claudeCredentialDirectoryAnswers.record(binaryPath, version, answer);
211554
+ }
211555
+ });
211471
211556
  probesByBinaryPath.set(binaryPath, probe);
211472
211557
  return probe;
211473
211558
  }
@@ -211478,7 +211563,7 @@ function claudeCredentialDirectoryProbeDeps(binaryPath, options = {}) {
211478
211563
  runAuthStatus: ({ credentialDirectory }) => run(AUTH_STATUS_ARGS, credentialDirectory),
211479
211564
  readBinaryVersion: async () => {
211480
211565
  const { stdout } = await run(VERSION_ARGS, null);
211481
- return VERSION_PATTERN.exec(stdout)?.[0] ?? null;
211566
+ return claudeVersionFromOutput(stdout);
211482
211567
  },
211483
211568
  makeProbeDirectory: () => (0, node_fs_promises.mkdtemp)((0, node_path.join)((0, node_os.tmpdir)(), PROBE_DIRECTORY_PREFIX)),
211484
211569
  removeProbeDirectory: (directory) => (0, node_fs_promises.rm)(directory, {
@@ -211647,6 +211732,171 @@ const makeProviderAuthProvenance = (input) => {
211647
211732
  };
211648
211733
  };
211649
211734
  //#endregion
211735
+ //#region src/provider/claudeCredentialStore.ts
211736
+ /**
211737
+ * Which Credential Store the Claude CLI uses on this machine, read the way the
211738
+ * CLI reads it.
211739
+ *
211740
+ * The CLI has two stores, `.credentials.json` in the credential directory and
211741
+ * the operating system's own, and no platform check picks between them. It
211742
+ * takes the OS store when `CLAUDE_CODE_FORCE_WINDOWS_CREDMAN` is `1`, and
211743
+ * otherwise when the remote flag it caches in its config file,
211744
+ * `cachedGrowthBookFeatures.tengu_windows_credman`, is `true`. That file is a
211745
+ * legacy `.config.json` in the config directory when one exists, and
211746
+ * `.claude.json` otherwise. Read from Claude Code 2.1.265 in #3086.
211747
+ *
211748
+ * The CLI takes the file when it cannot find, read or parse the config, and so
211749
+ * does this. A config that parses to JSON `null` reads `file` as well: the CLI
211750
+ * reads a property off the parsed value, which throws on `null`, and it falls
211751
+ * back to the file store on that throw. Any other config that parses but
211752
+ * carries no boolean flag also means the file to the CLI, but it is the shape a
211753
+ * moved key leaves, so this reads `unknown` rather than guess.
211754
+ *
211755
+ * Linux with no session bus has no secret service, so the OS store fails its
211756
+ * own check and the CLI falls back to the file whatever the flag says. Every
211757
+ * Sprite is that case, and it reads `file` without opening the config. Linux
211758
+ * with a session bus is `unknown` when the OS store is selected, because only
211759
+ * the secret service knows whether it would answer.
211760
+ * See `docs/adr/delivery-clears-the-os-credential-store-first.md`.
211761
+ *
211762
+ * Two things in 2.1.265 this does not follow. The CLI puts its OAuth name
211763
+ * suffix, `F$()` in that bundle, into the config name. The suffix is empty in a
211764
+ * production build and `-custom-oauth` with `CLAUDE_CODE_CUSTOM_OAUTH_URL` set,
211765
+ * so the config is then `.claude-custom-oauth.json` instead of `.claude.json`.
211766
+ * And `primeWindowsCredManBackendEnabled` can set the choice before the file is
211767
+ * read, but only with a v5 storage backend, and `tryCreateV5Backend` returns
211768
+ * nothing in that build, so it never does.
211769
+ */
211770
+ const CLAUDE_FORCE_OS_CREDENTIAL_STORE_ENV = "CLAUDE_CODE_FORCE_WINDOWS_CREDMAN";
211771
+ const CACHED_FEATURES_KEY = "cachedGrowthBookFeatures";
211772
+ const OS_STORE_FLAG_KEY = "tengu_windows_credman";
211773
+ function readClaudeCredentialStore(input) {
211774
+ if (input.platform === "linux" && !hasSessionBus(input)) return "file";
211775
+ const selectsOsStore = cliSelectsOsStore(input);
211776
+ if (selectsOsStore === null) return "unknown";
211777
+ if (!selectsOsStore) return "file";
211778
+ return input.platform === "darwin" || input.platform === "win32" ? "os" : "unknown";
211779
+ }
211780
+ /** The same read against this machine's home directory and disk. */
211781
+ const readClaudeCredentialStoreFromDisk = (context) => {
211782
+ let homeDirectory;
211783
+ try {
211784
+ homeDirectory = (0, node_os.homedir)();
211785
+ } catch {
211786
+ homeDirectory = null;
211787
+ }
211788
+ return readClaudeCredentialStore({
211789
+ ...context,
211790
+ homeDirectory: homeDirectory ?? "",
211791
+ fileExists: homeDirectory === null ? () => false : node_fs.existsSync,
211792
+ readFile: (path) => {
211793
+ if (homeDirectory === null) throw new Error("no home directory");
211794
+ return (0, node_fs.readFileSync)(path, "utf8");
211795
+ }
211796
+ });
211797
+ };
211798
+ /** True, false, or null when a parsed config does not say. */
211799
+ function cliSelectsOsStore(input) {
211800
+ if (input.env[CLAUDE_FORCE_OS_CREDENTIAL_STORE_ENV] === "1") return true;
211801
+ const config = readConfig(input);
211802
+ if (config === null) return false;
211803
+ const features = isRecord$11(config.parsed) ? config.parsed[CACHED_FEATURES_KEY] : void 0;
211804
+ const flag = isRecord$11(features) ? features[OS_STORE_FLAG_KEY] : void 0;
211805
+ return typeof flag === "boolean" ? flag : null;
211806
+ }
211807
+ /**
211808
+ * The parsed config, or null wherever the CLI's own read throws and it falls
211809
+ * back to the file store: a file that is missing, unreadable or not JSON, and a
211810
+ * config that parses to JSON `null`, because the CLI reads a property off it.
211811
+ */
211812
+ function readConfig(input) {
211813
+ try {
211814
+ const parsed = JSON.parse(input.readFile(cachedFlagFile(input)));
211815
+ return parsed === null ? null : { parsed };
211816
+ } catch {
211817
+ return null;
211818
+ }
211819
+ }
211820
+ function cachedFlagFile(input) {
211821
+ const configured = input.configDirectory?.trim();
211822
+ const legacy = (0, node_path.join)(configured || (0, node_path.join)(input.homeDirectory, ".claude"), ".config.json");
211823
+ if (input.fileExists(legacy)) return legacy;
211824
+ return (0, node_path.join)(configured || input.homeDirectory, ".claude.json");
211825
+ }
211826
+ /** libsecret reaches the secret service over the session bus, so no bus means no OS store. */
211827
+ function hasSessionBus(input) {
211828
+ if (input.env.DBUS_SESSION_BUS_ADDRESS?.trim()) return true;
211829
+ const runtimeDirectory = input.env.XDG_RUNTIME_DIR?.trim();
211830
+ return runtimeDirectory ? input.fileExists((0, node_path.join)(runtimeDirectory, "bus")) : false;
211831
+ }
211832
+ function isRecord$11(value) {
211833
+ return typeof value === "object" && value !== null && !Array.isArray(value);
211834
+ }
211835
+ //#endregion
211836
+ //#region src/provider/claudeCredentialAnswers.ts
211837
+ /**
211838
+ * The live resolver. The credential-directory answer is whatever the turn-time
211839
+ * probe last reached for this binary path and version, so the published answer
211840
+ * and the one that gated a turn are the same. Until a turn has probed, or with
211841
+ * no version to look it up by, the field stays absent.
211842
+ */
211843
+ function makeClaudeCredentialAnswersResolver(options) {
211844
+ const readCredentialStore = options.readCredentialStore ?? readClaudeCredentialStoreFromDisk;
211845
+ return (input) => require_Schema$1.gen(function* () {
211846
+ const platform = yield* HostProcessPlatform;
211847
+ const credentialStore = yield* require_Schema$1.sync(() => readCredentialStore({
211848
+ env: options.env ?? process.env,
211849
+ platform,
211850
+ configDirectory: input.configDirectory
211851
+ }));
211852
+ const credentialDirectory = input.version === null ? void 0 : options.credentialDirectoryAnswers.answerFor(input.binaryPath, input.version);
211853
+ return credentialDirectory === void 0 ? { credentialStore } : {
211854
+ credentialStore,
211855
+ credentialDirectory
211856
+ };
211857
+ });
211858
+ }
211859
+ //#endregion
211860
+ //#region src/runtimeDrain/supervisedRepeat.ts
211861
+ /**
211862
+ * Runs `work` on a fixed schedule, forever, and RESTARTS the schedule itself
211863
+ * if it ever dies for any reason other than this scope closing.
211864
+ *
211865
+ * `Effect.repeat(work, Schedule.spaced(interval)).pipe(Effect.forkScoped)`
211866
+ * alone has no restart path. `work` catching its own errors only protects
211867
+ * the TICK: an interrupt that lands while `Effect.repeat` is asleep between
211868
+ * ticks — which, at any non-trivial interval, is nearly this loop's entire
211869
+ * life — happens outside anything `work` wraps, and kills that one fiber
211870
+ * outright with nothing logged, because nothing was running to log from.
211871
+ * The process this runs in can otherwise be perfectly healthy while the
211872
+ * schedule is silently, permanently dead.
211873
+ *
211874
+ * This runs the schedule on its own child fiber, raced against an explicit
211875
+ * shutdown signal fired by a finalizer registered in this scope. Only that
211876
+ * signal stops the loop for good; any other death of the schedule fiber —
211877
+ * whatever causes it, defect or interrupt — logs and restarts it. `work`
211878
+ * itself must still handle its own EXPECTED failures (this only supervises
211879
+ * the schedule, and treats every death of it as unexpected).
211880
+ */
211881
+ function runSupervisedRepeat(input) {
211882
+ return require_Schema$1.gen(function* () {
211883
+ const shutdownSignal = yield* require_Schema$1.make$4();
211884
+ yield* require_Schema$1.addFinalizer(() => require_Schema$1.succeed$2(shutdownSignal, void 0));
211885
+ let firstAttempt = true;
211886
+ while (true) {
211887
+ if (!firstAttempt) yield* require_Schema$1.sleep(input.interval);
211888
+ firstAttempt = false;
211889
+ const scheduleFiber = yield* require_Schema$1.forkChild(require_Schema$1.repeat(input.work, require_Schema$1.spaced(input.interval)));
211890
+ const outcome = yield* require_Schema$1.race(require_Path.await_(scheduleFiber), require_Schema$1._await(shutdownSignal).pipe(require_Schema$1.as("shutdown")));
211891
+ if (outcome === "shutdown") {
211892
+ yield* require_Path.interrupt(scheduleFiber);
211893
+ return;
211894
+ }
211895
+ yield* require_Schema$1.logError(`${input.label} died unexpectedly — restarting`, { cause: require_Schema$1.isFailure(outcome) ? require_Schema$1.pretty(outcome.cause) : "unknown exit" });
211896
+ }
211897
+ });
211898
+ }
211899
+ //#endregion
211650
211900
  //#region src/provider/Layers/ClaudeProvider.ts
211651
211901
  function endpointProfileDisplayNames(settings) {
211652
211902
  return Object.fromEntries(settings.endpointProfiles.filter((p) => p.displayName).map((p) => [p.slug, p.displayName]));
@@ -212148,7 +212398,21 @@ const nativeClaudeProviderStatus = require_Schema$1.fn("nativeClaudeProviderStat
212148
212398
  }
212149
212399
  });
212150
212400
  });
212151
- const checkClaudeProviderStatus = require_Schema$1.fn("checkClaudeProviderStatus")(function* (resolveSubscriptionType, resolveSlashCommands, resolveModels) {
212401
+ /**
212402
+ * Adds what the CLI said about its credentials. Every check where
212403
+ * `claude --version` ran and exited 0 reaches here, including one whose
212404
+ * version did not parse; that one has no key to look a probe answer up by, so
212405
+ * only the store is added.
212406
+ */
212407
+ function withClaudeCredentialAnswers(provider, resolve, input) {
212408
+ if (!resolve) return require_Schema$1.succeed(provider);
212409
+ return resolve(input).pipe(require_Schema$1.map((answers) => ({
212410
+ ...provider,
212411
+ ...answers
212412
+ })));
212413
+ }
212414
+ const checkClaudeProviderStatus = require_Schema$1.fn("checkClaudeProviderStatus")(function* (resolvers = {}) {
212415
+ const { resolveSubscriptionType, resolveSlashCommands, resolveModels, resolveCredentialAnswers } = resolvers;
212152
212416
  const config = require_Schema$1.getOrElse(yield* require_Schema$1.serviceOption(ServerConfig), () => ({
212153
212417
  ...DEFAULT_PROVIDER_AUTH_CONFIG,
212154
212418
  forgeClaudeConfigPath: void 0
@@ -212220,19 +212484,24 @@ const checkClaudeProviderStatus = require_Schema$1.fn("checkClaudeProviderStatus
212220
212484
  });
212221
212485
  }
212222
212486
  const executableFallbackModels = modelsForClaudeCliVersion(fallbackModels, parsedVersion);
212223
- if (personalClaudeInVmEnabled()) return yield* nativeClaudeProviderStatus({
212487
+ const credentialAnswersInput = {
212488
+ binaryPath: claudeSettings.binaryPath,
212489
+ version: claudeVersionFromOutput(version.stdout),
212490
+ configDirectory: effectiveConfigPath
212491
+ };
212492
+ if (personalClaudeInVmEnabled()) return yield* withClaudeCredentialAnswers(yield* nativeClaudeProviderStatus({
212224
212493
  enabled: claudeSettings.enabled,
212225
212494
  checkedAt,
212226
212495
  version: parsedVersion,
212227
212496
  configPath: effectiveConfigPath,
212228
212497
  models: executableFallbackModels,
212229
212498
  provenance
212230
- });
212499
+ }), resolveCredentialAnswers, credentialAnswersInput);
212231
212500
  const capabilitiesProbeInput = claudeCapabilitiesProbeInput(claudeSettings.binaryPath, effectiveConfigPath);
212232
212501
  const discovery = yield* resolveClaudeDiscovery(capabilitiesProbeInput, resolveSlashCommands, resolveModels);
212233
212502
  const models = modelsForClaudeCliVersion(providerModelsFromSettings(resolveClaudeProviderModels(discovery.models), PROVIDER$12, claudeSettings.customModels, DEFAULT_CLAUDE_MODEL_CAPABILITIES, endpointProfileDisplayNames(claudeSettings)), parsedVersion);
212234
212503
  const authProbe = yield* runClaudeCommand(["auth", "status"]).pipe(require_Schema$1.timeoutOption(DEFAULT_TIMEOUT_MS$3), require_Schema$1.result);
212235
- return buildClaudeProviderFromAuthProbe({
212504
+ return yield* withClaudeCredentialAnswers(buildClaudeProviderFromAuthProbe({
212236
212505
  authProbe,
212237
212506
  authMetadata: yield* resolveClaudeAuthMetadata(authProbe, capabilitiesProbeInput, resolveSubscriptionType),
212238
212507
  checkedAt,
@@ -212241,7 +212510,7 @@ const checkClaudeProviderStatus = require_Schema$1.fn("checkClaudeProviderStatus
212241
212510
  slashCommands: discovery.slashCommands,
212242
212511
  parsedVersion,
212243
212512
  provenance
212244
- });
212513
+ }), resolveCredentialAnswers, credentialAnswersInput);
212245
212514
  });
212246
212515
  const makePendingClaudeProvider = (claudeSettings) => {
212247
212516
  const checkedAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -212273,30 +212542,76 @@ const makePendingClaudeProvider = (claudeSettings) => {
212273
212542
  }
212274
212543
  });
212275
212544
  };
212276
- const ClaudeProviderLive = require_Schema$1.effect(ClaudeProvider, require_Schema$1.gen(function* () {
212277
- const serverSettings = yield* ServerSettingsService;
212278
- const spawner = yield* require_NodeTerminal.ChildProcessSpawner;
212279
- const subscriptionProbeCache = yield* require_Cache.make({
212280
- capacity: 4,
212281
- timeToLive: require_Schema$1.minutes(5),
212282
- lookup: (key) => {
212283
- const [binaryPath, configPath] = JSON.parse(key);
212284
- return probeClaudeCapabilities({
212285
- binaryPath,
212286
- ...configPath ? { configPath } : {}
212287
- });
212288
- }
212289
- });
212290
- const getDiscovery = (input) => require_Cache.get(subscriptionProbeCache, JSON.stringify([input.binaryPath, input.configPath]));
212291
- const checkProvider = checkClaudeProviderStatus((input) => getDiscovery(input).pipe(require_Schema$1.map((probe) => probe?.subscriptionType)), (input) => getDiscovery(input).pipe(require_Schema$1.map((probe) => probe?.slashCommands)), (input) => getDiscovery(input).pipe(require_Schema$1.map((probe) => probe?.models))).pipe(require_Schema$1.provideService(ServerSettingsService, serverSettings), require_Schema$1.provideService(require_NodeTerminal.ChildProcessSpawner, spawner));
212292
- return yield* makeManagedServerProvider({
212293
- getSettings: serverSettings.getSettings.pipe(require_Schema$1.map((settings) => settings.providers.claudeAgent), require_Schema$1.orDie),
212294
- streamSettings: serverSettings.streamChanges.pipe(require_Path.map((settings) => settings.providers.claudeAgent)),
212295
- haveSettingsChanged: (previous, next) => !require_Schema$1.equals(previous, next),
212296
- initialSnapshot: makePendingClaudeProvider,
212297
- checkProvider
212298
- });
212299
- }));
212545
+ /**
212546
+ * A refresh can wait behind a check that already holds the provider's refresh
212547
+ * permit before running its own, so it gets two check budgets.
212548
+ */
212549
+ const CREDENTIAL_ANSWER_REFRESH_TIMEOUT_MS = 2 * (CLAUDE_VERSION_PROBE_TIMEOUT_MS + CAPABILITIES_PROBE_TIMEOUT_MS$1 + DEFAULT_TIMEOUT_MS$3);
212550
+ /** The gap after each answer refresh, and the pause before a restart. */
212551
+ const CREDENTIAL_ANSWER_REFRESH_SPACING = require_Schema$1.seconds(1);
212552
+ /**
212553
+ * Reruns the check when a probe reaches a new or changed answer, so the
212554
+ * inventory carries it without waiting for the next scheduled check. Answers
212555
+ * that arrive during a refresh collapse into one more refresh.
212556
+ *
212557
+ * A refresh that fails, dies or outlives its timeout is logged, and the loop
212558
+ * goes back to waiting for the next answer. The timeout interrupts the check,
212559
+ * which hands back the refresh permit. `runSupervisedRepeat` restarts the loop
212560
+ * after any interrupt that does not come from the scope closing; closing the
212561
+ * scope stops it and drops the subscription.
212562
+ */
212563
+ const refreshOnNewCredentialDirectoryAnswer = require_Schema$1.fn("refreshOnNewCredentialDirectoryAnswer")(function* (credentialDirectoryAnswers, refresh) {
212564
+ const changed = yield* require_Path.sliding(1);
212565
+ yield* require_Schema$1.acquireRelease(require_Schema$1.sync(() => credentialDirectoryAnswers.subscribe(() => {
212566
+ require_Path.offerUnsafe(changed, void 0);
212567
+ })), (unsubscribe) => require_Schema$1.sync(unsubscribe));
212568
+ const refreshOnce = refresh.pipe(require_Schema$1.timeout(CREDENTIAL_ANSWER_REFRESH_TIMEOUT_MS), require_Schema$1.asVoid, require_Schema$1.catchCause((cause) => require_Schema$1.hasInterruptsOnly(cause) ? require_Schema$1.interrupt : require_Schema$1.logWarning("Claude refresh for a new credential-directory answer failed", { cause: require_Schema$1.pretty(cause) })));
212569
+ yield* require_Schema$1.forkScoped(runSupervisedRepeat({
212570
+ label: "Claude credential-directory answer refresh",
212571
+ work: require_Path.take(changed).pipe(require_Schema$1.andThen(refreshOnce)),
212572
+ interval: CREDENTIAL_ANSWER_REFRESH_SPACING
212573
+ }));
212574
+ });
212575
+ /** The Claude provider. Tests hand in their own answers and store read. */
212576
+ function makeClaudeProviderLive(options = {}) {
212577
+ const credentialDirectoryAnswers = options.credentialDirectoryAnswers ?? claudeCredentialDirectoryAnswers;
212578
+ const resolveCredentialAnswers = makeClaudeCredentialAnswersResolver({
212579
+ ...options,
212580
+ credentialDirectoryAnswers
212581
+ });
212582
+ return require_Schema$1.effect(ClaudeProvider, require_Schema$1.gen(function* () {
212583
+ const serverSettings = yield* ServerSettingsService;
212584
+ const spawner = yield* require_NodeTerminal.ChildProcessSpawner;
212585
+ const subscriptionProbeCache = yield* require_Cache.make({
212586
+ capacity: 4,
212587
+ timeToLive: require_Schema$1.minutes(5),
212588
+ lookup: (key) => {
212589
+ const [binaryPath, configPath] = JSON.parse(key);
212590
+ return probeClaudeCapabilities({
212591
+ binaryPath,
212592
+ ...configPath ? { configPath } : {}
212593
+ });
212594
+ }
212595
+ });
212596
+ const getDiscovery = (input) => require_Cache.get(subscriptionProbeCache, JSON.stringify([input.binaryPath, input.configPath]));
212597
+ const checkProvider = checkClaudeProviderStatus({
212598
+ resolveSubscriptionType: (input) => getDiscovery(input).pipe(require_Schema$1.map((probe) => probe?.subscriptionType)),
212599
+ resolveSlashCommands: (input) => getDiscovery(input).pipe(require_Schema$1.map((probe) => probe?.slashCommands)),
212600
+ resolveModels: (input) => getDiscovery(input).pipe(require_Schema$1.map((probe) => probe?.models)),
212601
+ resolveCredentialAnswers
212602
+ }).pipe(require_Schema$1.provideService(ServerSettingsService, serverSettings), require_Schema$1.provideService(require_NodeTerminal.ChildProcessSpawner, spawner));
212603
+ const provider = yield* makeManagedServerProvider({
212604
+ getSettings: serverSettings.getSettings.pipe(require_Schema$1.map((settings) => settings.providers.claudeAgent), require_Schema$1.orDie),
212605
+ streamSettings: serverSettings.streamChanges.pipe(require_Path.map((settings) => settings.providers.claudeAgent)),
212606
+ haveSettingsChanged: (previous, next) => !require_Schema$1.equals(previous, next),
212607
+ initialSnapshot: makePendingClaudeProvider,
212608
+ checkProvider
212609
+ });
212610
+ yield* refreshOnNewCredentialDirectoryAnswer(credentialDirectoryAnswers, provider.refresh);
212611
+ return provider;
212612
+ }));
212613
+ }
212614
+ const ClaudeProviderLive = makeClaudeProviderLive();
212300
212615
  //#endregion
212301
212616
  //#region src/provider/Services/ClaudeAdapter.ts
212302
212617
  /**
@@ -287537,46 +287852,6 @@ const makeRuntimeDrainState = require_Schema$1.gen(function* () {
287537
287852
  var RuntimeDrainState = class extends require_Schema$1.Service()("forge/runtimeDrain/RuntimeDrainState") {};
287538
287853
  const RuntimeDrainStateLive = require_Schema$1.effect(RuntimeDrainState, makeRuntimeDrainState);
287539
287854
  //#endregion
287540
- //#region src/runtimeDrain/supervisedRepeat.ts
287541
- /**
287542
- * Runs `work` on a fixed schedule, forever, and RESTARTS the schedule itself
287543
- * if it ever dies for any reason other than this scope closing.
287544
- *
287545
- * `Effect.repeat(work, Schedule.spaced(interval)).pipe(Effect.forkScoped)`
287546
- * alone has no restart path. `work` catching its own errors only protects
287547
- * the TICK: an interrupt that lands while `Effect.repeat` is asleep between
287548
- * ticks — which, at any non-trivial interval, is nearly this loop's entire
287549
- * life — happens outside anything `work` wraps, and kills that one fiber
287550
- * outright with nothing logged, because nothing was running to log from.
287551
- * The process this runs in can otherwise be perfectly healthy while the
287552
- * schedule is silently, permanently dead.
287553
- *
287554
- * This runs the schedule on its own child fiber, raced against an explicit
287555
- * shutdown signal fired by a finalizer registered in this scope. Only that
287556
- * signal stops the loop for good; any other death of the schedule fiber —
287557
- * whatever causes it, defect or interrupt — logs and restarts it. `work`
287558
- * itself must still handle its own EXPECTED failures (this only supervises
287559
- * the schedule, and treats every death of it as unexpected).
287560
- */
287561
- function runSupervisedRepeat(input) {
287562
- return require_Schema$1.gen(function* () {
287563
- const shutdownSignal = yield* require_Schema$1.make$4();
287564
- yield* require_Schema$1.addFinalizer(() => require_Schema$1.succeed$2(shutdownSignal, void 0));
287565
- let firstAttempt = true;
287566
- while (true) {
287567
- if (!firstAttempt) yield* require_Schema$1.sleep(input.interval);
287568
- firstAttempt = false;
287569
- const scheduleFiber = yield* require_Schema$1.forkChild(require_Schema$1.repeat(input.work, require_Schema$1.spaced(input.interval)));
287570
- const outcome = yield* require_Schema$1.race(require_Path.await_(scheduleFiber), require_Schema$1._await(shutdownSignal).pipe(require_Schema$1.as("shutdown")));
287571
- if (outcome === "shutdown") {
287572
- yield* require_Path.interrupt(scheduleFiber);
287573
- return;
287574
- }
287575
- yield* require_Schema$1.logError(`${input.label} died unexpectedly — restarting`, { cause: require_Schema$1.isFailure(outcome) ? require_Schema$1.pretty(outcome.cause) : "unknown exit" });
287576
- }
287577
- });
287578
- }
287579
- //#endregion
287580
287855
  //#region src/runtimeDrain/RuntimeDrainReporter.ts
287581
287856
  const HEARTBEAT_INTERVAL = require_Schema$1.seconds(30);
287582
287857
  const HEARTBEAT_TICK_TIMEOUT = require_Schema$1.seconds(60);
@@ -294999,7 +295274,7 @@ function resolveBuildCommitFromEnv(env) {
294999
295274
  * environment descriptor down instead of reporting an honest "unknown".
295000
295275
  */
295001
295276
  function readBakedBuildCommit() {
295002
- return "ebc6c5d85de3dc3324a5054f8f29deb2dd89baa7";
295277
+ return "69affcc8397652715f8bd06fe2f226f4b607e1db";
295003
295278
  }
295004
295279
  async function resolveServerBuildCommit(input) {
295005
295280
  if (isFullCommitSha(input.baked)) return input.baked;