@codexhost/cli-win32-arm64 0.1.4 → 0.1.6

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.1.4
10
+ npm install -g @codexhost/cli@0.1.6
11
11
  ```
12
12
 
13
13
  Do not install this package directly. npm selects it through the optional dependencies of `@codexhost/cli`.
@@ -1 +1 @@
1
- {"schemaVersion":1,"version":"0.1.4","distribution":"npm","target":"windows-arm64"}
1
+ {"schemaVersion":1,"version":"0.1.6","distribution":"npm","target":"windows-arm64"}
@@ -1087,15 +1087,27 @@ var InstalledRendererControlSession = class {
1087
1087
  this.inspector.close();
1088
1088
  }
1089
1089
  };
1090
+ var startupTraceStartedAt = Date.now();
1091
+ function startupTrace(stage) {
1092
+ if (process.env.CODEXHOST_STARTUP_TRACE !== "1") return;
1093
+ console.error(
1094
+ `[codexhost startup +${Date.now() - startupTraceStartedAt}ms] renderer-session: ${stage}`
1095
+ );
1096
+ }
1090
1097
  async function createRendererControlSession(options) {
1091
1098
  const enabledAgents = options.enabledAgents ?? ["codex", "pi"];
1092
1099
  const timeoutMs = options.timeoutMs ?? 3e4;
1093
1100
  const pollIntervalMs = options.pollIntervalMs ?? 250;
1094
1101
  const operations = options.operations ?? defaultOperations;
1102
+ startupTrace("waiting for initial Renderer");
1095
1103
  const initial = await waitForRenderer(options.inspector, operations, timeoutMs, pollIntervalMs);
1104
+ startupTrace("installing title policy");
1096
1105
  const titlePolicy = await operations.installTitlePolicy(options.inspector, initial.id);
1106
+ startupTrace("reloading Renderer");
1097
1107
  await operations.reload(options.inspector, initial.id);
1108
+ startupTrace("waiting for reloaded Renderer");
1098
1109
  const selected = await waitForRenderer(options.inspector, operations, timeoutMs, pollIntervalMs);
1110
+ startupTrace("waiting for title policy readiness");
1099
1111
  const titlePolicyReadiness = await waitForRendererTitlePolicyReady(
1100
1112
  () => operations.markTitlePolicyReady(options.inspector, selected.id),
1101
1113
  {
@@ -1103,7 +1115,9 @@ async function createRendererControlSession(options) {
1103
1115
  pollIntervalMs
1104
1116
  }
1105
1117
  );
1118
+ startupTrace("injecting Renderer bundle");
1106
1119
  await operations.execute(options.inspector, selected.id, options.rendererSource);
1120
+ startupTrace("waiting for Renderer binding");
1107
1121
  const binding = await waitForBinding(
1108
1122
  options.inspector,
1109
1123
  operations,
@@ -1112,6 +1126,7 @@ async function createRendererControlSession(options) {
1112
1126
  timeoutMs,
1113
1127
  pollIntervalMs
1114
1128
  );
1129
+ startupTrace("installing draft prewarm policy");
1115
1130
  const draftPrewarmPolicy = await operations.installDraftPrewarmPolicy(
1116
1131
  options.inspector,
1117
1132
  selected.id
@@ -1135,12 +1150,15 @@ async function createRendererControlSession(options) {
1135
1150
  async function installRendererControlSession(options) {
1136
1151
  const timeoutMs = options.timeoutMs ?? 3e4;
1137
1152
  const pollIntervalMs = options.pollIntervalMs ?? 250;
1153
+ startupTrace("waiting for Electron Inspector target");
1138
1154
  const target = await waitForInspectorTarget(options.inspectorEndpoint, {
1139
1155
  timeoutMs,
1140
1156
  pollIntervalMs
1141
1157
  });
1158
+ startupTrace("connecting to Electron Inspector");
1142
1159
  const inspector = await CdpClient.connect(target.webSocketDebuggerUrl);
1143
1160
  try {
1161
+ startupTrace("enabling Inspector Runtime domain");
1144
1162
  await inspector.command("Runtime.enable");
1145
1163
  return await createRendererControlSession({
1146
1164
  ...options,
@@ -1161,6 +1179,14 @@ var TRANSIENT_INSTALL_ATTEMPTS = 3;
1161
1179
  var TRANSIENT_INSTALL_RETRY_MS = 250;
1162
1180
  var RECOVERY_RETRY_INITIAL_MS = 3e4;
1163
1181
  var RECOVERY_RETRY_MAX_MS = 3e5;
1182
+ var startupTraceStartedAt2 = Date.now();
1183
+ function startupTrace2(stage, detail) {
1184
+ if (process.env.CODEXHOST_STARTUP_TRACE !== "1") return;
1185
+ const suffix = detail === void 0 ? "" : `: ${detail instanceof Error ? detail.message : String(detail)}`;
1186
+ console.error(
1187
+ `[codexhost startup +${Date.now() - startupTraceStartedAt2}ms] controller: ${stage}${suffix}`
1188
+ );
1189
+ }
1164
1190
  function validCompatibilityIssue(state, issue) {
1165
1191
  const keys = Object.keys(issue);
1166
1192
  if (state === "compatible-with-warning") {
@@ -1316,9 +1342,11 @@ async function runDesktopController(options, signal, dependencies = defaultDepen
1316
1342
  recoveryDelayMs = RECOVERY_RETRY_INITIAL_MS;
1317
1343
  };
1318
1344
  const createSession = async () => {
1345
+ startupTrace2("reading Renderer bundle");
1319
1346
  const rendererSource = await dependencies.readRenderer(options.rendererPath);
1320
1347
  if (rendererSource.trim().length === 0) throw new Error("production Renderer Bundle is empty");
1321
- return installProductionSession(
1348
+ startupTrace2("installing Renderer Session");
1349
+ const installed = await installProductionSession(
1322
1350
  {
1323
1351
  inspectorEndpoint: options.inspectorEndpoint,
1324
1352
  rendererSource: `${configuration}
@@ -1328,11 +1356,15 @@ ${rendererSource}`,
1328
1356
  },
1329
1357
  dependencies
1330
1358
  );
1359
+ startupTrace2("Renderer Session installed");
1360
+ return installed;
1331
1361
  };
1362
+ startupTrace2("initialization started");
1332
1363
  try {
1333
1364
  session = await createSession();
1334
1365
  recordRecoverySuccess();
1335
- } catch {
1366
+ } catch (error) {
1367
+ startupTrace2("initial Renderer Session unavailable", error);
1336
1368
  session = void 0;
1337
1369
  recordRecoveryFailure();
1338
1370
  }
@@ -1367,6 +1399,7 @@ ${rendererSource}`,
1367
1399
  };
1368
1400
  let attachmentServer;
1369
1401
  try {
1402
+ startupTrace2("starting attachment server");
1370
1403
  attachmentServer = await dependencies.startAttachmentServer({
1371
1404
  port: options.attachmentPort,
1372
1405
  nonce: options.attachmentNonce,
@@ -1383,7 +1416,9 @@ ${rendererSource}`,
1383
1416
  await current.quitDesktop();
1384
1417
  })
1385
1418
  });
1419
+ startupTrace2("attachment server ready");
1386
1420
  const issues = session?.snapshot.titlePolicy.warnings ?? [];
1421
+ startupTrace2("publishing readiness");
1387
1422
  dependencies.ready({
1388
1423
  schemaVersion: 2,
1389
1424
  state: issues.length === 0 ? "compatible" : "compatible-with-warning",
@@ -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, path11) {
777
- if (!path11)
776
+ function getElementAtPath(obj, path12) {
777
+ if (!path12)
778
778
  return obj;
779
- return path11.reduce((acc, key) => acc?.[key], obj);
779
+ return path12.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(path11, issues) {
1188
+ function prefixIssues(path12, issues) {
1189
1189
  return issues.map((iss) => {
1190
1190
  var _a4;
1191
1191
  (_a4 = iss).path ?? (_a4.path = []);
1192
- iss.path.unshift(path11);
1192
+ iss.path.unshift(path12);
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, path11 = []) => {
1339
+ const processError = (error53, path12 = []) => {
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 }, [...path11, ...issue2.path]));
1342
+ issue2.errors.map((issues) => processError({ issues }, [...path12, ...issue2.path]));
1343
1343
  } else if (issue2.code === "invalid_key") {
1344
- processError({ issues: issue2.issues }, [...path11, ...issue2.path]);
1344
+ processError({ issues: issue2.issues }, [...path12, ...issue2.path]);
1345
1345
  } else if (issue2.code === "invalid_element") {
1346
- processError({ issues: issue2.issues }, [...path11, ...issue2.path]);
1346
+ processError({ issues: issue2.issues }, [...path12, ...issue2.path]);
1347
1347
  } else {
1348
- const fullpath = [...path11, ...issue2.path];
1348
+ const fullpath = [...path12, ...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, path11 = []) => {
1375
+ const processError = (error53, path12 = []) => {
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 }, [...path11, ...issue2.path]));
1379
+ issue2.errors.map((issues) => processError({ issues }, [...path12, ...issue2.path]));
1380
1380
  } else if (issue2.code === "invalid_key") {
1381
- processError({ issues: issue2.issues }, [...path11, ...issue2.path]);
1381
+ processError({ issues: issue2.issues }, [...path12, ...issue2.path]);
1382
1382
  } else if (issue2.code === "invalid_element") {
1383
- processError({ issues: issue2.issues }, [...path11, ...issue2.path]);
1383
+ processError({ issues: issue2.issues }, [...path12, ...issue2.path]);
1384
1384
  } else {
1385
- const fullpath = [...path11, ...issue2.path];
1385
+ const fullpath = [...path12, ...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 path11 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1418
- for (const seg of path11) {
1417
+ const path12 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1418
+ for (const seg of path12) {
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 path11 = ref.slice(1).split("/").filter(Boolean);
14111
- if (path11.length === 0) {
14110
+ const path12 = ref.slice(1).split("/").filter(Boolean);
14111
+ if (path12.length === 0) {
14112
14112
  return ctx.rootSchema;
14113
14113
  }
14114
14114
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
14115
- if (path11[0] === defsKey) {
14116
- const key = path11[1];
14115
+ if (path12[0] === defsKey) {
14116
+ const key = path12[1];
14117
14117
  if (!key || !ctx.defs[key]) {
14118
14118
  throw new Error(`Reference not found: ${ref}`);
14119
14119
  }
@@ -19111,8 +19111,8 @@ var qU = v(function(BU) {
19111
19111
  BU._globalThis = void 0;
19112
19112
  BU._globalThis = typeof globalThis === "object" ? globalThis : global;
19113
19113
  });
19114
- var GU = v(function(os3) {
19115
- var Axe = os3 && os3.__createBinding || (Object.create ? function(e, t, r, n) {
19114
+ var GU = v(function(os4) {
19115
+ var Axe = os4 && os4.__createBinding || (Object.create ? function(e, t, r, n) {
19116
19116
  if (n === void 0) n = r;
19117
19117
  Object.defineProperty(e, n, { enumerable: true, get: function() {
19118
19118
  return t[r];
@@ -19120,11 +19120,11 @@ var GU = v(function(os3) {
19120
19120
  } : function(e, t, r, n) {
19121
19121
  if (n === void 0) n = r;
19122
19122
  e[n] = t[r];
19123
- }), kxe = os3 && os3.__exportStar || function(e, t) {
19123
+ }), kxe = os4 && os4.__exportStar || function(e, t) {
19124
19124
  for (var r in e) if (r !== "default" && !Object.prototype.hasOwnProperty.call(t, r)) Axe(t, e, r);
19125
19125
  };
19126
- Object.defineProperty(os3, "__esModule", { value: true });
19127
- kxe(qU(), os3);
19126
+ Object.defineProperty(os4, "__esModule", { value: true });
19127
+ kxe(qU(), os4);
19128
19128
  });
19129
19129
  var WU = v(function(is) {
19130
19130
  var Oxe = is && is.__createBinding || (Object.create ? function(e, t, r, n) {
@@ -41033,6 +41033,7 @@ function userInstallCandidates(platform, environment, homeDirectory) {
41033
41033
  ];
41034
41034
  }
41035
41035
  return [
41036
+ path.join(homeDirectory, ".npm-global", "bin", "claude"),
41036
41037
  path.join(homeDirectory, ".local", "bin", "claude"),
41037
41038
  path.join(homeDirectory, ".claude", "local", "claude"),
41038
41039
  ...nvmCandidates(homeDirectory),
@@ -41055,6 +41056,17 @@ function resolveClaudeCodeExecutable(input = {}) {
41055
41056
  throw new ClaudeCodeExecutableError("Claude Code is not installed");
41056
41057
  return path.resolve(executable);
41057
41058
  }
41059
+ function withNodeRuntimeOnPath(environment, runtimeExecutable = process.execPath, platform = process.platform) {
41060
+ const pathKey = Object.keys(environment).find((name) => name.toLowerCase() === "path") ?? "PATH";
41061
+ const delimiter = platform === "win32" ? ";" : ":";
41062
+ const runtimeDirectory = path.dirname(runtimeExecutable);
41063
+ const directories = (environment[pathKey] ?? "").split(delimiter).filter(Boolean);
41064
+ const equal = platform === "win32" ? (value) => value.toLowerCase() : (value) => value;
41065
+ if (!directories.some((directory) => equal(directory) === equal(runtimeDirectory))) {
41066
+ directories.unshift(runtimeDirectory);
41067
+ }
41068
+ return { ...environment, [pathKey]: directories.join(delimiter) };
41069
+ }
41058
41070
 
41059
41071
  // packages/adapters/claude-code/dist/claude-fork.js
41060
41072
  import path2 from "node:path";
@@ -41687,13 +41699,6 @@ function assistantText(message3) {
41687
41699
  return null;
41688
41700
  return content.flatMap((block) => isRecord4(block) && block.type === "text" && typeof block.text === "string" ? [block.text] : []).join("");
41689
41701
  }
41690
- function assistantReasoning(message3) {
41691
- const content = assistantContent(message3);
41692
- if (!content)
41693
- return null;
41694
- const blocks = content.filter((block) => isRecord4(block) && block.type === "thinking" && typeof block.thinking === "string");
41695
- return blocks.length > 0 ? blocks.map((block) => block.thinking).join("") : null;
41696
- }
41697
41702
  function assistantError(message3) {
41698
41703
  return isRecord4(message3) && message3.type === "assistant" && typeof message3.error === "string" ? message3.error : null;
41699
41704
  }
@@ -41732,7 +41737,6 @@ var ClaudeNativeTurnAccumulator = class {
41732
41737
  #messageOrdinal = 0;
41733
41738
  #messages = /* @__PURE__ */ new Map();
41734
41739
  #protocolConflict = false;
41735
- #reasoningConflict = false;
41736
41740
  #textConflict = false;
41737
41741
  #tools = /* @__PURE__ */ new Map();
41738
41742
  requestCancel() {
@@ -41766,8 +41770,6 @@ var ClaudeNativeTurnAccumulator = class {
41766
41770
  let terminal;
41767
41771
  if (this.#protocolConflict) {
41768
41772
  terminal = failure("protocol");
41769
- } else if (this.#reasoningConflict) {
41770
- terminal = failure("reasoningConflict");
41771
41773
  } else if (this.#textConflict) {
41772
41774
  terminal = failure("textConflict");
41773
41775
  } else if (includesAuthenticationFailure(message3, this.#assistantErrors)) {
@@ -41820,8 +41822,6 @@ var ClaudeNativeTurnAccumulator = class {
41820
41822
  if (event.type !== "content_block_delta" || !isRecord4(event.delta))
41821
41823
  return;
41822
41824
  if (state.completed) {
41823
- if (event.delta.type === "thinking_delta")
41824
- this.#reasoningConflict = true;
41825
41825
  if (event.delta.type === "text_delta")
41826
41826
  this.#textConflict = true;
41827
41827
  return;
@@ -41846,19 +41846,7 @@ var ClaudeNativeTurnAccumulator = class {
41846
41846
  const state = this.#messageState(messageId);
41847
41847
  if (state.completed)
41848
41848
  return;
41849
- const completeReasoning = assistantReasoning(message3);
41850
- if (completeReasoning !== null) {
41851
- if (completeReasoning.startsWith(state.reasoning)) {
41852
- const suffix = completeReasoning.slice(state.reasoning.length);
41853
- if (suffix.length > 0) {
41854
- state.reasoning += suffix;
41855
- events.push({ type: "reasoning.delta", messageId, delta: suffix });
41856
- }
41857
- } else if (completeReasoning !== state.reasoning) {
41858
- this.#reasoningConflict = true;
41859
- }
41860
- }
41861
- if (state.reasoning.length > 0 && !this.#reasoningConflict) {
41849
+ if (state.reasoning.length > 0) {
41862
41850
  events.push({ type: "reasoning.completed", messageId });
41863
41851
  }
41864
41852
  const completeText = assistantText(message3);
@@ -41889,7 +41877,7 @@ var ClaudeNativeTurnAccumulator = class {
41889
41877
  arguments: argumentsResult.data
41890
41878
  });
41891
41879
  }
41892
- if (!this.#protocolConflict && !this.#reasoningConflict && !this.#textConflict) {
41880
+ if (!this.#protocolConflict && !this.#textConflict) {
41893
41881
  events.push({
41894
41882
  type: "message.completed",
41895
41883
  messageId,
@@ -42205,10 +42193,10 @@ var ClaudeSdkTransport = class {
42205
42193
  canUseTool: (toolName, input, options) => this.#canUseTool(toolName, input, options),
42206
42194
  persistSession: true,
42207
42195
  includePartialMessages: true,
42208
- env: {
42196
+ env: withNodeRuntimeOnPath({
42209
42197
  ...this.#environment,
42210
42198
  CLAUDE_AGENT_SDK_CLIENT_APP: CLIENT_APP
42211
- },
42199
+ }),
42212
42200
  spawnClaudeCodeProcess: (options) => this.#spawn(options)
42213
42201
  }
42214
42202
  });
@@ -42507,10 +42495,10 @@ var ClaudeSdkModelInspector = class {
42507
42495
  tools: [],
42508
42496
  persistSession: false,
42509
42497
  includePartialMessages: false,
42510
- env: {
42498
+ env: withNodeRuntimeOnPath({
42511
42499
  ...this.#environment,
42512
42500
  CLAUDE_AGENT_SDK_CLIENT_APP: CLIENT_APP
42513
- },
42501
+ }),
42514
42502
  spawnClaudeCodeProcess: (options) => this.#spawn(options)
42515
42503
  }
42516
42504
  });
@@ -42719,8 +42707,8 @@ function transportFailure(kind) {
42719
42707
  }
42720
42708
  return {
42721
42709
  code: "nativeFailure",
42722
- message: kind === "textConflict" ? "Claude Code returned inconsistent streamed text" : kind === "reasoningConflict" ? "Claude Code returned inconsistent streamed reasoning" : kind === "cancellationUnproven" ? "Claude Code cancellation could not be proven" : "Claude Code Turn failed",
42723
- retryable: kind !== "textConflict" && kind !== "reasoningConflict"
42710
+ message: kind === "textConflict" ? "Claude Code returned inconsistent streamed text" : kind === "cancellationUnproven" ? "Claude Code cancellation could not be proven" : "Claude Code Turn failed",
42711
+ retryable: kind !== "textConflict"
42724
42712
  };
42725
42713
  }
42726
42714
  function startupFailure(error52) {
@@ -44438,8 +44426,79 @@ async function rollbackPiLastTurn(transport, sourceSessionId, cwd) {
44438
44426
  // packages/adapters/pi/dist/pi-rpc-session.js
44439
44427
  import { spawn as spawn2, spawnSync } from "node:child_process";
44440
44428
  import { randomUUID as randomUUID2 } from "node:crypto";
44441
- import { statSync as statSync2 } from "node:fs";
44429
+ import path6 from "node:path";
44430
+
44431
+ // packages/adapters/pi/dist/command.js
44432
+ import { accessSync, constants, readdirSync as readdirSync2, statSync as statSync2 } from "node:fs";
44433
+ import os2 from "node:os";
44442
44434
  import path5 from "node:path";
44435
+ function environmentValue(environment, name) {
44436
+ return Object.entries(environment).find(([key]) => key.toLowerCase() === name.toLowerCase())?.[1];
44437
+ }
44438
+ function isExecutable2(filePath, platform) {
44439
+ try {
44440
+ accessSync(filePath, platform === "win32" ? constants.F_OK : constants.X_OK);
44441
+ return statSync2(filePath).isFile();
44442
+ } catch {
44443
+ return false;
44444
+ }
44445
+ }
44446
+ function pathCandidates(command, platform, environment) {
44447
+ const targetPath = platform === "win32" ? path5.win32 : path5.posix;
44448
+ if (targetPath.isAbsolute(command) || command.includes("/") || command.includes("\\")) {
44449
+ return [command];
44450
+ }
44451
+ const extensions = platform === "win32" && targetPath.extname(command) === "" ? (environmentValue(environment, "PATHEXT") ?? ".COM;.EXE;.BAT;.CMD").split(";").map((extension) => extension.trim()).filter(Boolean) : [""];
44452
+ return (environmentValue(environment, "PATH") ?? "").split(targetPath.delimiter).map((directory) => directory.trim().replace(/^"|"$/gu, "")).filter(Boolean).flatMap((directory) => extensions.map((extension) => targetPath.join(directory, command + extension)));
44453
+ }
44454
+ function nvmCandidates2(homeDirectory, executableName) {
44455
+ const versionsDirectory = path5.join(homeDirectory, ".nvm", "versions", "node");
44456
+ try {
44457
+ 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) => path5.join(versionsDirectory, version2, "bin", executableName));
44458
+ } catch {
44459
+ return [];
44460
+ }
44461
+ }
44462
+ function userInstallCandidates2(platform, environment, homeDirectory) {
44463
+ if (platform === "win32") {
44464
+ const appData = environment.APPDATA ?? path5.join(homeDirectory, "AppData", "Roaming");
44465
+ return [
44466
+ path5.join(appData, "npm", "pi.cmd"),
44467
+ path5.join(homeDirectory, ".local", "bin", "pi.exe"),
44468
+ path5.join(homeDirectory, ".local", "bin", "pi.cmd")
44469
+ ];
44470
+ }
44471
+ return [
44472
+ path5.join(homeDirectory, ".npm-global", "bin", "pi"),
44473
+ path5.join(homeDirectory, ".local", "bin", "pi"),
44474
+ ...nvmCandidates2(homeDirectory, "pi"),
44475
+ "/opt/homebrew/bin/pi",
44476
+ "/usr/local/bin/pi"
44477
+ ];
44478
+ }
44479
+ function resolvePiExecutable(input, dependencies = {}) {
44480
+ const platform = dependencies.platform ?? process.platform;
44481
+ const configuredCommand = input.command ?? input.environment.PI_COMMAND;
44482
+ const command = configuredCommand ?? "pi";
44483
+ const homeDirectory = dependencies.homeDirectory ?? input.environment.HOME ?? input.environment.USERPROFILE ?? os2.homedir();
44484
+ const candidates2 = [
44485
+ ...pathCandidates(command, platform, input.environment),
44486
+ ...configuredCommand ? [] : userInstallCandidates2(platform, input.environment, homeDirectory)
44487
+ ];
44488
+ const check2 = dependencies.isExecutable ?? ((candidate) => isExecutable2(candidate, platform));
44489
+ return candidates2.find(check2) ?? command;
44490
+ }
44491
+ function withNodeRuntimeOnPath2(environment, runtimeExecutable = process.execPath, platform = process.platform) {
44492
+ const pathKey = Object.keys(environment).find((name) => name.toLowerCase() === "path") ?? "PATH";
44493
+ const delimiter = platform === "win32" ? ";" : ":";
44494
+ const runtimeDirectory = path5.dirname(runtimeExecutable);
44495
+ const directories = (environment[pathKey] ?? "").split(delimiter).filter(Boolean);
44496
+ const equal = platform === "win32" ? (value) => value.toLowerCase() : (value) => value;
44497
+ if (!directories.some((directory) => equal(directory) === equal(runtimeDirectory))) {
44498
+ directories.unshift(runtimeDirectory);
44499
+ }
44500
+ return { ...environment, [pathKey]: directories.join(delimiter) };
44501
+ }
44443
44502
 
44444
44503
  // packages/adapters/pi/dist/pi-usage.js
44445
44504
  function isRecord8(value) {
@@ -44684,7 +44743,7 @@ function assistantMessageId(value) {
44684
44743
  return null;
44685
44744
  return nonBlankString(value.responseId) ? value.responseId : null;
44686
44745
  }
44687
- function assistantReasoning2(value) {
44746
+ function assistantReasoning(value) {
44688
44747
  if (!isRecord10(value) || value.role !== "assistant" || !Array.isArray(value.content))
44689
44748
  return null;
44690
44749
  return value.content.filter((content) => isRecord10(content) && content.type === "thinking" && typeof content.thinking === "string").map((content) => content.thinking).join("");
@@ -44722,36 +44781,6 @@ function waitForExit(child, timeoutMs) {
44722
44781
  new Promise((resolve2) => setTimeout(() => resolve2(false), timeoutMs))
44723
44782
  ]);
44724
44783
  }
44725
- function environmentValue(environment, name) {
44726
- return Object.entries(environment).find(([key]) => key.toLowerCase() === name.toLowerCase())?.[1];
44727
- }
44728
- function isRegularFile(filePath) {
44729
- try {
44730
- return statSync2(filePath).isFile();
44731
- } catch {
44732
- return false;
44733
- }
44734
- }
44735
- function resolveWindowsCommand(command, environment, isFile) {
44736
- if (path5.win32.isAbsolute(command) || command.includes("/") || command.includes("\\")) {
44737
- return command;
44738
- }
44739
- const extensions = path5.win32.extname(command) ? [""] : (environmentValue(environment, "PATHEXT") ?? ".COM;.EXE;.BAT;.CMD").split(";").map((extension) => extension.trim()).filter((extension) => extension.length > 0);
44740
- const pathValue2 = environmentValue(environment, "PATH");
44741
- if (!pathValue2)
44742
- return command;
44743
- for (const rawDirectory of pathValue2.split(path5.win32.delimiter)) {
44744
- const directory = rawDirectory.trim().replace(/^"|"$/gu, "");
44745
- if (!directory)
44746
- continue;
44747
- for (const extension of extensions) {
44748
- const candidate = path5.win32.join(directory, `${command}${extension}`);
44749
- if (isFile(candidate))
44750
- return candidate;
44751
- }
44752
- }
44753
- return command;
44754
- }
44755
44784
  function piRpcProcessCommand(options, dependencies = {}) {
44756
44785
  if (options.sessionFile && options.forkSessionFile) {
44757
44786
  throw new Error("Pi RPC cannot combine Session resume and Fork startup");
@@ -44760,12 +44789,18 @@ function piRpcProcessCommand(options, dependencies = {}) {
44760
44789
  throw new Error("Pi RPC cannot combine a startup Model with Session restore or Fork");
44761
44790
  }
44762
44791
  const platform = dependencies.platform ?? process.platform;
44763
- const selectedCommand = options.command ?? options.environment.PI_COMMAND ?? "pi";
44764
- const command = platform === "win32" ? resolveWindowsCommand(selectedCommand, options.environment, dependencies.isFile ?? isRegularFile) : selectedCommand;
44792
+ const command = resolvePiExecutable({
44793
+ ...options.command ? { command: options.command } : {},
44794
+ environment: options.environment
44795
+ }, {
44796
+ platform,
44797
+ ...dependencies.homeDirectory ? { homeDirectory: dependencies.homeDirectory } : {},
44798
+ ...dependencies.isExecutable ? { isExecutable: dependencies.isExecutable } : {}
44799
+ });
44765
44800
  const sessionArguments = options.forkSessionFile ? ["--fork", options.forkSessionFile] : options.sessionFile ? ["--session", options.sessionFile] : [];
44766
44801
  const modelArguments = options.model ? ["--provider", options.model.provider, "--model", options.model.id] : [];
44767
44802
  const arguments_2 = ["--mode", "rpc", ...modelArguments, ...sessionArguments];
44768
- const extension = path5.win32.extname(command).toLowerCase();
44803
+ const extension = path6.win32.extname(command).toLowerCase();
44769
44804
  if (platform !== "win32" || ![".cmd", ".bat"].includes(extension)) {
44770
44805
  return { command, arguments: arguments_2, windowsVerbatimArguments: false };
44771
44806
  }
@@ -44829,12 +44864,12 @@ var PiRpcSession = class {
44829
44864
  const child = this.#processAdapter.spawn({
44830
44865
  cwd: this.#options.cwd,
44831
44866
  ...this.#options.command ? { command: this.#options.command } : {},
44832
- environment: {
44867
+ environment: withNodeRuntimeOnPath2({
44833
44868
  ...process.env,
44834
44869
  ...this.#options.environment,
44835
44870
  PI_SKIP_VERSION_CHECK: "1",
44836
44871
  PI_TELEMETRY: "0"
44837
- },
44872
+ }),
44838
44873
  ...this.#options.sessionFile ? { sessionFile: this.#options.sessionFile } : {},
44839
44874
  ...this.#options.forkSessionFile ? { forkSessionFile: this.#options.forkSessionFile } : {},
44840
44875
  ...this.#options.model ? { model: this.#options.model } : {}
@@ -45405,7 +45440,7 @@ var PiRpcSession = class {
45405
45440
  }
45406
45441
  #finalizeAssistantMessage(active, value) {
45407
45442
  const finalText = assistantText2(value);
45408
- const finalReasoning = assistantReasoning2(value);
45443
+ const finalReasoning = assistantReasoning(value);
45409
45444
  const failure2 = assistantFailure(value);
45410
45445
  const cacheHitRatePercent = optionalPiCacheHitRatePercent(value);
45411
45446
  if (finalText === null || finalReasoning === null || failure2 === void 0)
@@ -45668,8 +45703,8 @@ function numberField(value, key) {
45668
45703
  const field = value[key];
45669
45704
  return typeof field === "number" || field === null ? field : void 0;
45670
45705
  }
45671
- function stripDiffPrefix(path11) {
45672
- return path11.startsWith("a/") || path11.startsWith("b/") ? path11.slice(2) : path11;
45706
+ function stripDiffPrefix(path12) {
45707
+ return path12.startsWith("a/") || path12.startsWith("b/") ? path12.slice(2) : path12;
45673
45708
  }
45674
45709
  function reliableFileChange(result) {
45675
45710
  if (!isRecord11(result) || !isRecord11(result.details) || typeof result.details.patch !== "string") {
@@ -45688,10 +45723,10 @@ function reliableFileChange(result) {
45688
45723
  const oldFile = file2.oldFileName;
45689
45724
  const newFile = file2.newFileName;
45690
45725
  const kind = oldFile === "/dev/null" ? "add" : newFile === "/dev/null" ? "delete" : "update";
45691
- const path11 = stripDiffPrefix(kind === "delete" ? oldFile : newFile);
45692
- if (!path11 || path11 === "/dev/null")
45726
+ const path12 = stripDiffPrefix(kind === "delete" ? oldFile : newFile);
45727
+ if (!path12 || path12 === "/dev/null")
45693
45728
  return null;
45694
- return [{ path: path11, kind, unifiedDiff: patch }];
45729
+ return [{ path: path12, kind, unifiedDiff: patch }];
45695
45730
  }
45696
45731
  function delay3(milliseconds) {
45697
45732
  return new Promise((resolve2) => setTimeout(resolve2, milliseconds));
@@ -46915,9 +46950,9 @@ import nodePath from "node:path";
46915
46950
  // packages/mapping-store/dist/mapping-store.js
46916
46951
  import { execFileSync } from "node:child_process";
46917
46952
  import { randomUUID as randomUUID4 } from "node:crypto";
46918
- import { constants } from "node:fs";
46953
+ import { constants as constants2 } from "node:fs";
46919
46954
  import { copyFile, mkdir, open as open2, readFile, readdir, rename, rm as rm2, stat } from "node:fs/promises";
46920
- import path6 from "node:path";
46955
+ import path7 from "node:path";
46921
46956
 
46922
46957
  // packages/mapping-store/dist/records.js
46923
46958
  var nonBlankTextSchema3 = external_exports.string().refine((value) => value.trim().length > 0, {
@@ -47122,11 +47157,11 @@ var MappingStore = class {
47122
47157
  #initialized = false;
47123
47158
  #lockHandle = null;
47124
47159
  constructor(options) {
47125
- this.#directory = path6.resolve(options.directory);
47126
- this.#threadsDirectory = path6.join(this.#directory, "threads");
47127
- this.#backupsDirectory = path6.join(this.#directory, "backups");
47128
- this.#quarantineDirectory = path6.join(this.#directory, "quarantine");
47129
- this.#lockPath = path6.join(this.#directory, "store.lock");
47160
+ this.#directory = path7.resolve(options.directory);
47161
+ this.#threadsDirectory = path7.join(this.#directory, "threads");
47162
+ this.#backupsDirectory = path7.join(this.#directory, "backups");
47163
+ this.#quarantineDirectory = path7.join(this.#directory, "quarantine");
47164
+ this.#lockPath = path7.join(this.#directory, "store.lock");
47130
47165
  this.#instanceId = options.instanceId ?? randomUUID4();
47131
47166
  this.#now = options.now ?? (() => /* @__PURE__ */ new Date());
47132
47167
  this.#beforeReplace = options.beforeReplace;
@@ -47144,8 +47179,8 @@ var MappingStore = class {
47144
47179
  await this.#cleanupTemps();
47145
47180
  const names = (await readdir(this.#threadsDirectory)).filter((name) => name.endsWith(".json"));
47146
47181
  for (const name of names) {
47147
- const primary = path6.join(this.#threadsDirectory, name);
47148
- const backup = path6.join(this.#backupsDirectory, name);
47182
+ const primary = path7.join(this.#threadsDirectory, name);
47183
+ const backup = path7.join(this.#backupsDirectory, name);
47149
47184
  let record3 = null;
47150
47185
  try {
47151
47186
  record3 = await this.#readRecord(primary, name);
@@ -47154,7 +47189,7 @@ var MappingStore = class {
47154
47189
  record3 = await this.#readRecord(backup, name);
47155
47190
  await this.#replaceFile(primary, record3, false);
47156
47191
  } catch (backupError) {
47157
- const quarantine = path6.join(this.#quarantineDirectory, `${name}.${this.#now().getTime()}.invalid`);
47192
+ const quarantine = path7.join(this.#quarantineDirectory, `${name}.${this.#now().getTime()}.invalid`);
47158
47193
  await rename(primary, quarantine).catch(() => void 0);
47159
47194
  void primaryError;
47160
47195
  void backupError;
@@ -47401,7 +47436,7 @@ var MappingStore = class {
47401
47436
  let handle = null;
47402
47437
  try {
47403
47438
  await this.#beforeReplace?.(cloneRecord(record3));
47404
- handle = await open2(temp, "wx", constants.S_IRUSR | constants.S_IWUSR);
47439
+ handle = await open2(temp, "wx", constants2.S_IRUSR | constants2.S_IWUSR);
47405
47440
  await handle.writeFile(`${JSON.stringify(record3, null, 2)}
47406
47441
  `, "utf8");
47407
47442
  await handle.sync();
@@ -47435,11 +47470,11 @@ var MappingStore = class {
47435
47470
  }
47436
47471
  async #cleanupTemps() {
47437
47472
  const names = await readdir(this.#threadsDirectory);
47438
- await Promise.all(names.filter((name) => name.includes(".tmp-")).map((name) => rm2(path6.join(this.#threadsDirectory, name), { force: true })));
47473
+ await Promise.all(names.filter((name) => name.includes(".tmp-")).map((name) => rm2(path7.join(this.#threadsDirectory, name), { force: true })));
47439
47474
  }
47440
47475
  async #acquireLock() {
47441
47476
  const attempt = async () => {
47442
- const handle = await open2(this.#lockPath, "wx", constants.S_IRUSR | constants.S_IWUSR);
47477
+ const handle = await open2(this.#lockPath, "wx", constants2.S_IRUSR | constants2.S_IWUSR);
47443
47478
  const lock = {
47444
47479
  pid: process.pid,
47445
47480
  instanceId: this.#instanceId,
@@ -47528,10 +47563,10 @@ var MappingStore = class {
47528
47563
  }
47529
47564
  }
47530
47565
  #recordPath(hostThreadId) {
47531
- return path6.join(this.#threadsDirectory, `${hostThreadId}.json`);
47566
+ return path7.join(this.#threadsDirectory, `${hostThreadId}.json`);
47532
47567
  }
47533
47568
  #backupPath(hostThreadId) {
47534
- return path6.join(this.#backupsDirectory, `${hostThreadId}.json`);
47569
+ return path7.join(this.#backupsDirectory, `${hostThreadId}.json`);
47535
47570
  }
47536
47571
  #requireInitialized() {
47537
47572
  if (!this.#initialized) {
@@ -47736,6 +47771,7 @@ function projectCodexQuestionRequest(input) {
47736
47771
  turnId: interaction.turnId,
47737
47772
  itemId: input.itemId,
47738
47773
  questions,
47774
+ isBlocking: true,
47739
47775
  autoResolutionMs
47740
47776
  }
47741
47777
  },
@@ -47899,8 +47935,8 @@ function projectItem(item, outcome, defaultCwd, includeCommandOutput = true) {
47899
47935
  return {
47900
47936
  id: item.itemId,
47901
47937
  type: "fileChange",
47902
- changes: item.changes.map(({ path: path11, kind, unifiedDiff }) => ({
47903
- path: path11,
47938
+ changes: item.changes.map(({ path: path12, kind, unifiedDiff }) => ({
47939
+ path: path12,
47904
47940
  kind,
47905
47941
  diff: unifiedDiff
47906
47942
  })),
@@ -48317,8 +48353,8 @@ var CodexTurnProjector = class {
48317
48353
  return messages;
48318
48354
  }
48319
48355
  #fileChangeUpdates(itemId2, changes) {
48320
- const projectedChanges = changes.map(({ path: path11, kind, unifiedDiff }) => ({
48321
- path: path11,
48356
+ const projectedChanges = changes.map(({ path: path12, kind, unifiedDiff }) => ({
48357
+ path: path12,
48322
48358
  kind,
48323
48359
  diff: unifiedDiff
48324
48360
  }));
@@ -48401,13 +48437,13 @@ function decodeThreadForkRequest(request) {
48401
48437
  if (runtimeWorkspaceRoots !== void 0 && runtimeWorkspaceRoots !== null && (!Array.isArray(runtimeWorkspaceRoots) || runtimeWorkspaceRoots.some((root) => typeof root !== "string" || root.length === 0))) {
48402
48438
  throw new Error("thread/fork params.runtimeWorkspaceRoots must be text paths or null");
48403
48439
  }
48404
- const path11 = optionalText(params, "path", { allowEmpty: true });
48440
+ const path12 = optionalText(params, "path", { allowEmpty: true });
48405
48441
  const ephemeral = optionalBoolean(params, "ephemeral");
48406
48442
  return {
48407
48443
  threadId: threadId2,
48408
48444
  ...lastTurnText ? { lastTurnId: hostTurnIdSchema.parse(lastTurnText) } : {},
48409
48445
  ...beforeTurnText ? { beforeTurnId: hostTurnIdSchema.parse(beforeTurnText) } : {},
48410
- ...path11 ? { path: path11 } : {},
48446
+ ...path12 ? { path: path12 } : {},
48411
48447
  ...optionalField(params, "model"),
48412
48448
  ...optionalField(params, "modelProvider"),
48413
48449
  ...optionalField(params, "cwd"),
@@ -48982,8 +49018,8 @@ var packageMetadata5 = {
48982
49018
 
48983
49019
  // packages/host-runtime/src/external-thread-repository.ts
48984
49020
  import { randomUUID as randomUUID5 } from "node:crypto";
48985
- import os2 from "node:os";
48986
- import path7 from "node:path";
49021
+ import os3 from "node:os";
49022
+ import path8 from "node:path";
48987
49023
  function nativeTurnKey2(ref) {
48988
49024
  return `${ref.harnessId}\0${ref.nativeSessionId}\0${ref.nativeTurnKey}\0${ref.formatVersion}`;
48989
49025
  }
@@ -48992,8 +49028,8 @@ function sameMapping(left, right) {
48992
49028
  }
48993
49029
  function defaultMappingStoreDirectory(environment) {
48994
49030
  const dataDirectory = environment.CODEXHOST_DATA_DIR;
48995
- return path7.join(
48996
- dataDirectory ? path7.resolve(dataDirectory) : path7.join(os2.homedir(), ".codexhost"),
49031
+ return path8.join(
49032
+ dataDirectory ? path8.resolve(dataDirectory) : path8.join(os3.homedir(), ".codexhost"),
48997
49033
  "mapping-store"
48998
49034
  );
48999
49035
  }
@@ -50281,25 +50317,25 @@ function resolveExternalSessionTreeIds(records) {
50281
50317
  const resolve2 = (start) => {
50282
50318
  const cached2 = resolved.get(start.hostThreadId);
50283
50319
  if (cached2) return cached2;
50284
- const path11 = [];
50320
+ const path12 = [];
50285
50321
  const visited = /* @__PURE__ */ new Set();
50286
50322
  let current = start;
50287
50323
  while (true) {
50288
50324
  const known = resolved.get(current.hostThreadId);
50289
50325
  if (known) {
50290
- for (const record3 of path11) resolved.set(record3.hostThreadId, known);
50326
+ for (const record3 of path12) resolved.set(record3.hostThreadId, known);
50291
50327
  return known;
50292
50328
  }
50293
50329
  if (visited.has(current.hostThreadId)) {
50294
50330
  throw new Error("External Thread Fork tree contains a cycle");
50295
50331
  }
50296
50332
  visited.add(current.hostThreadId);
50297
- path11.push(current);
50333
+ path12.push(current);
50298
50334
  const sourceId = current.forkSource?.hostThreadId;
50299
50335
  const source = sourceId ? byId.get(sourceId) : void 0;
50300
50336
  if (!source) {
50301
50337
  const root = current.hostThreadId;
50302
- for (const record3 of path11) resolved.set(record3.hostThreadId, root);
50338
+ for (const record3 of path12) resolved.set(record3.hostThreadId, root);
50303
50339
  return root;
50304
50340
  }
50305
50341
  current = source;
@@ -52352,7 +52388,7 @@ import { createConnection } from "node:net";
52352
52388
 
52353
52389
  // packages/update-manager/dist/distribution.js
52354
52390
  import { lstat, readFile as readFile2 } from "node:fs/promises";
52355
- import path8 from "node:path";
52391
+ import path9 from "node:path";
52356
52392
 
52357
52393
  // packages/update-manager/dist/status.js
52358
52394
  var STATUS_SCHEMA_VERSION = 1;
@@ -52438,9 +52474,9 @@ function parseDistributionMetadata(value) {
52438
52474
  }
52439
52475
  function absoluteEnvironmentPath(environment, name) {
52440
52476
  const value = environment[name];
52441
- if (!value || !path8.isAbsolute(value))
52477
+ if (!value || !path9.isAbsolute(value))
52442
52478
  throw new Error(`${name} must be an absolute path`);
52443
- return path8.normalize(value);
52479
+ return path9.normalize(value);
52444
52480
  }
52445
52481
  function positiveEnvironmentInteger(environment, name) {
52446
52482
  const value = Number(environment[name]);
@@ -52462,39 +52498,39 @@ function expectedTarget(platform, architecture) {
52462
52498
  function defaultUpdateStateDirectory(platform = process.platform, environment = process.env) {
52463
52499
  if (platform === "win32") {
52464
52500
  const root = environment.LOCALAPPDATA;
52465
- if (!root || !path8.isAbsolute(root))
52501
+ if (!root || !path9.isAbsolute(root))
52466
52502
  throw new Error("LOCALAPPDATA is unavailable");
52467
- return path8.join(root, "codexhost", "updates");
52503
+ return path9.join(root, "codexhost", "updates");
52468
52504
  }
52469
52505
  const home = environment.HOME;
52470
- if (!home || !path8.isAbsolute(home))
52506
+ if (!home || !path9.isAbsolute(home))
52471
52507
  throw new Error("HOME is unavailable");
52472
- return platform === "darwin" ? path8.join(home, "Library", "Application Support", "codexhost", "updates") : path8.join(home, ".codexhost", "updates");
52508
+ return platform === "darwin" ? path9.join(home, "Library", "Application Support", "codexhost", "updates") : path9.join(home, ".codexhost", "updates");
52473
52509
  }
52474
52510
  async function resolveInstalledUpdateContext(options) {
52475
52511
  const environment = options.environment ?? process.env;
52476
52512
  const platform = options.platform ?? process.platform;
52477
52513
  const architecture = options.architecture ?? process.arch;
52478
- if (!path8.isAbsolute(options.hostRuntimePath)) {
52514
+ if (!path9.isAbsolute(options.hostRuntimePath)) {
52479
52515
  throw new Error("Host Runtime path must be absolute");
52480
52516
  }
52481
- const hostRuntimePath = path8.normalize(options.hostRuntimePath);
52517
+ const hostRuntimePath = path9.normalize(options.hostRuntimePath);
52482
52518
  const runtimeMetadata = await lstat(hostRuntimePath);
52483
52519
  if (!runtimeMetadata.isFile() || runtimeMetadata.isSymbolicLink()) {
52484
52520
  throw new Error("Host Runtime must be a regular file");
52485
52521
  }
52486
- const appDirectory = path8.dirname(hostRuntimePath);
52487
- const metadata = parseDistributionMetadata(JSON.parse(await readFile2(path8.join(appDirectory, "codexhost-distribution.json"), "utf8")));
52522
+ const appDirectory = path9.dirname(hostRuntimePath);
52523
+ const metadata = parseDistributionMetadata(JSON.parse(await readFile2(path9.join(appDirectory, "codexhost-distribution.json"), "utf8")));
52488
52524
  const target = expectedTarget(platform, architecture);
52489
52525
  if (metadata.target !== target) {
52490
52526
  throw new Error(`installed target ${metadata.target} does not match ${target}`);
52491
52527
  }
52492
52528
  const launcherPid = positiveEnvironmentInteger(environment, UPDATE_RUNTIME_ENV.launcherPid);
52493
52529
  const launcherExecutable = absoluteEnvironmentPath(environment, UPDATE_RUNTIME_ENV.launcherExecutable);
52494
- const stateDirectory = path8.normalize(options.stateDirectory ?? defaultUpdateStateDirectory(platform, environment));
52495
- const resourcesRoot = path8.dirname(appDirectory);
52496
- const installationRoot = platform === "darwin" ? path8.dirname(path8.dirname(resourcesRoot)) : resourcesRoot;
52497
- const updaterExecutable = path8.join(resourcesRoot, "libexec", platform === "win32" ? "codexhost-updater.exe" : "codexhost-updater");
52530
+ const stateDirectory = path9.normalize(options.stateDirectory ?? defaultUpdateStateDirectory(platform, environment));
52531
+ const resourcesRoot = path9.dirname(appDirectory);
52532
+ const installationRoot = platform === "darwin" ? path9.dirname(path9.dirname(resourcesRoot)) : resourcesRoot;
52533
+ const updaterExecutable = path9.join(resourcesRoot, "libexec", platform === "win32" ? "codexhost-updater.exe" : "codexhost-updater");
52498
52534
  const common = {
52499
52535
  version: metadata.version,
52500
52536
  launcherPid,
@@ -52517,7 +52553,7 @@ async function resolveInstalledUpdateContext(options) {
52517
52553
  npmLauncherPath: absoluteEnvironmentPath(environment, UPDATE_RUNTIME_ENV.npmLauncherPath),
52518
52554
  packageRoot: absoluteEnvironmentPath(environment, UPDATE_RUNTIME_ENV.npmPackageRoot)
52519
52555
  };
52520
- if (path8.normalize(npmOptions.packageRoot) !== resourcesRoot) {
52556
+ if (path9.normalize(npmOptions.packageRoot) !== resourcesRoot) {
52521
52557
  throw new Error("npm platform package root does not own the Host Runtime");
52522
52558
  }
52523
52559
  return { metadata, common, controller, installation: { kind: "npm", options: npmOptions } };
@@ -52680,7 +52716,7 @@ function selectInstallerReleaseArtifact(release, target) {
52680
52716
 
52681
52717
  // packages/update-manager/dist/operation-state.js
52682
52718
  import { lstat as lstat2, mkdir as mkdir2, open as open3, readFile as readFile3, readdir as readdir2, rm as rm3, writeFile } from "node:fs/promises";
52683
- import path9 from "node:path";
52719
+ import path10 from "node:path";
52684
52720
  var LOCK_FILE = "active-update-v1.lock";
52685
52721
  var STATUS_FILE = "status-v1.json";
52686
52722
  var TERMINAL_PHASES = /* @__PURE__ */ new Set(["succeeded", "failed"]);
@@ -52695,12 +52731,12 @@ async function regularFile(filePath) {
52695
52731
  }
52696
52732
  }
52697
52733
  async function isUpdateOperationActive(stateDirectory) {
52698
- if (!path9.isAbsolute(stateDirectory))
52734
+ if (!path10.isAbsolute(stateDirectory))
52699
52735
  throw new Error("update state directory must be absolute");
52700
- return regularFile(path9.join(stateDirectory, LOCK_FILE));
52736
+ return regularFile(path10.join(stateDirectory, LOCK_FILE));
52701
52737
  }
52702
52738
  async function discoverLatestUpdateStatus(stateDirectory) {
52703
- if (!path9.isAbsolute(stateDirectory))
52739
+ if (!path10.isAbsolute(stateDirectory))
52704
52740
  throw new Error("update state directory must be absolute");
52705
52741
  let entries;
52706
52742
  try {
@@ -52714,7 +52750,7 @@ async function discoverLatestUpdateStatus(stateDirectory) {
52714
52750
  for (const entry of entries) {
52715
52751
  if (!entry.isDirectory() || entry.isSymbolicLink() || !entry.name.startsWith("update-"))
52716
52752
  continue;
52717
- const statusPath = path9.join(stateDirectory, entry.name, STATUS_FILE);
52753
+ const statusPath = path10.join(stateDirectory, entry.name, STATUS_FILE);
52718
52754
  if (!await regularFile(statusPath))
52719
52755
  continue;
52720
52756
  try {
@@ -52742,8 +52778,8 @@ async function cleanupTerminalUpdateState(stateDirectory, options = {}) {
52742
52778
  for (const entry of entries) {
52743
52779
  if (!entry.isDirectory() || entry.isSymbolicLink() || !entry.name.startsWith("update-"))
52744
52780
  continue;
52745
- const directory = path9.join(stateDirectory, entry.name);
52746
- const statusPath = path9.join(directory, STATUS_FILE);
52781
+ const directory = path10.join(stateDirectory, entry.name);
52782
+ const statusPath = path10.join(directory, STATUS_FILE);
52747
52783
  try {
52748
52784
  const status = parseUpdateStatus(JSON.parse(await readFile3(statusPath, "utf8")));
52749
52785
  if (TERMINAL_PHASES.has(status.phase) && now - status.updatedAt > retentionSeconds) {
@@ -52754,10 +52790,10 @@ async function cleanupTerminalUpdateState(stateDirectory, options = {}) {
52754
52790
  }
52755
52791
  }
52756
52792
  async function acquireUpdateOperationLock(stateDirectory) {
52757
- if (!path9.isAbsolute(stateDirectory))
52793
+ if (!path10.isAbsolute(stateDirectory))
52758
52794
  throw new Error("update state directory must be absolute");
52759
52795
  await mkdir2(stateDirectory, { recursive: true, mode: 448 });
52760
- const lockPath = path9.join(stateDirectory, LOCK_FILE);
52796
+ const lockPath = path10.join(stateDirectory, LOCK_FILE);
52761
52797
  let handle;
52762
52798
  try {
52763
52799
  handle = await open3(lockPath, "wx", 384);
@@ -52776,9 +52812,9 @@ async function acquireUpdateOperationLock(stateDirectory) {
52776
52812
  async setStatusPath(statusPath) {
52777
52813
  if (released)
52778
52814
  throw new Error("update operation lock is released");
52779
- if (!path9.isAbsolute(statusPath))
52815
+ if (!path10.isAbsolute(statusPath))
52780
52816
  throw new Error("update status path must be absolute");
52781
- await writeFile(lockPath, `${JSON.stringify({ ownerPid: process.pid, statusPath: path9.normalize(statusPath) })}
52817
+ await writeFile(lockPath, `${JSON.stringify({ ownerPid: process.pid, statusPath: path10.normalize(statusPath) })}
52782
52818
  `, { encoding: "utf8", mode: 384 });
52783
52819
  },
52784
52820
  async release() {
@@ -52800,7 +52836,7 @@ function processIsAlive(processId) {
52800
52836
  }
52801
52837
  }
52802
52838
  async function recoverUpdateOperationLock(stateDirectory) {
52803
- const lockPath = path9.join(stateDirectory, LOCK_FILE);
52839
+ const lockPath = path10.join(stateDirectory, LOCK_FILE);
52804
52840
  if (!await regularFile(lockPath))
52805
52841
  return;
52806
52842
  let ownerPid;
@@ -52812,7 +52848,7 @@ async function recoverUpdateOperationLock(stateDirectory) {
52812
52848
  } catch {
52813
52849
  return;
52814
52850
  }
52815
- if (typeof statusPath !== "string" || !path9.isAbsolute(statusPath))
52851
+ if (typeof statusPath !== "string" || !path10.isAbsolute(statusPath))
52816
52852
  return;
52817
52853
  try {
52818
52854
  const status = parseUpdateStatus(JSON.parse(await readFile3(statusPath, "utf8")));
@@ -52827,7 +52863,7 @@ async function recoverUpdateOperationLock(stateDirectory) {
52827
52863
  import { spawn as spawn4 } from "node:child_process";
52828
52864
  import { randomUUID as randomUUID8 } from "node:crypto";
52829
52865
  import { chmod, copyFile as copyFile2, lstat as lstat4, mkdir as mkdir3, readFile as readFile4, rename as rename2, rm as rm4, writeFile as writeFile2 } from "node:fs/promises";
52830
- import path10 from "node:path";
52866
+ import path11 from "node:path";
52831
52867
 
52832
52868
  // packages/update-manager/dist/artifact.js
52833
52869
  import { createHash as createHash2 } from "node:crypto";
@@ -52924,9 +52960,9 @@ function errorMessage4(error52) {
52924
52960
  return error52 instanceof Error ? error52.message : String(error52);
52925
52961
  }
52926
52962
  function requireAbsolutePath(value, label) {
52927
- if (!path10.isAbsolute(value))
52963
+ if (!path11.isAbsolute(value))
52928
52964
  throw new Error(`${label} must be an absolute path`);
52929
- return path10.normalize(value);
52965
+ return path11.normalize(value);
52930
52966
  }
52931
52967
  async function requireRegularFile(value, label) {
52932
52968
  const filePath = requireAbsolutePath(value, label);
@@ -52969,7 +53005,7 @@ function createBackgroundUpdateManager(dependencies = {}) {
52969
53005
  const now = dependencies.now ?? Date.now;
52970
53006
  const preparedRequests = /* @__PURE__ */ new Set();
52971
53007
  async function writeStatusSnapshot(statusPath, status) {
52972
- const temporaryPath = path10.join(path10.dirname(statusPath), `.update-status-${randomId()}.tmp`);
53008
+ const temporaryPath = path11.join(path11.dirname(statusPath), `.update-status-${randomId()}.tmp`);
52973
53009
  try {
52974
53010
  await writeFile2(temporaryPath, `${JSON.stringify(status)}
52975
53011
  `, {
@@ -53028,15 +53064,15 @@ function createBackgroundUpdateManager(dependencies = {}) {
53028
53064
  const updaterExecutable = await requireRegularFile(options.updaterExecutable, "Updater executable");
53029
53065
  const stateDirectory = requireAbsolutePath(options.stateDirectory, "update state directory");
53030
53066
  await mkdir3(stateDirectory, { recursive: true, mode: 448 });
53031
- const workDirectory = path10.join(stateDirectory, `update-${version2}-${randomId()}`);
53067
+ const workDirectory = path11.join(stateDirectory, `update-${version2}-${randomId()}`);
53032
53068
  await mkdir3(workDirectory, { recursive: false, mode: 448 });
53033
53069
  const executableSuffix = platform === "win32" ? ".exe" : "";
53034
- const helperPath = path10.join(workDirectory, `codexhost-updater${executableSuffix}`);
53070
+ const helperPath = path11.join(workDirectory, `codexhost-updater${executableSuffix}`);
53035
53071
  await copyFile2(updaterExecutable, helperPath);
53036
53072
  if (platform !== "win32")
53037
53073
  await chmod(helperPath, 448);
53038
- const requestPath = path10.join(workDirectory, "request-v1.json");
53039
- const statusPath = path10.join(workDirectory, "status-v1.json");
53074
+ const requestPath = path11.join(workDirectory, "request-v1.json");
53075
+ const statusPath = path11.join(workDirectory, "status-v1.json");
53040
53076
  await writePrivateJson(statusPath, preparedStatus(version2, installation, now()));
53041
53077
  await options.onPrepared?.({ version: version2, installation, statusPath });
53042
53078
  return {
@@ -53051,8 +53087,8 @@ function createBackgroundUpdateManager(dependencies = {}) {
53051
53087
  }
53052
53088
  async function prepareArtifact(common, installation, sourceValue, fileName) {
53053
53089
  const source = validateArtifact(sourceValue);
53054
- const temporaryPath = path10.join(common.workDirectory, `.${fileName}.download`);
53055
- const artifactPath = path10.join(common.workDirectory, fileName);
53090
+ const temporaryPath = path11.join(common.workDirectory, `.${fileName}.download`);
53091
+ const artifactPath = path11.join(common.workDirectory, fileName);
53056
53092
  const progress = progressReporter(common.statusPath, common.version, installation, source.size);
53057
53093
  try {
53058
53094
  const result = await download(source, temporaryPath, progress.update);
@@ -53101,8 +53137,7 @@ function createBackgroundUpdateManager(dependencies = {}) {
53101
53137
  kind: "npm",
53102
53138
  node_path: await requireRegularFile(options.nodePath, "npm Node.js executable"),
53103
53139
  npm_cli_path: await requireRegularFile(options.npmCliPath, "npm CLI"),
53104
- npm_launcher_path: await requireRegularFile(options.npmLauncherPath, "npm codexhost launcher"),
53105
- package_root: requireAbsolutePath(options.packageRoot, "npm platform package root")
53140
+ npm_launcher_path: await requireRegularFile(options.npmLauncherPath, "npm codexhost launcher")
53106
53141
  });
53107
53142
  } catch (error52) {
53108
53143
  await writeFailedStatus(common.statusPath, common.version, "npm", error52);
@@ -53126,7 +53161,7 @@ function createBackgroundUpdateManager(dependencies = {}) {
53126
53161
  throw new Error("macOS DMG updates require macOS");
53127
53162
  const common = await prepareCommon(options, "macos-dmg");
53128
53163
  const appPath = requireAbsolutePath(options.appPath, "macOS application path");
53129
- if (path10.extname(appPath) !== ".app") {
53164
+ if (path11.extname(appPath) !== ".app") {
53130
53165
  throw new Error("macOS application path must end in .app");
53131
53166
  }
53132
53167
  const artifact = await prepareArtifact(common, "macos-dmg", options.artifact, "update.dmg");
@@ -18168,15 +18168,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18168
18168
  locale: "en",
18169
18169
  title: "Settings",
18170
18170
  close: "Close settings",
18171
- interfaceLanguage: "Interface language",
18172
- automaticLanguage: "Automatic (follow Codex)",
18173
- englishLanguage: "English",
18174
- simplifiedChineseLanguage: "Simplified Chinese",
18175
- otherCodexLanguage: "Other Codex language",
18176
- languageUpdateFailed: "Could not update the language setting.",
18171
+ starOnGitHub: "Give us a Star~",
18177
18172
  sectionsLabel: "Settings sections",
18178
18173
  pageUnavailable: "Page unavailable",
18179
- availability: "Availability",
18174
+ inDevelopment: "In development",
18180
18175
  notAvailable: "Not available",
18181
18176
  runtimeCapabilityNotInstalled: "This runtime capability is not installed yet.",
18182
18177
  openSettings: "Open codexhost settings",
@@ -18195,11 +18190,15 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18195
18190
  updateChecking: "Checking for updates...",
18196
18191
  updateDownloading: "Downloading update...",
18197
18192
  updatePreparing: "Preparing update...",
18193
+ updateWaitingForExit: "Waiting for the application to close...",
18194
+ updateInstalling: "Installing update...",
18195
+ updateInstallingNpm: "Installing update through npm...",
18198
18196
  updateRequestTimeout: "The update service did not respond. Try again.",
18199
18197
  updateRestarting: "Restarting to finish the update...",
18200
18198
  updateSucceeded: "Update installed successfully.",
18201
18199
  updateFailed: "Update failed.",
18202
18200
  updateRetry: "Retry",
18201
+ updateManualNpmDescription: "To update manually, quit codexhost and run this command:",
18203
18202
  updateDownloadFromReleases: "Download from GitHub Releases",
18204
18203
  pageLabels: Object.freeze({
18205
18204
  connections: "Connections",
@@ -18213,15 +18212,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18213
18212
  locale: "zh-CN",
18214
18213
  title: "\u8BBE\u7F6E",
18215
18214
  close: "\u5173\u95ED\u8BBE\u7F6E",
18216
- interfaceLanguage: "\u754C\u9762\u8BED\u8A00",
18217
- automaticLanguage: "\u81EA\u52A8\uFF08\u8DDF\u968F Codex\uFF09",
18218
- englishLanguage: "English",
18219
- simplifiedChineseLanguage: "\u7B80\u4F53\u4E2D\u6587",
18220
- otherCodexLanguage: "\u5176\u4ED6 Codex \u8BED\u8A00",
18221
- languageUpdateFailed: "\u65E0\u6CD5\u66F4\u65B0\u8BED\u8A00\u8BBE\u7F6E\u3002",
18215
+ starOnGitHub: "\u70B9\u4E2A Star~",
18222
18216
  sectionsLabel: "\u8BBE\u7F6E\u5206\u7C7B",
18223
18217
  pageUnavailable: "\u9875\u9762\u4E0D\u53EF\u7528",
18224
- availability: "\u53EF\u7528\u6027",
18218
+ inDevelopment: "\u5F00\u53D1\u4E2D",
18225
18219
  notAvailable: "\u6682\u4E0D\u53EF\u7528",
18226
18220
  runtimeCapabilityNotInstalled: "\u8FD0\u884C\u65F6\u5C1A\u672A\u5B89\u88C5\u8BE5\u9879\u80FD\u529B\uFF0C\u56E0\u6B64\u6682\u4E0D\u53EF\u7528\u3002",
18227
18221
  openSettings: "\u6253\u5F00 codexhost \u8BBE\u7F6E",
@@ -18240,11 +18234,15 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18240
18234
  updateChecking: "\u6B63\u5728\u68C0\u67E5\u66F4\u65B0...",
18241
18235
  updateDownloading: "\u6B63\u5728\u4E0B\u8F7D\u66F4\u65B0...",
18242
18236
  updatePreparing: "\u6B63\u5728\u51C6\u5907\u66F4\u65B0...",
18237
+ updateWaitingForExit: "\u6B63\u5728\u7B49\u5F85\u5E94\u7528\u9000\u51FA...",
18238
+ updateInstalling: "\u6B63\u5728\u5B89\u88C5\u66F4\u65B0...",
18239
+ updateInstallingNpm: "\u6B63\u5728\u901A\u8FC7 npm \u5B89\u88C5...",
18243
18240
  updateRequestTimeout: "\u66F4\u65B0\u670D\u52A1\u672A\u54CD\u5E94\uFF0C\u8BF7\u91CD\u8BD5\u3002",
18244
18241
  updateRestarting: "\u6B63\u5728\u91CD\u542F\u4EE5\u5B8C\u6210\u66F4\u65B0...",
18245
18242
  updateSucceeded: "\u66F4\u65B0\u5B89\u88C5\u6210\u529F\u3002",
18246
18243
  updateFailed: "\u66F4\u65B0\u5931\u8D25\u3002",
18247
18244
  updateRetry: "\u91CD\u8BD5",
18245
+ updateManualNpmDescription: "\u5982\u9700\u624B\u52A8\u66F4\u65B0\uFF0C\u8BF7\u5728\u7EC8\u7AEF\u8FD0\u884C\u4EE5\u4E0B\u547D\u4EE4\u3002\u66F4\u65B0\u5B8C\u6210\u540E\uFF0C\u8BF7\u9000\u51FA Codex \u5E76\u901A\u8FC7 codexhost \u91CD\u65B0\u542F\u52A8\u3002",
18248
18246
  updateDownloadFromReleases: "\u524D\u5F80 GitHub Releases \u4E0B\u8F7D",
18249
18247
  pageLabels: Object.freeze({
18250
18248
  connections: "\u8FDE\u63A5",
@@ -18380,6 +18378,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18380
18378
  ["circle", { cx: "12", cy: "12", r: "3" }]
18381
18379
  ];
18382
18380
 
18381
+ // ../../node_modules/lucide/dist/esm/icons/star.mjs
18382
+ var Star = [
18383
+ [
18384
+ "path",
18385
+ {
18386
+ d: "M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z"
18387
+ }
18388
+ ]
18389
+ ];
18390
+
18383
18391
  // ../../node_modules/lucide/dist/esm/icons/x.mjs
18384
18392
  var X = [
18385
18393
  ["path", { d: "M18 6 6 18" }],
@@ -18393,6 +18401,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18393
18401
  var RENDERER_SETTINGS_ICON_NAMES = [
18394
18402
  "settings",
18395
18403
  "close",
18404
+ "star",
18396
18405
  "language",
18397
18406
  "connections",
18398
18407
  "model-pool",
@@ -18406,6 +18415,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18406
18415
  var iconNodes = {
18407
18416
  settings: Settings,
18408
18417
  close: X,
18418
+ star: Star,
18409
18419
  language: Languages,
18410
18420
  connections: PlugZap,
18411
18421
  "model-pool": Boxes,
@@ -18592,6 +18602,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18592
18602
 
18593
18603
  // src/settings/pages.ts
18594
18604
  var CODEXHOST_RELEASES_LATEST_URL = "https://github.com/BytePioneer-AI/codex-host/releases/latest";
18605
+ var CODEXHOST_NPM_MANUAL_UPDATE_COMMAND = "npm install -g @codexhost/cli@latest";
18595
18606
  var DEFAULT_RENDERER_SETTINGS_PAGE_IDS = [
18596
18607
  "connections",
18597
18608
  "model-pool",
@@ -18600,19 +18611,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18600
18611
  "updates"
18601
18612
  ];
18602
18613
  function appendUnavailableStatus(content, messages) {
18603
- const heading = content.ownerDocument.createElement("div");
18604
- heading.className = "settings-section-label";
18605
- heading.textContent = messages.availability;
18606
18614
  const status = content.ownerDocument.createElement("div");
18607
18615
  status.className = "settings-empty";
18608
18616
  const copy = content.ownerDocument.createElement("div");
18609
18617
  const title = content.ownerDocument.createElement("strong");
18610
- title.textContent = messages.notAvailable;
18611
- const detail = content.ownerDocument.createElement("span");
18612
- detail.textContent = messages.runtimeCapabilityNotInstalled;
18613
- copy.append(title, detail);
18618
+ title.textContent = messages.inDevelopment;
18619
+ copy.append(title);
18614
18620
  status.append(copy);
18615
- content.append(heading, status);
18621
+ content.append(status);
18616
18622
  }
18617
18623
  function unavailablePage(id, messages) {
18618
18624
  return Object.freeze({
@@ -18650,6 +18656,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18650
18656
  if (!status) return null;
18651
18657
  if (status.phase === "succeeded") return messages.updateSucceeded;
18652
18658
  if (status.phase === "failed") return status.error ?? messages.updateFailed;
18659
+ if (status.phase === "waiting-for-exit") return messages.updateWaitingForExit;
18660
+ if (status.phase === "installing") {
18661
+ return status.installation === "npm" ? messages.updateInstallingNpm : messages.updateInstalling;
18662
+ }
18653
18663
  if (status.phase === "restarting") return messages.updateRestarting;
18654
18664
  if (status.phase === "downloading") return messages.updateDownloading;
18655
18665
  return messages.updatePreparing;
@@ -18696,6 +18706,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18696
18706
  const panel = document2.createElement("section");
18697
18707
  panel.className = "settings-update-panel";
18698
18708
  panel.setAttribute("aria-live", "polite");
18709
+ const manualNpm = document2.createElement("div");
18710
+ manualNpm.className = "settings-update-manual";
18711
+ manualNpm.hidden = true;
18712
+ const manualNpmDescription = document2.createElement("span");
18713
+ manualNpmDescription.textContent = messages.updateManualNpmDescription;
18714
+ const manualNpmCommand = document2.createElement("code");
18715
+ manualNpmCommand.textContent = CODEXHOST_NPM_MANUAL_UPDATE_COMMAND;
18716
+ manualNpm.append(manualNpmDescription, manualNpmCommand);
18699
18717
  const actions = document2.createElement("div");
18700
18718
  actions.className = "settings-update-actions";
18701
18719
  const releaseLink = document2.createElement("a");
@@ -18708,7 +18726,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18708
18726
  createRendererSettingsIcon("external-link", 14)
18709
18727
  );
18710
18728
  actions.append(releaseLink);
18711
- context.content.append(heading, metadata, panel, actions);
18729
+ context.content.append(heading, metadata, panel, manualNpm, actions);
18712
18730
  let pollTimer;
18713
18731
  let pollAttempts = 0;
18714
18732
  let pending = false;
@@ -18813,6 +18831,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18813
18831
  const renderCheck = (result, client) => {
18814
18832
  currentVersionValue.textContent = `v${result.currentVersion}`;
18815
18833
  installationValue.textContent = installationLabel(result.installation, messages);
18834
+ manualNpm.hidden = result.installation !== "npm";
18816
18835
  if (result.releaseNotesUrl) releaseLink.href = result.releaseNotesUrl;
18817
18836
  const operationMessage = statusMessage(result.status, messages);
18818
18837
  if (isPendingStatus(result.status)) {
@@ -18904,10 +18923,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18904
18923
  }
18905
18924
 
18906
18925
  // src/settings/shell.css
18907
- var shell_default = ':host {\n --settings-bg: #181818;\n --settings-sidebar: #1c1c1c;\n --settings-panel: transparent;\n --settings-text: #f5f5f5;\n --settings-muted: #a1a1a1;\n --settings-border: rgb(255 255 255 / 10%);\n --settings-divider: rgb(255 255 255 / 10%);\n --settings-hover: rgb(255 255 255 / 6%);\n --settings-active: rgb(51 156 255 / 12%);\n --settings-focus: #339cff;\n color: var(--settings-text);\n color-scheme: dark;\n font:\n 14px/1.5 system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n letter-spacing: 0;\n}\n\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n letter-spacing: 0;\n}\n\nbutton,\ninput,\nselect {\n font: inherit;\n}\n\nbutton {\n color: inherit;\n}\n\n[hidden] {\n display: none !important;\n}\n\n.codexhost-settings-dialog {\n width: min(1120px, calc(100vw - 32px));\n height: min(780px, calc(100vh - 32px));\n max-width: none;\n max-height: none;\n margin: auto;\n padding: 0;\n overflow: hidden;\n color: var(--settings-text);\n background: var(--settings-bg);\n border: 1px solid var(--settings-border);\n border-radius: 12px;\n box-shadow: 0 24px 64px rgb(0 0 0 / 38%);\n}\n\n.codexhost-settings-dialog::backdrop {\n background: rgb(0 0 0 / 52%);\n}\n\n.settings-frame,\n.settings-layout {\n width: 100%;\n height: 100%;\n min-width: 0;\n min-height: 0;\n}\n\n.settings-frame {\n display: flex;\n flex-direction: column;\n}\n\n.settings-layout {\n flex: 1;\n display: grid;\n grid-template-columns: 240px minmax(0, 1fr);\n background: var(--settings-bg);\n}\n\n.settings-sidebar {\n display: flex;\n min-width: 0;\n min-height: 0;\n flex-direction: column;\n overflow: hidden;\n background: var(--settings-sidebar);\n border-right: 1px solid var(--settings-border);\n padding-top: 28px;\n}\n\n.settings-header {\n display: flex;\n align-items: center;\n min-width: 0;\n height: 64px;\n flex: none;\n padding: 0 16px;\n border-bottom: 1px solid var(--settings-border);\n}\n\n.settings-brand {\n display: flex;\n align-items: center;\n min-width: 0;\n gap: 8px;\n}\n\n.settings-brand__mark {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 36px;\n height: 36px;\n flex: none;\n color: var(--settings-text);\n}\n\n.settings-brand__mark .codexhost-settings-icon {\n width: 32px;\n height: 32px;\n object-fit: contain;\n}\n\n.settings-brand__copy {\n display: flex;\n min-width: 0;\n align-items: baseline;\n gap: 0;\n line-height: 20px;\n}\n\n.settings-brand__name {\n overflow: hidden;\n color: var(--settings-text);\n font-size: 14px;\n font-weight: 500;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.settings-brand__title {\n margin-left: 14px;\n padding-left: 14px;\n color: var(--settings-muted);\n font-size: 14px;\n font-weight: 400;\n border-left: 1px solid var(--settings-border);\n}\n\n.settings-nav {\n display: flex;\n min-width: 0;\n min-height: 0;\n flex: 1;\n flex-direction: column;\n gap: 4px;\n padding: 0 12px 16px;\n overflow-y: auto;\n}\n\n.settings-nav-button {\n display: grid;\n grid-template-columns: 16px minmax(0, 1fr);\n align-items: center;\n width: 100%;\n position: relative;\n min-height: 40px;\n flex: none;\n gap: 12px;\n padding: 8px 12px;\n color: var(--settings-text);\n font-size: 14px;\n line-height: 21px;\n text-align: left;\n background: transparent;\n border: 0;\n border-radius: 10px;\n cursor: pointer;\n}\n\n.settings-nav-button .codexhost-settings-icon {\n width: 18px;\n height: 18px;\n opacity: 0.9;\n}\n\n.settings-nav-button:hover {\n background: var(--settings-hover);\n}\n\n.settings-nav-button[aria-current="page"] {\n background: var(--settings-active);\n color: var(--settings-focus);\n}\n\n.settings-nav-button[aria-current="page"]::before {\n position: absolute;\n left: 0;\n width: 3px;\n height: 22px;\n content: "";\n background: var(--settings-focus);\n border-radius: 0 3px 3px 0;\n}\n\n.settings-nav-button span {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.settings-icon-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n flex: none;\n padding: 0;\n color: var(--settings-muted);\n background: transparent;\n border: 0;\n border-radius: 8px;\n cursor: pointer;\n}\n\n.settings-icon-button:hover {\n color: var(--settings-text);\n background: var(--settings-hover);\n}\n\n.settings-icon-button:focus-visible,\n.settings-nav-button:focus-visible {\n outline: 2px solid var(--settings-focus);\n outline-offset: 1px;\n}\n\n.settings-page {\n display: block;\n position: relative;\n min-width: 0;\n min-height: 0;\n overflow-y: auto;\n background: var(--settings-bg);\n scrollbar-gutter: stable;\n}\n\n.settings-page__content {\n width: min(930px, calc(100% - 80px));\n margin-inline: auto;\n}\n\n.settings-page__content {\n min-width: 0;\n padding: 44px 0 56px;\n}\n\n.settings-section-label {\n min-height: auto;\n padding: 0 0 28px;\n color: var(--settings-text);\n font-size: 24px;\n font-weight: 600;\n line-height: 30px;\n}\n\n.settings-status-list,\n.settings-empty {\n overflow: hidden;\n background: var(--settings-panel);\n}\n\n.settings-status-row {\n display: grid;\n grid-template-columns: minmax(170px, 1fr) auto minmax(280px, 1.45fr);\n position: relative;\n align-items: center;\n min-height: 88px;\n gap: 28px;\n padding: 16px 0;\n}\n\n.settings-status-row:not(:last-child)::after {\n content: "";\n position: absolute;\n right: 0;\n bottom: 0;\n left: 0;\n height: 1px;\n background: var(--settings-divider);\n}\n\n.settings-status-row__identity {\n display: inline-flex;\n align-items: center;\n min-width: 0;\n color: var(--settings-text);\n gap: 14px;\n font-size: 15px;\n font-weight: 500;\n line-height: 22px;\n}\n\n.settings-status-row__icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 44px;\n height: 44px;\n flex: none;\n color: var(--settings-muted);\n background: rgb(255 255 255 / 7%);\n border-radius: 50%;\n}\n\n.settings-status-badge {\n flex: none;\n padding: 5px 12px;\n color: var(--settings-muted);\n font-size: 13px;\n font-weight: 500;\n line-height: 18px;\n background: rgb(255 255 255 / 9%);\n border: 1px solid rgb(255 255 255 / 6%);\n border-radius: 6px;\n}\n\n.settings-status-row__detail {\n min-width: 0;\n color: var(--settings-muted);\n font-size: 13px;\n line-height: 20px;\n}\n\n.settings-empty {\n display: flex;\n align-items: center;\n min-height: 72px;\n padding: 12px 16px;\n}\n\n.settings-empty > div {\n display: grid;\n min-width: 0;\n gap: 2px;\n}\n\n.settings-empty strong {\n color: var(--settings-text);\n font-size: 13px;\n font-weight: 500;\n line-height: 19px;\n}\n\n.settings-empty span {\n color: var(--settings-muted);\n font-size: 13px;\n line-height: 19px;\n}\n\n.settings-page-error {\n padding: 16px;\n color: var(--settings-text);\n font-size: 13px;\n background: var(--settings-panel);\n border: 1px solid var(--settings-border);\n border-radius: 20px;\n}\n\n.settings-update-metadata {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: 24px;\n margin-bottom: 24px;\n padding: 0 4px 20px;\n border-bottom: 1px solid var(--settings-divider);\n}\n\n.settings-update-metadata__item {\n display: grid;\n min-width: 0;\n gap: 4px;\n}\n\n.settings-update-metadata__item span {\n color: var(--settings-muted);\n font-size: 12px;\n line-height: 18px;\n}\n\n.settings-update-metadata__item strong {\n min-width: 0;\n overflow-wrap: anywhere;\n color: var(--settings-text);\n font-size: 15px;\n font-weight: 500;\n line-height: 22px;\n}\n\n.settings-update-panel {\n display: grid;\n gap: 16px;\n min-height: 128px;\n padding: 20px;\n color: var(--settings-text);\n background: var(--settings-panel);\n border: 1px solid var(--settings-border);\n border-radius: 8px;\n}\n\n.settings-update-panel > strong,\n.settings-update-panel > span,\n.settings-update-summary,\n.settings-update-error {\n margin: 0;\n overflow-wrap: anywhere;\n font-size: 13px;\n line-height: 20px;\n}\n\n.settings-update-panel > span,\n.settings-update-summary {\n color: var(--settings-muted);\n}\n\n.settings-update-error {\n color: #ef4444;\n}\n\n.settings-update-progress {\n width: 100%;\n height: 8px;\n accent-color: #238be8;\n}\n\n.settings-update-progress-detail {\n color: var(--settings-muted);\n font-size: 12px;\n line-height: 18px;\n}\n\n.settings-update-notes {\n max-height: 240px;\n padding: 14px;\n overflow: auto;\n color: var(--settings-muted);\n font-size: 13px;\n line-height: 20px;\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n background: rgb(255 255 255 / 4%);\n border: 1px solid var(--settings-divider);\n border-radius: 6px;\n}\n\n.settings-update-version-row {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n align-items: center;\n gap: 20px;\n min-height: 32px;\n color: var(--settings-muted);\n font-size: 13px;\n}\n\n.settings-update-version-row strong {\n color: var(--settings-text);\n font-size: 15px;\n}\n\n.settings-update-actions {\n display: flex;\n min-width: 0;\n margin-top: 16px;\n}\n\n.settings-command-button,\n.settings-update-link {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: fit-content;\n min-height: 36px;\n gap: 8px;\n padding: 8px 12px;\n color: white;\n font: inherit;\n font-size: 13px;\n text-decoration: none;\n background: #1677d2;\n border: 1px solid #238be8;\n border-radius: 6px;\n cursor: pointer;\n}\n\n.settings-command-button--secondary,\n.settings-update-link {\n color: var(--settings-text);\n background: transparent;\n border-color: var(--settings-border);\n}\n\n.settings-command-button:hover,\n.settings-update-link:hover {\n filter: brightness(1.08);\n}\n\n.settings-command-button:focus-visible,\n.settings-update-link:focus-visible {\n outline: 2px solid var(--settings-focus);\n outline-offset: 2px;\n}\n\n.codexhost-settings-icon {\n display: block;\n flex: none;\n stroke: currentColor;\n}\n\n@media (max-width: 720px) {\n .codexhost-settings-dialog {\n width: calc(100vw - 16px);\n height: calc(100vh - 16px);\n border-radius: 10px;\n }\n\n .settings-layout {\n grid-template-columns: minmax(0, 1fr);\n grid-template-rows: auto minmax(0, 1fr);\n }\n\n .settings-sidebar {\n border-right: 0;\n border-bottom: 1px solid var(--settings-border);\n }\n\n .settings-header {\n height: 56px;\n padding-inline: 14px;\n }\n\n .settings-sidebar {\n padding-top: 20px;\n }\n\n .settings-nav {\n flex: none;\n flex-direction: row;\n gap: 4px;\n padding: 7px 8px 8px;\n overflow-x: auto;\n overflow-y: hidden;\n }\n\n .settings-nav-button {\n width: auto;\n min-width: max-content;\n min-height: 34px;\n grid-template-columns: 16px auto;\n border-radius: 10px;\n }\n\n .settings-page__content {\n width: calc(100% - 40px);\n }\n\n .settings-page__content {\n padding-top: 32px;\n padding-bottom: 32px;\n }\n\n .settings-section-label {\n padding-bottom: 20px;\n font-size: 20px;\n line-height: 26px;\n }\n\n .settings-status-row {\n grid-template-columns: minmax(0, 1fr) auto;\n gap: 16px;\n }\n\n .settings-status-row__detail {\n grid-column: 1 / -1;\n margin: -8px 0 0 58px;\n }\n}\n\n@media (forced-colors: active) {\n :host,\n :host([data-theme="dark"]) {\n --settings-bg: Canvas;\n --settings-sidebar: Canvas;\n --settings-panel: Canvas;\n --settings-text: CanvasText;\n --settings-muted: GrayText;\n --settings-border: ButtonBorder;\n --settings-divider: ButtonBorder;\n --settings-hover: Highlight;\n --settings-active: Highlight;\n --settings-focus: Highlight;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n *,\n *::before,\n *::after {\n scroll-behavior: auto !important;\n }\n}\n';
18926
+ var shell_default = ':host {\n --settings-bg: #181818;\n --settings-sidebar: #1c1c1c;\n --settings-panel: transparent;\n --settings-text: #f5f5f5;\n --settings-muted: #a1a1a1;\n --settings-border: rgb(255 255 255 / 10%);\n --settings-divider: rgb(255 255 255 / 10%);\n --settings-hover: rgb(255 255 255 / 6%);\n --settings-active: rgb(51 156 255 / 12%);\n --settings-focus: #339cff;\n color: var(--settings-text);\n color-scheme: dark;\n font:\n 14px/1.5 system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n letter-spacing: 0;\n}\n\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n letter-spacing: 0;\n}\n\nbutton,\ninput,\nselect {\n font: inherit;\n}\n\nbutton {\n color: inherit;\n}\n\n[hidden] {\n display: none !important;\n}\n\n.codexhost-settings-dialog {\n width: min(1120px, calc(100vw - 32px));\n height: min(780px, calc(100vh - 32px));\n max-width: none;\n max-height: none;\n margin: auto;\n padding: 0;\n overflow: hidden;\n color: var(--settings-text);\n background: var(--settings-bg);\n border: 1px solid var(--settings-border);\n border-radius: 12px;\n box-shadow: 0 24px 64px rgb(0 0 0 / 38%);\n}\n\n.codexhost-settings-dialog::backdrop {\n background: rgb(0 0 0 / 52%);\n}\n\n.settings-frame,\n.settings-layout {\n width: 100%;\n height: 100%;\n min-width: 0;\n min-height: 0;\n}\n\n.settings-frame {\n display: flex;\n flex-direction: column;\n}\n\n.settings-layout {\n flex: 1;\n display: grid;\n grid-template-columns: 240px minmax(0, 1fr);\n background: var(--settings-bg);\n}\n\n.settings-sidebar {\n display: flex;\n min-width: 0;\n min-height: 0;\n flex-direction: column;\n overflow: hidden;\n background: var(--settings-sidebar);\n border-right: 1px solid var(--settings-border);\n padding-top: 28px;\n}\n\n.settings-header {\n display: flex;\n align-items: center;\n min-width: 0;\n height: 64px;\n flex: none;\n padding: 0 16px;\n border-bottom: 1px solid var(--settings-border);\n}\n\n.settings-header-actions {\n display: flex;\n align-items: center;\n flex: none;\n gap: 12px;\n margin-left: auto;\n}\n\n.settings-icon-button.settings-star-link {\n width: auto;\n gap: 6px;\n padding-inline: 8px;\n font-size: 12px;\n line-height: 18px;\n text-decoration: none;\n border: 2px dashed #f5c542;\n white-space: nowrap;\n}\n\n.settings-star-link .codexhost-settings-icon {\n color: #f5c542;\n fill: currentColor;\n stroke: currentColor;\n}\n\n.settings-brand {\n display: flex;\n align-items: center;\n min-width: 0;\n gap: 8px;\n}\n\n.settings-brand__mark {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 36px;\n height: 36px;\n flex: none;\n color: var(--settings-text);\n}\n\n.settings-brand__mark .codexhost-settings-icon {\n width: 32px;\n height: 32px;\n object-fit: contain;\n}\n\n.settings-brand__copy {\n display: flex;\n min-width: 0;\n align-items: baseline;\n gap: 0;\n line-height: 20px;\n}\n\n.settings-brand__name {\n overflow: hidden;\n color: var(--settings-text);\n font-size: 14px;\n font-weight: 500;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.settings-brand__title {\n margin-left: 14px;\n padding-left: 14px;\n color: var(--settings-muted);\n font-size: 14px;\n font-weight: 400;\n border-left: 1px solid var(--settings-border);\n}\n\n.settings-nav {\n display: flex;\n min-width: 0;\n min-height: 0;\n flex: 1;\n flex-direction: column;\n gap: 4px;\n padding: 0 12px 16px;\n overflow-y: auto;\n}\n\n.settings-nav-button {\n display: grid;\n grid-template-columns: 16px minmax(0, 1fr);\n align-items: center;\n width: 100%;\n position: relative;\n min-height: 40px;\n flex: none;\n gap: 12px;\n padding: 8px 12px;\n color: var(--settings-text);\n font-size: 14px;\n line-height: 21px;\n text-align: left;\n background: transparent;\n border: 0;\n border-radius: 10px;\n cursor: pointer;\n}\n\n.settings-nav-button .codexhost-settings-icon {\n width: 18px;\n height: 18px;\n opacity: 0.9;\n}\n\n.settings-nav-button:hover {\n background: var(--settings-hover);\n}\n\n.settings-nav-button[aria-current="page"] {\n background: var(--settings-active);\n color: var(--settings-focus);\n}\n\n.settings-nav-button[aria-current="page"]::before {\n position: absolute;\n left: 0;\n width: 3px;\n height: 22px;\n content: "";\n background: var(--settings-focus);\n border-radius: 0 3px 3px 0;\n}\n\n.settings-nav-button span {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.settings-icon-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n flex: none;\n padding: 0;\n color: var(--settings-muted);\n background: transparent;\n border: 0;\n border-radius: 8px;\n cursor: pointer;\n}\n\n.settings-icon-button:hover {\n color: var(--settings-text);\n background: var(--settings-hover);\n}\n\n.settings-icon-button:focus-visible,\n.settings-nav-button:focus-visible {\n outline: 2px solid var(--settings-focus);\n outline-offset: 1px;\n}\n\n.settings-page {\n display: block;\n position: relative;\n min-width: 0;\n min-height: 0;\n overflow-y: auto;\n background: var(--settings-bg);\n scrollbar-gutter: stable;\n}\n\n.settings-page__content {\n width: min(930px, calc(100% - 80px));\n margin-inline: auto;\n}\n\n.settings-page__content {\n min-width: 0;\n padding: 44px 0 56px;\n}\n\n.settings-section-label {\n min-height: auto;\n padding: 0 0 28px;\n color: var(--settings-text);\n font-size: 24px;\n font-weight: 600;\n line-height: 30px;\n}\n\n.settings-status-list,\n.settings-empty {\n overflow: hidden;\n background: var(--settings-panel);\n}\n\n.settings-status-row {\n display: grid;\n grid-template-columns: minmax(170px, 1fr) auto minmax(280px, 1.45fr);\n position: relative;\n align-items: center;\n min-height: 88px;\n gap: 28px;\n padding: 16px 0;\n}\n\n.settings-status-row:not(:last-child)::after {\n content: "";\n position: absolute;\n right: 0;\n bottom: 0;\n left: 0;\n height: 1px;\n background: var(--settings-divider);\n}\n\n.settings-status-row__identity {\n display: inline-flex;\n align-items: center;\n min-width: 0;\n color: var(--settings-text);\n gap: 14px;\n font-size: 15px;\n font-weight: 500;\n line-height: 22px;\n}\n\n.settings-status-row__icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 44px;\n height: 44px;\n flex: none;\n color: var(--settings-muted);\n background: rgb(255 255 255 / 7%);\n border-radius: 50%;\n}\n\n.settings-status-badge {\n flex: none;\n padding: 5px 12px;\n color: var(--settings-muted);\n font-size: 13px;\n font-weight: 500;\n line-height: 18px;\n background: rgb(255 255 255 / 9%);\n border: 1px solid rgb(255 255 255 / 6%);\n border-radius: 6px;\n}\n\n.settings-status-row__detail {\n min-width: 0;\n color: var(--settings-muted);\n font-size: 13px;\n line-height: 20px;\n}\n\n.settings-empty {\n display: flex;\n align-items: center;\n min-height: 72px;\n padding: 12px 16px;\n}\n\n.settings-empty > div {\n display: grid;\n min-width: 0;\n gap: 2px;\n}\n\n.settings-empty strong {\n color: var(--settings-text);\n font-size: 13px;\n font-weight: 500;\n line-height: 19px;\n}\n\n.settings-empty span {\n color: var(--settings-muted);\n font-size: 13px;\n line-height: 19px;\n}\n\n.settings-page-error {\n padding: 16px;\n color: var(--settings-text);\n font-size: 13px;\n background: var(--settings-panel);\n border: 1px solid var(--settings-border);\n border-radius: 20px;\n}\n\n.settings-update-metadata {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: 24px;\n margin-bottom: 24px;\n padding: 0 4px 20px;\n border-bottom: 1px solid var(--settings-divider);\n}\n\n.settings-update-metadata__item {\n display: grid;\n min-width: 0;\n gap: 4px;\n}\n\n.settings-update-metadata__item span {\n color: var(--settings-muted);\n font-size: 12px;\n line-height: 18px;\n}\n\n.settings-update-metadata__item strong {\n min-width: 0;\n overflow-wrap: anywhere;\n color: var(--settings-text);\n font-size: 15px;\n font-weight: 500;\n line-height: 22px;\n}\n\n.settings-update-panel {\n display: grid;\n gap: 16px;\n min-height: 128px;\n padding: 20px;\n color: var(--settings-text);\n background: var(--settings-panel);\n border: 1px solid var(--settings-border);\n border-radius: 8px;\n}\n\n.settings-update-panel > strong,\n.settings-update-panel > span,\n.settings-update-summary,\n.settings-update-error {\n margin: 0;\n overflow-wrap: anywhere;\n font-size: 13px;\n line-height: 20px;\n}\n\n.settings-update-panel > span,\n.settings-update-summary {\n color: var(--settings-muted);\n}\n\n.settings-update-error {\n color: #ef4444;\n}\n\n.settings-update-progress {\n width: 100%;\n height: 8px;\n accent-color: #238be8;\n}\n\n.settings-update-progress-detail {\n color: var(--settings-muted);\n font-size: 12px;\n line-height: 18px;\n}\n\n.settings-update-notes {\n max-height: 240px;\n padding: 14px;\n overflow: auto;\n color: var(--settings-muted);\n font-size: 13px;\n line-height: 20px;\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n background: rgb(255 255 255 / 4%);\n border: 1px solid var(--settings-divider);\n border-radius: 6px;\n}\n\n.settings-update-version-row {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n align-items: center;\n gap: 20px;\n min-height: 32px;\n color: var(--settings-muted);\n font-size: 13px;\n}\n\n.settings-update-version-row strong {\n color: var(--settings-text);\n font-size: 15px;\n}\n\n.settings-update-manual {\n display: grid;\n min-width: 0;\n gap: 6px;\n margin-top: 14px;\n padding-inline: 4px;\n}\n\n.settings-update-manual[hidden] {\n display: none;\n}\n\n.settings-update-manual span {\n color: var(--settings-muted);\n font-size: 12px;\n line-height: 18px;\n}\n\n.settings-update-manual code {\n overflow-wrap: anywhere;\n color: var(--settings-text);\n font-family: ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", monospace;\n font-size: 12px;\n line-height: 18px;\n}\n\n.settings-update-actions {\n display: flex;\n min-width: 0;\n margin-top: 16px;\n}\n\n.settings-command-button,\n.settings-update-link {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: fit-content;\n min-height: 36px;\n gap: 8px;\n padding: 8px 12px;\n color: white;\n font: inherit;\n font-size: 13px;\n text-decoration: none;\n background: #1677d2;\n border: 1px solid #238be8;\n border-radius: 6px;\n cursor: pointer;\n}\n\n.settings-command-button--secondary,\n.settings-update-link {\n color: var(--settings-text);\n background: transparent;\n border-color: var(--settings-border);\n}\n\n.settings-command-button:hover,\n.settings-update-link:hover {\n filter: brightness(1.08);\n}\n\n.settings-command-button:focus-visible,\n.settings-update-link:focus-visible {\n outline: 2px solid var(--settings-focus);\n outline-offset: 2px;\n}\n\n.codexhost-settings-icon {\n display: block;\n flex: none;\n stroke: currentColor;\n}\n\n@media (max-width: 720px) {\n .codexhost-settings-dialog {\n width: calc(100vw - 16px);\n height: calc(100vh - 16px);\n border-radius: 10px;\n }\n\n .settings-layout {\n grid-template-columns: minmax(0, 1fr);\n grid-template-rows: auto minmax(0, 1fr);\n }\n\n .settings-sidebar {\n border-right: 0;\n border-bottom: 1px solid var(--settings-border);\n }\n\n .settings-header {\n height: 56px;\n padding-inline: 14px;\n }\n\n .settings-icon-button.settings-star-link {\n width: 28px;\n padding: 0;\n }\n\n .settings-star-link span {\n display: none;\n }\n\n .settings-sidebar {\n padding-top: 20px;\n }\n\n .settings-nav {\n flex: none;\n flex-direction: row;\n gap: 4px;\n padding: 7px 8px 8px;\n overflow-x: auto;\n overflow-y: hidden;\n }\n\n .settings-nav-button {\n width: auto;\n min-width: max-content;\n min-height: 34px;\n grid-template-columns: 16px auto;\n border-radius: 10px;\n }\n\n .settings-page__content {\n width: calc(100% - 40px);\n }\n\n .settings-page__content {\n padding-top: 32px;\n padding-bottom: 32px;\n }\n\n .settings-section-label {\n padding-bottom: 20px;\n font-size: 20px;\n line-height: 26px;\n }\n\n .settings-status-row {\n grid-template-columns: minmax(0, 1fr) auto;\n gap: 16px;\n }\n\n .settings-status-row__detail {\n grid-column: 1 / -1;\n margin: -8px 0 0 58px;\n }\n}\n\n@media (forced-colors: active) {\n :host,\n :host([data-theme="dark"]) {\n --settings-bg: Canvas;\n --settings-sidebar: Canvas;\n --settings-panel: Canvas;\n --settings-text: CanvasText;\n --settings-muted: GrayText;\n --settings-border: ButtonBorder;\n --settings-divider: ButtonBorder;\n --settings-hover: Highlight;\n --settings-active: Highlight;\n --settings-focus: Highlight;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n *,\n *::before,\n *::after {\n scroll-behavior: auto !important;\n }\n}\n';
18908
18927
 
18909
18928
  // src/settings/shell.ts
18910
18929
  var SETTINGS_SHELL_ATTRIBUTE = "data-codexhost-settings-shell";
18930
+ var CODEXHOST_GITHUB_REPOSITORY_URL = "https://github.com/BytePioneer-AI/codex-host";
18911
18931
  function isRendererSettingsDialogSupported(dialog) {
18912
18932
  return typeof dialog.showModal === "function" && typeof dialog.close === "function";
18913
18933
  }
@@ -18952,13 +18972,26 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18952
18972
  brandTitle.textContent = messages.title;
18953
18973
  brandCopy.append(brandName, brandTitle);
18954
18974
  brand.append(brandMark, brandCopy);
18975
+ const headerActions = ownerDocument.createElement("div");
18976
+ headerActions.className = "settings-header-actions";
18977
+ const starLink = ownerDocument.createElement("a");
18978
+ starLink.className = "settings-icon-button settings-star-link";
18979
+ starLink.href = CODEXHOST_GITHUB_REPOSITORY_URL;
18980
+ starLink.target = "_blank";
18981
+ starLink.rel = "noopener noreferrer";
18982
+ starLink.setAttribute("aria-label", messages.starOnGitHub);
18983
+ starLink.title = messages.starOnGitHub;
18984
+ const starLabel = ownerDocument.createElement("span");
18985
+ starLabel.textContent = messages.starOnGitHub;
18986
+ starLink.append(createRendererSettingsIcon("star", 16), starLabel);
18955
18987
  const closeButton = ownerDocument.createElement("button");
18956
18988
  closeButton.type = "button";
18957
18989
  closeButton.className = "settings-icon-button";
18958
18990
  closeButton.setAttribute("aria-label", messages.close);
18959
18991
  closeButton.title = messages.close;
18960
18992
  closeButton.append(createRendererSettingsIcon("close", 18));
18961
- header.append(brand, closeButton);
18993
+ headerActions.append(starLink, closeButton);
18994
+ header.append(brand, headerActions);
18962
18995
  const layout = ownerDocument.createElement("div");
18963
18996
  layout.className = "settings-layout";
18964
18997
  const sidebar = ownerDocument.createElement("aside");
@@ -20874,6 +20907,7 @@ lucide/dist/esm/icons/plug-zap.mjs:
20874
20907
  lucide/dist/esm/icons/refresh-cw.mjs:
20875
20908
  lucide/dist/esm/icons/route.mjs:
20876
20909
  lucide/dist/esm/icons/settings.mjs:
20910
+ lucide/dist/esm/icons/star.mjs:
20877
20911
  lucide/dist/esm/icons/x.mjs:
20878
20912
  (**
20879
20913
  * @license lucide v1.28.0 - ISC
package/bin/codexhost.exe CHANGED
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codexhost/cli-win32-arm64",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Run Pi and Claude Code as first-class external harnesses inside Codex Desktop.",
5
5
  "type": "module",
6
6
  "files": [