@codexhost/cli-darwin-arm64 0.2.0 → 0.2.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.
@@ -773,10 +773,10 @@ function mergeDefs(...defs) {
773
773
  function cloneDef(schema) {
774
774
  return mergeDefs(schema._zod.def);
775
775
  }
776
- function getElementAtPath(obj, path17) {
777
- if (!path17)
776
+ function getElementAtPath(obj, path18) {
777
+ if (!path18)
778
778
  return obj;
779
- return path17.reduce((acc, key) => acc?.[key], obj);
779
+ return path18.reduce((acc, key) => acc?.[key], obj);
780
780
  }
781
781
  function promiseAllObject(promisesObj) {
782
782
  const keys = Object.keys(promisesObj);
@@ -1185,11 +1185,11 @@ function explicitlyAborted(x2, startIndex = 0) {
1185
1185
  }
1186
1186
  return false;
1187
1187
  }
1188
- function prefixIssues(path17, issues) {
1188
+ function prefixIssues(path18, issues) {
1189
1189
  return issues.map((iss) => {
1190
1190
  var _a4;
1191
1191
  (_a4 = iss).path ?? (_a4.path = []);
1192
- iss.path.unshift(path17);
1192
+ iss.path.unshift(path18);
1193
1193
  return iss;
1194
1194
  });
1195
1195
  }
@@ -1336,16 +1336,16 @@ function flattenError(error52, mapper = (issue2) => issue2.message) {
1336
1336
  }
1337
1337
  function formatError(error52, mapper = (issue2) => issue2.message) {
1338
1338
  const fieldErrors = { _errors: [] };
1339
- const processError = (error53, path17 = []) => {
1339
+ const processError = (error53, path18 = []) => {
1340
1340
  for (const issue2 of error53.issues) {
1341
1341
  if (issue2.code === "invalid_union" && issue2.errors.length) {
1342
- issue2.errors.map((issues) => processError({ issues }, [...path17, ...issue2.path]));
1342
+ issue2.errors.map((issues) => processError({ issues }, [...path18, ...issue2.path]));
1343
1343
  } else if (issue2.code === "invalid_key") {
1344
- processError({ issues: issue2.issues }, [...path17, ...issue2.path]);
1344
+ processError({ issues: issue2.issues }, [...path18, ...issue2.path]);
1345
1345
  } else if (issue2.code === "invalid_element") {
1346
- processError({ issues: issue2.issues }, [...path17, ...issue2.path]);
1346
+ processError({ issues: issue2.issues }, [...path18, ...issue2.path]);
1347
1347
  } else {
1348
- const fullpath = [...path17, ...issue2.path];
1348
+ const fullpath = [...path18, ...issue2.path];
1349
1349
  if (fullpath.length === 0) {
1350
1350
  fieldErrors._errors.push(mapper(issue2));
1351
1351
  } else {
@@ -1372,17 +1372,17 @@ function formatError(error52, mapper = (issue2) => issue2.message) {
1372
1372
  }
1373
1373
  function treeifyError(error52, mapper = (issue2) => issue2.message) {
1374
1374
  const result = { errors: [] };
1375
- const processError = (error53, path17 = []) => {
1375
+ const processError = (error53, path18 = []) => {
1376
1376
  var _a4, _b2;
1377
1377
  for (const issue2 of error53.issues) {
1378
1378
  if (issue2.code === "invalid_union" && issue2.errors.length) {
1379
- issue2.errors.map((issues) => processError({ issues }, [...path17, ...issue2.path]));
1379
+ issue2.errors.map((issues) => processError({ issues }, [...path18, ...issue2.path]));
1380
1380
  } else if (issue2.code === "invalid_key") {
1381
- processError({ issues: issue2.issues }, [...path17, ...issue2.path]);
1381
+ processError({ issues: issue2.issues }, [...path18, ...issue2.path]);
1382
1382
  } else if (issue2.code === "invalid_element") {
1383
- processError({ issues: issue2.issues }, [...path17, ...issue2.path]);
1383
+ processError({ issues: issue2.issues }, [...path18, ...issue2.path]);
1384
1384
  } else {
1385
- const fullpath = [...path17, ...issue2.path];
1385
+ const fullpath = [...path18, ...issue2.path];
1386
1386
  if (fullpath.length === 0) {
1387
1387
  result.errors.push(mapper(issue2));
1388
1388
  continue;
@@ -1414,8 +1414,8 @@ function treeifyError(error52, mapper = (issue2) => issue2.message) {
1414
1414
  }
1415
1415
  function toDotPath(_path) {
1416
1416
  const segs = [];
1417
- const path17 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1418
- for (const seg of path17) {
1417
+ const path18 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1418
+ for (const seg of path18) {
1419
1419
  if (typeof seg === "number")
1420
1420
  segs.push(`[${seg}]`);
1421
1421
  else if (typeof seg === "symbol")
@@ -14107,13 +14107,13 @@ function resolveRef(ref, ctx) {
14107
14107
  if (!ref.startsWith("#")) {
14108
14108
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
14109
14109
  }
14110
- const path17 = ref.slice(1).split("/").filter(Boolean);
14111
- if (path17.length === 0) {
14110
+ const path18 = ref.slice(1).split("/").filter(Boolean);
14111
+ if (path18.length === 0) {
14112
14112
  return ctx.rootSchema;
14113
14113
  }
14114
14114
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
14115
- if (path17[0] === defsKey) {
14116
- const key = path17[1];
14115
+ if (path18[0] === defsKey) {
14116
+ const key = path18[1];
14117
14117
  if (!key || !ctx.defs[key]) {
14118
14118
  throw new Error(`Reference not found: ${ref}`);
14119
14119
  }
@@ -14690,12 +14690,24 @@ var threadUsageSnapshotSchema = external_exports.object({
14690
14690
  });
14691
14691
  }
14692
14692
  });
14693
+ var usagePercentSchema = external_exports.number().finite().min(0).max(100);
14694
+ var accountCreditsProductUsageSchema = external_exports.object({
14695
+ product: external_exports.string().min(1),
14696
+ usagePercent: usagePercentSchema
14697
+ }).strict();
14698
+ var accountCreditsSnapshotSchema = external_exports.object({
14699
+ usedPercent: usagePercentSchema,
14700
+ resetsAt: external_exports.string().min(1).optional(),
14701
+ periodType: external_exports.enum(["weekly", "monthly", "unknown"]),
14702
+ productUsage: external_exports.array(accountCreditsProductUsageSchema).min(1).optional()
14703
+ }).strict();
14693
14704
  var threadUsageInspectionParamsSchema = external_exports.object({
14694
14705
  threadId: hostThreadIdSchema
14695
14706
  }).strict();
14696
14707
  var threadUsageInspectionSchema = external_exports.object({
14697
14708
  threadId: hostThreadIdSchema,
14698
- usage: threadUsageSnapshotSchema.nullable()
14709
+ usage: threadUsageSnapshotSchema.nullable(),
14710
+ accountCredits: accountCreditsSnapshotSchema.optional()
14699
14711
  }).strict();
14700
14712
 
14701
14713
  // packages/shared-contracts/dist/harness-models.js
@@ -19116,8 +19128,8 @@ var qU = v(function(BU) {
19116
19128
  BU._globalThis = void 0;
19117
19129
  BU._globalThis = typeof globalThis === "object" ? globalThis : global;
19118
19130
  });
19119
- var GU = v(function(os6) {
19120
- var Axe = os6 && os6.__createBinding || (Object.create ? function(e, t, r, n) {
19131
+ var GU = v(function(os7) {
19132
+ var Axe = os7 && os7.__createBinding || (Object.create ? function(e, t, r, n) {
19121
19133
  if (n === void 0) n = r;
19122
19134
  Object.defineProperty(e, n, { enumerable: true, get: function() {
19123
19135
  return t[r];
@@ -19125,11 +19137,11 @@ var GU = v(function(os6) {
19125
19137
  } : function(e, t, r, n) {
19126
19138
  if (n === void 0) n = r;
19127
19139
  e[n] = t[r];
19128
- }), kxe = os6 && os6.__exportStar || function(e, t) {
19140
+ }), kxe = os7 && os7.__exportStar || function(e, t) {
19129
19141
  for (var r in e) if (r !== "default" && !Object.prototype.hasOwnProperty.call(t, r)) Axe(t, e, r);
19130
19142
  };
19131
- Object.defineProperty(os6, "__esModule", { value: true });
19132
- kxe(qU(), os6);
19143
+ Object.defineProperty(os7, "__esModule", { value: true });
19144
+ kxe(qU(), os7);
19133
19145
  });
19134
19146
  var WU = v(function(is) {
19135
19147
  var Oxe = is && is.__createBinding || (Object.create ? function(e, t, r, n) {
@@ -44826,16 +44838,16 @@ var AbstractApiClient = class {
44826
44838
  * Shared POST leg of both C→S carriers (callUnary/respond): JSON body,
44827
44839
  * optional default timeout merged with the caller's external signal, non-2xx → transport throw.
44828
44840
  */
44829
- async postJson(path17, body, signal, timeoutPolicy = "default") {
44841
+ async postJson(path18, body, signal, timeoutPolicy = "default") {
44830
44842
  const requestSignal = timeoutPolicy === "default" ? signal === void 0 ? AbortSignal.timeout(this.timeoutMs) : AbortSignal.any([AbortSignal.timeout(this.timeoutMs), signal]) : signal;
44831
- const response = await this.doFetch(new URL(path17, this.resolveBase()), {
44843
+ const response = await this.doFetch(new URL(path18, this.resolveBase()), {
44832
44844
  method: "POST",
44833
44845
  headers: { "content-type": "application/json" },
44834
44846
  body: JSON.stringify(body),
44835
44847
  ...requestSignal === void 0 ? {} : { signal: requestSignal }
44836
44848
  });
44837
44849
  if (!response.ok)
44838
- throw new Error(`transport failure for ${path17}: HTTP ${response.status}`);
44850
+ throw new Error(`transport failure for ${path18}: HTTP ${response.status}`);
44839
44851
  return response;
44840
44852
  }
44841
44853
  /**
@@ -44871,10 +44883,10 @@ var AbstractApiClient = class {
44871
44883
  * either parse level is reported and skipped (one corrupt frame must not kill the stream; the
44872
44884
  * client's gap detection covers whatever the frame carried).
44873
44885
  */
44874
- async *readSse(path17, signal, frameSchema, onOpen) {
44875
- const response = await this.doFetch(new URL(path17, this.resolveBase()), { signal });
44886
+ async *readSse(path18, signal, frameSchema, onOpen) {
44887
+ const response = await this.doFetch(new URL(path18, this.resolveBase()), { signal });
44876
44888
  if (!response.ok || response.body === null)
44877
- throw new Error(`transport failure for ${path17}: HTTP ${response.status}`);
44889
+ throw new Error(`transport failure for ${path18}: HTTP ${response.status}`);
44878
44890
  onOpen?.();
44879
44891
  const reader = response.body.getReader();
44880
44892
  const decoder2 = new TextDecoder();
@@ -44898,7 +44910,7 @@ var AbstractApiClient = class {
44898
44910
  full = serverRequestSchema.parse(JSON.parse(data));
44899
44911
  frame = frameSchema.parse(full.payload);
44900
44912
  } catch (error52) {
44901
- console.error(`[apiproxy] dropping malformed SSE frame on ${path17}:`, error52);
44913
+ console.error(`[apiproxy] dropping malformed SSE frame on ${path18}:`, error52);
44902
44914
  continue;
44903
44915
  }
44904
44916
  this.onEnvelope(full);
@@ -45473,16 +45485,16 @@ var Diff = class {
45473
45485
  }
45474
45486
  }
45475
45487
  }
45476
- addToPath(path17, added, removed, oldPosInc, options) {
45477
- const last = path17.lastComponent;
45488
+ addToPath(path18, added, removed, oldPosInc, options) {
45489
+ const last = path18.lastComponent;
45478
45490
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
45479
45491
  return {
45480
- oldPos: path17.oldPos + oldPosInc,
45492
+ oldPos: path18.oldPos + oldPosInc,
45481
45493
  lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
45482
45494
  };
45483
45495
  } else {
45484
45496
  return {
45485
- oldPos: path17.oldPos + oldPosInc,
45497
+ oldPos: path18.oldPos + oldPosInc,
45486
45498
  lastComponent: { count: 1, added, removed, previousComponent: last }
45487
45499
  };
45488
45500
  }
@@ -46657,13 +46669,7 @@ var DeepSeekHarnessSession = class {
46657
46669
  error: invalidState2(`DeepSeek Harness rejected Interaction: ${receipt.reason}`)
46658
46670
  };
46659
46671
  }
46660
- active.interactions.delete(command.interactionId);
46661
- this.#emit({
46662
- type: "interaction.closed",
46663
- interactionId: command.interactionId,
46664
- turnId: active.command.turnId,
46665
- reason: "responded"
46666
- });
46672
+ this.#closeHostInteraction(active, command.interactionId, "responded");
46667
46673
  return { ok: true, value: { accepted: true } };
46668
46674
  } catch (error52) {
46669
46675
  return { ok: false, error: normalizedError(error52, "nativeFailure") };
@@ -46945,15 +46951,19 @@ var DeepSeekHarnessSession = class {
46945
46951
  const matches = type === "approval" ? pending.type === "approval" && pending.approvalId === nativeId : pending.type === "question" && pending.rpcId === nativeId;
46946
46952
  if (!matches)
46947
46953
  continue;
46948
- active.interactions.delete(interactionId);
46949
- this.#emit({
46950
- type: "interaction.closed",
46951
- interactionId,
46952
- turnId: active.command.turnId,
46953
- reason: "responded"
46954
- });
46954
+ this.#closeHostInteraction(active, interactionId, "responded");
46955
46955
  }
46956
46956
  }
46957
+ #closeHostInteraction(active, interactionId, reason) {
46958
+ if (!active.interactions.delete(interactionId))
46959
+ return;
46960
+ this.#emit({
46961
+ type: "interaction.closed",
46962
+ interactionId,
46963
+ turnId: active.command.turnId,
46964
+ reason
46965
+ });
46966
+ }
46957
46967
  #finishTurn(active, reason) {
46958
46968
  const terminal = projectTurnReason(reason);
46959
46969
  const itemOutcome3 = terminal.outcome.status === "succeeded" ? { status: "succeeded" } : terminal.outcome.status === "cancelled" ? {
@@ -46965,15 +46975,9 @@ var DeepSeekHarnessSession = class {
46965
46975
  for (const tool of active.tools.values())
46966
46976
  this.#completeItem(active, tool.item, itemOutcome3);
46967
46977
  active.tools.clear();
46968
- for (const [interactionId] of active.interactions) {
46969
- this.#emit({
46970
- type: "interaction.closed",
46971
- interactionId,
46972
- turnId: active.command.turnId,
46973
- reason: "cancelled"
46974
- });
46978
+ for (const interactionId of [...active.interactions.keys()]) {
46979
+ this.#closeHostInteraction(active, interactionId, "cancelled");
46975
46980
  }
46976
- active.interactions.clear();
46977
46981
  const nativeTurnRef2 = this.#nativeTurnRef(active.nativeTurn);
46978
46982
  this.#turns.push({
46979
46983
  nativeTurnRef: nativeTurnRef2,
@@ -47046,15 +47050,9 @@ var DeepSeekHarnessSession = class {
47046
47050
  for (const tool of active.tools.values())
47047
47051
  this.#completeItem(active, tool.item, outcome);
47048
47052
  active.tools.clear();
47049
- for (const [interactionId] of active.interactions) {
47050
- this.#emit({
47051
- type: "interaction.closed",
47052
- interactionId,
47053
- turnId: active.command.turnId,
47054
- reason: "cancelled"
47055
- });
47053
+ for (const interactionId of [...active.interactions.keys()]) {
47054
+ this.#closeHostInteraction(active, interactionId, "cancelled");
47056
47055
  }
47057
- active.interactions.clear();
47058
47056
  this.#emit({
47059
47057
  type: "turn.completed",
47060
47058
  turnId: active.command.turnId,
@@ -47248,7 +47246,7 @@ var packageMetadata3 = {
47248
47246
 
47249
47247
  // packages/adapters/grok/dist/grok-adapter.js
47250
47248
  import { randomUUID as randomUUID3 } from "node:crypto";
47251
- import path9 from "node:path";
47249
+ import path10 from "node:path";
47252
47250
 
47253
47251
  // packages/adapters/grok/dist/acp-transport.js
47254
47252
  import { spawn as spawn3, spawnSync } from "node:child_process";
@@ -51605,8 +51603,8 @@ function transportEvent(update, metadata) {
51605
51603
  function nativeSessionFile(options, sessionId, fileName) {
51606
51604
  const environment = { ...process.env, ...options.environment };
51607
51605
  const home = environment.HOME ?? environment.USERPROFILE ?? os3.homedir();
51608
- const grokHome = environment.GROK_HOME ?? path8.join(home, ".grok");
51609
- return path8.join(grokHome, "sessions", encodeURIComponent(path8.resolve(options.cwd)), sessionId, fileName);
51606
+ const grokHome2 = environment.GROK_HOME ?? path8.join(home, ".grok");
51607
+ return path8.join(grokHome2, "sessions", encodeURIComponent(path8.resolve(options.cwd)), sessionId, fileName);
51610
51608
  }
51611
51609
  function nativeHistoryPath(options, sessionId) {
51612
51610
  return nativeSessionFile(options, sessionId, "updates.jsonl");
@@ -51904,7 +51902,16 @@ function terminalOutcome(stopReason) {
51904
51902
  }
51905
51903
  };
51906
51904
  }
51905
+ var systemReminderPattern = /^\s*<system-reminder>[\s\S]*$/u;
51906
+ var taskCompletedTurnKeyPattern = /^task-completed-/u;
51907
+ function isSyntheticGrokUserText(text) {
51908
+ return systemReminderPattern.test(text);
51909
+ }
51910
+ function isSyntheticGrokTurnKey(nativeTurnKey3) {
51911
+ return taskCompletedTurnKeyPattern.test(nativeTurnKey3);
51912
+ }
51907
51913
  function mapGrokReplay(replay, harnessId, sessionId, knownTurnRefs = []) {
51914
+ const knownByNativeKey = new Map(knownTurnRefs.filter((ref) => ref.harnessId === harnessId && ref.nativeSessionId === sessionId).map((ref) => [ref.nativeTurnKey, ref]));
51908
51915
  const turns = [];
51909
51916
  let input = "";
51910
51917
  let items = [];
@@ -51935,13 +51942,11 @@ function mapGrokReplay(replay, harnessId, sessionId, knownTurnRefs = []) {
51935
51942
  const completeTurn = (outcome, terminalKey) => {
51936
51943
  if (input.length === 0)
51937
51944
  return;
51938
- const known = knownTurnRefs[turnIndex];
51939
- if (known && (known.harnessId !== harnessId || known.nativeSessionId !== sessionId)) {
51940
- throw new Error("Known Grok Turn identity does not belong to the Native Session");
51941
- }
51942
- const stableKey = known?.nativeTurnKey ?? terminalKey ?? nativeTurnKey3;
51943
- if (!stableKey)
51945
+ const reconstructedKey = terminalKey ?? nativeTurnKey3;
51946
+ if (!reconstructedKey)
51944
51947
  throw new Error("Grok Native history Turn has no stable identity");
51948
+ const known = knownByNativeKey.get(reconstructedKey);
51949
+ const stableKey = known?.nativeTurnKey ?? reconstructedKey;
51945
51950
  completeReasoning();
51946
51951
  completeAgent();
51947
51952
  completeTools();
@@ -51964,6 +51969,8 @@ function mapGrokReplay(replay, harnessId, sessionId, knownTurnRefs = []) {
51964
51969
  };
51965
51970
  for (const event of replay) {
51966
51971
  if (event.type === "user.text") {
51972
+ if (isSyntheticGrokUserText(event.text))
51973
+ continue;
51967
51974
  if (input.length > 0) {
51968
51975
  completeTurn({
51969
51976
  status: "unknown",
@@ -51982,6 +51989,8 @@ function mapGrokReplay(replay, harnessId, sessionId, knownTurnRefs = []) {
51982
51989
  if (input.length === 0)
51983
51990
  continue;
51984
51991
  if (event.type === "turn.completed") {
51992
+ if (isSyntheticGrokTurnKey(event.nativeTurnKey))
51993
+ continue;
51985
51994
  completeTurn(terminalOutcome(event.stopReason), event.nativeTurnKey);
51986
51995
  } else if (event.type === "agent.text") {
51987
51996
  if (!agent) {
@@ -52023,9 +52032,6 @@ function mapGrokReplay(replay, harnessId, sessionId, knownTurnRefs = []) {
52023
52032
  }
52024
52033
  }
52025
52034
  completeTurn({ status: "unknown", reason: "Grok Native history has no terminal signal" });
52026
- if (knownTurnRefs.length > turns.length) {
52027
- throw new Error("Grok Native history is missing persisted Turns");
52028
- }
52029
52035
  return { turns };
52030
52036
  }
52031
52037
 
@@ -52124,9 +52130,115 @@ function stateForGrokModel(modelState, nativeState, model = modelState.currentMo
52124
52130
  };
52125
52131
  }
52126
52132
 
52133
+ // packages/adapters/grok/dist/grok-credits.js
52134
+ import { readFile as readFile2 } from "node:fs/promises";
52135
+ import os4 from "node:os";
52136
+ import path9 from "node:path";
52137
+ var GROK_CREDITS_ENDPOINT = "https://cli-chat-proxy.grok.com/v1/billing?format=credits";
52138
+ var REQUEST_TIMEOUT_MS = 15e3;
52139
+ function isRecord11(value) {
52140
+ return typeof value === "object" && value !== null && !Array.isArray(value);
52141
+ }
52142
+ function finitePercent(value) {
52143
+ if (typeof value !== "number" || !Number.isFinite(value))
52144
+ return void 0;
52145
+ return Math.min(100, Math.max(0, value));
52146
+ }
52147
+ function nonNegativeNumber(value) {
52148
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0)
52149
+ return void 0;
52150
+ return value;
52151
+ }
52152
+ function grokHome(environment) {
52153
+ return environment.GROK_HOME ?? path9.join(environment.HOME ?? environment.USERPROFILE ?? os4.homedir(), ".grok");
52154
+ }
52155
+ function periodTypeFrom(value) {
52156
+ if (typeof value !== "string")
52157
+ return "unknown";
52158
+ const normalized = value.toUpperCase();
52159
+ if (normalized.includes("WEEKLY"))
52160
+ return "weekly";
52161
+ if (normalized.includes("MONTHLY"))
52162
+ return "monthly";
52163
+ return "unknown";
52164
+ }
52165
+ function productUsageFrom(value) {
52166
+ if (!Array.isArray(value))
52167
+ return void 0;
52168
+ const products = value.flatMap((entry) => {
52169
+ if (!isRecord11(entry) || typeof entry.product !== "string")
52170
+ return [];
52171
+ const usagePercent = finitePercent(entry.usagePercent);
52172
+ return usagePercent === void 0 ? [] : [{ product: entry.product, usagePercent }];
52173
+ });
52174
+ return products.length > 0 ? products : void 0;
52175
+ }
52176
+ function parseGrokCreditsResponse(value, fetchedAt = (/* @__PURE__ */ new Date()).toISOString()) {
52177
+ if (!isRecord11(value) || !isRecord11(value.config))
52178
+ return null;
52179
+ const config2 = value.config;
52180
+ const period = isRecord11(config2.currentPeriod) ? config2.currentPeriod : void 0;
52181
+ const resetsAt = (typeof period?.end === "string" && period.end.length > 0 ? period.end : void 0) ?? (typeof config2.billingPeriodEnd === "string" && config2.billingPeriodEnd.length > 0 ? config2.billingPeriodEnd : void 0);
52182
+ const onDemandCap = isRecord11(config2.onDemandCap) ? nonNegativeNumber(config2.onDemandCap.val) : void 0;
52183
+ const onDemandUsed = isRecord11(config2.onDemandUsed) ? nonNegativeNumber(config2.onDemandUsed.val) : void 0;
52184
+ const usedPercent = finitePercent(config2.creditUsagePercent) ?? (onDemandCap !== void 0 && onDemandCap > 0 && onDemandUsed !== void 0 ? Math.min(100, Math.max(0, onDemandUsed / onDemandCap * 100)) : resetsAt ? 0 : void 0);
52185
+ if (usedPercent === void 0)
52186
+ return null;
52187
+ const productUsage = productUsageFrom(config2.productUsage);
52188
+ return {
52189
+ usedPercent,
52190
+ periodType: periodTypeFrom(period?.type),
52191
+ fetchedAt,
52192
+ ...resetsAt ? { resetsAt } : {},
52193
+ ...productUsage ? { productUsage } : {}
52194
+ };
52195
+ }
52196
+ function selectAccessToken(auth, now) {
52197
+ if (!isRecord11(auth))
52198
+ return null;
52199
+ const entries = Object.entries(auth).filter(([, value]) => isRecord11(value) && typeof value.key === "string" && value.key.length > 0).sort(([left], [right]) => Number(right.startsWith("https://auth.x.ai")) - Number(left.startsWith("https://auth.x.ai")));
52200
+ for (const [, value] of entries) {
52201
+ if (!isRecord11(value) || typeof value.key !== "string")
52202
+ continue;
52203
+ if (typeof value.expires_at === "string") {
52204
+ const expiresAt = Date.parse(value.expires_at);
52205
+ if (Number.isFinite(expiresAt) && expiresAt <= now.getTime())
52206
+ continue;
52207
+ }
52208
+ return value.key;
52209
+ }
52210
+ return null;
52211
+ }
52212
+ async function fetchGrokCredits(input = {}) {
52213
+ try {
52214
+ const environment = input.environment ?? process.env;
52215
+ const now = input.now ?? /* @__PURE__ */ new Date();
52216
+ const authPath = path9.join(grokHome(environment), "auth.json");
52217
+ const raw = input.readAuthFile ? await input.readAuthFile(authPath) : await readFile2(authPath, "utf8");
52218
+ const token = selectAccessToken(JSON.parse(raw), now);
52219
+ if (!token)
52220
+ return null;
52221
+ const fetchImpl = input.fetch ?? fetch;
52222
+ const response = await fetchImpl(GROK_CREDITS_ENDPOINT, {
52223
+ method: "GET",
52224
+ headers: {
52225
+ Authorization: `Bearer ${token}`,
52226
+ "x-xai-token-auth": "xai-grok-cli",
52227
+ Accept: "application/json"
52228
+ },
52229
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
52230
+ });
52231
+ if (!response.ok)
52232
+ return null;
52233
+ return parseGrokCreditsResponse(await response.json(), now.toISOString());
52234
+ } catch {
52235
+ return null;
52236
+ }
52237
+ }
52238
+
52127
52239
  // packages/adapters/grok/dist/grok-usage.js
52128
52240
  var USD_TICKS_PER_DOLLAR = 1e10;
52129
- function isRecord11(value) {
52241
+ function isRecord12(value) {
52130
52242
  return typeof value === "object" && value !== null && !Array.isArray(value);
52131
52243
  }
52132
52244
  function optionalToken(value) {
@@ -52143,7 +52255,7 @@ function combineUsage(base, next) {
52143
52255
  return base === null ? next : parseHostUsage({ ...base, ...next });
52144
52256
  }
52145
52257
  function usageFromNative(value) {
52146
- if (!isRecord11(value))
52258
+ if (!isRecord12(value))
52147
52259
  return null;
52148
52260
  const inputTokens = optionalToken(value.inputTokens);
52149
52261
  const cachedRead = optionalToken(value.cachedReadTokens);
@@ -52170,7 +52282,7 @@ function usageFromPrompt(response) {
52170
52282
  return response.usage ? usageFromNative(response.usage) : null;
52171
52283
  }
52172
52284
  function usageFromSignals(value) {
52173
- if (!isRecord11(value))
52285
+ if (!isRecord12(value))
52174
52286
  return null;
52175
52287
  try {
52176
52288
  return parseHostUsage({
@@ -52181,21 +52293,80 @@ function usageFromSignals(value) {
52181
52293
  return null;
52182
52294
  }
52183
52295
  }
52184
- function lastTurnUsage(events) {
52185
- for (let index = events.length - 1; index >= 0; index -= 1) {
52186
- const event = events[index];
52296
+ var summedUsageFields = [
52297
+ "inputTokens",
52298
+ "cachedInputTokens",
52299
+ "cacheWriteInputTokens",
52300
+ "outputTokens",
52301
+ "reasoningOutputTokens",
52302
+ "totalTokens"
52303
+ ];
52304
+ function nativeCostTicks(value) {
52305
+ if (!isRecord12(value))
52306
+ return void 0;
52307
+ const ticks = value.costUsdTicks;
52308
+ if (typeof ticks !== "number" || !Number.isSafeInteger(ticks) || ticks < 0)
52309
+ return void 0;
52310
+ return ticks;
52311
+ }
52312
+ function historyTurnKey(event, index) {
52313
+ const key = event.nativeTurnKey;
52314
+ if (typeof key === "string" && key.startsWith("task-completed-"))
52315
+ return null;
52316
+ return typeof key === "string" && key.length > 0 ? key : `anon-${index}`;
52317
+ }
52318
+ function sessionUsageFromHistory(events) {
52319
+ const latestByKey = /* @__PURE__ */ new Map();
52320
+ let lastCacheHitRatePercent;
52321
+ let index = 0;
52322
+ for (const event of events) {
52187
52323
  if (event?.type !== "turn.completed")
52188
52324
  continue;
52325
+ const key = historyTurnKey(event, index);
52326
+ index += 1;
52327
+ if (key === null)
52328
+ continue;
52189
52329
  const usage = usageFromNative(event.usage);
52190
- if (usage)
52191
- return usage;
52330
+ if (!usage)
52331
+ continue;
52332
+ const ticks2 = nativeCostTicks(event.usage);
52333
+ latestByKey.set(key, ticks2 === void 0 ? { usage } : { usage, ticks: ticks2 });
52334
+ if (usage.cacheHitRatePercent !== void 0) {
52335
+ lastCacheHitRatePercent = usage.cacheHitRatePercent;
52336
+ }
52337
+ }
52338
+ if (latestByKey.size === 0)
52339
+ return null;
52340
+ const totals = {};
52341
+ let ticks = 0;
52342
+ let hasTicks = false;
52343
+ for (const entry of latestByKey.values()) {
52344
+ for (const field of summedUsageFields) {
52345
+ const value = entry.usage[field];
52346
+ if (value === void 0)
52347
+ continue;
52348
+ totals[field] = (totals[field] ?? 0) + value;
52349
+ }
52350
+ if (entry.ticks === void 0)
52351
+ continue;
52352
+ ticks += entry.ticks;
52353
+ hasTicks = true;
52354
+ }
52355
+ const totalCostUsd = hasTicks ? optionalCostUsd(ticks) : void 0;
52356
+ try {
52357
+ return parseHostUsage({
52358
+ ...totals,
52359
+ ...totalCostUsd !== void 0 ? { totalCostUsd } : {},
52360
+ ...lastCacheHitRatePercent !== void 0 ? { cacheHitRatePercent: lastCacheHitRatePercent } : {}
52361
+ });
52362
+ } catch {
52363
+ return null;
52192
52364
  }
52193
- return null;
52194
52365
  }
52195
52366
  function usageFromUpdate(update, metadata, contextWindowTokens) {
52196
52367
  try {
52197
52368
  if (update?.sessionUpdate === "usage_update") {
52198
- const cost = isRecord11(update.cost) ? update.cost : null;
52369
+ const cost = isRecord12(update.cost) ? update.cost : null;
52199
52370
  return parseHostUsage({
52200
52371
  contextUsedTokens: update.used,
52201
52372
  contextWindowTokens: update.size,
@@ -52229,7 +52400,7 @@ function capabilitiesForModels(modelState) {
52229
52400
  }
52230
52401
  var DEFAULT_CLOSE_TIMEOUT_MS3 = 2e3;
52231
52402
  var DEFAULT_TOOL_OUTPUT_LIMIT3 = 64e3;
52232
- function isRecord12(value) {
52403
+ function isRecord13(value) {
52233
52404
  return typeof value === "object" && value !== null && !Array.isArray(value);
52234
52405
  }
52235
52406
  function invalidState3(message3) {
@@ -52264,7 +52435,7 @@ function contentText2(content) {
52264
52435
  if (!content)
52265
52436
  return "";
52266
52437
  return content.flatMap((entry) => {
52267
- if (!isRecord12(entry) || entry.type !== "content" || !isRecord12(entry.content))
52438
+ if (!isRecord13(entry) || entry.type !== "content" || !isRecord13(entry.content))
52268
52439
  return [];
52269
52440
  return entry.content.type === "text" && typeof entry.content.text === "string" ? [entry.content.text] : [];
52270
52441
  }).join("\n");
@@ -52318,6 +52489,7 @@ var GrokHarnessSession = class {
52318
52489
  #cwd;
52319
52490
  #modelState;
52320
52491
  #onClosed;
52492
+ #refreshCredits;
52321
52493
  #randomUUID;
52322
52494
  #snapshot;
52323
52495
  #toolOutputLimit;
@@ -52333,6 +52505,7 @@ var GrokHarnessSession = class {
52333
52505
  this.#transport = transport;
52334
52506
  this.#modelState = modelState;
52335
52507
  this.#onClosed = onClosed;
52508
+ this.#refreshCredits = options.refreshCredits;
52336
52509
  this.#closeTimeoutMs = options.closeTimeoutMs;
52337
52510
  this.#randomUUID = options.randomUUID;
52338
52511
  this.#toolOutputLimit = options.toolOutputLimit;
@@ -52599,11 +52772,7 @@ var GrokHarnessSession = class {
52599
52772
  this.#startTool(active, event);
52600
52773
  else if (event.type === "tool.update")
52601
52774
  this.#updateTool(active, event);
52602
- else if (event.type === "turn.completed") {
52603
- const usage = usageFromNative(event.usage);
52604
- if (usage)
52605
- this.#publishUsage(usage, active.command.turnId);
52606
- } else if (event.type === "usage")
52775
+ else if (event.type === "usage" || event.type === "turn.completed")
52607
52776
  return;
52608
52777
  }
52609
52778
  #appendAgent(active, text, messageId) {
@@ -52740,7 +52909,8 @@ var GrokHarnessSession = class {
52740
52909
  outcome = { status: "failed", error: normalizeError(error52, "protocolError") };
52741
52910
  }
52742
52911
  }
52743
- this.#finish(active, outcome, lastTurnUsage(history) ?? (response ? usageFromPrompt(response) : null), nativeTurnRef2);
52912
+ await this.#refreshCredits().catch(() => void 0);
52913
+ this.#finish(active, outcome, sessionUsageFromHistory(history) ?? (response ? usageFromPrompt(response) : null), nativeTurnRef2);
52744
52914
  }
52745
52915
  #finish(active, outcome, usage = null, nativeTurnRef2) {
52746
52916
  if (this.#active !== active)
@@ -52827,22 +52997,53 @@ var GrokAdapter = class {
52827
52997
  harnessId = grokHarnessId;
52828
52998
  #closeTimeoutMs;
52829
52999
  #dependencies;
53000
+ #environment;
53001
+ #fetchCredits;
52830
53002
  #inspectionCache = /* @__PURE__ */ new Map();
52831
53003
  #sessions = /* @__PURE__ */ new Set();
52832
53004
  #toolOutputLimit;
52833
53005
  #closePromise = null;
53006
+ #credits = null;
53007
+ #creditsRefresh = null;
52834
53008
  constructor(options = {}, dependencies) {
52835
53009
  this.#closeTimeoutMs = options.closeTimeoutMs ?? DEFAULT_CLOSE_TIMEOUT_MS3;
53010
+ this.#environment = options.environment;
52836
53011
  this.#toolOutputLimit = options.toolOutputLimit ?? DEFAULT_TOOL_OUTPUT_LIMIT3;
52837
53012
  this.#dependencies = dependencies ?? {
52838
53013
  randomUUID: randomUUID3,
52839
53014
  createTransport: (transportOptions) => new GrokAcpTransport({ ...options, ...transportOptions })
52840
53015
  };
53016
+ this.#fetchCredits = this.#dependencies.fetchCredits ?? ((input) => fetchGrokCredits(input.environment ? { environment: input.environment } : this.#environment ? { environment: this.#environment } : {}));
53017
+ }
53018
+ credits() {
53019
+ return this.#credits;
53020
+ }
53021
+ refreshCredits() {
53022
+ if (this.#closePromise)
53023
+ return Promise.resolve(this.#credits);
53024
+ if (this.#creditsRefresh)
53025
+ return this.#creditsRefresh;
53026
+ this.#creditsRefresh = this.#loadCredits().finally(() => {
53027
+ this.#creditsRefresh = null;
53028
+ });
53029
+ return this.#creditsRefresh;
53030
+ }
53031
+ #scheduleCreditsRefresh() {
53032
+ void this.refreshCredits();
53033
+ }
53034
+ async #loadCredits() {
53035
+ try {
53036
+ const snapshot = await this.#fetchCredits(this.#environment ? { environment: this.#environment } : {});
53037
+ if (snapshot)
53038
+ this.#credits = snapshot;
53039
+ } catch {
53040
+ }
53041
+ return this.#credits;
52841
53042
  }
52842
53043
  async inspect(input = {}) {
52843
53044
  if (this.#closePromise)
52844
53045
  return { status: "unavailable", error: invalidState3("Grok Adapter is closed") };
52845
- const cwd = path9.resolve(input.cwd ?? process.cwd());
53046
+ const cwd = path10.resolve(input.cwd ?? process.cwd());
52846
53047
  if (!input.refresh) {
52847
53048
  const cached2 = this.#inspectionCache.get(cwd);
52848
53049
  if (cached2)
@@ -52862,6 +53063,7 @@ var GrokAdapter = class {
52862
53063
  capabilities: capabilitiesForModels(modelState)
52863
53064
  };
52864
53065
  this.#inspectionCache.set(cwd, ready);
53066
+ this.#scheduleCreditsRefresh();
52865
53067
  return ready;
52866
53068
  } catch (error52) {
52867
53069
  await transport?.close().catch(() => void 0);
@@ -52900,7 +53102,7 @@ var GrokAdapter = class {
52900
53102
  }
52901
53103
  };
52902
53104
  }
52903
- const cwd = path9.resolve(input.cwd);
53105
+ const cwd = path10.resolve(input.cwd);
52904
53106
  const parsedRef = input.kind === "resume" ? nativeSessionRefSchema.safeParse(input.nativeRef) : null;
52905
53107
  if (parsedRef && (!parsedRef.success || parsedRef.data.harnessId !== this.harnessId)) {
52906
53108
  return {
@@ -52938,17 +53140,19 @@ var GrokAdapter = class {
52938
53140
  }
52939
53141
  }
52940
53142
  const history = await transport.getHistory();
52941
- const initialUsage = input.kind === "resume" ? combineUsage(lastTurnUsage(history), usageFromSignals(opened.signals)) : null;
53143
+ const initialUsage = input.kind === "resume" ? combineUsage(sessionUsageFromHistory(history), usageFromSignals(opened.signals)) : null;
52942
53144
  const openedSession = new GrokHarnessSession(cwd, transport, opened, modelState, () => this.#sessions.delete(openedSession), {
52943
53145
  closeTimeoutMs: this.#closeTimeoutMs,
52944
53146
  history,
52945
53147
  initialUsage,
52946
53148
  ...input.kind === "resume" && input.knownTurnRefs ? { knownTurnRefs: input.knownTurnRefs } : {},
52947
53149
  randomUUID: this.#dependencies.randomUUID,
53150
+ refreshCredits: () => this.refreshCredits(),
52948
53151
  toolOutputLimit: this.#toolOutputLimit
52949
53152
  });
52950
53153
  session = openedSession;
52951
53154
  this.#sessions.add(openedSession);
53155
+ this.#scheduleCreditsRefresh();
52952
53156
  return { ok: true, value: openedSession };
52953
53157
  } catch (error52) {
52954
53158
  await transport.close().catch(() => void 0);
@@ -53086,7 +53290,7 @@ function normalizePiModelCatalog(nativeModels, effectiveModel, thinkingLevels, e
53086
53290
 
53087
53291
  // packages/adapters/pi/dist/pi-history.js
53088
53292
  var piHarnessId = harnessIdSchema.parse("pi");
53089
- function isRecord13(value) {
53293
+ function isRecord14(value) {
53090
53294
  return typeof value === "object" && value !== null && !Array.isArray(value);
53091
53295
  }
53092
53296
  function textContent(value) {
@@ -53094,12 +53298,12 @@ function textContent(value) {
53094
53298
  return value;
53095
53299
  if (!Array.isArray(value))
53096
53300
  return "";
53097
- return value.filter((part) => isRecord13(part) && part.type === "text" && typeof part.text === "string").map((part) => part.text).join("");
53301
+ return value.filter((part) => isRecord14(part) && part.type === "text" && typeof part.text === "string").map((part) => part.text).join("");
53098
53302
  }
53099
53303
  function thinkingContent(value) {
53100
53304
  if (!Array.isArray(value))
53101
53305
  return "";
53102
- return value.filter((part) => isRecord13(part) && part.type === "thinking" && typeof part.thinking === "string").map((part) => part.thinking).join("");
53306
+ return value.filter((part) => isRecord14(part) && part.type === "thinking" && typeof part.thinking === "string").map((part) => part.thinking).join("");
53103
53307
  }
53104
53308
  function validatedEntry(value) {
53105
53309
  if (typeof value.id !== "string" || value.id.length === 0 || value.parentId !== null && typeof value.parentId !== "string" || typeof value.type !== "string") {
@@ -53130,7 +53334,7 @@ function activePiEntries(history) {
53130
53334
  return reversed.reverse();
53131
53335
  }
53132
53336
  function message(entry) {
53133
- return entry.type === "message" && isRecord13(entry.message) ? entry.message : null;
53337
+ return entry.type === "message" && isRecord14(entry.message) ? entry.message : null;
53134
53338
  }
53135
53339
  function messageRole(entry) {
53136
53340
  const value = message(entry)?.role;
@@ -53192,7 +53396,7 @@ function snapshotItems(entries, outcome) {
53192
53396
  let projectedText = false;
53193
53397
  let projectedReasoning = false;
53194
53398
  for (const [ordinal, part] of content.entries()) {
53195
- if (!isRecord13(part))
53399
+ if (!isRecord14(part))
53196
53400
  continue;
53197
53401
  if (part.type === "thinking" && !projectedReasoning && reasoning.length > 0) {
53198
53402
  const item2 = {
@@ -53384,12 +53588,12 @@ async function rollbackPiLastTurn(transport, sourceSessionId, cwd) {
53384
53588
  // packages/adapters/pi/dist/pi-rpc-session.js
53385
53589
  import { spawn as spawn4, spawnSync as spawnSync2 } from "node:child_process";
53386
53590
  import { randomUUID as randomUUID4 } from "node:crypto";
53387
- import path11 from "node:path";
53591
+ import path12 from "node:path";
53388
53592
 
53389
53593
  // packages/adapters/pi/dist/command.js
53390
53594
  import { accessSync as accessSync2, constants as constants2, readdirSync as readdirSync2, statSync as statSync3 } from "node:fs";
53391
- import os4 from "node:os";
53392
- import path10 from "node:path";
53595
+ import os5 from "node:os";
53596
+ import path11 from "node:path";
53393
53597
  function environmentValue2(environment, name) {
53394
53598
  return Object.entries(environment).find(([key]) => key.toLowerCase() === name.toLowerCase())?.[1];
53395
53599
  }
@@ -53402,34 +53606,35 @@ function isExecutable3(filePath, platform) {
53402
53606
  }
53403
53607
  }
53404
53608
  function pathCandidates(command, platform, environment) {
53405
- const targetPath = platform === "win32" ? path10.win32 : path10.posix;
53609
+ const targetPath = platform === "win32" ? path11.win32 : path11.posix;
53406
53610
  if (targetPath.isAbsolute(command) || command.includes("/") || command.includes("\\")) {
53407
53611
  return [command];
53408
53612
  }
53409
53613
  const extensions = platform === "win32" && targetPath.extname(command) === "" ? (environmentValue2(environment, "PATHEXT") ?? ".COM;.EXE;.BAT;.CMD").split(";").map((extension) => extension.trim()).filter(Boolean) : [""];
53410
53614
  return (environmentValue2(environment, "PATH") ?? "").split(targetPath.delimiter).map((directory) => directory.trim().replace(/^"|"$/gu, "")).filter(Boolean).flatMap((directory) => extensions.map((extension) => targetPath.join(directory, command + extension)));
53411
53615
  }
53412
- function nvmCandidates2(homeDirectory, executableName) {
53413
- const versionsDirectory = path10.join(homeDirectory, ".nvm", "versions", "node");
53616
+ function nvmCandidates2(homeDirectory, executableName, targetPath) {
53617
+ const versionsDirectory = targetPath.join(homeDirectory, ".nvm", "versions", "node");
53414
53618
  try {
53415
- return readdirSync2(versionsDirectory, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort((left, right) => right.localeCompare(left, void 0, { numeric: true })).map((version2) => path10.join(versionsDirectory, version2, "bin", executableName));
53619
+ return readdirSync2(versionsDirectory, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort((left, right) => right.localeCompare(left, void 0, { numeric: true })).map((version2) => targetPath.join(versionsDirectory, version2, "bin", executableName));
53416
53620
  } catch {
53417
53621
  return [];
53418
53622
  }
53419
53623
  }
53420
53624
  function userInstallCandidates2(platform, environment, homeDirectory) {
53625
+ const targetPath = platform === "win32" ? path11.win32 : path11.posix;
53421
53626
  if (platform === "win32") {
53422
- const appData = environment.APPDATA ?? path10.join(homeDirectory, "AppData", "Roaming");
53627
+ const appData = environment.APPDATA ?? targetPath.join(homeDirectory, "AppData", "Roaming");
53423
53628
  return [
53424
- path10.join(appData, "npm", "pi.cmd"),
53425
- path10.join(homeDirectory, ".local", "bin", "pi.exe"),
53426
- path10.join(homeDirectory, ".local", "bin", "pi.cmd")
53629
+ targetPath.join(appData, "npm", "pi.cmd"),
53630
+ targetPath.join(homeDirectory, ".local", "bin", "pi.exe"),
53631
+ targetPath.join(homeDirectory, ".local", "bin", "pi.cmd")
53427
53632
  ];
53428
53633
  }
53429
53634
  return [
53430
- path10.join(homeDirectory, ".npm-global", "bin", "pi"),
53431
- path10.join(homeDirectory, ".local", "bin", "pi"),
53432
- ...nvmCandidates2(homeDirectory, "pi"),
53635
+ targetPath.join(homeDirectory, ".npm-global", "bin", "pi"),
53636
+ targetPath.join(homeDirectory, ".local", "bin", "pi"),
53637
+ ...nvmCandidates2(homeDirectory, "pi", targetPath),
53433
53638
  "/opt/homebrew/bin/pi",
53434
53639
  "/usr/local/bin/pi"
53435
53640
  ];
@@ -53438,7 +53643,7 @@ function resolvePiExecutable(input, dependencies = {}) {
53438
53643
  const platform = dependencies.platform ?? process.platform;
53439
53644
  const configuredCommand = input.command ?? input.environment.PI_COMMAND;
53440
53645
  const command = configuredCommand ?? "pi";
53441
- const homeDirectory = dependencies.homeDirectory ?? input.environment.HOME ?? input.environment.USERPROFILE ?? os4.homedir();
53646
+ const homeDirectory = dependencies.homeDirectory ?? input.environment.HOME ?? input.environment.USERPROFILE ?? os5.homedir();
53442
53647
  const candidates2 = [
53443
53648
  ...pathCandidates(command, platform, input.environment),
53444
53649
  ...configuredCommand ? [] : userInstallCandidates2(platform, input.environment, homeDirectory)
@@ -53449,7 +53654,7 @@ function resolvePiExecutable(input, dependencies = {}) {
53449
53654
  function withNodeRuntimeOnPath2(environment, runtimeExecutable = process.execPath, platform = process.platform) {
53450
53655
  const pathKey = Object.keys(environment).find((name) => name.toLowerCase() === "path") ?? "PATH";
53451
53656
  const delimiter = platform === "win32" ? ";" : ":";
53452
- const runtimeDirectory = path10.dirname(runtimeExecutable);
53657
+ const runtimeDirectory = path11.dirname(runtimeExecutable);
53453
53658
  const directories = (environment[pathKey] ?? "").split(delimiter).filter(Boolean);
53454
53659
  const equal = platform === "win32" ? (value) => value.toLowerCase() : (value) => value;
53455
53660
  if (!directories.some((directory) => equal(directory) === equal(runtimeDirectory))) {
@@ -53459,14 +53664,14 @@ function withNodeRuntimeOnPath2(environment, runtimeExecutable = process.execPat
53459
53664
  }
53460
53665
 
53461
53666
  // packages/adapters/pi/dist/pi-usage.js
53462
- function isRecord14(value) {
53667
+ function isRecord15(value) {
53463
53668
  return typeof value === "object" && value !== null && !Array.isArray(value);
53464
53669
  }
53465
53670
  function nonNegativeSafeInteger2(value) {
53466
53671
  return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : null;
53467
53672
  }
53468
53673
  function optionalPiCacheHitRatePercent(value) {
53469
- if (!isRecord14(value) || value.role !== "assistant" || !isRecord14(value.usage))
53674
+ if (!isRecord15(value) || value.role !== "assistant" || !isRecord15(value.usage))
53470
53675
  return null;
53471
53676
  const input = nonNegativeSafeInteger2(value.usage.input);
53472
53677
  const cacheRead = nonNegativeSafeInteger2(value.usage.cacheRead);
@@ -53479,20 +53684,20 @@ function optionalPiCacheHitRatePercent(value) {
53479
53684
  function latestPiCacheHitRatePercent(history) {
53480
53685
  let latest = null;
53481
53686
  for (const entry of activePiEntries(history)) {
53482
- if (entry.type === "message" && isRecord14(entry.message) && entry.message.role === "assistant") {
53687
+ if (entry.type === "message" && isRecord15(entry.message) && entry.message.role === "assistant") {
53483
53688
  latest = optionalPiCacheHitRatePercent(entry.message);
53484
53689
  }
53485
53690
  }
53486
53691
  return latest;
53487
53692
  }
53488
53693
  function responseData(response, operation) {
53489
- if (!isRecord14(response.data)) {
53694
+ if (!isRecord15(response.data)) {
53490
53695
  throw new Error(`Pi RPC ${operation} response has no data`);
53491
53696
  }
53492
53697
  return response.data;
53493
53698
  }
53494
53699
  function contextUsage(value) {
53495
- if (!isRecord14(value))
53700
+ if (!isRecord15(value))
53496
53701
  throw new Error("Pi RPC context Usage is invalid");
53497
53702
  return parseHostUsage({
53498
53703
  contextUsedTokens: value.tokens,
@@ -53502,15 +53707,15 @@ function contextUsage(value) {
53502
53707
  function parsePiSessionUsage(response) {
53503
53708
  const data = responseData(response, "Session stats");
53504
53709
  const tokens = data.tokens;
53505
- if (tokens !== void 0 && !isRecord14(tokens)) {
53710
+ if (tokens !== void 0 && !isRecord15(tokens)) {
53506
53711
  throw new Error("Pi RPC Session stats tokens are invalid");
53507
53712
  }
53508
53713
  return parseHostUsage({
53509
- ...isRecord14(tokens) && tokens.input !== void 0 ? { inputTokens: tokens.input } : {},
53510
- ...isRecord14(tokens) && tokens.cacheRead !== void 0 ? { cachedInputTokens: tokens.cacheRead } : {},
53511
- ...isRecord14(tokens) && tokens.cacheWrite !== void 0 ? { cacheWriteInputTokens: tokens.cacheWrite } : {},
53512
- ...isRecord14(tokens) && tokens.output !== void 0 ? { outputTokens: tokens.output } : {},
53513
- ...isRecord14(tokens) && tokens.total !== void 0 ? { totalTokens: tokens.total } : {},
53714
+ ...isRecord15(tokens) && tokens.input !== void 0 ? { inputTokens: tokens.input } : {},
53715
+ ...isRecord15(tokens) && tokens.cacheRead !== void 0 ? { cachedInputTokens: tokens.cacheRead } : {},
53716
+ ...isRecord15(tokens) && tokens.cacheWrite !== void 0 ? { cacheWriteInputTokens: tokens.cacheWrite } : {},
53717
+ ...isRecord15(tokens) && tokens.output !== void 0 ? { outputTokens: tokens.output } : {},
53718
+ ...isRecord15(tokens) && tokens.total !== void 0 ? { totalTokens: tokens.total } : {},
53514
53719
  ...data.cost !== void 0 ? { totalCostUsd: data.cost } : {},
53515
53720
  ...data.contextUsage !== void 0 ? contextUsage(data.contextUsage) : {}
53516
53721
  });
@@ -53533,7 +53738,7 @@ function optionalPiStateContextUsage(value) {
53533
53738
  import { open, realpath } from "node:fs/promises";
53534
53739
  var MAX_SESSION_HEADER_BYTES = 64 * 1024;
53535
53740
  var utf8Decoder = new TextDecoder("utf-8", { fatal: true });
53536
- function isRecord15(value) {
53741
+ function isRecord16(value) {
53537
53742
  return typeof value === "object" && value !== null && !Array.isArray(value);
53538
53743
  }
53539
53744
  async function readPiSessionHeader(sessionFile) {
@@ -53553,7 +53758,7 @@ async function readPiSessionHeader(sessionFile) {
53553
53758
  } catch {
53554
53759
  throw new Error("Pi Session header is not valid JSON");
53555
53760
  }
53556
- if (!isRecord15(parsed) || parsed.type !== "session" || typeof parsed.id !== "string" || parsed.id.length === 0 || typeof parsed.cwd !== "string" || parsed.cwd.length === 0) {
53761
+ if (!isRecord16(parsed) || parsed.type !== "session" || typeof parsed.id !== "string" || parsed.id.length === 0 || typeof parsed.cwd !== "string" || parsed.cwd.length === 0) {
53557
53762
  throw new Error("Pi Session header is invalid");
53558
53763
  }
53559
53764
  return { type: "session", id: parsed.id, cwd: parsed.cwd };
@@ -53595,7 +53800,7 @@ var PiRpcUnsupportedCommandError = class extends Error {
53595
53800
  }
53596
53801
  };
53597
53802
  var textDecoder = new TextDecoder("utf-8", { fatal: true });
53598
- function isRecord16(value) {
53803
+ function isRecord17(value) {
53599
53804
  return typeof value === "object" && value !== null && !Array.isArray(value);
53600
53805
  }
53601
53806
  function message2(value) {
@@ -53607,13 +53812,13 @@ function nonBlankString2(value) {
53607
53812
  function parseNativeModel(value, context) {
53608
53813
  if (value === null || value === void 0)
53609
53814
  return null;
53610
- if (!isRecord16(value) || !nonBlankString2(value.provider) || !nonBlankString2(value.id)) {
53815
+ if (!isRecord17(value) || !nonBlankString2(value.provider) || !nonBlankString2(value.id)) {
53611
53816
  throw new PiRpcFaultError("protocolError", `Pi RPC returned an invalid ${context} Model`);
53612
53817
  }
53613
53818
  return { provider: value.provider, id: value.id };
53614
53819
  }
53615
53820
  function sessionStateData(response) {
53616
- const data = isRecord16(response.data) ? response.data : null;
53821
+ const data = isRecord17(response.data) ? response.data : null;
53617
53822
  if (!data)
53618
53823
  throw new PiRpcFaultError("protocolError", "Pi RPC state response has no data");
53619
53824
  return data;
@@ -53645,13 +53850,13 @@ function parseSessionStreaming(response) {
53645
53850
  return isStreaming;
53646
53851
  }
53647
53852
  function parseSessionHistory(response) {
53648
- const data = isRecord16(response.data) ? response.data : null;
53853
+ const data = isRecord17(response.data) ? response.data : null;
53649
53854
  if (!data || !Array.isArray(data.entries)) {
53650
53855
  throw new PiRpcFaultError("protocolError", "Pi RPC entries response has no Entries");
53651
53856
  }
53652
53857
  const entries = data.entries.map((entry) => {
53653
53858
  const parsed = jsonValueSchema.safeParse(entry);
53654
- if (!parsed.success || !isRecord16(parsed.data)) {
53859
+ if (!parsed.success || !isRecord17(parsed.data)) {
53655
53860
  throw new PiRpcFaultError("protocolError", "Pi RPC entries response contains an invalid Entry");
53656
53861
  }
53657
53862
  return parsed.data;
@@ -53662,7 +53867,7 @@ function parseSessionHistory(response) {
53662
53867
  return { entries, leafId: data.leafId };
53663
53868
  }
53664
53869
  function parseAvailableThinkingLevels(response) {
53665
- const data = isRecord16(response.data) ? response.data : null;
53870
+ const data = isRecord17(response.data) ? response.data : null;
53666
53871
  if (!data || !Array.isArray(data.levels) || data.levels.length === 0) {
53667
53872
  throw new PiRpcFaultError("protocolError", "Pi RPC Thinking catalog response has no levels");
53668
53873
  }
@@ -53679,35 +53884,35 @@ function parseAvailableThinkingLevels(response) {
53679
53884
  return levels;
53680
53885
  }
53681
53886
  function parseAvailableModels(response) {
53682
- const data = isRecord16(response.data) ? response.data : null;
53887
+ const data = isRecord17(response.data) ? response.data : null;
53683
53888
  if (!data || !Array.isArray(data.models)) {
53684
53889
  throw new PiRpcFaultError("protocolError", "Pi RPC Model catalog response has no models");
53685
53890
  }
53686
53891
  return data.models.map((model) => {
53687
53892
  const parsed = parseNativeModel(model, "catalog");
53688
- if (!parsed || !isRecord16(model) || typeof model.reasoning !== "boolean") {
53893
+ if (!parsed || !isRecord17(model) || typeof model.reasoning !== "boolean") {
53689
53894
  throw new PiRpcFaultError("protocolError", "Pi RPC catalog contains a Model without reasoning capability");
53690
53895
  }
53691
53896
  return { ...parsed, reasoning: model.reasoning };
53692
53897
  });
53693
53898
  }
53694
53899
  function assistantText2(value) {
53695
- if (!isRecord16(value) || value.role !== "assistant" || !Array.isArray(value.content))
53900
+ if (!isRecord17(value) || value.role !== "assistant" || !Array.isArray(value.content))
53696
53901
  return null;
53697
- return value.content.filter((content) => isRecord16(content) && content.type === "text" && typeof content.text === "string").map((content) => content.text).join("");
53902
+ return value.content.filter((content) => isRecord17(content) && content.type === "text" && typeof content.text === "string").map((content) => content.text).join("");
53698
53903
  }
53699
53904
  function assistantMessageId(value) {
53700
- if (!isRecord16(value) || value.role !== "assistant")
53905
+ if (!isRecord17(value) || value.role !== "assistant")
53701
53906
  return null;
53702
53907
  return nonBlankString2(value.responseId) ? value.responseId : null;
53703
53908
  }
53704
53909
  function assistantReasoning(value) {
53705
- if (!isRecord16(value) || value.role !== "assistant" || !Array.isArray(value.content))
53910
+ if (!isRecord17(value) || value.role !== "assistant" || !Array.isArray(value.content))
53706
53911
  return null;
53707
- return value.content.filter((content) => isRecord16(content) && content.type === "thinking" && typeof content.thinking === "string").map((content) => content.thinking).join("");
53912
+ return value.content.filter((content) => isRecord17(content) && content.type === "thinking" && typeof content.thinking === "string").map((content) => content.thinking).join("");
53708
53913
  }
53709
53914
  function assistantFailure(value) {
53710
- if (!isRecord16(value) || value.role !== "assistant")
53915
+ if (!isRecord17(value) || value.role !== "assistant")
53711
53916
  return void 0;
53712
53917
  if (value.stopReason !== "error" && value.stopReason !== "aborted")
53713
53918
  return null;
@@ -53727,7 +53932,7 @@ function signalProcessTree2(child, signal) {
53727
53932
  try {
53728
53933
  process.kill(-child.pid, signal);
53729
53934
  } catch (error52) {
53730
- if (!isRecord16(error52) || error52.code !== "ESRCH")
53935
+ if (!isRecord17(error52) || error52.code !== "ESRCH")
53731
53936
  throw error52;
53732
53937
  }
53733
53938
  }
@@ -53758,7 +53963,7 @@ function piRpcProcessCommand(options, dependencies = {}) {
53758
53963
  const sessionArguments = options.forkSessionFile ? ["--fork", options.forkSessionFile] : options.sessionFile ? ["--session", options.sessionFile] : [];
53759
53964
  const modelArguments = options.model ? ["--provider", options.model.provider, "--model", options.model.id] : [];
53760
53965
  const arguments_2 = ["--mode", "rpc", ...modelArguments, ...sessionArguments];
53761
- const extension = path11.win32.extname(command).toLowerCase();
53966
+ const extension = path12.win32.extname(command).toLowerCase();
53762
53967
  if (platform !== "win32" || ![".cmd", ".bat"].includes(extension)) {
53763
53968
  return { command, arguments: arguments_2, windowsVerbatimArguments: false };
53764
53969
  }
@@ -53841,7 +54046,7 @@ var PiRpcSession = class {
53841
54046
  });
53842
54047
  child.stderr.resume();
53843
54048
  child.once("error", (error52) => {
53844
- const kind = isRecord16(error52) && error52.code === "ENOENT" ? "notInstalled" : "unavailable";
54049
+ const kind = isRecord17(error52) && error52.code === "ENOENT" ? "notInstalled" : "unavailable";
53845
54050
  this.#fail(new PiRpcFaultError(kind, `Pi RPC failed to start: ${error52.message}`));
53846
54051
  });
53847
54052
  child.once("exit", (code, signal) => {
@@ -54093,7 +54298,7 @@ var PiRpcSession = class {
54093
54298
  this.#buffer = this.#buffer.subarray(newline3 + 1);
54094
54299
  try {
54095
54300
  const value = JSON.parse(textDecoder.decode(frame));
54096
- if (!isRecord16(value) || typeof value.type !== "string") {
54301
+ if (!isRecord17(value) || typeof value.type !== "string") {
54097
54302
  throw new PiRpcFaultError("protocolError", "Pi RPC returned an invalid envelope");
54098
54303
  }
54099
54304
  this.#handle(value);
@@ -54132,7 +54337,7 @@ var PiRpcSession = class {
54132
54337
  }
54133
54338
  compactionTurn?.onEvent({
54134
54339
  type: "compaction.completed",
54135
- outcome: value.aborted === true ? "cancelled" : isRecord16(value.result) ? "succeeded" : "failed",
54340
+ outcome: value.aborted === true ? "cancelled" : isRecord17(value.result) ? "succeeded" : "failed",
54136
54341
  ...nonBlankString2(value.errorMessage) ? { errorMessage: value.errorMessage } : {}
54137
54342
  });
54138
54343
  return;
@@ -54152,7 +54357,7 @@ var PiRpcSession = class {
54152
54357
  this.#startAssistantMessage(active, value.message);
54153
54358
  return;
54154
54359
  }
54155
- if (value.type === "message_update" && isRecord16(value.assistantMessageEvent)) {
54360
+ if (value.type === "message_update" && isRecord17(value.assistantMessageEvent)) {
54156
54361
  const event = value.assistantMessageEvent;
54157
54362
  if (event.type === "text_delta" && typeof event.delta === "string") {
54158
54363
  const messageId = this.#ensureAssistantMessage(active, value.message);
@@ -54546,7 +54751,7 @@ var PiRpcSession = class {
54546
54751
  // packages/adapters/pi/dist/pi-adapter.js
54547
54752
  var piHarnessId2 = harnessIdSchema.parse("pi");
54548
54753
  var DEFAULT_TOOL_OUTPUT_LIMIT4 = 64e3;
54549
- function isRecord17(value) {
54754
+ function isRecord18(value) {
54550
54755
  return typeof value === "object" && value !== null && !Array.isArray(value);
54551
54756
  }
54552
54757
  function errorMessage(error52) {
@@ -54620,7 +54825,7 @@ function nativeModelForHistory(state) {
54620
54825
  return nativeModelFromState(state);
54621
54826
  }
54622
54827
  function sessionFileFromRef(ref) {
54623
- if (ref.harnessId !== piHarnessId2 || !isRecord17(ref.locator) || typeof ref.locator.sessionFile !== "string" || ref.locator.sessionFile.length === 0) {
54828
+ if (ref.harnessId !== piHarnessId2 || !isRecord18(ref.locator) || typeof ref.locator.sessionFile !== "string" || ref.locator.sessionFile.length === 0) {
54624
54829
  throw new Error("Pi Native Session Ref has no resumable Session file");
54625
54830
  }
54626
54831
  return ref.locator.sessionFile;
@@ -54635,9 +54840,9 @@ function toolFailure2(toolName) {
54635
54840
  function nativeText(value) {
54636
54841
  if (typeof value === "string")
54637
54842
  return value;
54638
- if (!isRecord17(value) || !Array.isArray(value.content))
54843
+ if (!isRecord18(value) || !Array.isArray(value.content))
54639
54844
  return "";
54640
- return value.content.filter((content) => isRecord17(content) && content.type === "text" && typeof content.text === "string").map(({ text }) => text).join("");
54845
+ return value.content.filter((content) => isRecord18(content) && content.type === "text" && typeof content.text === "string").map(({ text }) => text).join("");
54641
54846
  }
54642
54847
  function boundedOutput(value, limit) {
54643
54848
  const text = nativeText(value);
@@ -54653,19 +54858,19 @@ function outputText2(output) {
54653
54858
  return output?.content.filter((content) => content.type === "text").map(({ text }) => text).join("") ?? "";
54654
54859
  }
54655
54860
  function stringField2(value, key) {
54656
- return isRecord17(value) && typeof value[key] === "string" ? value[key] : void 0;
54861
+ return isRecord18(value) && typeof value[key] === "string" ? value[key] : void 0;
54657
54862
  }
54658
54863
  function numberField(value, key) {
54659
- if (!isRecord17(value))
54864
+ if (!isRecord18(value))
54660
54865
  return void 0;
54661
54866
  const field = value[key];
54662
54867
  return typeof field === "number" || field === null ? field : void 0;
54663
54868
  }
54664
- function stripDiffPrefix(path17) {
54665
- return path17.startsWith("a/") || path17.startsWith("b/") ? path17.slice(2) : path17;
54869
+ function stripDiffPrefix(path18) {
54870
+ return path18.startsWith("a/") || path18.startsWith("b/") ? path18.slice(2) : path18;
54666
54871
  }
54667
54872
  function reliableFileChange(result) {
54668
- if (!isRecord17(result) || !isRecord17(result.details) || typeof result.details.patch !== "string") {
54873
+ if (!isRecord18(result) || !isRecord18(result.details) || typeof result.details.patch !== "string") {
54669
54874
  return null;
54670
54875
  }
54671
54876
  const patch = result.details.patch;
@@ -54681,10 +54886,10 @@ function reliableFileChange(result) {
54681
54886
  const oldFile = file2.oldFileName;
54682
54887
  const newFile = file2.newFileName;
54683
54888
  const kind = oldFile === "/dev/null" ? "add" : newFile === "/dev/null" ? "delete" : "update";
54684
- const path17 = stripDiffPrefix(kind === "delete" ? oldFile : newFile);
54685
- if (!path17 || path17 === "/dev/null")
54889
+ const path18 = stripDiffPrefix(kind === "delete" ? oldFile : newFile);
54890
+ if (!path18 || path18 === "/dev/null")
54686
54891
  return null;
54687
- return [{ path: path17, kind, unifiedDiff: patch }];
54892
+ return [{ path: path18, kind, unifiedDiff: patch }];
54688
54893
  }
54689
54894
  function delay3(milliseconds) {
54690
54895
  return new Promise((resolve2) => setTimeout(resolve2, milliseconds));
@@ -55927,8 +56132,8 @@ import nodePath from "node:path";
55927
56132
  import { execFileSync } from "node:child_process";
55928
56133
  import { randomUUID as randomUUID6 } from "node:crypto";
55929
56134
  import { constants as constants3 } from "node:fs";
55930
- import { copyFile, mkdir, open as open2, readFile as readFile2, readdir, rename, rm as rm2, stat } from "node:fs/promises";
55931
- import path12 from "node:path";
56135
+ import { copyFile, mkdir, open as open2, readFile as readFile3, readdir, rename, rm as rm2, stat } from "node:fs/promises";
56136
+ import path13 from "node:path";
55932
56137
 
55933
56138
  // packages/mapping-store/dist/records.js
55934
56139
  var nonBlankTextSchema3 = external_exports.string().refine((value) => value.trim().length > 0, {
@@ -56095,6 +56300,18 @@ function isNodeExecutable(value) {
56095
56300
  function lockOwnerIsLive(lock) {
56096
56301
  if (typeof lock.pid !== "number")
56097
56302
  return false;
56303
+ if (lock.pid === process.pid) {
56304
+ if (lock.executablePath && normalizeExecutablePath(lock.executablePath) !== normalizeExecutablePath(process.execPath)) {
56305
+ return false;
56306
+ }
56307
+ if (lock.processStartedAt) {
56308
+ const expected = Date.parse(lock.processStartedAt);
56309
+ const actual = Date.now() - process.uptime() * 1e3;
56310
+ if (Number.isFinite(expected) && Math.abs(actual - expected) > 5e3)
56311
+ return false;
56312
+ }
56313
+ return true;
56314
+ }
56098
56315
  const identity = processIdentity(lock.pid);
56099
56316
  if (!identity)
56100
56317
  return false;
@@ -56133,11 +56350,11 @@ var MappingStore = class {
56133
56350
  #initialized = false;
56134
56351
  #lockHandle = null;
56135
56352
  constructor(options) {
56136
- this.#directory = path12.resolve(options.directory);
56137
- this.#threadsDirectory = path12.join(this.#directory, "threads");
56138
- this.#backupsDirectory = path12.join(this.#directory, "backups");
56139
- this.#quarantineDirectory = path12.join(this.#directory, "quarantine");
56140
- this.#lockPath = path12.join(this.#directory, "store.lock");
56353
+ this.#directory = path13.resolve(options.directory);
56354
+ this.#threadsDirectory = path13.join(this.#directory, "threads");
56355
+ this.#backupsDirectory = path13.join(this.#directory, "backups");
56356
+ this.#quarantineDirectory = path13.join(this.#directory, "quarantine");
56357
+ this.#lockPath = path13.join(this.#directory, "store.lock");
56141
56358
  this.#instanceId = options.instanceId ?? randomUUID6();
56142
56359
  this.#now = options.now ?? (() => /* @__PURE__ */ new Date());
56143
56360
  this.#beforeReplace = options.beforeReplace;
@@ -56155,8 +56372,8 @@ var MappingStore = class {
56155
56372
  await this.#cleanupTemps();
56156
56373
  const names = (await readdir(this.#threadsDirectory)).filter((name) => name.endsWith(".json"));
56157
56374
  for (const name of names) {
56158
- const primary = path12.join(this.#threadsDirectory, name);
56159
- const backup = path12.join(this.#backupsDirectory, name);
56375
+ const primary = path13.join(this.#threadsDirectory, name);
56376
+ const backup = path13.join(this.#backupsDirectory, name);
56160
56377
  let record3 = null;
56161
56378
  try {
56162
56379
  record3 = await this.#readRecord(primary, name);
@@ -56165,7 +56382,7 @@ var MappingStore = class {
56165
56382
  record3 = await this.#readRecord(backup, name);
56166
56383
  await this.#replaceFile(primary, record3, false);
56167
56384
  } catch (backupError) {
56168
- const quarantine = path12.join(this.#quarantineDirectory, `${name}.${this.#now().getTime()}.invalid`);
56385
+ const quarantine = path13.join(this.#quarantineDirectory, `${name}.${this.#now().getTime()}.invalid`);
56169
56386
  await rename(primary, quarantine).catch(() => void 0);
56170
56387
  void primaryError;
56171
56388
  void backupError;
@@ -56274,27 +56491,29 @@ var MappingStore = class {
56274
56491
  if (current.state !== "ready" || !current.nativeSessionRef) {
56275
56492
  throw new MappingStoreError("MAPPING_CONFLICT", "Only a ready Thread can reconcile Snapshot mappings");
56276
56493
  }
56277
- const merged = this.#mergeMappings(current.turnMappings, mappings);
56278
- if (merged.length !== mappings.length) {
56279
- throw new MappingStoreError("MAPPING_CONFLICT", "Snapshot reconciliation must retain every existing Turn mapping");
56280
- }
56281
- const mergedByHost = new Map(merged.map((mapping) => [mapping.hostTurnId, mapping]));
56282
- const ordered = mappings.map(({ hostTurnId }) => {
56283
- const mapping = mergedByHost.get(hostTurnId);
56284
- if (!mapping) {
56494
+ const byHost = new Map(current.turnMappings.map((mapping) => [mapping.hostTurnId, mapping]));
56495
+ const byNative = new Map(current.turnMappings.map((mapping) => [nativeTurnKey(mapping), mapping]));
56496
+ const seenHost = /* @__PURE__ */ new Set();
56497
+ const seenNative = /* @__PURE__ */ new Set();
56498
+ const ordered = mappings.map((update) => {
56499
+ const hostMatch = byHost.get(update.hostTurnId);
56500
+ const nativeMatch = byNative.get(nativeTurnKey(update));
56501
+ if (hostMatch && nativeMatch && hostMatch !== nativeMatch) {
56502
+ throw new MappingStoreError("MAPPING_CONFLICT", "Turn identity mapping conflicts");
56503
+ }
56504
+ if (hostMatch && !sameJson(hostMatch.nativeTurnRef, update.nativeTurnRef)) {
56505
+ throw new MappingStoreError("MAPPING_CONFLICT", "Host Turn maps to another Native Turn");
56506
+ }
56507
+ if (nativeMatch && nativeMatch.hostTurnId !== update.hostTurnId) {
56508
+ throw new MappingStoreError("MAPPING_CONFLICT", "Native Turn maps to another Host Turn");
56509
+ }
56510
+ if (seenHost.has(update.hostTurnId) || seenNative.has(nativeTurnKey(update))) {
56285
56511
  throw new MappingStoreError("MAPPING_CONFLICT", "Snapshot reconciliation contains a duplicate Turn mapping");
56286
56512
  }
56287
- return mapping;
56513
+ seenHost.add(update.hostTurnId);
56514
+ seenNative.add(nativeTurnKey(update));
56515
+ return { ...update };
56288
56516
  });
56289
- const orderedIndexByHost = new Map(ordered.map(({ hostTurnId }, index) => [hostTurnId, index]));
56290
- let previousIndex = -1;
56291
- for (const existing of current.turnMappings) {
56292
- const nextIndex = orderedIndexByHost.get(existing.hostTurnId);
56293
- if (nextIndex === void 0 || nextIndex <= previousIndex) {
56294
- throw new MappingStoreError("MAPPING_CONFLICT", "Snapshot reconciliation reordered an existing Turn mapping");
56295
- }
56296
- previousIndex = nextIndex;
56297
- }
56298
56517
  return sameJson(current.turnMappings, ordered) ? null : { ...current, turnMappings: ordered };
56299
56518
  });
56300
56519
  }
@@ -56339,7 +56558,7 @@ var MappingStore = class {
56339
56558
  if (handle)
56340
56559
  await handle.close().catch(() => void 0);
56341
56560
  try {
56342
- const current = JSON.parse(await readFile2(this.#lockPath, "utf8"));
56561
+ const current = JSON.parse(await readFile3(this.#lockPath, "utf8"));
56343
56562
  if (current.instanceId === this.#instanceId)
56344
56563
  await rm2(this.#lockPath, { force: true });
56345
56564
  } catch {
@@ -56433,7 +56652,7 @@ var MappingStore = class {
56433
56652
  }
56434
56653
  }
56435
56654
  async #readRecord(file2, expectedName) {
56436
- const parsed = storedThreadRecordV1Schema.safeParse(JSON.parse(await readFile2(file2, "utf8")));
56655
+ const parsed = storedThreadRecordV1Schema.safeParse(JSON.parse(await readFile3(file2, "utf8")));
56437
56656
  if (!parsed.success) {
56438
56657
  throw new MappingStoreError("INVALID_RECORD", "Mapping Store record is invalid", {
56439
56658
  cause: parsed.error
@@ -56446,7 +56665,7 @@ var MappingStore = class {
56446
56665
  }
56447
56666
  async #cleanupTemps() {
56448
56667
  const names = await readdir(this.#threadsDirectory);
56449
- await Promise.all(names.filter((name) => name.includes(".tmp-")).map((name) => rm2(path12.join(this.#threadsDirectory, name), { force: true })));
56668
+ await Promise.all(names.filter((name) => name.includes(".tmp-")).map((name) => rm2(path13.join(this.#threadsDirectory, name), { force: true })));
56450
56669
  }
56451
56670
  async #acquireLock() {
56452
56671
  const attempt = async () => {
@@ -56472,7 +56691,7 @@ var MappingStore = class {
56472
56691
  }
56473
56692
  let existing = {};
56474
56693
  try {
56475
- existing = JSON.parse(await readFile2(this.#lockPath, "utf8"));
56694
+ existing = JSON.parse(await readFile3(this.#lockPath, "utf8"));
56476
56695
  } catch {
56477
56696
  }
56478
56697
  if (typeof existing.pid === "number" && lockOwnerIsLive(existing)) {
@@ -56539,10 +56758,10 @@ var MappingStore = class {
56539
56758
  }
56540
56759
  }
56541
56760
  #recordPath(hostThreadId) {
56542
- return path12.join(this.#threadsDirectory, `${hostThreadId}.json`);
56761
+ return path13.join(this.#threadsDirectory, `${hostThreadId}.json`);
56543
56762
  }
56544
56763
  #backupPath(hostThreadId) {
56545
- return path12.join(this.#backupsDirectory, `${hostThreadId}.json`);
56764
+ return path13.join(this.#backupsDirectory, `${hostThreadId}.json`);
56546
56765
  }
56547
56766
  #requireInitialized() {
56548
56767
  if (!this.#initialized) {
@@ -56561,7 +56780,7 @@ var packageMetadata5 = {
56561
56780
  var TITLE_MAX_LENGTH = 120;
56562
56781
  var DESCRIPTION_MAX_LENGTH = 500;
56563
56782
  var SERVER_NAME_MAX_LENGTH = 80;
56564
- function isRecord18(value) {
56783
+ function isRecord19(value) {
56565
56784
  return typeof value === "object" && value !== null && !Array.isArray(value);
56566
56785
  }
56567
56786
  function boundedText(value, field, maxLength) {
@@ -56605,7 +56824,7 @@ function responseError(message3) {
56605
56824
  function responsePersist(value) {
56606
56825
  if (value === void 0 || value === null)
56607
56826
  return null;
56608
- if (!isRecord18(value) || Object.keys(value).length !== 1 || value.persist !== "session" && value.persist !== "always") {
56827
+ if (!isRecord19(value) || Object.keys(value).length !== 1 || value.persist !== "session" && value.persist !== "always") {
56609
56828
  throw responseError("contains malformed persist metadata");
56610
56829
  }
56611
56830
  return value.persist;
@@ -56648,7 +56867,7 @@ function projectCodexApprovalRequest(input) {
56648
56867
  },
56649
56868
  denyResponse,
56650
56869
  parseResponse(result) {
56651
- if (!isRecord18(result) || typeof result.action !== "string") {
56870
+ if (!isRecord19(result) || typeof result.action !== "string") {
56652
56871
  throw responseError("missing action");
56653
56872
  }
56654
56873
  if (Object.keys(result).some((key) => key !== "action" && key !== "content" && key !== "_meta")) {
@@ -56656,7 +56875,7 @@ function projectCodexApprovalRequest(input) {
56656
56875
  }
56657
56876
  const selectedPersist = responsePersist(result._meta);
56658
56877
  if (result.action === "accept") {
56659
- if ("content" in result && (!isRecord18(result.content) || Object.keys(result.content).length !== 0)) {
56878
+ if ("content" in result && (!isRecord19(result.content) || Object.keys(result.content).length !== 0)) {
56660
56879
  throw responseError("contains non-empty accepted content");
56661
56880
  }
56662
56881
  if (selectedPersist === "session") {
@@ -56683,7 +56902,7 @@ function projectCodexApprovalRequest(input) {
56683
56902
  }
56684
56903
 
56685
56904
  // packages/protocol-core/dist/codex-question.js
56686
- function isRecord19(value) {
56905
+ function isRecord20(value) {
56687
56906
  return typeof value === "object" && value !== null && !Array.isArray(value);
56688
56907
  }
56689
56908
  function responseError2(message3) {
@@ -56752,7 +56971,7 @@ function projectCodexQuestionRequest(input) {
56752
56971
  }
56753
56972
  },
56754
56973
  parseResponse(result) {
56755
- if (!isRecord19(result) || !isRecord19(result.answers)) {
56974
+ if (!isRecord20(result) || !isRecord20(result.answers)) {
56756
56975
  throw responseError2("missing answers object");
56757
56976
  }
56758
56977
  const rawAnswers = result.answers;
@@ -56765,7 +56984,7 @@ function projectCodexQuestionRequest(input) {
56765
56984
  const question = interaction.questions.find(({ id: id2 }) => id2 === questionId);
56766
56985
  if (!question)
56767
56986
  throw responseError2("contains an unknown Question ID");
56768
- if (!isRecord19(answerValue) || !Array.isArray(answerValue.answers)) {
56987
+ if (!isRecord20(answerValue) || !Array.isArray(answerValue.answers)) {
56769
56988
  throw responseError2("answer entry has no answers array");
56770
56989
  }
56771
56990
  const values = answerValue.answers;
@@ -56911,8 +57130,8 @@ function projectItem(item, outcome, defaultCwd, includeCommandOutput = true) {
56911
57130
  return {
56912
57131
  id: item.itemId,
56913
57132
  type: "fileChange",
56914
- changes: item.changes.map(({ path: path17, kind, unifiedDiff }) => ({
56915
- path: path17,
57133
+ changes: item.changes.map(({ path: path18, kind, unifiedDiff }) => ({
57134
+ path: path18,
56916
57135
  kind,
56917
57136
  diff: unifiedDiff
56918
57137
  })),
@@ -57329,8 +57548,8 @@ var CodexTurnProjector = class {
57329
57548
  return messages;
57330
57549
  }
57331
57550
  #fileChangeUpdates(itemId3, changes) {
57332
- const projectedChanges = changes.map(({ path: path17, kind, unifiedDiff }) => ({
57333
- path: path17,
57551
+ const projectedChanges = changes.map(({ path: path18, kind, unifiedDiff }) => ({
57552
+ path: path18,
57334
57553
  kind,
57335
57554
  diff: unifiedDiff
57336
57555
  }));
@@ -57375,7 +57594,7 @@ var CodexTurnProjector = class {
57375
57594
  };
57376
57595
 
57377
57596
  // packages/protocol-core/dist/thread-fork.js
57378
- function isRecord20(value) {
57597
+ function isRecord21(value) {
57379
57598
  return typeof value === "object" && value !== null && !Array.isArray(value);
57380
57599
  }
57381
57600
  function optionalText(params, name, options = {}) {
@@ -57398,7 +57617,7 @@ function optionalBoolean(params, name) {
57398
57617
  function decodeThreadForkRequest(request) {
57399
57618
  if (request.method !== "thread/fork")
57400
57619
  return null;
57401
- if (!isRecord20(request.params))
57620
+ if (!isRecord21(request.params))
57402
57621
  throw new Error("thread/fork params must be an object");
57403
57622
  const params = request.params;
57404
57623
  const threadId2 = optionalText(params, "threadId");
@@ -57413,13 +57632,13 @@ function decodeThreadForkRequest(request) {
57413
57632
  if (runtimeWorkspaceRoots !== void 0 && runtimeWorkspaceRoots !== null && (!Array.isArray(runtimeWorkspaceRoots) || runtimeWorkspaceRoots.some((root) => typeof root !== "string" || root.length === 0))) {
57414
57633
  throw new Error("thread/fork params.runtimeWorkspaceRoots must be text paths or null");
57415
57634
  }
57416
- const path17 = optionalText(params, "path", { allowEmpty: true });
57635
+ const path18 = optionalText(params, "path", { allowEmpty: true });
57417
57636
  const ephemeral = optionalBoolean(params, "ephemeral");
57418
57637
  return {
57419
57638
  threadId: threadId2,
57420
57639
  ...lastTurnText ? { lastTurnId: hostTurnIdSchema.parse(lastTurnText) } : {},
57421
57640
  ...beforeTurnText ? { beforeTurnId: hostTurnIdSchema.parse(beforeTurnText) } : {},
57422
- ...path17 ? { path: path17 } : {},
57641
+ ...path18 ? { path: path18 } : {},
57423
57642
  ...optionalField(params, "model"),
57424
57643
  ...optionalField(params, "modelProvider"),
57425
57644
  ...optionalField(params, "cwd"),
@@ -57434,7 +57653,7 @@ function decodeThreadForkRequest(request) {
57434
57653
  function decodeThreadRollbackRequest(request) {
57435
57654
  if (request.method !== "thread/rollback")
57436
57655
  return null;
57437
- if (!isRecord20(request.params))
57656
+ if (!isRecord21(request.params))
57438
57657
  throw new Error("thread/rollback params must be an object");
57439
57658
  const { threadId: threadId2, numTurns } = request.params;
57440
57659
  if (typeof threadId2 !== "string" || threadId2.length === 0) {
@@ -57528,13 +57747,13 @@ var THREAD_SOURCE_KINDS = /* @__PURE__ */ new Set([
57528
57747
  "subAgentOther",
57529
57748
  "unknown"
57530
57749
  ]);
57531
- function isRecord21(value) {
57750
+ function isRecord22(value) {
57532
57751
  return typeof value === "object" && value !== null && !Array.isArray(value);
57533
57752
  }
57534
57753
  function paramsObject(request, method) {
57535
57754
  if (request.params === void 0 && method === "thread/list")
57536
57755
  return {};
57537
- if (!isRecord21(request.params))
57756
+ if (!isRecord22(request.params))
57538
57757
  throw new Error(`${method} params must be an object`);
57539
57758
  return request.params;
57540
57759
  }
@@ -57606,7 +57825,7 @@ function cursorPayload(value) {
57606
57825
  };
57607
57826
  }
57608
57827
  function parseCursorPayload(value) {
57609
- if (!isRecord21(value) || value.formatVersion !== 1)
57828
+ if (!isRecord22(value) || value.formatVersion !== 1)
57610
57829
  throw new Error("Host cursor is invalid");
57611
57830
  const { queryFingerprint: fingerprint, sortDirection: sortDirection2, officialCursor, officialDone } = value;
57612
57831
  const { externalAnchor: externalAnchor2, externalDone } = value;
@@ -57615,7 +57834,7 @@ function parseCursorPayload(value) {
57615
57834
  }
57616
57835
  let anchor = null;
57617
57836
  if (externalAnchor2 !== null) {
57618
- if (!isRecord21(externalAnchor2) || !Number.isSafeInteger(externalAnchor2.timestamp) || typeof externalAnchor2.threadId !== "string" || externalAnchor2.threadId.length === 0) {
57837
+ if (!isRecord22(externalAnchor2) || !Number.isSafeInteger(externalAnchor2.timestamp) || typeof externalAnchor2.threadId !== "string" || externalAnchor2.threadId.length === 0) {
57619
57838
  throw new Error("Host cursor is invalid");
57620
57839
  }
57621
57840
  anchor = {
@@ -57735,7 +57954,7 @@ function decodeThreadMetadataUpdateRequest(request) {
57735
57954
  if (params.gitInfo === null) {
57736
57955
  gitInfo = null;
57737
57956
  } else if (params.gitInfo !== void 0) {
57738
- if (!isRecord21(params.gitInfo)) {
57957
+ if (!isRecord22(params.gitInfo)) {
57739
57958
  throw new Error("thread/metadata/update params.gitInfo must be an object or null");
57740
57959
  }
57741
57960
  gitInfo = {};
@@ -57763,7 +57982,7 @@ function optionalCursor(value, name) {
57763
57982
  return value;
57764
57983
  }
57765
57984
  function decodeOfficialThreadListPage(value) {
57766
- if (!isRecord21(value) || !Array.isArray(value.data) || value.data.some((row) => !isRecord21(row))) {
57985
+ if (!isRecord22(value) || !Array.isArray(value.data) || value.data.some((row) => !isRecord22(row))) {
57767
57986
  throw new Error("Official thread/list response is invalid");
57768
57987
  }
57769
57988
  return {
@@ -58084,8 +58303,8 @@ var packageMetadata6 = {
58084
58303
 
58085
58304
  // packages/host-runtime/src/external-thread-repository.ts
58086
58305
  import { randomUUID as randomUUID7 } from "node:crypto";
58087
- import os5 from "node:os";
58088
- import path13 from "node:path";
58306
+ import os6 from "node:os";
58307
+ import path14 from "node:path";
58089
58308
  function nativeTurnKey2(ref) {
58090
58309
  return `${ref.harnessId}\0${ref.nativeSessionId}\0${ref.nativeTurnKey}\0${ref.formatVersion}`;
58091
58310
  }
@@ -58094,8 +58313,8 @@ function sameMapping(left, right) {
58094
58313
  }
58095
58314
  function defaultMappingStoreDirectory(environment) {
58096
58315
  const dataDirectory = environment.CODEXHOST_DATA_DIR;
58097
- return path13.join(
58098
- dataDirectory ? path13.resolve(dataDirectory) : path13.join(os5.homedir(), ".codexhost"),
58316
+ return path14.join(
58317
+ dataDirectory ? path14.resolve(dataDirectory) : path14.join(os6.homedir(), ".codexhost"),
58099
58318
  "mapping-store"
58100
58319
  );
58101
58320
  }
@@ -58305,25 +58524,14 @@ var ExternalThreadRepository = class {
58305
58524
  ...turn.checkpoint ? { nativeCheckpointRef: turn.checkpoint } : {}
58306
58525
  };
58307
58526
  return {
58308
- existing,
58309
58527
  snapshot: turn,
58310
58528
  mapping: {
58311
58529
  ...mapping,
58530
+ nativeTurnRef: turn.nativeTurnRef,
58312
58531
  ...turn.checkpoint ? { nativeCheckpointRef: turn.checkpoint } : {}
58313
58532
  }
58314
58533
  };
58315
58534
  });
58316
- let existingIndex = 0;
58317
- for (const { existing } of aligned) {
58318
- if (!existing) continue;
58319
- if (existing.hostTurnId !== record3.turnMappings[existingIndex]?.hostTurnId) {
58320
- throw new Error("Persisted Turn mappings do not match the Native Snapshot order");
58321
- }
58322
- existingIndex += 1;
58323
- }
58324
- if (existingIndex !== record3.turnMappings.length) {
58325
- throw new Error("Persisted Turn mappings do not match the Native Snapshot order");
58326
- }
58327
58535
  const orderedMappings = aligned.map(({ mapping }) => mapping);
58328
58536
  const mappingsChanged = orderedMappings.length !== record3.turnMappings.length || orderedMappings.some((mapping, index) => {
58329
58537
  const persisted = record3.turnMappings[index];
@@ -59180,7 +59388,7 @@ var ExternalThreadRuntime = class {
59180
59388
  import { randomUUID as randomUUID8 } from "node:crypto";
59181
59389
  var INTERNAL_REQUEST_PREFIX = "codexhost:official:";
59182
59390
  var MAX_RETIRED_IDS = 1024;
59183
- function isRecord22(value) {
59391
+ function isRecord23(value) {
59184
59392
  return typeof value === "object" && value !== null && !Array.isArray(value);
59185
59393
  }
59186
59394
  var OfficialRequestBroker = class {
@@ -59223,7 +59431,7 @@ var OfficialRequestBroker = class {
59223
59431
  });
59224
59432
  }
59225
59433
  handle(value) {
59226
- if (!isRecord22(value) || typeof value.id !== "string") return false;
59434
+ if (!isRecord23(value) || typeof value.id !== "string") return false;
59227
59435
  const pending = this.#pending.get(value.id);
59228
59436
  if (!pending) return this.#retired.has(value.id);
59229
59437
  clearTimeout(pending.timeout);
@@ -59252,11 +59460,11 @@ var OfficialRequestBroker = class {
59252
59460
  };
59253
59461
 
59254
59462
  // packages/host-runtime/src/route-observation.ts
59255
- function isRecord23(value) {
59463
+ function isRecord24(value) {
59256
59464
  return typeof value === "object" && value !== null && !Array.isArray(value);
59257
59465
  }
59258
59466
  function classifyThreadPurpose(request) {
59259
- return isRecord23(request.params) && request.params.ephemeral === true ? "ephemeral" : "conversation";
59467
+ return isRecord24(request.params) && request.params.ephemeral === true ? "ephemeral" : "conversation";
59260
59468
  }
59261
59469
  var RequestRouteObservationTracker = class {
59262
59470
  #nextCreateOrdinal = 0;
@@ -59281,13 +59489,13 @@ var RequestRouteObservationTracker = class {
59281
59489
  this.#createByThreadId.set(threadId2, tracked);
59282
59490
  }
59283
59491
  bindOfficialResponse(response) {
59284
- if (!isRecord23(response) || !("id" in response)) return;
59492
+ if (!isRecord24(response) || !("id" in response)) return;
59285
59493
  const tracked = this.#pendingByRequestId.get(response.id);
59286
59494
  if (!tracked) return;
59287
59495
  this.#pendingByRequestId.delete(response.id);
59288
59496
  const result = response.result;
59289
- const thread = isRecord23(result) ? result.thread : null;
59290
- if (isRecord23(thread) && typeof thread.id === "string") {
59497
+ const thread = isRecord24(result) ? result.thread : null;
59498
+ if (isRecord24(thread) && typeof thread.id === "string") {
59291
59499
  this.#createByThreadId.set(thread.id, tracked);
59292
59500
  }
59293
59501
  }
@@ -59384,25 +59592,25 @@ function resolveExternalSessionTreeIds(records) {
59384
59592
  const resolve2 = (start) => {
59385
59593
  const cached2 = resolved.get(start.hostThreadId);
59386
59594
  if (cached2) return cached2;
59387
- const path17 = [];
59595
+ const path18 = [];
59388
59596
  const visited = /* @__PURE__ */ new Set();
59389
59597
  let current = start;
59390
59598
  while (true) {
59391
59599
  const known = resolved.get(current.hostThreadId);
59392
59600
  if (known) {
59393
- for (const record3 of path17) resolved.set(record3.hostThreadId, known);
59601
+ for (const record3 of path18) resolved.set(record3.hostThreadId, known);
59394
59602
  return known;
59395
59603
  }
59396
59604
  if (visited.has(current.hostThreadId)) {
59397
59605
  throw new Error("External Thread Fork tree contains a cycle");
59398
59606
  }
59399
59607
  visited.add(current.hostThreadId);
59400
- path17.push(current);
59608
+ path18.push(current);
59401
59609
  const sourceId = current.forkSource?.hostThreadId;
59402
59610
  const source = sourceId ? byId.get(sourceId) : void 0;
59403
59611
  if (!source) {
59404
59612
  const root = current.hostThreadId;
59405
- for (const record3 of path17) resolved.set(record3.hostThreadId, root);
59613
+ for (const record3 of path18) resolved.set(record3.hostThreadId, root);
59406
59614
  return root;
59407
59615
  }
59408
59616
  current = source;
@@ -59453,11 +59661,11 @@ var OfficialThreadListError = class extends Error {
59453
59661
  }
59454
59662
  rpcError;
59455
59663
  };
59456
- function isRecord24(value) {
59664
+ function isRecord25(value) {
59457
59665
  return typeof value === "object" && value !== null && !Array.isArray(value);
59458
59666
  }
59459
59667
  function officialThreadListPageFromResponse(response) {
59460
- if (isRecord24(response.error)) {
59668
+ if (isRecord25(response.error)) {
59461
59669
  if (!Number.isSafeInteger(response.error.code) || typeof response.error.message !== "string") {
59462
59670
  throw new Error("Official thread/list error response is invalid");
59463
59671
  }
@@ -59617,9 +59825,19 @@ async function aggregateThreadList(input) {
59617
59825
  }
59618
59826
 
59619
59827
  // packages/host-runtime/src/app-server-host.ts
59620
- function isRecord25(value) {
59828
+ function isRecord26(value) {
59621
59829
  return typeof value === "object" && value !== null && !Array.isArray(value);
59622
59830
  }
59831
+ function isCreditsAdapter(adapter) {
59832
+ return typeof adapter.credits === "function" && typeof adapter.refreshCredits === "function";
59833
+ }
59834
+ function projectAccountCredits(value) {
59835
+ if (!isRecord26(value)) return null;
59836
+ const rest = { ...value };
59837
+ delete rest.fetchedAt;
59838
+ const parsed = accountCreditsSnapshotSchema.safeParse(rest);
59839
+ return parsed.success ? parsed.data : null;
59840
+ }
59623
59841
  function errorMessage3(error52) {
59624
59842
  return error52 instanceof Error ? error52.message : String(error52);
59625
59843
  }
@@ -59636,6 +59854,7 @@ function officialEnvironment(source) {
59636
59854
  "CODEXHOST_STOCK_CODEX_PATH",
59637
59855
  "CODEXHOST_LAUNCHER_PID",
59638
59856
  "CODEXHOST_LAUNCHER_EXECUTABLE",
59857
+ "CODEXHOST_RUNTIME_DESCRIPTOR_PATH",
59639
59858
  "CODEXHOST_CONTROL_PORT",
59640
59859
  "CODEXHOST_CONTROL_NONCE",
59641
59860
  "CODEXHOST_NPM_NODE_PATH",
@@ -59713,12 +59932,12 @@ function classifyCreateRequestRoute(request, defaultAgent2) {
59713
59932
  };
59714
59933
  }
59715
59934
  function requestObject(request) {
59716
- if (!isRecord25(request.params)) throw new Error(`${request.method} params must be an object`);
59935
+ if (!isRecord26(request.params)) throw new Error(`${request.method} params must be an object`);
59717
59936
  return request.params;
59718
59937
  }
59719
59938
  function requestText(params) {
59720
59939
  if (!Array.isArray(params.input)) throw new Error("turn/start input must be an array");
59721
- const text = params.input.filter((item) => isRecord25(item) && item.type === "text").map((item) => item.text).filter((value) => typeof value === "string").join("\n");
59940
+ const text = params.input.filter((item) => isRecord26(item) && item.type === "text").map((item) => item.text).filter((value) => typeof value === "string").join("\n");
59722
59941
  if (!text) throw new Error("turn/start must contain text input");
59723
59942
  return text;
59724
59943
  }
@@ -59872,11 +60091,11 @@ var AppServerHost = class {
59872
60091
  }
59873
60092
  const request = requestResult.data;
59874
60093
  if (request.method === "codexhost/update/check" || request.method === "codexhost/update/start" || request.method === "codexhost/update/status") {
59875
- await this.#handleUpdateRequest(request);
60094
+ this.#dispatchDesktopRequest(() => this.#handleUpdateRequest(request));
59876
60095
  continue;
59877
60096
  }
59878
60097
  if (request.method === "codexhost/harness/inspect") {
59879
- await this.#inspectHarness(request);
60098
+ this.#dispatchDesktopRequest(() => this.#inspectHarness(request));
59880
60099
  continue;
59881
60100
  }
59882
60101
  if (request.method === "codexhost/thread/fork") {
@@ -59921,7 +60140,7 @@ var AppServerHost = class {
59921
60140
  await writeFrame(official.stdin, frame);
59922
60141
  continue;
59923
60142
  }
59924
- await this.#listThreads(request, listRequest);
60143
+ this.#dispatchDesktopRequest(() => this.#listThreads(request, listRequest));
59925
60144
  continue;
59926
60145
  }
59927
60146
  if (request.method === "thread/archive" || request.method === "thread/unarchive") {
@@ -59992,7 +60211,7 @@ var AppServerHost = class {
59992
60211
  continue;
59993
60212
  }
59994
60213
  if (request.method === "thread/fork") {
59995
- const params = isRecord25(request.params) ? request.params : {};
60214
+ const params = isRecord26(request.params) ? request.params : {};
59996
60215
  const resolution = typeof params.threadId === "string" ? await this.#resolveExternalThread(params.threadId) : { kind: "official" };
59997
60216
  if (resolution.kind === "error") {
59998
60217
  await this.#writer.json(
@@ -60015,7 +60234,7 @@ var AppServerHost = class {
60015
60234
  }
60016
60235
  }
60017
60236
  if (request.method === "thread/rollback") {
60018
- const params = isRecord25(request.params) ? request.params : {};
60237
+ const params = isRecord26(request.params) ? request.params : {};
60019
60238
  const resolution = typeof params.threadId === "string" ? await this.#resolveExternalThread(params.threadId) : { kind: "official" };
60020
60239
  if (resolution.kind === "error") {
60021
60240
  await this.#writer.json(
@@ -60155,7 +60374,7 @@ var AppServerHost = class {
60155
60374
  continue;
60156
60375
  }
60157
60376
  }
60158
- if (request.method.startsWith("thread/") && !EXPLICIT_EXTERNAL_THREAD_METHODS.has(request.method) && isRecord25(request.params) && typeof request.params.threadId === "string") {
60377
+ if (request.method.startsWith("thread/") && !EXPLICIT_EXTERNAL_THREAD_METHODS.has(request.method) && isRecord26(request.params) && typeof request.params.threadId === "string") {
60159
60378
  const location = await this.#locateExternalThread(request.params.threadId);
60160
60379
  if (await this.#writeResolutionError(request, location)) continue;
60161
60380
  if (location.kind === "external") {
@@ -60276,7 +60495,6 @@ var AppServerHost = class {
60276
60495
  }
60277
60496
  const result = updateStartResultSchema.parse(await coordinator.start());
60278
60497
  await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(result) }));
60279
- coordinator.requestShutdown();
60280
60498
  } catch (error52) {
60281
60499
  await this.#writer.json(rpcError(request, -32091, errorMessage3(error52).slice(0, 500)));
60282
60500
  }
@@ -60371,9 +60589,13 @@ var AppServerHost = class {
60371
60589
  );
60372
60590
  return;
60373
60591
  }
60592
+ const adapter = this.#externalAdapters.get(resolution.thread.harnessId);
60593
+ if (adapter && isCreditsAdapter(adapter)) void adapter.refreshCredits();
60594
+ const credits = adapter && isCreditsAdapter(adapter) ? projectAccountCredits(adapter.credits()) : null;
60374
60595
  const result = threadUsageInspectionSchema.parse({
60375
60596
  threadId: params.data.threadId,
60376
- usage: resolution.thread.latestUsage
60597
+ usage: resolution.thread.latestUsage,
60598
+ ...credits ? { accountCredits: credits } : {}
60377
60599
  });
60378
60600
  await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(result) }));
60379
60601
  }
@@ -60975,10 +61197,10 @@ var AppServerHost = class {
60975
61197
  ...typeof params.serviceTier === "string" ? { serviceTier: params.serviceTier } : {}
60976
61198
  });
60977
61199
  try {
60978
- if (params.initialTurnsPage !== void 0 && params.initialTurnsPage !== null && !isRecord25(params.initialTurnsPage)) {
61200
+ if (params.initialTurnsPage !== void 0 && params.initialTurnsPage !== null && !isRecord26(params.initialTurnsPage)) {
60979
61201
  throw new ExternalHistoryRequestError("initialTurnsPage must be an object");
60980
61202
  }
60981
- const initialPageParams = isRecord25(params.initialTurnsPage) ? params.initialTurnsPage : null;
61203
+ const initialPageParams = isRecord26(params.initialTurnsPage) ? params.initialTurnsPage : null;
60982
61204
  const initialTurnsPage = initialPageParams ? listExternalTurns(turns, initialPageParams) : null;
60983
61205
  const paginated = thread.record.historyMode === "paginated";
60984
61206
  const turnsBackwardsCursor = paginated ? listExternalTurns(turns, { limit: 1, itemsView: "notLoaded" }).backwardsCursor : null;
@@ -61230,7 +61452,7 @@ var AppServerHost = class {
61230
61452
  }
61231
61453
  }
61232
61454
  async #handleDesktopApprovalResponse(value) {
61233
- if (!isRecord25(value) || !isHostApprovalRequestId(value.id)) return false;
61455
+ if (!isRecord26(value) || !isHostApprovalRequestId(value.id)) return false;
61234
61456
  const pending = this.#pendingDesktopApprovals.get(value.id);
61235
61457
  if (!pending) return true;
61236
61458
  this.#pendingDesktopApprovals.delete(value.id);
@@ -61352,7 +61574,7 @@ var AppServerHost = class {
61352
61574
  }
61353
61575
  }
61354
61576
  async #handleDesktopQuestionResponse(value) {
61355
- if (!isRecord25(value) || !isHostQuestionRequestId(value.id)) return false;
61577
+ if (!isRecord26(value) || !isHostQuestionRequestId(value.id)) return false;
61356
61578
  const pending = this.#pendingDesktopQuestions.get(value.id);
61357
61579
  if (!pending) return true;
61358
61580
  this.#pendingDesktopQuestions.delete(value.id);
@@ -61453,18 +61675,18 @@ var AppServerHost = class {
61453
61675
  }
61454
61676
  await this.#writer.json(projection);
61455
61677
  }
61678
+ #dispatchDesktopRequest(run) {
61679
+ void run().catch((error52) => this.#diagnose(error52));
61680
+ }
61456
61681
  #diagnose(error52) {
61457
61682
  this.#options.diagnosticOutput.write(`codexhost Host Runtime: ${errorMessage3(error52)}
61458
61683
  `);
61459
61684
  }
61460
61685
  };
61461
61686
 
61462
- // packages/host-runtime/src/update-coordinator.ts
61463
- import { createConnection } from "node:net";
61464
-
61465
61687
  // packages/update-manager/dist/distribution.js
61466
- import { lstat, readFile as readFile3 } from "node:fs/promises";
61467
- import path14 from "node:path";
61688
+ import { lstat, readFile as readFile4 } from "node:fs/promises";
61689
+ import path15 from "node:path";
61468
61690
 
61469
61691
  // packages/update-manager/dist/status.js
61470
61692
  var STATUS_SCHEMA_VERSION = 1;
@@ -61519,6 +61741,7 @@ function parseUpdateStatus(value) {
61519
61741
  var UPDATE_RUNTIME_ENV = Object.freeze({
61520
61742
  launcherPid: "CODEXHOST_LAUNCHER_PID",
61521
61743
  launcherExecutable: "CODEXHOST_LAUNCHER_EXECUTABLE",
61744
+ runtimeDescriptorPath: "CODEXHOST_RUNTIME_DESCRIPTOR_PATH",
61522
61745
  controllerPort: "CODEXHOST_CONTROL_PORT",
61523
61746
  controllerNonce: "CODEXHOST_CONTROL_NONCE",
61524
61747
  npmNodePath: "CODEXHOST_NPM_NODE_PATH",
@@ -61538,7 +61761,7 @@ function parseDistributionMetadata(value) {
61538
61761
  if (Object.keys(metadata).some((key) => !allowed2.includes(key))) {
61539
61762
  throw new Error("distribution metadata contains unknown fields");
61540
61763
  }
61541
- if (metadata.schemaVersion !== 1 || metadata.distribution !== "npm" && metadata.distribution !== "installer" || !["macos-arm64", "macos-x64", "windows-x64", "windows-arm64"].includes(String(metadata.target)) || typeof metadata.version !== "string") {
61764
+ if (metadata.schemaVersion !== 1 || metadata.distribution !== "npm" && metadata.distribution !== "installer" || !["macos-arm64", "macos-x64", "windows-x64", "windows-arm64", "linux-x64"].includes(String(metadata.target)) || typeof metadata.version !== "string") {
61542
61765
  throw new Error("distribution metadata is invalid");
61543
61766
  }
61544
61767
  return {
@@ -61550,9 +61773,9 @@ function parseDistributionMetadata(value) {
61550
61773
  }
61551
61774
  function absoluteEnvironmentPath(environment, name) {
61552
61775
  const value = environment[name];
61553
- if (!value || !path14.isAbsolute(value))
61776
+ if (!value || !path15.isAbsolute(value))
61554
61777
  throw new Error(`${name} must be an absolute path`);
61555
- return path14.normalize(value);
61778
+ return path15.normalize(value);
61556
61779
  }
61557
61780
  function positiveEnvironmentInteger(environment, name) {
61558
61781
  const value = Number(environment[name]);
@@ -61569,48 +61792,52 @@ function expectedTarget(platform, architecture) {
61569
61792
  return "windows-arm64";
61570
61793
  if (platform === "win32" && architecture === "x64")
61571
61794
  return "windows-x64";
61795
+ if (platform === "linux" && architecture === "x64")
61796
+ return "linux-x64";
61572
61797
  throw new Error(`unsupported update host ${platform}/${architecture}`);
61573
61798
  }
61574
61799
  function defaultUpdateStateDirectory(platform = process.platform, environment = process.env) {
61575
61800
  if (platform === "win32") {
61576
61801
  const root = environment.LOCALAPPDATA;
61577
- if (!root || !path14.isAbsolute(root))
61802
+ if (!root || !path15.isAbsolute(root))
61578
61803
  throw new Error("LOCALAPPDATA is unavailable");
61579
- return path14.join(root, "codexhost", "updates");
61804
+ return path15.join(root, "codexhost", "updates");
61580
61805
  }
61581
61806
  const home = environment.HOME;
61582
- if (!home || !path14.isAbsolute(home))
61807
+ if (!home || !path15.isAbsolute(home))
61583
61808
  throw new Error("HOME is unavailable");
61584
- return platform === "darwin" ? path14.join(home, "Library", "Application Support", "codexhost", "updates") : path14.join(home, ".codexhost", "updates");
61809
+ return platform === "darwin" ? path15.join(home, "Library", "Application Support", "codexhost", "updates") : path15.join(home, ".codexhost", "updates");
61585
61810
  }
61586
61811
  async function resolveInstalledUpdateContext(options) {
61587
61812
  const environment = options.environment ?? process.env;
61588
61813
  const platform = options.platform ?? process.platform;
61589
61814
  const architecture = options.architecture ?? process.arch;
61590
- if (!path14.isAbsolute(options.hostRuntimePath)) {
61815
+ if (!path15.isAbsolute(options.hostRuntimePath)) {
61591
61816
  throw new Error("Host Runtime path must be absolute");
61592
61817
  }
61593
- const hostRuntimePath = path14.normalize(options.hostRuntimePath);
61818
+ const hostRuntimePath = path15.normalize(options.hostRuntimePath);
61594
61819
  const runtimeMetadata = await lstat(hostRuntimePath);
61595
61820
  if (!runtimeMetadata.isFile() || runtimeMetadata.isSymbolicLink()) {
61596
61821
  throw new Error("Host Runtime must be a regular file");
61597
61822
  }
61598
- const appDirectory = path14.dirname(hostRuntimePath);
61599
- const metadata = parseDistributionMetadata(JSON.parse(await readFile3(path14.join(appDirectory, "codexhost-distribution.json"), "utf8")));
61823
+ const appDirectory = path15.dirname(hostRuntimePath);
61824
+ const metadata = parseDistributionMetadata(JSON.parse(await readFile4(path15.join(appDirectory, "codexhost-distribution.json"), "utf8")));
61600
61825
  const target = expectedTarget(platform, architecture);
61601
61826
  if (metadata.target !== target) {
61602
61827
  throw new Error(`installed target ${metadata.target} does not match ${target}`);
61603
61828
  }
61604
61829
  const launcherPid = positiveEnvironmentInteger(environment, UPDATE_RUNTIME_ENV.launcherPid);
61605
61830
  const launcherExecutable = absoluteEnvironmentPath(environment, UPDATE_RUNTIME_ENV.launcherExecutable);
61606
- const stateDirectory = path14.normalize(options.stateDirectory ?? defaultUpdateStateDirectory(platform, environment));
61607
- const resourcesRoot = path14.dirname(appDirectory);
61608
- const installationRoot = platform === "darwin" ? path14.dirname(path14.dirname(resourcesRoot)) : resourcesRoot;
61609
- const updaterExecutable = path14.join(resourcesRoot, "libexec", platform === "win32" ? "codexhost-updater.exe" : "codexhost-updater");
61831
+ const runtimeDescriptorPath = absoluteEnvironmentPath(environment, UPDATE_RUNTIME_ENV.runtimeDescriptorPath);
61832
+ const stateDirectory = path15.normalize(options.stateDirectory ?? defaultUpdateStateDirectory(platform, environment));
61833
+ const resourcesRoot = path15.dirname(appDirectory);
61834
+ const installationRoot = platform === "darwin" ? path15.dirname(path15.dirname(resourcesRoot)) : resourcesRoot;
61835
+ const updaterExecutable = path15.join(resourcesRoot, "libexec", platform === "win32" ? "codexhost-updater.exe" : "codexhost-updater");
61610
61836
  const common = {
61611
61837
  version: metadata.version,
61612
61838
  launcherPid,
61613
61839
  launcherExecutable,
61840
+ runtimeDescriptorPath,
61614
61841
  updaterExecutable,
61615
61842
  stateDirectory
61616
61843
  };
@@ -61629,7 +61856,7 @@ async function resolveInstalledUpdateContext(options) {
61629
61856
  npmLauncherPath: absoluteEnvironmentPath(environment, UPDATE_RUNTIME_ENV.npmLauncherPath),
61630
61857
  packageRoot: absoluteEnvironmentPath(environment, UPDATE_RUNTIME_ENV.npmPackageRoot)
61631
61858
  };
61632
- if (path14.normalize(npmOptions.packageRoot) !== resourcesRoot) {
61859
+ if (path15.normalize(npmOptions.packageRoot) !== resourcesRoot) {
61633
61860
  throw new Error("npm platform package root does not own the Host Runtime");
61634
61861
  }
61635
61862
  return { metadata, common, controller, installation: { kind: "npm", options: npmOptions } };
@@ -61791,8 +62018,8 @@ function selectInstallerReleaseArtifact(release, target) {
61791
62018
  }
61792
62019
 
61793
62020
  // packages/update-manager/dist/operation-state.js
61794
- import { lstat as lstat2, mkdir as mkdir2, open as open3, readFile as readFile4, readdir as readdir2, rm as rm3, writeFile } from "node:fs/promises";
61795
- import path15 from "node:path";
62021
+ import { lstat as lstat2, mkdir as mkdir2, open as open3, readFile as readFile5, readdir as readdir2, rm as rm3, writeFile } from "node:fs/promises";
62022
+ import path16 from "node:path";
61796
62023
  var LOCK_FILE = "active-update-v1.lock";
61797
62024
  var STATUS_FILE = "status-v1.json";
61798
62025
  var TERMINAL_PHASES = /* @__PURE__ */ new Set(["succeeded", "failed"]);
@@ -61807,12 +62034,12 @@ async function regularFile(filePath) {
61807
62034
  }
61808
62035
  }
61809
62036
  async function isUpdateOperationActive(stateDirectory) {
61810
- if (!path15.isAbsolute(stateDirectory))
62037
+ if (!path16.isAbsolute(stateDirectory))
61811
62038
  throw new Error("update state directory must be absolute");
61812
- return regularFile(path15.join(stateDirectory, LOCK_FILE));
62039
+ return regularFile(path16.join(stateDirectory, LOCK_FILE));
61813
62040
  }
61814
62041
  async function discoverLatestUpdateStatus(stateDirectory) {
61815
- if (!path15.isAbsolute(stateDirectory))
62042
+ if (!path16.isAbsolute(stateDirectory))
61816
62043
  throw new Error("update state directory must be absolute");
61817
62044
  let entries;
61818
62045
  try {
@@ -61826,13 +62053,13 @@ async function discoverLatestUpdateStatus(stateDirectory) {
61826
62053
  for (const entry of entries) {
61827
62054
  if (!entry.isDirectory() || entry.isSymbolicLink() || !entry.name.startsWith("update-"))
61828
62055
  continue;
61829
- const statusPath = path15.join(stateDirectory, entry.name, STATUS_FILE);
62056
+ const statusPath = path16.join(stateDirectory, entry.name, STATUS_FILE);
61830
62057
  if (!await regularFile(statusPath))
61831
62058
  continue;
61832
62059
  try {
61833
62060
  candidates2.push({
61834
62061
  statusPath,
61835
- status: parseUpdateStatus(JSON.parse(await readFile4(statusPath, "utf8")))
62062
+ status: parseUpdateStatus(JSON.parse(await readFile5(statusPath, "utf8")))
61836
62063
  });
61837
62064
  } catch {
61838
62065
  }
@@ -61854,10 +62081,10 @@ async function cleanupTerminalUpdateState(stateDirectory, options = {}) {
61854
62081
  for (const entry of entries) {
61855
62082
  if (!entry.isDirectory() || entry.isSymbolicLink() || !entry.name.startsWith("update-"))
61856
62083
  continue;
61857
- const directory = path15.join(stateDirectory, entry.name);
61858
- const statusPath = path15.join(directory, STATUS_FILE);
62084
+ const directory = path16.join(stateDirectory, entry.name);
62085
+ const statusPath = path16.join(directory, STATUS_FILE);
61859
62086
  try {
61860
- const status = parseUpdateStatus(JSON.parse(await readFile4(statusPath, "utf8")));
62087
+ const status = parseUpdateStatus(JSON.parse(await readFile5(statusPath, "utf8")));
61861
62088
  if (TERMINAL_PHASES.has(status.phase) && now - status.updatedAt > retentionSeconds) {
61862
62089
  await rm3(directory, { recursive: true, force: true });
61863
62090
  }
@@ -61866,10 +62093,10 @@ async function cleanupTerminalUpdateState(stateDirectory, options = {}) {
61866
62093
  }
61867
62094
  }
61868
62095
  async function acquireUpdateOperationLock(stateDirectory) {
61869
- if (!path15.isAbsolute(stateDirectory))
62096
+ if (!path16.isAbsolute(stateDirectory))
61870
62097
  throw new Error("update state directory must be absolute");
61871
62098
  await mkdir2(stateDirectory, { recursive: true, mode: 448 });
61872
- const lockPath = path15.join(stateDirectory, LOCK_FILE);
62099
+ const lockPath = path16.join(stateDirectory, LOCK_FILE);
61873
62100
  let handle;
61874
62101
  try {
61875
62102
  handle = await open3(lockPath, "wx", 384);
@@ -61888,9 +62115,9 @@ async function acquireUpdateOperationLock(stateDirectory) {
61888
62115
  async setStatusPath(statusPath) {
61889
62116
  if (released)
61890
62117
  throw new Error("update operation lock is released");
61891
- if (!path15.isAbsolute(statusPath))
62118
+ if (!path16.isAbsolute(statusPath))
61892
62119
  throw new Error("update status path must be absolute");
61893
- await writeFile(lockPath, `${JSON.stringify({ ownerPid: process.pid, statusPath: path15.normalize(statusPath) })}
62120
+ await writeFile(lockPath, `${JSON.stringify({ ownerPid: process.pid, statusPath: path16.normalize(statusPath) })}
61894
62121
  `, { encoding: "utf8", mode: 384 });
61895
62122
  },
61896
62123
  async release() {
@@ -61912,22 +62139,22 @@ function processIsAlive(processId) {
61912
62139
  }
61913
62140
  }
61914
62141
  async function recoverUpdateOperationLock(stateDirectory) {
61915
- const lockPath = path15.join(stateDirectory, LOCK_FILE);
62142
+ const lockPath = path16.join(stateDirectory, LOCK_FILE);
61916
62143
  if (!await regularFile(lockPath))
61917
62144
  return;
61918
62145
  let ownerPid;
61919
62146
  let statusPath;
61920
62147
  try {
61921
- const value = JSON.parse(await readFile4(lockPath, "utf8"));
62148
+ const value = JSON.parse(await readFile5(lockPath, "utf8"));
61922
62149
  ownerPid = value.ownerPid;
61923
62150
  statusPath = value.statusPath;
61924
62151
  } catch {
61925
62152
  return;
61926
62153
  }
61927
- if (typeof statusPath !== "string" || !path15.isAbsolute(statusPath))
62154
+ if (typeof statusPath !== "string" || !path16.isAbsolute(statusPath))
61928
62155
  return;
61929
62156
  try {
61930
- const status = parseUpdateStatus(JSON.parse(await readFile4(statusPath, "utf8")));
62157
+ const status = parseUpdateStatus(JSON.parse(await readFile5(statusPath, "utf8")));
61931
62158
  if (TERMINAL_PHASES.has(status.phase) || typeof ownerPid !== "number" || !processIsAlive(ownerPid)) {
61932
62159
  await rm3(lockPath, { force: true });
61933
62160
  }
@@ -61938,8 +62165,8 @@ async function recoverUpdateOperationLock(stateDirectory) {
61938
62165
  // packages/update-manager/dist/update-manager.js
61939
62166
  import { spawn as spawn6 } from "node:child_process";
61940
62167
  import { randomUUID as randomUUID10 } from "node:crypto";
61941
- import { chmod, copyFile as copyFile2, lstat as lstat4, mkdir as mkdir3, readFile as readFile5, rename as rename2, rm as rm4, writeFile as writeFile2 } from "node:fs/promises";
61942
- import path16 from "node:path";
62168
+ import { chmod, copyFile as copyFile2, lstat as lstat4, mkdir as mkdir3, readFile as readFile6, rename as rename2, rm as rm4, writeFile as writeFile2 } from "node:fs/promises";
62169
+ import path17 from "node:path";
61943
62170
 
61944
62171
  // packages/update-manager/dist/artifact.js
61945
62172
  import { createHash as createHash2 } from "node:crypto";
@@ -62032,13 +62259,37 @@ async function verifyDownloadedArtifact(source, filePath, result) {
62032
62259
 
62033
62260
  // packages/update-manager/dist/update-manager.js
62034
62261
  var REQUEST_SCHEMA_VERSION = 1;
62262
+ var WINDOWS_RENAME_RETRY_DELAYS_MS = [10, 30, 70, 150, 300];
62035
62263
  function errorMessage4(error52) {
62036
62264
  return error52 instanceof Error ? error52.message : String(error52);
62037
62265
  }
62266
+ function systemErrorCode2(error52) {
62267
+ return typeof error52 === "object" && error52 !== null && "code" in error52 ? String(error52.code) : null;
62268
+ }
62269
+ function delay4(milliseconds) {
62270
+ return new Promise((resolve2) => setTimeout(resolve2, milliseconds));
62271
+ }
62272
+ async function replaceStatusFile(temporaryPath, statusPath) {
62273
+ let retryIndex = 0;
62274
+ for (; ; ) {
62275
+ try {
62276
+ await rename2(temporaryPath, statusPath);
62277
+ return;
62278
+ } catch (error52) {
62279
+ const retryDelay = WINDOWS_RENAME_RETRY_DELAYS_MS[retryIndex];
62280
+ const code = systemErrorCode2(error52);
62281
+ if (process.platform !== "win32" || retryDelay === void 0 || code !== "EACCES" && code !== "EBUSY" && code !== "EPERM") {
62282
+ throw error52;
62283
+ }
62284
+ retryIndex += 1;
62285
+ await delay4(retryDelay);
62286
+ }
62287
+ }
62288
+ }
62038
62289
  function requireAbsolutePath(value, label) {
62039
- if (!path16.isAbsolute(value))
62290
+ if (!path17.isAbsolute(value))
62040
62291
  throw new Error(`${label} must be an absolute path`);
62041
- return path16.normalize(value);
62292
+ return path17.normalize(value);
62042
62293
  }
62043
62294
  async function requireRegularFile(value, label) {
62044
62295
  const filePath = requireAbsolutePath(value, label);
@@ -62081,7 +62332,7 @@ function createBackgroundUpdateManager(dependencies = {}) {
62081
62332
  const now = dependencies.now ?? Date.now;
62082
62333
  const preparedRequests = /* @__PURE__ */ new Set();
62083
62334
  async function writeStatusSnapshot(statusPath, status) {
62084
- const temporaryPath = path16.join(path16.dirname(statusPath), `.update-status-${randomId()}.tmp`);
62335
+ const temporaryPath = path17.join(path17.dirname(statusPath), `.update-status-${randomId()}.tmp`);
62085
62336
  try {
62086
62337
  await writeFile2(temporaryPath, `${JSON.stringify(status)}
62087
62338
  `, {
@@ -62089,7 +62340,7 @@ function createBackgroundUpdateManager(dependencies = {}) {
62089
62340
  mode: 384,
62090
62341
  flag: "wx"
62091
62342
  });
62092
- await rename2(temporaryPath, statusPath);
62343
+ await replaceStatusFile(temporaryPath, statusPath);
62093
62344
  } catch (error52) {
62094
62345
  await rm4(temporaryPath, { force: true });
62095
62346
  throw error52;
@@ -62137,24 +62388,26 @@ function createBackgroundUpdateManager(dependencies = {}) {
62137
62388
  const version2 = requireSemanticVersion(options.version);
62138
62389
  const launcherPid = requireLauncherPid(options.launcherPid);
62139
62390
  const launcherExecutable = await requireRegularFile(options.launcherExecutable, "Launcher executable");
62391
+ const runtimeDescriptorPath = requireAbsolutePath(options.runtimeDescriptorPath, "runtime descriptor path");
62140
62392
  const updaterExecutable = await requireRegularFile(options.updaterExecutable, "Updater executable");
62141
62393
  const stateDirectory = requireAbsolutePath(options.stateDirectory, "update state directory");
62142
62394
  await mkdir3(stateDirectory, { recursive: true, mode: 448 });
62143
- const workDirectory = path16.join(stateDirectory, `update-${version2}-${randomId()}`);
62395
+ const workDirectory = path17.join(stateDirectory, `update-${version2}-${randomId()}`);
62144
62396
  await mkdir3(workDirectory, { recursive: false, mode: 448 });
62145
62397
  const executableSuffix = platform === "win32" ? ".exe" : "";
62146
- const helperPath = path16.join(workDirectory, `codexhost-updater${executableSuffix}`);
62398
+ const helperPath = path17.join(workDirectory, `codexhost-updater${executableSuffix}`);
62147
62399
  await copyFile2(updaterExecutable, helperPath);
62148
62400
  if (platform !== "win32")
62149
62401
  await chmod(helperPath, 448);
62150
- const requestPath = path16.join(workDirectory, "request-v1.json");
62151
- const statusPath = path16.join(workDirectory, "status-v1.json");
62402
+ const requestPath = path17.join(workDirectory, "request-v1.json");
62403
+ const statusPath = path17.join(workDirectory, "status-v1.json");
62152
62404
  await writePrivateJson(statusPath, preparedStatus(version2, installation, now()));
62153
62405
  await options.onPrepared?.({ version: version2, installation, statusPath });
62154
62406
  return {
62155
62407
  version: version2,
62156
62408
  launcherPid,
62157
62409
  launcherExecutable,
62410
+ runtimeDescriptorPath,
62158
62411
  workDirectory,
62159
62412
  helperPath,
62160
62413
  requestPath,
@@ -62163,8 +62416,8 @@ function createBackgroundUpdateManager(dependencies = {}) {
62163
62416
  }
62164
62417
  async function prepareArtifact(common, installation, sourceValue, fileName) {
62165
62418
  const source = validateArtifact(sourceValue);
62166
- const temporaryPath = path16.join(common.workDirectory, `.${fileName}.download`);
62167
- const artifactPath = path16.join(common.workDirectory, fileName);
62419
+ const temporaryPath = path17.join(common.workDirectory, `.${fileName}.download`);
62420
+ const artifactPath = path17.join(common.workDirectory, fileName);
62168
62421
  const progress = progressReporter(common.statusPath, common.version, installation, source.size);
62169
62422
  try {
62170
62423
  const result = await download(source, temporaryPath, progress.update);
@@ -62190,6 +62443,7 @@ function createBackgroundUpdateManager(dependencies = {}) {
62190
62443
  version: common.version,
62191
62444
  wait_pid: common.launcherPid,
62192
62445
  wait_executable: common.launcherExecutable,
62446
+ runtime_descriptor_path: common.runtimeDescriptorPath,
62193
62447
  status_path: common.statusPath,
62194
62448
  installation
62195
62449
  };
@@ -62237,7 +62491,7 @@ function createBackgroundUpdateManager(dependencies = {}) {
62237
62491
  throw new Error("macOS DMG updates require macOS");
62238
62492
  const common = await prepareCommon(options, "macos-dmg");
62239
62493
  const appPath = requireAbsolutePath(options.appPath, "macOS application path");
62240
- if (path16.extname(appPath) !== ".app") {
62494
+ if (path17.extname(appPath) !== ".app") {
62241
62495
  throw new Error("macOS application path must end in .app");
62242
62496
  }
62243
62497
  const artifact = await prepareArtifact(common, "macos-dmg", options.artifact, "update.dmg");
@@ -62260,7 +62514,7 @@ function createBackgroundUpdateManager(dependencies = {}) {
62260
62514
  async readStatus(statusPathValue) {
62261
62515
  const statusPath = requireAbsolutePath(statusPathValue, "update status path");
62262
62516
  try {
62263
- return parseUpdateStatus(JSON.parse(await readFile5(statusPath, "utf8")));
62517
+ return parseUpdateStatus(JSON.parse(await readFile6(statusPath, "utf8")));
62264
62518
  } catch (error52) {
62265
62519
  if (error52.code === "ENOENT")
62266
62520
  return null;
@@ -62272,37 +62526,10 @@ function createBackgroundUpdateManager(dependencies = {}) {
62272
62526
 
62273
62527
  // packages/host-runtime/src/update-coordinator.ts
62274
62528
  var ERROR_MAX_LENGTH = 500;
62275
- var CONTROLLER_TIMEOUT_MS = 5e3;
62276
- var UPDATER_READY_TIMEOUT_MS = 1e4;
62277
- var UPDATER_READY_POLL_MS = 20;
62278
62529
  function boundedError(error52) {
62279
62530
  const message3 = error52 instanceof Error ? error52.message : String(error52);
62280
62531
  return message3.slice(0, ERROR_MAX_LENGTH) || "Update operation failed";
62281
62532
  }
62282
- function delay4(milliseconds) {
62283
- return new Promise((resolve2) => setTimeout(resolve2, milliseconds));
62284
- }
62285
- async function waitForUpdaterReady(manager, statusPath) {
62286
- const deadline = Date.now() + UPDATER_READY_TIMEOUT_MS;
62287
- while (Date.now() < deadline) {
62288
- const status = await manager.readStatus(statusPath);
62289
- switch (status?.phase) {
62290
- case "waiting-for-exit":
62291
- case "installing":
62292
- case "restarting":
62293
- case "succeeded":
62294
- return;
62295
- case "failed":
62296
- throw new Error(status.error ?? "Background Updater failed before Desktop shutdown");
62297
- case "prepared":
62298
- break;
62299
- default:
62300
- throw new Error("Background Updater reported an unexpected startup phase");
62301
- }
62302
- await delay4(UPDATER_READY_POLL_MS);
62303
- }
62304
- throw new Error("Background Updater did not become ready before Desktop shutdown");
62305
- }
62306
62533
  function publicStatus(status) {
62307
62534
  return {
62308
62535
  version: status.version,
@@ -62314,34 +62541,6 @@ function publicStatus(status) {
62314
62541
  error: status.error?.slice(0, ERROR_MAX_LENGTH) ?? null
62315
62542
  };
62316
62543
  }
62317
- function requestControllerShutdown(controller) {
62318
- return new Promise((resolve2, reject) => {
62319
- const socket = createConnection({ host: "127.0.0.1", port: controller.port });
62320
- let response = "";
62321
- const timeout = setTimeout(
62322
- () => socket.destroy(new Error("Controller shutdown timed out")),
62323
- CONTROLLER_TIMEOUT_MS
62324
- );
62325
- const settle = (operation) => {
62326
- clearTimeout(timeout);
62327
- operation();
62328
- };
62329
- socket.setEncoding("utf8");
62330
- socket.once("error", (error52) => settle(() => reject(error52)));
62331
- socket.on("data", (chunk) => {
62332
- response += chunk;
62333
- });
62334
- socket.once(
62335
- "end",
62336
- () => settle(() => {
62337
- if (response === "ready\n") resolve2();
62338
- else reject(new Error("Desktop Controller rejected the shutdown request"));
62339
- })
62340
- );
62341
- socket.once("connect", () => socket.write(`SHUTDOWN ${controller.nonce}
62342
- `));
62343
- });
62344
- }
62345
62544
  function createHostUpdateCoordinator(options) {
62346
62545
  const platform = options.platform ?? process.platform;
62347
62546
  const manager = options.manager ?? createBackgroundUpdateManager({ platform });
@@ -62352,16 +62551,7 @@ function createHostUpdateCoordinator(options) {
62352
62551
  ...options.architecture ? { architecture: options.architecture } : {}
62353
62552
  });
62354
62553
  const fetchLatest = options.fetchLatest ?? ((signal) => fetchLatestGitHubRelease({ signal: signal ?? AbortSignal.timeout(15e3) }));
62355
- const shutdown = options.shutdown ?? requestControllerShutdown;
62356
62554
  let candidate = null;
62357
- let shutdownPending = null;
62358
- let shutdownRequested = false;
62359
- const scheduleShutdown = () => {
62360
- if (!shutdownRequested || !shutdownPending) return;
62361
- const controller = shutdownPending;
62362
- shutdownPending = null;
62363
- setTimeout(() => void shutdown(controller).catch(() => void 0), 50).unref();
62364
- };
62365
62555
  async function latestStatus(context) {
62366
62556
  const discovered = await discoverLatestUpdateStatus(context.common.stateDirectory);
62367
62557
  if (!discovered) return null;
@@ -62371,9 +62561,11 @@ function createHostUpdateCoordinator(options) {
62371
62561
  return publicStatus(discovered.status);
62372
62562
  }
62373
62563
  async function installable(context, release) {
62374
- if (context.metadata.distribution === "npm") return true;
62564
+ if (context.installation.kind === "npm") return true;
62565
+ const target = context.metadata.target;
62566
+ if (target === "linux-x64") return false;
62375
62567
  try {
62376
- selectInstallerReleaseArtifact(release, context.metadata.target);
62568
+ selectInstallerReleaseArtifact(release, target);
62377
62569
  return true;
62378
62570
  } catch {
62379
62571
  return false;
@@ -62471,10 +62663,11 @@ function createHostUpdateCoordinator(options) {
62471
62663
  onPrepared
62472
62664
  });
62473
62665
  } else {
62474
- const artifact = selectInstallerReleaseArtifact(
62475
- release,
62476
- context.metadata.target
62477
- ).source;
62666
+ const target = context.metadata.target;
62667
+ if (target === "linux-x64") {
62668
+ throw new Error("Linux installer updates are unsupported");
62669
+ }
62670
+ const artifact = selectInstallerReleaseArtifact(release, target).source;
62478
62671
  prepared2 = context.installation.kind === "windows-installer" ? await manager.prepareWindowsInstaller({
62479
62672
  ...context.installation.options,
62480
62673
  version: release.version,
@@ -62488,9 +62681,6 @@ function createHostUpdateCoordinator(options) {
62488
62681
  });
62489
62682
  }
62490
62683
  if (platform !== "darwin") manager.start(prepared2);
62491
- await waitForUpdaterReady(manager, prepared2.statusPath);
62492
- shutdownPending = context.controller;
62493
- scheduleShutdown();
62494
62684
  } catch (error52) {
62495
62685
  await lock.release();
62496
62686
  rejectPrepared(error52);
@@ -62514,10 +62704,6 @@ function createHostUpdateCoordinator(options) {
62514
62704
  } catch {
62515
62705
  return { status: null };
62516
62706
  }
62517
- },
62518
- requestShutdown() {
62519
- shutdownRequested = true;
62520
- scheduleShutdown();
62521
62707
  }
62522
62708
  });
62523
62709
  }