@codexhost/cli-darwin-arm64 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -7,7 +7,7 @@ Run Pi and Claude Code as first-class external harnesses inside Codex Desktop.
7
7
  ## Install
8
8
 
9
9
  ```bash
10
- npm install -g @codexhost/cli@0.1.1
10
+ npm install -g @codexhost/cli@0.1.2
11
11
  ```
12
12
 
13
13
  Do not install this package directly. npm selects it through the optional dependencies of `@codexhost/cli`.
@@ -18,6 +18,7 @@ This package is platform-specific (`os=darwin`, `cpu=arm64`).
18
18
 
19
19
  ```bash
20
20
  codexhost
21
+ codexhost --version
21
22
  codexhost inspect
22
23
  codexhost launch --agent pi
23
24
  codexhost launch --agent codex
@@ -1 +1 @@
1
- {"schemaVersion":1,"version":"0.1.1","distribution":"npm","target":"macos-arm64"}
1
+ {"schemaVersion":1,"version":"0.1.2","distribution":"npm","target":"macos-arm64"}
@@ -15006,6 +15006,7 @@ var updateSemanticVersionSchema = external_exports.string().regex(UPDATE_SEMVER_
15006
15006
  var updateInstallationSchema = external_exports.enum(["npm", "windows-installer", "macos-dmg"]);
15007
15007
  var updatePhaseSchema = external_exports.enum([
15008
15008
  "prepared",
15009
+ "downloading",
15009
15010
  "waiting-for-exit",
15010
15011
  "installing",
15011
15012
  "restarting",
@@ -15017,12 +15018,23 @@ var updateStatusSchema = external_exports.strictObject({
15017
15018
  installation: updateInstallationSchema,
15018
15019
  phase: updatePhaseSchema,
15019
15020
  updatedAt: external_exports.number().int().nonnegative(),
15021
+ downloadedBytes: external_exports.number().int().nonnegative().optional(),
15022
+ totalBytes: external_exports.number().int().positive().optional(),
15020
15023
  error: external_exports.string().min(1).max(UPDATE_ERROR_MAX_LENGTH).nullable()
15024
+ }).superRefine((status, context) => {
15025
+ if (status.downloadedBytes !== void 0 && status.totalBytes !== void 0 && status.downloadedBytes > status.totalBytes) {
15026
+ context.addIssue({
15027
+ code: "custom",
15028
+ path: ["downloadedBytes"],
15029
+ message: "downloadedBytes must not exceed totalBytes"
15030
+ });
15031
+ }
15021
15032
  });
15022
15033
  var updateEmptyParamsSchema = external_exports.strictObject({});
15023
15034
  var githubReleaseNotesUrlSchema = external_exports.string().max(300).regex(/^https:\/\/github\.com\/BytePioneer-AI\/codex-host\/releases\/tag\/v[0-9A-Za-z.+-]+$/u, "release notes URL must identify a codexhost GitHub Release");
15024
15035
  var updateCheckResultSchema = external_exports.strictObject({
15025
15036
  currentVersion: updateSemanticVersionSchema,
15037
+ installation: updateInstallationSchema.nullable(),
15026
15038
  latestVersion: updateSemanticVersionSchema.nullable(),
15027
15039
  updateAvailable: external_exports.boolean(),
15028
15040
  installationAvailable: external_exports.boolean(),
@@ -52364,11 +52376,28 @@ function parseUpdateStatus(value) {
52364
52376
  throw new Error("background update status must be an object");
52365
52377
  }
52366
52378
  const status = value;
52367
- const allowed2 = ["error", "installation", "phase", "schemaVersion", "updatedAt", "version"];
52379
+ const allowed2 = [
52380
+ "downloadedBytes",
52381
+ "error",
52382
+ "installation",
52383
+ "phase",
52384
+ "schemaVersion",
52385
+ "totalBytes",
52386
+ "updatedAt",
52387
+ "version"
52388
+ ];
52368
52389
  if (Object.keys(status).some((key) => !allowed2.includes(key))) {
52369
52390
  throw new Error("background update status contains unknown fields");
52370
52391
  }
52371
- if (status.schemaVersion !== STATUS_SCHEMA_VERSION || typeof status.version !== "string" || !SEMVER_PATTERN.test(status.version) || !["npm", "windows-installer", "macos-dmg"].includes(String(status.installation)) || !["prepared", "waiting-for-exit", "installing", "restarting", "succeeded", "failed"].includes(String(status.phase)) || !Number.isSafeInteger(status.updatedAt) || status.error !== void 0 && typeof status.error !== "string") {
52392
+ if (status.schemaVersion !== STATUS_SCHEMA_VERSION || typeof status.version !== "string" || !SEMVER_PATTERN.test(status.version) || !["npm", "windows-installer", "macos-dmg"].includes(String(status.installation)) || ![
52393
+ "prepared",
52394
+ "downloading",
52395
+ "waiting-for-exit",
52396
+ "installing",
52397
+ "restarting",
52398
+ "succeeded",
52399
+ "failed"
52400
+ ].includes(String(status.phase)) || !Number.isSafeInteger(status.updatedAt) || status.downloadedBytes !== void 0 && (typeof status.downloadedBytes !== "number" || !Number.isSafeInteger(status.downloadedBytes) || status.downloadedBytes < 0) || status.totalBytes !== void 0 && (typeof status.totalBytes !== "number" || !Number.isSafeInteger(status.totalBytes) || status.totalBytes <= 0) || typeof status.downloadedBytes === "number" && typeof status.totalBytes === "number" && status.downloadedBytes > status.totalBytes || status.error !== void 0 && typeof status.error !== "string") {
52372
52401
  throw new Error("background update status is invalid");
52373
52402
  }
52374
52403
  return status;
@@ -52665,6 +52694,11 @@ async function regularFile(filePath) {
52665
52694
  throw error52;
52666
52695
  }
52667
52696
  }
52697
+ async function isUpdateOperationActive(stateDirectory) {
52698
+ if (!path9.isAbsolute(stateDirectory))
52699
+ throw new Error("update state directory must be absolute");
52700
+ return regularFile(path9.join(stateDirectory, LOCK_FILE));
52701
+ }
52668
52702
  async function discoverLatestUpdateStatus(stateDirectory) {
52669
52703
  if (!path9.isAbsolute(stateDirectory))
52670
52704
  throw new Error("update state directory must be absolute");
@@ -52810,7 +52844,7 @@ async function writeChunk(file2, chunk) {
52810
52844
  offset += result.bytesWritten;
52811
52845
  }
52812
52846
  }
52813
- async function downloadArtifact(source, destination) {
52847
+ async function downloadArtifact(source, destination, onProgress) {
52814
52848
  const response = await fetch(source.url, {
52815
52849
  redirect: "follow",
52816
52850
  headers: { "accept-encoding": "identity" }
@@ -52836,6 +52870,7 @@ async function downloadArtifact(source, destination) {
52836
52870
  throw new Error(`update artifact exceeds ${MAX_ARTIFACT_BYTES} bytes`);
52837
52871
  }
52838
52872
  await writeChunk(file2, item.value);
52873
+ await onProgress?.({ downloadedBytes: bytes, totalBytes: source.size });
52839
52874
  }
52840
52875
  await file2.sync();
52841
52876
  } finally {
@@ -52920,6 +52955,59 @@ function createBackgroundUpdateManager(dependencies = {}) {
52920
52955
  const spawnUpdater = dependencies.spawnUpdater ?? defaultSpawnUpdater;
52921
52956
  const now = dependencies.now ?? Date.now;
52922
52957
  const preparedRequests = /* @__PURE__ */ new Set();
52958
+ async function writeStatusSnapshot(statusPath, status) {
52959
+ const temporaryPath = path10.join(path10.dirname(statusPath), `.update-status-${randomId()}.tmp`);
52960
+ try {
52961
+ await writeFile2(temporaryPath, `${JSON.stringify(status)}
52962
+ `, {
52963
+ encoding: "utf8",
52964
+ mode: 384,
52965
+ flag: "wx"
52966
+ });
52967
+ await rename2(temporaryPath, statusPath);
52968
+ } catch (error52) {
52969
+ await rm4(temporaryPath, { force: true });
52970
+ throw error52;
52971
+ }
52972
+ }
52973
+ function statusSnapshot(version2, installation, phase, progress, error52) {
52974
+ return {
52975
+ schemaVersion: 1,
52976
+ version: version2,
52977
+ installation,
52978
+ phase,
52979
+ updatedAt: Math.floor(now() / 1e3),
52980
+ ...progress?.downloadedBytes === void 0 ? {} : { downloadedBytes: progress.downloadedBytes },
52981
+ ...progress?.totalBytes === void 0 ? {} : { totalBytes: progress.totalBytes },
52982
+ ...error52 === void 0 ? {} : { error: errorMessage4(error52).slice(0, 500) }
52983
+ };
52984
+ }
52985
+ async function writeFailedStatus(statusPath, version2, installation, error52) {
52986
+ await writeStatusSnapshot(statusPath, statusSnapshot(version2, installation, "failed", void 0, error52)).catch(() => void 0);
52987
+ }
52988
+ function progressReporter(statusPath, version2, installation, totalBytes) {
52989
+ let lastProgress = { downloadedBytes: 0, totalBytes };
52990
+ let lastWriteAt = 0;
52991
+ let queued = Promise.resolve();
52992
+ const enqueue = (progress, force = false) => {
52993
+ lastProgress = progress;
52994
+ const currentTime = Date.now();
52995
+ if (!force && currentTime - lastWriteAt < 250)
52996
+ return;
52997
+ lastWriteAt = currentTime;
52998
+ queued = queued.then(() => writeStatusSnapshot(statusPath, statusSnapshot(version2, installation, "downloading", lastProgress))).catch(() => void 0);
52999
+ };
53000
+ enqueue(lastProgress, true);
53001
+ return {
53002
+ update(progress) {
53003
+ enqueue(progress);
53004
+ },
53005
+ async flush() {
53006
+ enqueue(lastProgress, true);
53007
+ await queued;
53008
+ }
53009
+ };
53010
+ }
52923
53011
  async function prepareCommon(options, installation) {
52924
53012
  const version2 = requireSemanticVersion(options.version);
52925
53013
  const launcherPid = requireLauncherPid(options.launcherPid);
@@ -52937,6 +53025,7 @@ function createBackgroundUpdateManager(dependencies = {}) {
52937
53025
  const requestPath = path10.join(workDirectory, "request-v1.json");
52938
53026
  const statusPath = path10.join(workDirectory, "status-v1.json");
52939
53027
  await writePrivateJson(statusPath, preparedStatus(version2, installation, now()));
53028
+ await options.onPrepared?.({ version: version2, installation, statusPath });
52940
53029
  return {
52941
53030
  version: version2,
52942
53031
  launcherPid,
@@ -52947,12 +53036,15 @@ function createBackgroundUpdateManager(dependencies = {}) {
52947
53036
  statusPath
52948
53037
  };
52949
53038
  }
52950
- async function prepareArtifact(sourceValue, workDirectory, fileName) {
53039
+ async function prepareArtifact(common, installation, sourceValue, fileName) {
52951
53040
  const source = validateArtifact(sourceValue);
52952
- const temporaryPath = path10.join(workDirectory, `.${fileName}.download`);
52953
- const artifactPath = path10.join(workDirectory, fileName);
53041
+ const temporaryPath = path10.join(common.workDirectory, `.${fileName}.download`);
53042
+ const artifactPath = path10.join(common.workDirectory, fileName);
53043
+ const progress = progressReporter(common.statusPath, common.version, installation, source.size);
52954
53044
  try {
52955
- const result = await download(source, temporaryPath);
53045
+ const result = await download(source, temporaryPath, progress.update);
53046
+ progress.update({ downloadedBytes: result.bytes, totalBytes: source.size });
53047
+ await progress.flush();
52956
53048
  const finalUrl = new URL(result.finalUrl);
52957
53049
  if (finalUrl.protocol !== "https:" || finalUrl.username || finalUrl.password) {
52958
53050
  throw new Error("update artifact downloader returned a non-HTTPS URL");
@@ -52962,6 +53054,8 @@ function createBackgroundUpdateManager(dependencies = {}) {
52962
53054
  return { source, artifactPath };
52963
53055
  } catch (error52) {
52964
53056
  await rm4(temporaryPath, { force: true });
53057
+ await progress.flush();
53058
+ await writeFailedStatus(common.statusPath, common.version, installation, error52);
52965
53059
  throw error52;
52966
53060
  }
52967
53061
  }
@@ -52975,6 +53069,7 @@ function createBackgroundUpdateManager(dependencies = {}) {
52975
53069
  installation
52976
53070
  };
52977
53071
  await writePrivateJson(common.requestPath, request);
53072
+ await writeStatusSnapshot(common.statusPath, statusSnapshot(common.version, installation.kind, "prepared"));
52978
53073
  preparedRequests.add(common.requestPath);
52979
53074
  return Object.freeze({
52980
53075
  version: common.version,
@@ -52988,19 +53083,24 @@ function createBackgroundUpdateManager(dependencies = {}) {
52988
53083
  return Object.freeze({
52989
53084
  async prepareNpm(options) {
52990
53085
  const common = await prepareCommon(options, "npm");
52991
- return finalize2(common, {
52992
- kind: "npm",
52993
- node_path: await requireRegularFile(options.nodePath, "npm Node.js executable"),
52994
- npm_cli_path: await requireRegularFile(options.npmCliPath, "npm CLI"),
52995
- npm_launcher_path: await requireRegularFile(options.npmLauncherPath, "npm codexhost launcher"),
52996
- package_root: requireAbsolutePath(options.packageRoot, "npm platform package root")
52997
- });
53086
+ try {
53087
+ return await finalize2(common, {
53088
+ kind: "npm",
53089
+ node_path: await requireRegularFile(options.nodePath, "npm Node.js executable"),
53090
+ npm_cli_path: await requireRegularFile(options.npmCliPath, "npm CLI"),
53091
+ npm_launcher_path: await requireRegularFile(options.npmLauncherPath, "npm codexhost launcher"),
53092
+ package_root: requireAbsolutePath(options.packageRoot, "npm platform package root")
53093
+ });
53094
+ } catch (error52) {
53095
+ await writeFailedStatus(common.statusPath, common.version, "npm", error52);
53096
+ throw error52;
53097
+ }
52998
53098
  },
52999
53099
  async prepareWindowsInstaller(options) {
53000
53100
  if (platform !== "win32")
53001
53101
  throw new Error("Windows installer updates require Windows");
53002
53102
  const common = await prepareCommon(options, "windows-installer");
53003
- const artifact = await prepareArtifact(options.artifact, common.workDirectory, "update.exe");
53103
+ const artifact = await prepareArtifact(common, "windows-installer", options.artifact, "update.exe");
53004
53104
  return finalize2(common, {
53005
53105
  kind: "windows-installer",
53006
53106
  installer_path: artifact.artifactPath,
@@ -53016,7 +53116,7 @@ function createBackgroundUpdateManager(dependencies = {}) {
53016
53116
  if (path10.extname(appPath) !== ".app") {
53017
53117
  throw new Error("macOS application path must end in .app");
53018
53118
  }
53019
- const artifact = await prepareArtifact(options.artifact, common.workDirectory, "update.dmg");
53119
+ const artifact = await prepareArtifact(common, "macos-dmg", options.artifact, "update.dmg");
53020
53120
  return finalize2(common, {
53021
53121
  kind: "macos-dmg",
53022
53122
  dmg_path: artifact.artifactPath,
@@ -53073,6 +53173,8 @@ function publicStatus(status) {
53073
53173
  installation: status.installation,
53074
53174
  phase: status.phase,
53075
53175
  updatedAt: status.updatedAt,
53176
+ ...status.downloadedBytes === void 0 ? {} : { downloadedBytes: status.downloadedBytes },
53177
+ ...status.totalBytes === void 0 ? {} : { totalBytes: status.totalBytes },
53076
53178
  error: status.error?.slice(0, ERROR_MAX_LENGTH) ?? null
53077
53179
  };
53078
53180
  }
@@ -53116,9 +53218,20 @@ function createHostUpdateCoordinator(options) {
53116
53218
  const shutdown = options.shutdown ?? requestControllerShutdown;
53117
53219
  let candidate = null;
53118
53220
  let shutdownPending = null;
53221
+ let shutdownRequested = false;
53222
+ const scheduleShutdown = () => {
53223
+ if (!shutdownRequested || !shutdownPending) return;
53224
+ const controller = shutdownPending;
53225
+ shutdownPending = null;
53226
+ setTimeout(() => void shutdown(controller).catch(() => void 0), 50).unref();
53227
+ };
53119
53228
  async function latestStatus(context) {
53120
53229
  const discovered = await discoverLatestUpdateStatus(context.common.stateDirectory);
53121
- return discovered ? publicStatus(discovered.status) : null;
53230
+ if (!discovered) return null;
53231
+ if (discovered.status.phase !== "succeeded" && discovered.status.phase !== "failed" && !await isUpdateOperationActive(context.common.stateDirectory)) {
53232
+ return null;
53233
+ }
53234
+ return publicStatus(discovered.status);
53122
53235
  }
53123
53236
  async function installable(context, release) {
53124
53237
  if (context.metadata.distribution === "npm") return true;
@@ -53139,6 +53252,7 @@ function createHostUpdateCoordinator(options) {
53139
53252
  } catch (error52) {
53140
53253
  return {
53141
53254
  currentVersion: "0.0.0",
53255
+ installation: null,
53142
53256
  latestVersion: null,
53143
53257
  updateAvailable: false,
53144
53258
  installationAvailable: false,
@@ -53163,6 +53277,7 @@ function createHostUpdateCoordinator(options) {
53163
53277
  }
53164
53278
  return {
53165
53279
  currentVersion: context.metadata.version,
53280
+ installation: context.installation.kind,
53166
53281
  latestVersion: release.version,
53167
53282
  updateAvailable,
53168
53283
  installationAvailable,
@@ -53174,6 +53289,7 @@ function createHostUpdateCoordinator(options) {
53174
53289
  } catch (error52) {
53175
53290
  return {
53176
53291
  currentVersion: context.metadata.version,
53292
+ installation: context.installation.kind,
53177
53293
  latestVersion: null,
53178
53294
  updateAvailable: false,
53179
53295
  installationAvailable: false,
@@ -53193,34 +53309,59 @@ function createHostUpdateCoordinator(options) {
53193
53309
  if (existing) return { status: existing };
53194
53310
  throw new Error("Another update operation is already active");
53195
53311
  }
53312
+ let resolvePrepared;
53313
+ let rejectPrepared;
53314
+ const preparedReady = new Promise((resolve2, reject) => {
53315
+ resolvePrepared = resolve2;
53316
+ rejectPrepared = reject;
53317
+ });
53196
53318
  try {
53197
53319
  const release = await fetchLatest();
53198
53320
  if (compareSemanticVersions(context.metadata.version, release.version) >= 0 || candidate && candidate.version !== release.version) {
53199
53321
  throw new Error("The selected update is no longer the current GitHub Release");
53200
53322
  }
53201
- let prepared;
53202
- if (context.installation.kind === "npm") {
53203
- prepared = await manager.prepareNpm({
53204
- ...context.installation.options,
53205
- version: release.version
53206
- });
53207
- } else {
53208
- const artifact = selectInstallerReleaseArtifact(release, context.metadata.target).source;
53209
- prepared = context.installation.kind === "windows-installer" ? await manager.prepareWindowsInstaller({
53210
- ...context.installation.options,
53211
- version: release.version,
53212
- artifact
53213
- }) : await manager.prepareMacOsDmg({
53214
- ...context.installation.options,
53215
- version: release.version,
53216
- artifact
53217
- });
53218
- }
53219
- await lock.setStatusPath(prepared.statusPath);
53220
- manager.start(prepared);
53323
+ const onPrepared = async (info) => {
53324
+ await lock.setStatusPath(info.statusPath);
53325
+ resolvePrepared(info);
53326
+ };
53327
+ const prepareAndStart = async () => {
53328
+ try {
53329
+ let prepared2;
53330
+ if (context.installation.kind === "npm") {
53331
+ prepared2 = await manager.prepareNpm({
53332
+ ...context.installation.options,
53333
+ version: release.version,
53334
+ onPrepared
53335
+ });
53336
+ } else {
53337
+ const artifact = selectInstallerReleaseArtifact(
53338
+ release,
53339
+ context.metadata.target
53340
+ ).source;
53341
+ prepared2 = context.installation.kind === "windows-installer" ? await manager.prepareWindowsInstaller({
53342
+ ...context.installation.options,
53343
+ version: release.version,
53344
+ artifact,
53345
+ onPrepared
53346
+ }) : await manager.prepareMacOsDmg({
53347
+ ...context.installation.options,
53348
+ version: release.version,
53349
+ artifact,
53350
+ onPrepared
53351
+ });
53352
+ }
53353
+ manager.start(prepared2);
53354
+ shutdownPending = context.controller;
53355
+ scheduleShutdown();
53356
+ } catch (error52) {
53357
+ await lock.release();
53358
+ rejectPrepared(error52);
53359
+ }
53360
+ };
53361
+ void prepareAndStart();
53362
+ const prepared = await preparedReady;
53221
53363
  const status = await manager.readStatus(prepared.statusPath);
53222
- if (!status) throw new Error("Background Updater did not create status");
53223
- shutdownPending = context.controller;
53364
+ if (!status) throw new Error("Background update did not create status");
53224
53365
  return { status: publicStatus(status) };
53225
53366
  } catch (error52) {
53226
53367
  await lock.release();
@@ -53237,10 +53378,8 @@ function createHostUpdateCoordinator(options) {
53237
53378
  }
53238
53379
  },
53239
53380
  requestShutdown() {
53240
- const controller = shutdownPending;
53241
- shutdownPending = null;
53242
- if (!controller) return;
53243
- setTimeout(() => void shutdown(controller).catch(() => void 0), 50).unref();
53381
+ shutdownRequested = true;
53382
+ scheduleShutdown();
53244
53383
  }
53245
53384
  });
53246
53385
  }
@@ -15242,6 +15242,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15242
15242
  var updateInstallationSchema = external_exports.enum(["npm", "windows-installer", "macos-dmg"]);
15243
15243
  var updatePhaseSchema = external_exports.enum([
15244
15244
  "prepared",
15245
+ "downloading",
15245
15246
  "waiting-for-exit",
15246
15247
  "installing",
15247
15248
  "restarting",
@@ -15253,12 +15254,23 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15253
15254
  installation: updateInstallationSchema,
15254
15255
  phase: updatePhaseSchema,
15255
15256
  updatedAt: external_exports.number().int().nonnegative(),
15257
+ downloadedBytes: external_exports.number().int().nonnegative().optional(),
15258
+ totalBytes: external_exports.number().int().positive().optional(),
15256
15259
  error: external_exports.string().min(1).max(UPDATE_ERROR_MAX_LENGTH).nullable()
15260
+ }).superRefine((status, context) => {
15261
+ if (status.downloadedBytes !== void 0 && status.totalBytes !== void 0 && status.downloadedBytes > status.totalBytes) {
15262
+ context.addIssue({
15263
+ code: "custom",
15264
+ path: ["downloadedBytes"],
15265
+ message: "downloadedBytes must not exceed totalBytes"
15266
+ });
15267
+ }
15257
15268
  });
15258
15269
  var updateEmptyParamsSchema = external_exports.strictObject({});
15259
15270
  var githubReleaseNotesUrlSchema = external_exports.string().max(300).regex(/^https:\/\/github\.com\/BytePioneer-AI\/codex-host\/releases\/tag\/v[0-9A-Za-z.+-]+$/u, "release notes URL must identify a codexhost GitHub Release");
15260
15271
  var updateCheckResultSchema = external_exports.strictObject({
15261
15272
  currentVersion: updateSemanticVersionSchema,
15273
+ installation: updateInstallationSchema.nullable(),
15262
15274
  latestVersion: updateSemanticVersionSchema.nullable(),
15263
15275
  updateAvailable: external_exports.boolean(),
15264
15276
  installationAvailable: external_exports.boolean(),
@@ -18101,11 +18113,19 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18101
18113
  settingsButtonTitle: "codexhost settings",
18102
18114
  settingsUnavailableTitle: "codexhost settings unavailable",
18103
18115
  updateCurrentVersion: "Current version",
18116
+ updateInstallation: "Installation method",
18117
+ updateInstallationNpm: "npm",
18118
+ updateInstallationWindowsInstaller: "Windows installer",
18119
+ updateInstallationMacOsDmg: "macOS DMG",
18120
+ updateInstallationUnknown: "Unknown",
18104
18121
  updateLatestVersion: "Latest version",
18105
18122
  updateUpToDate: "You are up to date.",
18106
18123
  updateAvailable: "A new version is available.",
18107
18124
  updateAndRestart: "Update and restart",
18125
+ updateChecking: "Checking for updates...",
18126
+ updateDownloading: "Downloading update...",
18108
18127
  updatePreparing: "Preparing update...",
18128
+ updateRequestTimeout: "The update service did not respond. Try again.",
18109
18129
  updateRestarting: "Restarting to finish the update...",
18110
18130
  updateSucceeded: "Update installed successfully.",
18111
18131
  updateFailed: "Update failed.",
@@ -18138,11 +18158,19 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18138
18158
  settingsButtonTitle: "codexhost \u8BBE\u7F6E",
18139
18159
  settingsUnavailableTitle: "codexhost \u8BBE\u7F6E\u4E0D\u53EF\u7528",
18140
18160
  updateCurrentVersion: "\u5F53\u524D\u7248\u672C",
18161
+ updateInstallation: "\u5B89\u88C5\u65B9\u5F0F",
18162
+ updateInstallationNpm: "npm",
18163
+ updateInstallationWindowsInstaller: "Windows \u5B89\u88C5\u7A0B\u5E8F",
18164
+ updateInstallationMacOsDmg: "macOS DMG",
18165
+ updateInstallationUnknown: "\u672A\u77E5",
18141
18166
  updateLatestVersion: "\u6700\u65B0\u7248\u672C",
18142
18167
  updateUpToDate: "\u5F53\u524D\u5DF2\u662F\u6700\u65B0\u7248\u672C\u3002",
18143
18168
  updateAvailable: "\u6709\u65B0\u7248\u672C\u53EF\u7528\u3002",
18144
18169
  updateAndRestart: "\u66F4\u65B0\u5E76\u91CD\u542F",
18170
+ updateChecking: "\u6B63\u5728\u68C0\u67E5\u66F4\u65B0...",
18171
+ updateDownloading: "\u6B63\u5728\u4E0B\u8F7D\u66F4\u65B0...",
18145
18172
  updatePreparing: "\u6B63\u5728\u51C6\u5907\u66F4\u65B0...",
18173
+ updateRequestTimeout: "\u66F4\u65B0\u670D\u52A1\u672A\u54CD\u5E94\uFF0C\u8BF7\u91CD\u8BD5\u3002",
18146
18174
  updateRestarting: "\u6B63\u5728\u91CD\u542F\u4EE5\u5B8C\u6210\u66F4\u65B0...",
18147
18175
  updateSucceeded: "\u66F4\u65B0\u5B89\u88C5\u6210\u529F\u3002",
18148
18176
  updateFailed: "\u66F4\u65B0\u5931\u8D25\u3002",
@@ -18449,6 +18477,49 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18449
18477
  }
18450
18478
  };
18451
18479
 
18480
+ // src/settings/update-request.ts
18481
+ var RENDERER_UPDATE_REQUEST_TIMEOUT_MS = 15e3;
18482
+ var RendererUpdateRequestTimeoutError = class extends Error {
18483
+ constructor() {
18484
+ super("Update request timed out");
18485
+ this.name = "RendererUpdateRequestTimeoutError";
18486
+ }
18487
+ };
18488
+ function runBoundedRendererUpdateRequest(operation, signal, timeoutMs = RENDERER_UPDATE_REQUEST_TIMEOUT_MS) {
18489
+ return new Promise((resolve, reject) => {
18490
+ let settled = false;
18491
+ const settle = (handler) => {
18492
+ if (settled) return;
18493
+ settled = true;
18494
+ clearTimeout(timeout);
18495
+ signal.removeEventListener("abort", abort);
18496
+ handler();
18497
+ };
18498
+ const timeout = setTimeout(() => {
18499
+ settle(() => reject(new RendererUpdateRequestTimeoutError()));
18500
+ }, timeoutMs);
18501
+ const abort = () => {
18502
+ settle(() => reject(new Error("Update request was aborted")));
18503
+ };
18504
+ const rejectRequest = (error51) => {
18505
+ settle(() => reject(error51));
18506
+ };
18507
+ if (signal.aborted) {
18508
+ abort();
18509
+ return;
18510
+ }
18511
+ signal.addEventListener("abort", abort, { once: true });
18512
+ try {
18513
+ void operation().then(
18514
+ (value) => settle(() => resolve(value)),
18515
+ (error51) => rejectRequest(error51)
18516
+ );
18517
+ } catch (error51) {
18518
+ rejectRequest(error51);
18519
+ }
18520
+ });
18521
+ }
18522
+
18452
18523
  // src/settings/pages.ts
18453
18524
  var DEFAULT_RENDERER_SETTINGS_PAGE_IDS = [
18454
18525
  "connections",
@@ -18493,6 +18564,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18493
18564
  row.append(name, value);
18494
18565
  return row;
18495
18566
  }
18567
+ function installationLabel(installation, messages) {
18568
+ if (installation === "npm") return messages.updateInstallationNpm;
18569
+ if (installation === "windows-installer") {
18570
+ return messages.updateInstallationWindowsInstaller;
18571
+ }
18572
+ if (installation === "macos-dmg") return messages.updateInstallationMacOsDmg;
18573
+ return messages.updateInstallationUnknown;
18574
+ }
18496
18575
  function isPendingStatus(status) {
18497
18576
  return status !== null && status.phase !== "succeeded" && status.phase !== "failed";
18498
18577
  }
@@ -18501,8 +18580,21 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18501
18580
  if (status.phase === "succeeded") return messages.updateSucceeded;
18502
18581
  if (status.phase === "failed") return status.error ?? messages.updateFailed;
18503
18582
  if (status.phase === "restarting") return messages.updateRestarting;
18583
+ if (status.phase === "downloading") return messages.updateDownloading;
18504
18584
  return messages.updatePreparing;
18505
18585
  }
18586
+ function formatUpdateBytes(value) {
18587
+ if (value < 1024) return `${value} B`;
18588
+ const units = ["KB", "MB", "GB"];
18589
+ let scaled = value;
18590
+ let unit = "B";
18591
+ for (const nextUnit of units) {
18592
+ scaled /= 1024;
18593
+ unit = nextUnit;
18594
+ if (scaled < 1024 || nextUnit === units.at(-1)) break;
18595
+ }
18596
+ return `${scaled.toFixed(scaled >= 10 ? 0 : 1)} ${unit}`;
18597
+ }
18506
18598
  function updatesPage(messages, getClient) {
18507
18599
  return Object.freeze({
18508
18600
  id: "updates",
@@ -18513,10 +18605,27 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18513
18605
  const heading = document2.createElement("div");
18514
18606
  heading.className = "settings-section-label";
18515
18607
  heading.textContent = messages.pageLabels.updates;
18608
+ const metadata = document2.createElement("div");
18609
+ metadata.className = "settings-update-metadata";
18610
+ const currentVersion = document2.createElement("div");
18611
+ currentVersion.className = "settings-update-metadata__item";
18612
+ const currentVersionLabel = document2.createElement("span");
18613
+ currentVersionLabel.textContent = messages.updateCurrentVersion;
18614
+ const currentVersionValue = document2.createElement("strong");
18615
+ currentVersionValue.textContent = "-";
18616
+ currentVersion.append(currentVersionLabel, currentVersionValue);
18617
+ const installation = document2.createElement("div");
18618
+ installation.className = "settings-update-metadata__item";
18619
+ const installationName = document2.createElement("span");
18620
+ installationName.textContent = messages.updateInstallation;
18621
+ const installationValue = document2.createElement("strong");
18622
+ installationValue.textContent = "-";
18623
+ installation.append(installationName, installationValue);
18624
+ metadata.append(currentVersion, installation);
18516
18625
  const panel = document2.createElement("section");
18517
18626
  panel.className = "settings-update-panel";
18518
18627
  panel.setAttribute("aria-live", "polite");
18519
- context.content.append(heading, panel);
18628
+ context.content.append(heading, metadata, panel);
18520
18629
  let pollTimer;
18521
18630
  let pollAttempts = 0;
18522
18631
  let pending = false;
@@ -18535,22 +18644,35 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18535
18644
  copy.textContent = detail;
18536
18645
  panel.append(title, copy);
18537
18646
  };
18647
+ const renderRequestFailure = (error51) => {
18648
+ renderPendingStatus(
18649
+ null,
18650
+ error51 instanceof RendererUpdateRequestTimeoutError ? messages.updateRequestTimeout : error51 instanceof Error ? error51.message : messages.updateFailed,
18651
+ "failed"
18652
+ );
18653
+ };
18538
18654
  const scheduleStatusPoll = (client, resetAttempts = false) => {
18539
18655
  clearPoll();
18540
18656
  if (resetAttempts) pollAttempts = 0;
18541
- if (pollAttempts >= 320) return;
18657
+ if (pollAttempts >= 320) {
18658
+ renderPendingStatus(null, messages.updateRequestTimeout, "failed");
18659
+ return;
18660
+ }
18542
18661
  pollAttempts += 1;
18543
18662
  pollTimer = document2.defaultView?.setTimeout(() => {
18544
- void context.runLatest(() => client.readUpdateStatus(), {
18545
- success(result) {
18546
- const message = statusMessage(result.status, messages);
18547
- if (isPendingStatus(result.status)) scheduleStatusPoll(client);
18548
- if (message) renderPendingStatus(result.status, message);
18549
- },
18550
- failure(error51) {
18551
- renderUnavailable(error51 instanceof Error ? error51.message : messages.updateFailed);
18663
+ void context.runLatest(
18664
+ (signal) => runBoundedRendererUpdateRequest(() => client.readUpdateStatus(), signal),
18665
+ {
18666
+ success(result) {
18667
+ const message = statusMessage(result.status, messages);
18668
+ if (isPendingStatus(result.status)) scheduleStatusPoll(client);
18669
+ if (message) renderPendingStatus(result.status, message);
18670
+ },
18671
+ failure(error51) {
18672
+ renderRequestFailure(error51);
18673
+ }
18552
18674
  }
18553
- });
18675
+ );
18554
18676
  }, 750);
18555
18677
  };
18556
18678
  const renderPendingStatus = (status, message, viewPhase = status?.phase ?? "pending") => {
@@ -18559,6 +18681,21 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18559
18681
  const state = document2.createElement("strong");
18560
18682
  state.textContent = message;
18561
18683
  panel.append(state);
18684
+ if (status?.phase === "downloading" && status.totalBytes !== void 0 && status.downloadedBytes !== void 0) {
18685
+ const progress = document2.createElement("progress");
18686
+ progress.className = "settings-update-progress";
18687
+ progress.max = status.totalBytes;
18688
+ progress.value = Math.min(status.downloadedBytes, status.totalBytes);
18689
+ progress.setAttribute("aria-label", messages.updateDownloading);
18690
+ const detail = document2.createElement("span");
18691
+ detail.className = "settings-update-progress-detail";
18692
+ const percent = Math.min(
18693
+ 100,
18694
+ Math.round(status.downloadedBytes / status.totalBytes * 1e3) / 10
18695
+ );
18696
+ detail.textContent = `${percent}% \xB7 ${formatUpdateBytes(status.downloadedBytes)} / ${formatUpdateBytes(status.totalBytes)}`;
18697
+ panel.append(progress, detail);
18698
+ }
18562
18699
  if (viewPhase === "failed") {
18563
18700
  const retry = document2.createElement("button");
18564
18701
  retry.type = "button";
@@ -18572,26 +18709,27 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18572
18709
  if (pending) return;
18573
18710
  pending = true;
18574
18711
  renderPendingStatus(null, messages.updatePreparing);
18575
- void context.runLatest(() => client.startUpdate(), {
18576
- success(result) {
18577
- pending = false;
18578
- renderPendingStatus(
18579
- result.status,
18580
- statusMessage(result.status, messages) ?? messages.updatePreparing
18581
- );
18582
- if (isPendingStatus(result.status)) scheduleStatusPoll(client, true);
18583
- },
18584
- failure(error51) {
18585
- pending = false;
18586
- renderPendingStatus(
18587
- null,
18588
- error51 instanceof Error ? error51.message : messages.updateFailed,
18589
- "failed"
18590
- );
18712
+ void context.runLatest(
18713
+ (signal) => runBoundedRendererUpdateRequest(() => client.startUpdate(), signal),
18714
+ {
18715
+ success(result) {
18716
+ pending = false;
18717
+ renderPendingStatus(
18718
+ result.status,
18719
+ statusMessage(result.status, messages) ?? messages.updatePreparing
18720
+ );
18721
+ if (isPendingStatus(result.status)) scheduleStatusPoll(client, true);
18722
+ },
18723
+ failure(error51) {
18724
+ pending = false;
18725
+ renderRequestFailure(error51);
18726
+ }
18591
18727
  }
18592
- });
18728
+ );
18593
18729
  };
18594
18730
  const renderCheck = (result, client) => {
18731
+ currentVersionValue.textContent = `v${result.currentVersion}`;
18732
+ installationValue.textContent = installationLabel(result.installation, messages);
18595
18733
  const operationMessage = statusMessage(result.status, messages);
18596
18734
  if (isPendingStatus(result.status)) {
18597
18735
  renderPendingStatus(result.status, operationMessage ?? messages.updatePreparing);
@@ -18599,9 +18737,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18599
18737
  return;
18600
18738
  }
18601
18739
  panel.dataset.updateState = result.error ? "error" : result.updateAvailable ? "available" : "current";
18602
- panel.replaceChildren(
18603
- versionRow(context, messages.updateCurrentVersion, result.currentVersion)
18604
- );
18740
+ panel.replaceChildren();
18605
18741
  if (result.latestVersion) {
18606
18742
  panel.append(versionRow(context, messages.updateLatestVersion, result.latestVersion));
18607
18743
  }
@@ -18657,17 +18793,20 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18657
18793
  return Promise.resolve();
18658
18794
  }
18659
18795
  pending = true;
18660
- renderPendingStatus(null, messages.updatePreparing);
18661
- return context.runLatest(() => client.checkUpdate(), {
18662
- success(result) {
18663
- pending = false;
18664
- renderCheck(result, client);
18665
- },
18666
- failure(error51) {
18667
- pending = false;
18668
- renderUnavailable(error51 instanceof Error ? error51.message : messages.updateFailed);
18796
+ renderPendingStatus(null, messages.updateChecking);
18797
+ return context.runLatest(
18798
+ (signal) => runBoundedRendererUpdateRequest(() => client.checkUpdate(), signal),
18799
+ {
18800
+ success(result) {
18801
+ pending = false;
18802
+ renderCheck(result, client);
18803
+ },
18804
+ failure(error51) {
18805
+ pending = false;
18806
+ renderRequestFailure(error51);
18807
+ }
18669
18808
  }
18670
- });
18809
+ );
18671
18810
  };
18672
18811
  void load();
18673
18812
  return clearPoll;
@@ -18690,7 +18829,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18690
18829
  }
18691
18830
 
18692
18831
  // src/settings/shell.css
18693
- 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-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-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-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';
18832
+ 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-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';
18694
18833
 
18695
18834
  // src/settings/shell.ts
18696
18835
  var SETTINGS_SHELL_ATTRIBUTE = "data-codexhost-settings-shell";
package/bin/codexhost CHANGED
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codexhost/cli-darwin-arm64",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Run Pi and Claude Code as first-class external harnesses inside Codex Desktop.",
5
5
  "type": "module",
6
6
  "files": [