@codexhost/cli-darwin-x64 0.2.1 → 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.
package/README.md CHANGED
@@ -7,7 +7,7 @@ Run Pi and Claude Code as first-class external harnesses inside Codex Desktop.
7
7
  ## Install
8
8
 
9
9
  ```bash
10
- npm install -g @codexhost/cli@0.2.1
10
+ npm install -g @codexhost/cli@0.2.2
11
11
  ```
12
12
 
13
13
  Do not install this package directly. npm selects it through the optional dependencies of `@codexhost/cli`.
@@ -32,7 +32,7 @@ The `codexhost` command launches the packaged Rust launcher with:
32
32
  ## Requirements
33
33
 
34
34
  - Node.js 22 or 24 (Node 20 and older are not supported)
35
- - Official Codex Desktop for macOS or Windows
35
+ - Official ChatGPT/Codex Desktop for macOS, Windows, or Linux
36
36
  - Pi on `PATH` when using the Pi agent
37
37
  - Claude Code installed when using the Claude Code adapter
38
38
 
@@ -1 +1 @@
1
- {"schemaVersion":1,"version":"0.2.1","distribution":"npm","target":"macos-x64"}
1
+ {"schemaVersion":1,"version":"0.2.2","distribution":"npm","target":"macos-x64"}
@@ -51911,6 +51911,7 @@ function isSyntheticGrokTurnKey(nativeTurnKey3) {
51911
51911
  return taskCompletedTurnKeyPattern.test(nativeTurnKey3);
51912
51912
  }
51913
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]));
51914
51915
  const turns = [];
51915
51916
  let input = "";
51916
51917
  let items = [];
@@ -51941,13 +51942,11 @@ function mapGrokReplay(replay, harnessId, sessionId, knownTurnRefs = []) {
51941
51942
  const completeTurn = (outcome, terminalKey) => {
51942
51943
  if (input.length === 0)
51943
51944
  return;
51944
- const known = knownTurnRefs[turnIndex];
51945
- if (known && (known.harnessId !== harnessId || known.nativeSessionId !== sessionId)) {
51946
- throw new Error("Known Grok Turn identity does not belong to the Native Session");
51947
- }
51948
- const stableKey = known?.nativeTurnKey ?? terminalKey ?? nativeTurnKey3;
51949
- if (!stableKey)
51945
+ const reconstructedKey = terminalKey ?? nativeTurnKey3;
51946
+ if (!reconstructedKey)
51950
51947
  throw new Error("Grok Native history Turn has no stable identity");
51948
+ const known = knownByNativeKey.get(reconstructedKey);
51949
+ const stableKey = known?.nativeTurnKey ?? reconstructedKey;
51951
51950
  completeReasoning();
51952
51951
  completeAgent();
51953
51952
  completeTools();
@@ -52033,9 +52032,6 @@ function mapGrokReplay(replay, harnessId, sessionId, knownTurnRefs = []) {
52033
52032
  }
52034
52033
  }
52035
52034
  completeTurn({ status: "unknown", reason: "Grok Native history has no terminal signal" });
52036
- if (knownTurnRefs.length > turns.length) {
52037
- throw new Error("Grok Native history is missing persisted Turns");
52038
- }
52039
52035
  return { turns };
52040
52036
  }
52041
52037
 
@@ -52297,16 +52293,75 @@ function usageFromSignals(value) {
52297
52293
  return null;
52298
52294
  }
52299
52295
  }
52300
- function lastTurnUsage(events) {
52301
- for (let index = events.length - 1; index >= 0; index -= 1) {
52302
- 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) {
52303
52323
  if (event?.type !== "turn.completed")
52304
52324
  continue;
52325
+ const key = historyTurnKey(event, index);
52326
+ index += 1;
52327
+ if (key === null)
52328
+ continue;
52305
52329
  const usage = usageFromNative(event.usage);
52306
- if (usage)
52307
- 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;
52308
52364
  }
52309
- return null;
52310
52365
  }
52311
52366
  function usageFromUpdate(update, metadata, contextWindowTokens) {
52312
52367
  try {
@@ -52434,6 +52489,7 @@ var GrokHarnessSession = class {
52434
52489
  #cwd;
52435
52490
  #modelState;
52436
52491
  #onClosed;
52492
+ #refreshCredits;
52437
52493
  #randomUUID;
52438
52494
  #snapshot;
52439
52495
  #toolOutputLimit;
@@ -52449,6 +52505,7 @@ var GrokHarnessSession = class {
52449
52505
  this.#transport = transport;
52450
52506
  this.#modelState = modelState;
52451
52507
  this.#onClosed = onClosed;
52508
+ this.#refreshCredits = options.refreshCredits;
52452
52509
  this.#closeTimeoutMs = options.closeTimeoutMs;
52453
52510
  this.#randomUUID = options.randomUUID;
52454
52511
  this.#toolOutputLimit = options.toolOutputLimit;
@@ -52715,11 +52772,7 @@ var GrokHarnessSession = class {
52715
52772
  this.#startTool(active, event);
52716
52773
  else if (event.type === "tool.update")
52717
52774
  this.#updateTool(active, event);
52718
- else if (event.type === "turn.completed") {
52719
- const usage = usageFromNative(event.usage);
52720
- if (usage)
52721
- this.#publishUsage(usage, active.command.turnId);
52722
- } else if (event.type === "usage")
52775
+ else if (event.type === "usage" || event.type === "turn.completed")
52723
52776
  return;
52724
52777
  }
52725
52778
  #appendAgent(active, text, messageId) {
@@ -52856,7 +52909,8 @@ var GrokHarnessSession = class {
52856
52909
  outcome = { status: "failed", error: normalizeError(error52, "protocolError") };
52857
52910
  }
52858
52911
  }
52859
- 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);
52860
52914
  }
52861
52915
  #finish(active, outcome, usage = null, nativeTurnRef2) {
52862
52916
  if (this.#active !== active)
@@ -53086,13 +53140,14 @@ var GrokAdapter = class {
53086
53140
  }
53087
53141
  }
53088
53142
  const history = await transport.getHistory();
53089
- 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;
53090
53144
  const openedSession = new GrokHarnessSession(cwd, transport, opened, modelState, () => this.#sessions.delete(openedSession), {
53091
53145
  closeTimeoutMs: this.#closeTimeoutMs,
53092
53146
  history,
53093
53147
  initialUsage,
53094
53148
  ...input.kind === "resume" && input.knownTurnRefs ? { knownTurnRefs: input.knownTurnRefs } : {},
53095
53149
  randomUUID: this.#dependencies.randomUUID,
53150
+ refreshCredits: () => this.refreshCredits(),
53096
53151
  toolOutputLimit: this.#toolOutputLimit
53097
53152
  });
53098
53153
  session = openedSession;
@@ -53558,27 +53613,28 @@ function pathCandidates(command, platform, environment) {
53558
53613
  const extensions = platform === "win32" && targetPath.extname(command) === "" ? (environmentValue2(environment, "PATHEXT") ?? ".COM;.EXE;.BAT;.CMD").split(";").map((extension) => extension.trim()).filter(Boolean) : [""];
53559
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)));
53560
53615
  }
53561
- function nvmCandidates2(homeDirectory, executableName) {
53562
- const versionsDirectory = path11.join(homeDirectory, ".nvm", "versions", "node");
53616
+ function nvmCandidates2(homeDirectory, executableName, targetPath) {
53617
+ const versionsDirectory = targetPath.join(homeDirectory, ".nvm", "versions", "node");
53563
53618
  try {
53564
- 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) => path11.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));
53565
53620
  } catch {
53566
53621
  return [];
53567
53622
  }
53568
53623
  }
53569
53624
  function userInstallCandidates2(platform, environment, homeDirectory) {
53625
+ const targetPath = platform === "win32" ? path11.win32 : path11.posix;
53570
53626
  if (platform === "win32") {
53571
- const appData = environment.APPDATA ?? path11.join(homeDirectory, "AppData", "Roaming");
53627
+ const appData = environment.APPDATA ?? targetPath.join(homeDirectory, "AppData", "Roaming");
53572
53628
  return [
53573
- path11.join(appData, "npm", "pi.cmd"),
53574
- path11.join(homeDirectory, ".local", "bin", "pi.exe"),
53575
- path11.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")
53576
53632
  ];
53577
53633
  }
53578
53634
  return [
53579
- path11.join(homeDirectory, ".npm-global", "bin", "pi"),
53580
- path11.join(homeDirectory, ".local", "bin", "pi"),
53581
- ...nvmCandidates2(homeDirectory, "pi"),
53635
+ targetPath.join(homeDirectory, ".npm-global", "bin", "pi"),
53636
+ targetPath.join(homeDirectory, ".local", "bin", "pi"),
53637
+ ...nvmCandidates2(homeDirectory, "pi", targetPath),
53582
53638
  "/opt/homebrew/bin/pi",
53583
53639
  "/usr/local/bin/pi"
53584
53640
  ];
@@ -56244,6 +56300,18 @@ function isNodeExecutable(value) {
56244
56300
  function lockOwnerIsLive(lock) {
56245
56301
  if (typeof lock.pid !== "number")
56246
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
+ }
56247
56315
  const identity = processIdentity(lock.pid);
56248
56316
  if (!identity)
56249
56317
  return false;
@@ -56423,27 +56491,29 @@ var MappingStore = class {
56423
56491
  if (current.state !== "ready" || !current.nativeSessionRef) {
56424
56492
  throw new MappingStoreError("MAPPING_CONFLICT", "Only a ready Thread can reconcile Snapshot mappings");
56425
56493
  }
56426
- const merged = this.#mergeMappings(current.turnMappings, mappings);
56427
- if (merged.length !== mappings.length) {
56428
- throw new MappingStoreError("MAPPING_CONFLICT", "Snapshot reconciliation must retain every existing Turn mapping");
56429
- }
56430
- const mergedByHost = new Map(merged.map((mapping) => [mapping.hostTurnId, mapping]));
56431
- const ordered = mappings.map(({ hostTurnId }) => {
56432
- const mapping = mergedByHost.get(hostTurnId);
56433
- 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))) {
56434
56511
  throw new MappingStoreError("MAPPING_CONFLICT", "Snapshot reconciliation contains a duplicate Turn mapping");
56435
56512
  }
56436
- return mapping;
56513
+ seenHost.add(update.hostTurnId);
56514
+ seenNative.add(nativeTurnKey(update));
56515
+ return { ...update };
56437
56516
  });
56438
- const orderedIndexByHost = new Map(ordered.map(({ hostTurnId }, index) => [hostTurnId, index]));
56439
- let previousIndex = -1;
56440
- for (const existing of current.turnMappings) {
56441
- const nextIndex = orderedIndexByHost.get(existing.hostTurnId);
56442
- if (nextIndex === void 0 || nextIndex <= previousIndex) {
56443
- throw new MappingStoreError("MAPPING_CONFLICT", "Snapshot reconciliation reordered an existing Turn mapping");
56444
- }
56445
- previousIndex = nextIndex;
56446
- }
56447
56517
  return sameJson(current.turnMappings, ordered) ? null : { ...current, turnMappings: ordered };
56448
56518
  });
56449
56519
  }
@@ -58454,25 +58524,14 @@ var ExternalThreadRepository = class {
58454
58524
  ...turn.checkpoint ? { nativeCheckpointRef: turn.checkpoint } : {}
58455
58525
  };
58456
58526
  return {
58457
- existing,
58458
58527
  snapshot: turn,
58459
58528
  mapping: {
58460
58529
  ...mapping,
58530
+ nativeTurnRef: turn.nativeTurnRef,
58461
58531
  ...turn.checkpoint ? { nativeCheckpointRef: turn.checkpoint } : {}
58462
58532
  }
58463
58533
  };
58464
58534
  });
58465
- let existingIndex = 0;
58466
- for (const { existing } of aligned) {
58467
- if (!existing) continue;
58468
- if (existing.hostTurnId !== record3.turnMappings[existingIndex]?.hostTurnId) {
58469
- throw new Error("Persisted Turn mappings do not match the Native Snapshot order");
58470
- }
58471
- existingIndex += 1;
58472
- }
58473
- if (existingIndex !== record3.turnMappings.length) {
58474
- throw new Error("Persisted Turn mappings do not match the Native Snapshot order");
58475
- }
58476
58535
  const orderedMappings = aligned.map(({ mapping }) => mapping);
58477
58536
  const mappingsChanged = orderedMappings.length !== record3.turnMappings.length || orderedMappings.some((mapping, index) => {
58478
58537
  const persisted = record3.turnMappings[index];
@@ -59795,6 +59854,7 @@ function officialEnvironment(source) {
59795
59854
  "CODEXHOST_STOCK_CODEX_PATH",
59796
59855
  "CODEXHOST_LAUNCHER_PID",
59797
59856
  "CODEXHOST_LAUNCHER_EXECUTABLE",
59857
+ "CODEXHOST_RUNTIME_DESCRIPTOR_PATH",
59798
59858
  "CODEXHOST_CONTROL_PORT",
59799
59859
  "CODEXHOST_CONTROL_NONCE",
59800
59860
  "CODEXHOST_NPM_NODE_PATH",
@@ -61681,6 +61741,7 @@ function parseUpdateStatus(value) {
61681
61741
  var UPDATE_RUNTIME_ENV = Object.freeze({
61682
61742
  launcherPid: "CODEXHOST_LAUNCHER_PID",
61683
61743
  launcherExecutable: "CODEXHOST_LAUNCHER_EXECUTABLE",
61744
+ runtimeDescriptorPath: "CODEXHOST_RUNTIME_DESCRIPTOR_PATH",
61684
61745
  controllerPort: "CODEXHOST_CONTROL_PORT",
61685
61746
  controllerNonce: "CODEXHOST_CONTROL_NONCE",
61686
61747
  npmNodePath: "CODEXHOST_NPM_NODE_PATH",
@@ -61700,7 +61761,7 @@ function parseDistributionMetadata(value) {
61700
61761
  if (Object.keys(metadata).some((key) => !allowed2.includes(key))) {
61701
61762
  throw new Error("distribution metadata contains unknown fields");
61702
61763
  }
61703
- 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") {
61704
61765
  throw new Error("distribution metadata is invalid");
61705
61766
  }
61706
61767
  return {
@@ -61731,6 +61792,8 @@ function expectedTarget(platform, architecture) {
61731
61792
  return "windows-arm64";
61732
61793
  if (platform === "win32" && architecture === "x64")
61733
61794
  return "windows-x64";
61795
+ if (platform === "linux" && architecture === "x64")
61796
+ return "linux-x64";
61734
61797
  throw new Error(`unsupported update host ${platform}/${architecture}`);
61735
61798
  }
61736
61799
  function defaultUpdateStateDirectory(platform = process.platform, environment = process.env) {
@@ -61765,6 +61828,7 @@ async function resolveInstalledUpdateContext(options) {
61765
61828
  }
61766
61829
  const launcherPid = positiveEnvironmentInteger(environment, UPDATE_RUNTIME_ENV.launcherPid);
61767
61830
  const launcherExecutable = absoluteEnvironmentPath(environment, UPDATE_RUNTIME_ENV.launcherExecutable);
61831
+ const runtimeDescriptorPath = absoluteEnvironmentPath(environment, UPDATE_RUNTIME_ENV.runtimeDescriptorPath);
61768
61832
  const stateDirectory = path15.normalize(options.stateDirectory ?? defaultUpdateStateDirectory(platform, environment));
61769
61833
  const resourcesRoot = path15.dirname(appDirectory);
61770
61834
  const installationRoot = platform === "darwin" ? path15.dirname(path15.dirname(resourcesRoot)) : resourcesRoot;
@@ -61773,6 +61837,7 @@ async function resolveInstalledUpdateContext(options) {
61773
61837
  version: metadata.version,
61774
61838
  launcherPid,
61775
61839
  launcherExecutable,
61840
+ runtimeDescriptorPath,
61776
61841
  updaterExecutable,
61777
61842
  stateDirectory
61778
61843
  };
@@ -62194,9 +62259,33 @@ async function verifyDownloadedArtifact(source, filePath, result) {
62194
62259
 
62195
62260
  // packages/update-manager/dist/update-manager.js
62196
62261
  var REQUEST_SCHEMA_VERSION = 1;
62262
+ var WINDOWS_RENAME_RETRY_DELAYS_MS = [10, 30, 70, 150, 300];
62197
62263
  function errorMessage4(error52) {
62198
62264
  return error52 instanceof Error ? error52.message : String(error52);
62199
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
+ }
62200
62289
  function requireAbsolutePath(value, label) {
62201
62290
  if (!path17.isAbsolute(value))
62202
62291
  throw new Error(`${label} must be an absolute path`);
@@ -62251,7 +62340,7 @@ function createBackgroundUpdateManager(dependencies = {}) {
62251
62340
  mode: 384,
62252
62341
  flag: "wx"
62253
62342
  });
62254
- await rename2(temporaryPath, statusPath);
62343
+ await replaceStatusFile(temporaryPath, statusPath);
62255
62344
  } catch (error52) {
62256
62345
  await rm4(temporaryPath, { force: true });
62257
62346
  throw error52;
@@ -62299,6 +62388,7 @@ function createBackgroundUpdateManager(dependencies = {}) {
62299
62388
  const version2 = requireSemanticVersion(options.version);
62300
62389
  const launcherPid = requireLauncherPid(options.launcherPid);
62301
62390
  const launcherExecutable = await requireRegularFile(options.launcherExecutable, "Launcher executable");
62391
+ const runtimeDescriptorPath = requireAbsolutePath(options.runtimeDescriptorPath, "runtime descriptor path");
62302
62392
  const updaterExecutable = await requireRegularFile(options.updaterExecutable, "Updater executable");
62303
62393
  const stateDirectory = requireAbsolutePath(options.stateDirectory, "update state directory");
62304
62394
  await mkdir3(stateDirectory, { recursive: true, mode: 448 });
@@ -62317,6 +62407,7 @@ function createBackgroundUpdateManager(dependencies = {}) {
62317
62407
  version: version2,
62318
62408
  launcherPid,
62319
62409
  launcherExecutable,
62410
+ runtimeDescriptorPath,
62320
62411
  workDirectory,
62321
62412
  helperPath,
62322
62413
  requestPath,
@@ -62352,6 +62443,7 @@ function createBackgroundUpdateManager(dependencies = {}) {
62352
62443
  version: common.version,
62353
62444
  wait_pid: common.launcherPid,
62354
62445
  wait_executable: common.launcherExecutable,
62446
+ runtime_descriptor_path: common.runtimeDescriptorPath,
62355
62447
  status_path: common.statusPath,
62356
62448
  installation
62357
62449
  };
@@ -62469,9 +62561,11 @@ function createHostUpdateCoordinator(options) {
62469
62561
  return publicStatus(discovered.status);
62470
62562
  }
62471
62563
  async function installable(context, release) {
62472
- 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;
62473
62567
  try {
62474
- selectInstallerReleaseArtifact(release, context.metadata.target);
62568
+ selectInstallerReleaseArtifact(release, target);
62475
62569
  return true;
62476
62570
  } catch {
62477
62571
  return false;
@@ -62569,10 +62663,11 @@ function createHostUpdateCoordinator(options) {
62569
62663
  onPrepared
62570
62664
  });
62571
62665
  } else {
62572
- const artifact = selectInstallerReleaseArtifact(
62573
- release,
62574
- context.metadata.target
62575
- ).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;
62576
62671
  prepared2 = context.installation.kind === "windows-installer" ? await manager.prepareWindowsInstaller({
62577
62672
  ...context.installation.options,
62578
62673
  version: release.version,
@@ -16429,30 +16429,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16429
16429
  function formatRendererCreditsPercent(value) {
16430
16430
  return `${decimal(value, 1)}%`;
16431
16431
  }
16432
- function rendererUsageTriggerMaxWidth(hasAccountCredits) {
16433
- return hasAccountCredits ? "min(300px, 44vw)" : "min(180px, 30vw)";
16434
- }
16435
- function formatRendererCreditsReset(value) {
16436
- const date5 = new Date(value);
16437
- if (Number.isNaN(date5.getTime())) return value;
16438
- return date5.toLocaleString(void 0, {
16439
- month: "long",
16440
- day: "numeric",
16441
- hour: "numeric",
16442
- minute: "2-digit"
16443
- });
16444
- }
16445
- function creditsPeriodLabel(periodType) {
16446
- if (periodType === "weekly") return "Weekly limit";
16447
- if (periodType === "monthly") return "Monthly limit";
16448
- return "Account limit";
16449
- }
16450
- function productLabel(product) {
16451
- if (product === "GrokBuild") return "Build";
16452
- if (product === "GrokChat") return "Chat";
16453
- if (product === "GrokImagine") return "Imagine";
16454
- if (product === "GrokVoice") return "Voice";
16455
- return product;
16432
+ function rendererUsageTriggerMaxWidth() {
16433
+ return "min(180px, 30vw)";
16456
16434
  }
16457
16435
  function addDetailRow(parent, label, value) {
16458
16436
  const row = document.createElement("div");
@@ -16470,30 +16448,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16470
16448
  row.append(labelElement, valueElement);
16471
16449
  parent.append(row);
16472
16450
  }
16473
- function renderDetails(popover, usage, accountCredits) {
16451
+ function renderDetails(popover, usage) {
16474
16452
  popover.replaceChildren();
16475
16453
  const heading = document.createElement("div");
16476
16454
  heading.textContent = "Usage";
16477
16455
  heading.style.fontWeight = "600";
16478
16456
  heading.style.marginBottom = "6px";
16479
16457
  popover.append(heading);
16480
- if (accountCredits) {
16481
- addDetailRow(
16482
- popover,
16483
- creditsPeriodLabel(accountCredits.periodType),
16484
- formatRendererCreditsPercent(accountCredits.usedPercent)
16485
- );
16486
- if (accountCredits.resetsAt) {
16487
- addDetailRow(popover, "Resets", formatRendererCreditsReset(accountCredits.resetsAt));
16488
- }
16489
- for (const product of accountCredits.productUsage ?? []) {
16490
- addDetailRow(
16491
- popover,
16492
- productLabel(product.product),
16493
- formatRendererCreditsPercent(product.usagePercent)
16494
- );
16495
- }
16496
- }
16497
16458
  if (usage?.contextUsedTokens !== void 0 && usage.contextWindowTokens !== void 0) {
16498
16459
  const contextPercent = usage.contextWindowTokens > 0 ? usage.contextUsedTokens / usage.contextWindowTokens * 100 : null;
16499
16460
  addDetailRow(
@@ -16586,7 +16547,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16586
16547
  trigger.style.display = "inline-flex";
16587
16548
  trigger.style.alignItems = "center";
16588
16549
  trigger.style.width = "fit-content";
16589
- trigger.style.maxWidth = rendererUsageTriggerMaxWidth(false);
16550
+ trigger.style.maxWidth = rendererUsageTriggerMaxWidth();
16590
16551
  trigger.style.height = "24px";
16591
16552
  trigger.style.padding = "0 4px";
16592
16553
  trigger.style.borderRadius = "9999px";
@@ -16689,33 +16650,281 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16689
16650
  document.body.append(popover);
16690
16651
  return control;
16691
16652
  }
16692
- function renderRendererUsageControl(control, usage, accountCredits = null) {
16653
+ function renderRendererUsageControl(control, usage) {
16693
16654
  const cacheHitRatePercent = usage?.cacheHitRatePercent;
16694
16655
  const outputTokensPerSecond = usage?.outputTokensPerSecond;
16695
16656
  const totalCostUsd = usage?.totalCostUsd;
16696
16657
  const hasCacheHitRate = cacheHitRatePercent !== void 0;
16697
16658
  const hasOutputSpeed = outputTokensPerSecond !== void 0;
16698
16659
  const hasCost = totalCostUsd !== void 0;
16699
- const hasCredits = accountCredits !== null;
16700
- const visible = hasCacheHitRate || hasOutputSpeed || hasCost || hasCredits;
16660
+ const visible = hasCacheHitRate || hasOutputSpeed || hasCost;
16701
16661
  control.root.style.display = visible ? "inline-flex" : "none";
16702
16662
  if (!visible) {
16703
16663
  closePopover(control);
16704
16664
  return false;
16705
16665
  }
16706
16666
  const summary = [
16707
- accountCredits ? `${creditsPeriodLabel(accountCredits.periodType)} ${formatRendererCreditsPercent(accountCredits.usedPercent)}` : null,
16708
16667
  cacheHitRatePercent !== void 0 ? formatRendererCacheHitRate(cacheHitRatePercent) : null,
16709
16668
  outputTokensPerSecond !== void 0 ? formatRendererTokenRate(outputTokensPerSecond) : null,
16710
16669
  totalCostUsd !== void 0 ? formatRendererCost(totalCostUsd) : null
16711
16670
  ].filter((value) => value !== null);
16712
16671
  const compactSummary = summary.join(" \xB7 ");
16713
16672
  const accessibleSummary = `Thread Usage: ${compactSummary}`;
16714
- control.trigger.style.maxWidth = rendererUsageTriggerMaxWidth(hasCredits);
16673
+ control.trigger.style.maxWidth = rendererUsageTriggerMaxWidth();
16715
16674
  control.trigger.setAttribute("aria-label", accessibleSummary);
16716
16675
  control.trigger.title = accessibleSummary;
16717
16676
  control.label.textContent = compactSummary;
16718
- renderDetails(control.popover, usage, accountCredits);
16677
+ renderDetails(control.popover, usage);
16678
+ return true;
16679
+ }
16680
+
16681
+ // src/renderer-credits-control.ts
16682
+ function rendererCreditsTone(usedPercent) {
16683
+ if (usedPercent >= 90) return "hot";
16684
+ if (usedPercent >= 70) return "warn";
16685
+ return "ok";
16686
+ }
16687
+ function formatRendererCreditsReset(value) {
16688
+ const date5 = new Date(value);
16689
+ if (Number.isNaN(date5.getTime())) return value;
16690
+ return date5.toLocaleString(void 0, {
16691
+ month: "long",
16692
+ day: "numeric",
16693
+ hour: "numeric",
16694
+ minute: "2-digit"
16695
+ });
16696
+ }
16697
+ function creditsPeriodLabel(periodType) {
16698
+ if (periodType === "weekly") return "Weekly limit";
16699
+ if (periodType === "monthly") return "Monthly limit";
16700
+ return "Account limit";
16701
+ }
16702
+ function productLabel(product) {
16703
+ if (product === "GrokBuild") return "Build";
16704
+ if (product === "GrokChat") return "Chat";
16705
+ if (product === "GrokImagine") return "Imagine";
16706
+ if (product === "GrokVoice") return "Voice";
16707
+ return product;
16708
+ }
16709
+ function toneColor(tone) {
16710
+ if (tone === "hot") return "#c45c4a";
16711
+ if (tone === "warn") return "#c9a227";
16712
+ return "#3d9a64";
16713
+ }
16714
+ function addDetailRow2(parent, label, value) {
16715
+ const row = document.createElement("div");
16716
+ row.style.display = "grid";
16717
+ row.style.gridTemplateColumns = "minmax(0, 1fr) auto";
16718
+ row.style.gap = "20px";
16719
+ row.style.padding = "4px 0";
16720
+ const labelElement = document.createElement("span");
16721
+ labelElement.textContent = label;
16722
+ labelElement.style.color = "color-mix(in srgb, currentColor 68%, transparent)";
16723
+ const valueElement = document.createElement("span");
16724
+ valueElement.textContent = value;
16725
+ valueElement.style.fontVariantNumeric = "tabular-nums";
16726
+ valueElement.style.textAlign = "right";
16727
+ row.append(labelElement, valueElement);
16728
+ parent.append(row);
16729
+ }
16730
+ function renderDetails2(popover, credits) {
16731
+ popover.replaceChildren();
16732
+ const heading = document.createElement("div");
16733
+ heading.textContent = creditsPeriodLabel(credits.periodType);
16734
+ heading.style.fontWeight = "600";
16735
+ heading.style.marginBottom = "6px";
16736
+ popover.append(heading);
16737
+ addDetailRow2(popover, "Used", formatRendererCreditsPercent(credits.usedPercent));
16738
+ if (credits.resetsAt) {
16739
+ addDetailRow2(popover, "Resets", formatRendererCreditsReset(credits.resetsAt));
16740
+ }
16741
+ for (const product of credits.productUsage ?? []) {
16742
+ addDetailRow2(
16743
+ popover,
16744
+ productLabel(product.product),
16745
+ formatRendererCreditsPercent(product.usagePercent)
16746
+ );
16747
+ }
16748
+ }
16749
+ function popoverIsOpen2(popover) {
16750
+ try {
16751
+ return popover.matches(":popover-open");
16752
+ } catch {
16753
+ return !popover.hidden;
16754
+ }
16755
+ }
16756
+ function positionPopover2(control) {
16757
+ const triggerRect = control.trigger.getBoundingClientRect();
16758
+ const width = Math.min(280, Math.max(220, window.innerWidth - 24));
16759
+ const left = Math.max(12, Math.min(triggerRect.left, window.innerWidth - width - 12));
16760
+ control.popover.style.width = `${width}px`;
16761
+ control.popover.style.left = `${left}px`;
16762
+ control.popover.style.right = "auto";
16763
+ control.popover.style.top = "auto";
16764
+ control.popover.style.bottom = `${Math.max(12, window.innerHeight - triggerRect.top + 8)}px`;
16765
+ }
16766
+ function closePopover2(control) {
16767
+ if (popoverIsOpen2(control.popover) && typeof control.popover.hidePopover === "function") {
16768
+ control.popover.hidePopover();
16769
+ }
16770
+ control.popover.hidden = true;
16771
+ control.trigger.setAttribute("aria-expanded", "false");
16772
+ }
16773
+ function openPopover2(control) {
16774
+ positionPopover2(control);
16775
+ control.popover.hidden = false;
16776
+ if (typeof control.popover.showPopover === "function" && !popoverIsOpen2(control.popover)) {
16777
+ control.popover.showPopover();
16778
+ }
16779
+ control.trigger.setAttribute("aria-expanded", "true");
16780
+ }
16781
+ function togglePopover2(control) {
16782
+ if (control.trigger.getAttribute("aria-expanded") === "true") closePopover2(control);
16783
+ else openPopover2(control);
16784
+ }
16785
+ function mountRendererCreditsControl(composerId, nativeModelClassName) {
16786
+ const root = document.createElement("div");
16787
+ root.dataset.codexhostCreditsControl = composerId;
16788
+ root.className = "relative min-w-0";
16789
+ root.style.display = "none";
16790
+ const trigger = document.createElement("button");
16791
+ const syncNativeModelClassName = (className) => {
16792
+ trigger.className = className?.trim() || RENDERER_MODEL_TRIGGER_FALLBACK_CLASSES;
16793
+ };
16794
+ syncNativeModelClassName(nativeModelClassName);
16795
+ trigger.type = "button";
16796
+ trigger.setAttribute("aria-haspopup", "dialog");
16797
+ trigger.setAttribute("aria-expanded", "false");
16798
+ trigger.setAttribute("aria-label", "Account limit");
16799
+ trigger.title = "Account limit";
16800
+ trigger.style.display = "inline-flex";
16801
+ trigger.style.alignItems = "center";
16802
+ trigger.style.gap = "5px";
16803
+ trigger.style.width = "fit-content";
16804
+ trigger.style.maxWidth = "min(72px, 18vw)";
16805
+ trigger.style.height = "24px";
16806
+ trigger.style.padding = "0 6px";
16807
+ trigger.style.borderRadius = "9999px";
16808
+ trigger.style.fontSize = "12px";
16809
+ trigger.style.lineHeight = "16px";
16810
+ trigger.style.fontVariantNumeric = "tabular-nums";
16811
+ trigger.style.letterSpacing = "0";
16812
+ trigger.style.whiteSpace = "nowrap";
16813
+ trigger.style.cursor = "pointer";
16814
+ const dot = document.createElement("span");
16815
+ dot.dataset.codexhostCreditsDot = "";
16816
+ dot.setAttribute("aria-hidden", "true");
16817
+ dot.style.display = "inline-block";
16818
+ dot.style.width = "7px";
16819
+ dot.style.height = "7px";
16820
+ dot.style.borderRadius = "9999px";
16821
+ dot.style.flex = "0 0 auto";
16822
+ const label = document.createElement("span");
16823
+ label.dataset.codexhostCreditsLabel = "";
16824
+ label.style.display = "inline-block";
16825
+ label.style.maxWidth = "100%";
16826
+ label.style.overflow = "hidden";
16827
+ label.style.textOverflow = "ellipsis";
16828
+ label.style.whiteSpace = "nowrap";
16829
+ trigger.append(dot, label);
16830
+ const popover = document.createElement("div");
16831
+ popover.id = `${composerId}-credits-popover`;
16832
+ popover.setAttribute("role", "dialog");
16833
+ popover.setAttribute("aria-label", "Account limit details");
16834
+ popover.setAttribute("popover", "auto");
16835
+ popover.hidden = typeof popover.showPopover !== "function";
16836
+ popover.style.position = "fixed";
16837
+ popover.style.inset = "auto";
16838
+ popover.style.width = "240px";
16839
+ popover.style.maxWidth = "min(280px, calc(100vw - 24px))";
16840
+ popover.style.padding = "10px 12px";
16841
+ popover.style.border = "1px solid rgba(127, 127, 127, 0.35)";
16842
+ popover.style.borderRadius = "6px";
16843
+ popover.style.background = "Canvas";
16844
+ popover.style.color = "CanvasText";
16845
+ popover.style.boxShadow = "0 8px 24px rgba(0, 0, 0, 0.28)";
16846
+ popover.style.font = "13px/1.35 system-ui, sans-serif";
16847
+ popover.style.letterSpacing = "0";
16848
+ popover.style.zIndex = "2147483647";
16849
+ trigger.setAttribute("aria-controls", popover.id);
16850
+ let placementReference = null;
16851
+ const control = {
16852
+ root,
16853
+ trigger,
16854
+ popover,
16855
+ anchor: null,
16856
+ syncNativeModelClassName,
16857
+ dispose() {
16858
+ closePopover2(control);
16859
+ if (closeTimer !== null) window.clearTimeout(closeTimer);
16860
+ root.remove();
16861
+ popover.remove();
16862
+ placementReference = null;
16863
+ },
16864
+ place(anchor) {
16865
+ if (!anchor?.parentElement) return false;
16866
+ const parent = anchor.parentElement;
16867
+ const next = anchor.nextElementSibling;
16868
+ if (control.anchor === anchor && placementReference === anchor && root.parentElement === parent && root.previousElementSibling === anchor) {
16869
+ return true;
16870
+ }
16871
+ control.anchor = anchor;
16872
+ placementReference = anchor;
16873
+ if (next && next !== root) parent.insertBefore(root, next);
16874
+ else if (next !== root) parent.append(root);
16875
+ return true;
16876
+ }
16877
+ };
16878
+ let closeTimer = null;
16879
+ const cancelClose = () => {
16880
+ if (closeTimer === null) return;
16881
+ window.clearTimeout(closeTimer);
16882
+ closeTimer = null;
16883
+ };
16884
+ const scheduleClose = () => {
16885
+ cancelClose();
16886
+ closeTimer = window.setTimeout(() => {
16887
+ closeTimer = null;
16888
+ if (!trigger.matches(":hover") && !popover.matches(":hover")) closePopover2(control);
16889
+ }, 140);
16890
+ };
16891
+ trigger.addEventListener("click", () => togglePopover2(control));
16892
+ trigger.addEventListener("pointerenter", () => {
16893
+ cancelClose();
16894
+ openPopover2(control);
16895
+ });
16896
+ trigger.addEventListener("pointerleave", scheduleClose);
16897
+ trigger.addEventListener("focus", () => {
16898
+ cancelClose();
16899
+ openPopover2(control);
16900
+ });
16901
+ trigger.addEventListener("blur", scheduleClose);
16902
+ popover.addEventListener("pointerenter", cancelClose);
16903
+ popover.addEventListener("pointerleave", scheduleClose);
16904
+ popover.addEventListener("toggle", () => {
16905
+ trigger.setAttribute("aria-expanded", String(popoverIsOpen2(popover)));
16906
+ });
16907
+ root.append(trigger);
16908
+ document.body.append(popover);
16909
+ return control;
16910
+ }
16911
+ function renderRendererCreditsControl(control, accountCredits) {
16912
+ if (accountCredits === null) {
16913
+ control.root.style.display = "none";
16914
+ closePopover2(control);
16915
+ return false;
16916
+ }
16917
+ const percent = formatRendererCreditsPercent(accountCredits.usedPercent);
16918
+ const title = `${creditsPeriodLabel(accountCredits.periodType)} ${percent}`;
16919
+ const tone = rendererCreditsTone(accountCredits.usedPercent);
16920
+ const dot = control.trigger.querySelector("[data-codexhost-credits-dot]");
16921
+ const label = control.trigger.querySelector("[data-codexhost-credits-label]");
16922
+ if (dot) dot.style.background = toneColor(tone);
16923
+ if (label) label.textContent = percent;
16924
+ control.root.style.display = "inline-flex";
16925
+ control.trigger.setAttribute("aria-label", title);
16926
+ control.trigger.title = title;
16927
+ renderDetails2(control.popover, accountCredits);
16719
16928
  return true;
16720
16929
  }
16721
16930
 
@@ -16830,7 +17039,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16830
17039
  }
16831
17040
  var contextUsageDescriptionPattern = /(context|token|上下文|令牌)/iu;
16832
17041
  function isNativeContextUsageControlCandidate(element) {
16833
- if (element.hasAttribute("data-codexhost-usage-control")) return false;
17042
+ if (element.hasAttribute("data-codexhost-usage-control") || element.hasAttribute("data-codexhost-credits-control")) {
17043
+ return false;
17044
+ }
16834
17045
  const description = [
16835
17046
  element.getAttribute("aria-label"),
16836
17047
  element.getAttribute("title"),
@@ -16863,6 +17074,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16863
17074
  const candidate = nativeModelControlForComposer(control.composer);
16864
17075
  if (!candidate) {
16865
17076
  control.usage.syncNativeModelClassName();
17077
+ control.credits.syncNativeModelClassName();
16866
17078
  return;
16867
17079
  }
16868
17080
  if (candidate !== control.nativeModelControl?.element) {
@@ -16871,6 +17083,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16871
17083
  syncRendererModelTriggerClass(control.modelPicker, candidate.className);
16872
17084
  }
16873
17085
  control.usage.syncNativeModelClassName(candidate.className);
17086
+ control.credits.syncNativeModelClassName(candidate.className);
16874
17087
  }
16875
17088
  function usagePlacementAnchor(control) {
16876
17089
  const context = nativeContextUsageControlForComposer(control.composer);
@@ -16880,14 +17093,44 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16880
17093
  const native = control.nativeModelControl?.element;
16881
17094
  return native?.parentElement ? native : null;
16882
17095
  }
17096
+ function firstMaterialChild(parent) {
17097
+ for (const child of parent.children) {
17098
+ if (typeof child.hasAttribute !== "function") continue;
17099
+ const element = child;
17100
+ if (element.hasAttribute("data-codexhost-credits-control")) continue;
17101
+ return element;
17102
+ }
17103
+ return null;
17104
+ }
17105
+ function creditsPlacementAnchor(composer, usageRoot) {
17106
+ let current = usageRoot;
17107
+ while (current && current !== composer) {
17108
+ const parent = current.parentElement;
17109
+ if (!parent) break;
17110
+ const first = firstMaterialChild(parent);
17111
+ if (first && first !== current && !first.contains(usageRoot)) return first;
17112
+ if (parent === composer) break;
17113
+ current = parent;
17114
+ }
17115
+ return null;
17116
+ }
16883
17117
  function refreshUsagePlacement(control) {
16884
17118
  const anchor = usagePlacementAnchor(control);
16885
17119
  if (!anchor) {
16886
17120
  if (control.usage.anchor) control.usage.root.remove();
16887
17121
  control.usage.anchor = null;
17122
+ if (control.credits.anchor) control.credits.root.remove();
17123
+ control.credits.anchor = null;
16888
17124
  return;
16889
17125
  }
16890
17126
  control.usage.place(anchor);
17127
+ const leading = creditsPlacementAnchor(control.composer, control.usage.root);
17128
+ if (!leading) {
17129
+ if (control.credits.anchor) control.credits.root.remove();
17130
+ control.credits.anchor = null;
17131
+ return;
17132
+ }
17133
+ control.credits.place(leading);
16891
17134
  }
16892
17135
  function refreshNativePermissionModeControl(control) {
16893
17136
  const semanticCandidate = semanticNativePermissionModeControlForComposer(control.composer);
@@ -16942,6 +17185,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16942
17185
  onSelectPermissionMode
16943
17186
  );
16944
17187
  const usage = mountRendererUsageControl(composerId, nativeModelControl?.element.className);
17188
+ const credits = mountRendererCreditsControl(composerId, nativeModelControl?.element.className);
16945
17189
  const permissionParent = nativePermissionModeControl?.element.parentElement;
16946
17190
  if (permissionParent && nativePermissionModeControl && nativePermissionModeControlVerified) {
16947
17191
  permissionParent.insertBefore(permissionModePicker.root, nativePermissionModeControl.element);
@@ -16964,6 +17208,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16964
17208
  nativeModelControl,
16965
17209
  nativePermissionModeControl,
16966
17210
  nativePermissionModeControlVerified,
17211
+ credits,
16967
17212
  usage,
16968
17213
  sendButton,
16969
17214
  sendDisabledBeforeSwitch: null
@@ -17008,7 +17253,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17008
17253
  permissionModeView,
17009
17254
  permissionModeVisible
17010
17255
  );
17011
- renderRendererUsageControl(control.usage, usage, accountCredits);
17256
+ renderRendererUsageControl(control.usage, usage);
17257
+ renderRendererCreditsControl(control.credits, accountCredits);
17012
17258
  }
17013
17259
  function disposeComposerAgentControl(control) {
17014
17260
  if (control.sendDisabledBeforeSwitch !== null) {
@@ -17016,6 +17262,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17016
17262
  }
17017
17263
  restoreNativeControl(control.nativeModelControl);
17018
17264
  restoreNativeControl(control.nativePermissionModeControl);
17265
+ control.credits.dispose();
17019
17266
  control.usage.dispose();
17020
17267
  control.permissionModePicker.dispose();
17021
17268
  control.modelPicker.dispose();
package/bin/codexhost CHANGED
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codexhost/cli-darwin-x64",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "Run Pi and Claude Code as first-class external harnesses inside Codex Desktop.",
5
5
  "type": "module",
6
6
  "files": [