@codexhost/cli-win32-arm64 0.1.1 → 0.1.3
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 +2 -1
- package/app/codexhost-distribution.json +1 -1
- package/app/desktop-controller.mjs +4 -1
- package/app/host-runtime.mjs +225 -45
- package/app/renderer-extension.js +261 -54
- package/bin/codexhost.exe +0 -0
- package/libexec/codexhost-shim.exe +0 -0
- package/libexec/codexhost-updater.exe +0 -0
- package/package.json +1 -1
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.
|
|
10
|
+
npm install -g @codexhost/cli@0.1.3
|
|
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=win32`, `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
|
+
{"schemaVersion":1,"version":"0.1.3","distribution":"npm","target":"windows-arm64"}
|
|
@@ -1344,12 +1344,15 @@ function isTransientElectronInstallError(error) {
|
|
|
1344
1344
|
}
|
|
1345
1345
|
return false;
|
|
1346
1346
|
}
|
|
1347
|
+
function shouldRetryInstallError(error) {
|
|
1348
|
+
return !(error instanceof RendererCompatibilityError) || isTransientElectronInstallError(error);
|
|
1349
|
+
}
|
|
1347
1350
|
async function installProductionSession(options, dependencies) {
|
|
1348
1351
|
for (let attempt = 1; attempt <= TRANSIENT_INSTALL_ATTEMPTS; attempt += 1) {
|
|
1349
1352
|
try {
|
|
1350
1353
|
return await dependencies.install(options);
|
|
1351
1354
|
} catch (error) {
|
|
1352
|
-
if (attempt === TRANSIENT_INSTALL_ATTEMPTS || !
|
|
1355
|
+
if (attempt === TRANSIENT_INSTALL_ATTEMPTS || !shouldRetryInstallError(error)) {
|
|
1353
1356
|
throw error;
|
|
1354
1357
|
}
|
|
1355
1358
|
await dependencies.sleep(TRANSIENT_INSTALL_RETRY_MS);
|
package/app/host-runtime.mjs
CHANGED
|
@@ -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 = [
|
|
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)) || ![
|
|
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");
|
|
@@ -52755,13 +52789,25 @@ async function acquireUpdateOperationLock(stateDirectory) {
|
|
|
52755
52789
|
}
|
|
52756
52790
|
};
|
|
52757
52791
|
}
|
|
52792
|
+
function processIsAlive(processId) {
|
|
52793
|
+
if (!Number.isSafeInteger(processId) || processId <= 0)
|
|
52794
|
+
return false;
|
|
52795
|
+
try {
|
|
52796
|
+
process.kill(processId, 0);
|
|
52797
|
+
return true;
|
|
52798
|
+
} catch (error52) {
|
|
52799
|
+
return error52.code === "EPERM";
|
|
52800
|
+
}
|
|
52801
|
+
}
|
|
52758
52802
|
async function recoverUpdateOperationLock(stateDirectory) {
|
|
52759
52803
|
const lockPath = path9.join(stateDirectory, LOCK_FILE);
|
|
52760
52804
|
if (!await regularFile(lockPath))
|
|
52761
52805
|
return;
|
|
52806
|
+
let ownerPid;
|
|
52762
52807
|
let statusPath;
|
|
52763
52808
|
try {
|
|
52764
52809
|
const value = JSON.parse(await readFile3(lockPath, "utf8"));
|
|
52810
|
+
ownerPid = value.ownerPid;
|
|
52765
52811
|
statusPath = value.statusPath;
|
|
52766
52812
|
} catch {
|
|
52767
52813
|
return;
|
|
@@ -52770,8 +52816,9 @@ async function recoverUpdateOperationLock(stateDirectory) {
|
|
|
52770
52816
|
return;
|
|
52771
52817
|
try {
|
|
52772
52818
|
const status = parseUpdateStatus(JSON.parse(await readFile3(statusPath, "utf8")));
|
|
52773
|
-
if (TERMINAL_PHASES.has(status.phase))
|
|
52819
|
+
if (TERMINAL_PHASES.has(status.phase) || typeof ownerPid !== "number" || !processIsAlive(ownerPid)) {
|
|
52774
52820
|
await rm3(lockPath, { force: true });
|
|
52821
|
+
}
|
|
52775
52822
|
} catch {
|
|
52776
52823
|
}
|
|
52777
52824
|
}
|
|
@@ -52810,7 +52857,7 @@ async function writeChunk(file2, chunk) {
|
|
|
52810
52857
|
offset += result.bytesWritten;
|
|
52811
52858
|
}
|
|
52812
52859
|
}
|
|
52813
|
-
async function downloadArtifact(source, destination) {
|
|
52860
|
+
async function downloadArtifact(source, destination, onProgress) {
|
|
52814
52861
|
const response = await fetch(source.url, {
|
|
52815
52862
|
redirect: "follow",
|
|
52816
52863
|
headers: { "accept-encoding": "identity" }
|
|
@@ -52836,6 +52883,7 @@ async function downloadArtifact(source, destination) {
|
|
|
52836
52883
|
throw new Error(`update artifact exceeds ${MAX_ARTIFACT_BYTES} bytes`);
|
|
52837
52884
|
}
|
|
52838
52885
|
await writeChunk(file2, item.value);
|
|
52886
|
+
await onProgress?.({ downloadedBytes: bytes, totalBytes: source.size });
|
|
52839
52887
|
}
|
|
52840
52888
|
await file2.sync();
|
|
52841
52889
|
} finally {
|
|
@@ -52920,6 +52968,59 @@ function createBackgroundUpdateManager(dependencies = {}) {
|
|
|
52920
52968
|
const spawnUpdater = dependencies.spawnUpdater ?? defaultSpawnUpdater;
|
|
52921
52969
|
const now = dependencies.now ?? Date.now;
|
|
52922
52970
|
const preparedRequests = /* @__PURE__ */ new Set();
|
|
52971
|
+
async function writeStatusSnapshot(statusPath, status) {
|
|
52972
|
+
const temporaryPath = path10.join(path10.dirname(statusPath), `.update-status-${randomId()}.tmp`);
|
|
52973
|
+
try {
|
|
52974
|
+
await writeFile2(temporaryPath, `${JSON.stringify(status)}
|
|
52975
|
+
`, {
|
|
52976
|
+
encoding: "utf8",
|
|
52977
|
+
mode: 384,
|
|
52978
|
+
flag: "wx"
|
|
52979
|
+
});
|
|
52980
|
+
await rename2(temporaryPath, statusPath);
|
|
52981
|
+
} catch (error52) {
|
|
52982
|
+
await rm4(temporaryPath, { force: true });
|
|
52983
|
+
throw error52;
|
|
52984
|
+
}
|
|
52985
|
+
}
|
|
52986
|
+
function statusSnapshot(version2, installation, phase, progress, error52) {
|
|
52987
|
+
return {
|
|
52988
|
+
schemaVersion: 1,
|
|
52989
|
+
version: version2,
|
|
52990
|
+
installation,
|
|
52991
|
+
phase,
|
|
52992
|
+
updatedAt: Math.floor(now() / 1e3),
|
|
52993
|
+
...progress?.downloadedBytes === void 0 ? {} : { downloadedBytes: progress.downloadedBytes },
|
|
52994
|
+
...progress?.totalBytes === void 0 ? {} : { totalBytes: progress.totalBytes },
|
|
52995
|
+
...error52 === void 0 ? {} : { error: errorMessage4(error52).slice(0, 500) }
|
|
52996
|
+
};
|
|
52997
|
+
}
|
|
52998
|
+
async function writeFailedStatus(statusPath, version2, installation, error52) {
|
|
52999
|
+
await writeStatusSnapshot(statusPath, statusSnapshot(version2, installation, "failed", void 0, error52)).catch(() => void 0);
|
|
53000
|
+
}
|
|
53001
|
+
function progressReporter(statusPath, version2, installation, totalBytes) {
|
|
53002
|
+
let lastProgress = { downloadedBytes: 0, totalBytes };
|
|
53003
|
+
let lastWriteAt = 0;
|
|
53004
|
+
let queued = Promise.resolve();
|
|
53005
|
+
const enqueue = (progress, force = false) => {
|
|
53006
|
+
lastProgress = progress;
|
|
53007
|
+
const currentTime = Date.now();
|
|
53008
|
+
if (!force && currentTime - lastWriteAt < 250)
|
|
53009
|
+
return;
|
|
53010
|
+
lastWriteAt = currentTime;
|
|
53011
|
+
queued = queued.then(() => writeStatusSnapshot(statusPath, statusSnapshot(version2, installation, "downloading", lastProgress))).catch(() => void 0);
|
|
53012
|
+
};
|
|
53013
|
+
enqueue(lastProgress, true);
|
|
53014
|
+
return {
|
|
53015
|
+
update(progress) {
|
|
53016
|
+
enqueue(progress);
|
|
53017
|
+
},
|
|
53018
|
+
async flush() {
|
|
53019
|
+
enqueue(lastProgress, true);
|
|
53020
|
+
await queued;
|
|
53021
|
+
}
|
|
53022
|
+
};
|
|
53023
|
+
}
|
|
52923
53024
|
async function prepareCommon(options, installation) {
|
|
52924
53025
|
const version2 = requireSemanticVersion(options.version);
|
|
52925
53026
|
const launcherPid = requireLauncherPid(options.launcherPid);
|
|
@@ -52937,6 +53038,7 @@ function createBackgroundUpdateManager(dependencies = {}) {
|
|
|
52937
53038
|
const requestPath = path10.join(workDirectory, "request-v1.json");
|
|
52938
53039
|
const statusPath = path10.join(workDirectory, "status-v1.json");
|
|
52939
53040
|
await writePrivateJson(statusPath, preparedStatus(version2, installation, now()));
|
|
53041
|
+
await options.onPrepared?.({ version: version2, installation, statusPath });
|
|
52940
53042
|
return {
|
|
52941
53043
|
version: version2,
|
|
52942
53044
|
launcherPid,
|
|
@@ -52947,12 +53049,15 @@ function createBackgroundUpdateManager(dependencies = {}) {
|
|
|
52947
53049
|
statusPath
|
|
52948
53050
|
};
|
|
52949
53051
|
}
|
|
52950
|
-
async function prepareArtifact(
|
|
53052
|
+
async function prepareArtifact(common, installation, sourceValue, fileName) {
|
|
52951
53053
|
const source = validateArtifact(sourceValue);
|
|
52952
|
-
const temporaryPath = path10.join(workDirectory, `.${fileName}.download`);
|
|
52953
|
-
const artifactPath = path10.join(workDirectory, fileName);
|
|
53054
|
+
const temporaryPath = path10.join(common.workDirectory, `.${fileName}.download`);
|
|
53055
|
+
const artifactPath = path10.join(common.workDirectory, fileName);
|
|
53056
|
+
const progress = progressReporter(common.statusPath, common.version, installation, source.size);
|
|
52954
53057
|
try {
|
|
52955
|
-
const result = await download(source, temporaryPath);
|
|
53058
|
+
const result = await download(source, temporaryPath, progress.update);
|
|
53059
|
+
progress.update({ downloadedBytes: result.bytes, totalBytes: source.size });
|
|
53060
|
+
await progress.flush();
|
|
52956
53061
|
const finalUrl = new URL(result.finalUrl);
|
|
52957
53062
|
if (finalUrl.protocol !== "https:" || finalUrl.username || finalUrl.password) {
|
|
52958
53063
|
throw new Error("update artifact downloader returned a non-HTTPS URL");
|
|
@@ -52962,6 +53067,8 @@ function createBackgroundUpdateManager(dependencies = {}) {
|
|
|
52962
53067
|
return { source, artifactPath };
|
|
52963
53068
|
} catch (error52) {
|
|
52964
53069
|
await rm4(temporaryPath, { force: true });
|
|
53070
|
+
await progress.flush();
|
|
53071
|
+
await writeFailedStatus(common.statusPath, common.version, installation, error52);
|
|
52965
53072
|
throw error52;
|
|
52966
53073
|
}
|
|
52967
53074
|
}
|
|
@@ -52975,6 +53082,7 @@ function createBackgroundUpdateManager(dependencies = {}) {
|
|
|
52975
53082
|
installation
|
|
52976
53083
|
};
|
|
52977
53084
|
await writePrivateJson(common.requestPath, request);
|
|
53085
|
+
await writeStatusSnapshot(common.statusPath, statusSnapshot(common.version, installation.kind, "prepared"));
|
|
52978
53086
|
preparedRequests.add(common.requestPath);
|
|
52979
53087
|
return Object.freeze({
|
|
52980
53088
|
version: common.version,
|
|
@@ -52988,19 +53096,24 @@ function createBackgroundUpdateManager(dependencies = {}) {
|
|
|
52988
53096
|
return Object.freeze({
|
|
52989
53097
|
async prepareNpm(options) {
|
|
52990
53098
|
const common = await prepareCommon(options, "npm");
|
|
52991
|
-
|
|
52992
|
-
|
|
52993
|
-
|
|
52994
|
-
|
|
52995
|
-
|
|
52996
|
-
|
|
52997
|
-
|
|
53099
|
+
try {
|
|
53100
|
+
return await finalize2(common, {
|
|
53101
|
+
kind: "npm",
|
|
53102
|
+
node_path: await requireRegularFile(options.nodePath, "npm Node.js executable"),
|
|
53103
|
+
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")
|
|
53106
|
+
});
|
|
53107
|
+
} catch (error52) {
|
|
53108
|
+
await writeFailedStatus(common.statusPath, common.version, "npm", error52);
|
|
53109
|
+
throw error52;
|
|
53110
|
+
}
|
|
52998
53111
|
},
|
|
52999
53112
|
async prepareWindowsInstaller(options) {
|
|
53000
53113
|
if (platform !== "win32")
|
|
53001
53114
|
throw new Error("Windows installer updates require Windows");
|
|
53002
53115
|
const common = await prepareCommon(options, "windows-installer");
|
|
53003
|
-
const artifact = await prepareArtifact(options.artifact,
|
|
53116
|
+
const artifact = await prepareArtifact(common, "windows-installer", options.artifact, "update.exe");
|
|
53004
53117
|
return finalize2(common, {
|
|
53005
53118
|
kind: "windows-installer",
|
|
53006
53119
|
installer_path: artifact.artifactPath,
|
|
@@ -53016,7 +53129,7 @@ function createBackgroundUpdateManager(dependencies = {}) {
|
|
|
53016
53129
|
if (path10.extname(appPath) !== ".app") {
|
|
53017
53130
|
throw new Error("macOS application path must end in .app");
|
|
53018
53131
|
}
|
|
53019
|
-
const artifact = await prepareArtifact(options.artifact,
|
|
53132
|
+
const artifact = await prepareArtifact(common, "macos-dmg", options.artifact, "update.dmg");
|
|
53020
53133
|
return finalize2(common, {
|
|
53021
53134
|
kind: "macos-dmg",
|
|
53022
53135
|
dmg_path: artifact.artifactPath,
|
|
@@ -53049,6 +53162,8 @@ function createBackgroundUpdateManager(dependencies = {}) {
|
|
|
53049
53162
|
// packages/host-runtime/src/update-coordinator.ts
|
|
53050
53163
|
var ERROR_MAX_LENGTH = 500;
|
|
53051
53164
|
var CONTROLLER_TIMEOUT_MS = 5e3;
|
|
53165
|
+
var UPDATER_READY_TIMEOUT_MS = 1e4;
|
|
53166
|
+
var UPDATER_READY_POLL_MS = 20;
|
|
53052
53167
|
async function startCompatibilityUpdate(coordinator) {
|
|
53053
53168
|
try {
|
|
53054
53169
|
const check2 = await coordinator.check();
|
|
@@ -53067,12 +53182,38 @@ function boundedError(error52) {
|
|
|
53067
53182
|
const message3 = error52 instanceof Error ? error52.message : String(error52);
|
|
53068
53183
|
return message3.slice(0, ERROR_MAX_LENGTH) || "Update operation failed";
|
|
53069
53184
|
}
|
|
53185
|
+
function delay4(milliseconds) {
|
|
53186
|
+
return new Promise((resolve2) => setTimeout(resolve2, milliseconds));
|
|
53187
|
+
}
|
|
53188
|
+
async function waitForUpdaterReady(manager, statusPath) {
|
|
53189
|
+
const deadline = Date.now() + UPDATER_READY_TIMEOUT_MS;
|
|
53190
|
+
while (Date.now() < deadline) {
|
|
53191
|
+
const status = await manager.readStatus(statusPath);
|
|
53192
|
+
switch (status?.phase) {
|
|
53193
|
+
case "waiting-for-exit":
|
|
53194
|
+
case "installing":
|
|
53195
|
+
case "restarting":
|
|
53196
|
+
case "succeeded":
|
|
53197
|
+
return;
|
|
53198
|
+
case "failed":
|
|
53199
|
+
throw new Error(status.error ?? "Background Updater failed before Desktop shutdown");
|
|
53200
|
+
case "prepared":
|
|
53201
|
+
break;
|
|
53202
|
+
default:
|
|
53203
|
+
throw new Error("Background Updater reported an unexpected startup phase");
|
|
53204
|
+
}
|
|
53205
|
+
await delay4(UPDATER_READY_POLL_MS);
|
|
53206
|
+
}
|
|
53207
|
+
throw new Error("Background Updater did not become ready before Desktop shutdown");
|
|
53208
|
+
}
|
|
53070
53209
|
function publicStatus(status) {
|
|
53071
53210
|
return {
|
|
53072
53211
|
version: status.version,
|
|
53073
53212
|
installation: status.installation,
|
|
53074
53213
|
phase: status.phase,
|
|
53075
53214
|
updatedAt: status.updatedAt,
|
|
53215
|
+
...status.downloadedBytes === void 0 ? {} : { downloadedBytes: status.downloadedBytes },
|
|
53216
|
+
...status.totalBytes === void 0 ? {} : { totalBytes: status.totalBytes },
|
|
53076
53217
|
error: status.error?.slice(0, ERROR_MAX_LENGTH) ?? null
|
|
53077
53218
|
};
|
|
53078
53219
|
}
|
|
@@ -53105,7 +53246,8 @@ function requestControllerShutdown(controller) {
|
|
|
53105
53246
|
});
|
|
53106
53247
|
}
|
|
53107
53248
|
function createHostUpdateCoordinator(options) {
|
|
53108
|
-
const
|
|
53249
|
+
const platform = options.platform ?? process.platform;
|
|
53250
|
+
const manager = options.manager ?? createBackgroundUpdateManager({ platform });
|
|
53109
53251
|
const contextPromise = resolveInstalledUpdateContext({
|
|
53110
53252
|
hostRuntimePath: options.hostRuntimePath,
|
|
53111
53253
|
...options.environment ? { environment: options.environment } : {},
|
|
@@ -53116,9 +53258,20 @@ function createHostUpdateCoordinator(options) {
|
|
|
53116
53258
|
const shutdown = options.shutdown ?? requestControllerShutdown;
|
|
53117
53259
|
let candidate = null;
|
|
53118
53260
|
let shutdownPending = null;
|
|
53261
|
+
let shutdownRequested = false;
|
|
53262
|
+
const scheduleShutdown = () => {
|
|
53263
|
+
if (!shutdownRequested || !shutdownPending) return;
|
|
53264
|
+
const controller = shutdownPending;
|
|
53265
|
+
shutdownPending = null;
|
|
53266
|
+
setTimeout(() => void shutdown(controller).catch(() => void 0), 50).unref();
|
|
53267
|
+
};
|
|
53119
53268
|
async function latestStatus(context) {
|
|
53120
53269
|
const discovered = await discoverLatestUpdateStatus(context.common.stateDirectory);
|
|
53121
|
-
|
|
53270
|
+
if (!discovered) return null;
|
|
53271
|
+
if (discovered.status.phase !== "succeeded" && discovered.status.phase !== "failed" && !await isUpdateOperationActive(context.common.stateDirectory)) {
|
|
53272
|
+
return null;
|
|
53273
|
+
}
|
|
53274
|
+
return publicStatus(discovered.status);
|
|
53122
53275
|
}
|
|
53123
53276
|
async function installable(context, release) {
|
|
53124
53277
|
if (context.metadata.distribution === "npm") return true;
|
|
@@ -53139,6 +53292,7 @@ function createHostUpdateCoordinator(options) {
|
|
|
53139
53292
|
} catch (error52) {
|
|
53140
53293
|
return {
|
|
53141
53294
|
currentVersion: "0.0.0",
|
|
53295
|
+
installation: null,
|
|
53142
53296
|
latestVersion: null,
|
|
53143
53297
|
updateAvailable: false,
|
|
53144
53298
|
installationAvailable: false,
|
|
@@ -53163,6 +53317,7 @@ function createHostUpdateCoordinator(options) {
|
|
|
53163
53317
|
}
|
|
53164
53318
|
return {
|
|
53165
53319
|
currentVersion: context.metadata.version,
|
|
53320
|
+
installation: context.installation.kind,
|
|
53166
53321
|
latestVersion: release.version,
|
|
53167
53322
|
updateAvailable,
|
|
53168
53323
|
installationAvailable,
|
|
@@ -53174,6 +53329,7 @@ function createHostUpdateCoordinator(options) {
|
|
|
53174
53329
|
} catch (error52) {
|
|
53175
53330
|
return {
|
|
53176
53331
|
currentVersion: context.metadata.version,
|
|
53332
|
+
installation: context.installation.kind,
|
|
53177
53333
|
latestVersion: null,
|
|
53178
53334
|
updateAvailable: false,
|
|
53179
53335
|
installationAvailable: false,
|
|
@@ -53193,34 +53349,60 @@ function createHostUpdateCoordinator(options) {
|
|
|
53193
53349
|
if (existing) return { status: existing };
|
|
53194
53350
|
throw new Error("Another update operation is already active");
|
|
53195
53351
|
}
|
|
53352
|
+
let resolvePrepared;
|
|
53353
|
+
let rejectPrepared;
|
|
53354
|
+
const preparedReady = new Promise((resolve2, reject) => {
|
|
53355
|
+
resolvePrepared = resolve2;
|
|
53356
|
+
rejectPrepared = reject;
|
|
53357
|
+
});
|
|
53196
53358
|
try {
|
|
53197
53359
|
const release = await fetchLatest();
|
|
53198
53360
|
if (compareSemanticVersions(context.metadata.version, release.version) >= 0 || candidate && candidate.version !== release.version) {
|
|
53199
53361
|
throw new Error("The selected update is no longer the current GitHub Release");
|
|
53200
53362
|
}
|
|
53201
|
-
|
|
53202
|
-
|
|
53203
|
-
|
|
53204
|
-
|
|
53205
|
-
|
|
53206
|
-
|
|
53207
|
-
|
|
53208
|
-
|
|
53209
|
-
|
|
53210
|
-
|
|
53211
|
-
|
|
53212
|
-
|
|
53213
|
-
|
|
53214
|
-
|
|
53215
|
-
|
|
53216
|
-
|
|
53217
|
-
|
|
53218
|
-
|
|
53219
|
-
|
|
53220
|
-
|
|
53363
|
+
const onPrepared = async (info) => {
|
|
53364
|
+
await lock.setStatusPath(info.statusPath);
|
|
53365
|
+
resolvePrepared(info);
|
|
53366
|
+
};
|
|
53367
|
+
const prepareAndStart = async () => {
|
|
53368
|
+
try {
|
|
53369
|
+
let prepared2;
|
|
53370
|
+
if (context.installation.kind === "npm") {
|
|
53371
|
+
prepared2 = await manager.prepareNpm({
|
|
53372
|
+
...context.installation.options,
|
|
53373
|
+
version: release.version,
|
|
53374
|
+
onPrepared
|
|
53375
|
+
});
|
|
53376
|
+
} else {
|
|
53377
|
+
const artifact = selectInstallerReleaseArtifact(
|
|
53378
|
+
release,
|
|
53379
|
+
context.metadata.target
|
|
53380
|
+
).source;
|
|
53381
|
+
prepared2 = context.installation.kind === "windows-installer" ? await manager.prepareWindowsInstaller({
|
|
53382
|
+
...context.installation.options,
|
|
53383
|
+
version: release.version,
|
|
53384
|
+
artifact,
|
|
53385
|
+
onPrepared
|
|
53386
|
+
}) : await manager.prepareMacOsDmg({
|
|
53387
|
+
...context.installation.options,
|
|
53388
|
+
version: release.version,
|
|
53389
|
+
artifact,
|
|
53390
|
+
onPrepared
|
|
53391
|
+
});
|
|
53392
|
+
}
|
|
53393
|
+
if (platform !== "darwin") manager.start(prepared2);
|
|
53394
|
+
await waitForUpdaterReady(manager, prepared2.statusPath);
|
|
53395
|
+
shutdownPending = context.controller;
|
|
53396
|
+
scheduleShutdown();
|
|
53397
|
+
} catch (error52) {
|
|
53398
|
+
await lock.release();
|
|
53399
|
+
rejectPrepared(error52);
|
|
53400
|
+
}
|
|
53401
|
+
};
|
|
53402
|
+
void prepareAndStart();
|
|
53403
|
+
const prepared = await preparedReady;
|
|
53221
53404
|
const status = await manager.readStatus(prepared.statusPath);
|
|
53222
|
-
if (!status) throw new Error("Background
|
|
53223
|
-
shutdownPending = context.controller;
|
|
53405
|
+
if (!status) throw new Error("Background update did not create status");
|
|
53224
53406
|
return { status: publicStatus(status) };
|
|
53225
53407
|
} catch (error52) {
|
|
53226
53408
|
await lock.release();
|
|
@@ -53237,10 +53419,8 @@ function createHostUpdateCoordinator(options) {
|
|
|
53237
53419
|
}
|
|
53238
53420
|
},
|
|
53239
53421
|
requestShutdown() {
|
|
53240
|
-
|
|
53241
|
-
|
|
53242
|
-
if (!controller) return;
|
|
53243
|
-
setTimeout(() => void shutdown(controller).catch(() => void 0), 50).unref();
|
|
53422
|
+
shutdownRequested = true;
|
|
53423
|
+
scheduleShutdown();
|
|
53244
53424
|
}
|
|
53245
53425
|
});
|
|
53246
53426
|
}
|
|
@@ -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,16 +18113,24 @@ 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.",
|
|
18112
18132
|
updateRetry: "Retry",
|
|
18113
|
-
|
|
18133
|
+
updateDownloadFromReleases: "Download from GitHub Releases",
|
|
18114
18134
|
pageLabels: Object.freeze({
|
|
18115
18135
|
connections: "Connections",
|
|
18116
18136
|
"model-pool": "Model Pool",
|
|
@@ -18138,16 +18158,24 @@ 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",
|
|
18149
18177
|
updateRetry: "\u91CD\u8BD5",
|
|
18150
|
-
|
|
18178
|
+
updateDownloadFromReleases: "\u524D\u5F80 GitHub Releases \u4E0B\u8F7D",
|
|
18151
18179
|
pageLabels: Object.freeze({
|
|
18152
18180
|
connections: "\u8FDE\u63A5",
|
|
18153
18181
|
"model-pool": "\u6A21\u578B\u6C60",
|
|
@@ -18449,7 +18477,51 @@ 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
|
|
18524
|
+
var CODEXHOST_RELEASES_LATEST_URL = "https://github.com/BytePioneer-AI/codex-host/releases/latest";
|
|
18453
18525
|
var DEFAULT_RENDERER_SETTINGS_PAGE_IDS = [
|
|
18454
18526
|
"connections",
|
|
18455
18527
|
"model-pool",
|
|
@@ -18493,6 +18565,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
18493
18565
|
row.append(name, value);
|
|
18494
18566
|
return row;
|
|
18495
18567
|
}
|
|
18568
|
+
function installationLabel(installation, messages) {
|
|
18569
|
+
if (installation === "npm") return messages.updateInstallationNpm;
|
|
18570
|
+
if (installation === "windows-installer") {
|
|
18571
|
+
return messages.updateInstallationWindowsInstaller;
|
|
18572
|
+
}
|
|
18573
|
+
if (installation === "macos-dmg") return messages.updateInstallationMacOsDmg;
|
|
18574
|
+
return messages.updateInstallationUnknown;
|
|
18575
|
+
}
|
|
18496
18576
|
function isPendingStatus(status) {
|
|
18497
18577
|
return status !== null && status.phase !== "succeeded" && status.phase !== "failed";
|
|
18498
18578
|
}
|
|
@@ -18501,8 +18581,21 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
18501
18581
|
if (status.phase === "succeeded") return messages.updateSucceeded;
|
|
18502
18582
|
if (status.phase === "failed") return status.error ?? messages.updateFailed;
|
|
18503
18583
|
if (status.phase === "restarting") return messages.updateRestarting;
|
|
18584
|
+
if (status.phase === "downloading") return messages.updateDownloading;
|
|
18504
18585
|
return messages.updatePreparing;
|
|
18505
18586
|
}
|
|
18587
|
+
function formatUpdateBytes(value) {
|
|
18588
|
+
if (value < 1024) return `${value} B`;
|
|
18589
|
+
const units = ["KB", "MB", "GB"];
|
|
18590
|
+
let scaled = value;
|
|
18591
|
+
let unit = "B";
|
|
18592
|
+
for (const nextUnit of units) {
|
|
18593
|
+
scaled /= 1024;
|
|
18594
|
+
unit = nextUnit;
|
|
18595
|
+
if (scaled < 1024 || nextUnit === units.at(-1)) break;
|
|
18596
|
+
}
|
|
18597
|
+
return `${scaled.toFixed(scaled >= 10 ? 0 : 1)} ${unit}`;
|
|
18598
|
+
}
|
|
18506
18599
|
function updatesPage(messages, getClient) {
|
|
18507
18600
|
return Object.freeze({
|
|
18508
18601
|
id: "updates",
|
|
@@ -18513,10 +18606,39 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
18513
18606
|
const heading = document2.createElement("div");
|
|
18514
18607
|
heading.className = "settings-section-label";
|
|
18515
18608
|
heading.textContent = messages.pageLabels.updates;
|
|
18609
|
+
const metadata = document2.createElement("div");
|
|
18610
|
+
metadata.className = "settings-update-metadata";
|
|
18611
|
+
const currentVersion = document2.createElement("div");
|
|
18612
|
+
currentVersion.className = "settings-update-metadata__item";
|
|
18613
|
+
const currentVersionLabel = document2.createElement("span");
|
|
18614
|
+
currentVersionLabel.textContent = messages.updateCurrentVersion;
|
|
18615
|
+
const currentVersionValue = document2.createElement("strong");
|
|
18616
|
+
currentVersionValue.textContent = "-";
|
|
18617
|
+
currentVersion.append(currentVersionLabel, currentVersionValue);
|
|
18618
|
+
const installation = document2.createElement("div");
|
|
18619
|
+
installation.className = "settings-update-metadata__item";
|
|
18620
|
+
const installationName = document2.createElement("span");
|
|
18621
|
+
installationName.textContent = messages.updateInstallation;
|
|
18622
|
+
const installationValue = document2.createElement("strong");
|
|
18623
|
+
installationValue.textContent = "-";
|
|
18624
|
+
installation.append(installationName, installationValue);
|
|
18625
|
+
metadata.append(currentVersion, installation);
|
|
18516
18626
|
const panel = document2.createElement("section");
|
|
18517
18627
|
panel.className = "settings-update-panel";
|
|
18518
18628
|
panel.setAttribute("aria-live", "polite");
|
|
18519
|
-
|
|
18629
|
+
const actions = document2.createElement("div");
|
|
18630
|
+
actions.className = "settings-update-actions";
|
|
18631
|
+
const releaseLink = document2.createElement("a");
|
|
18632
|
+
releaseLink.className = "settings-update-link";
|
|
18633
|
+
releaseLink.href = CODEXHOST_RELEASES_LATEST_URL;
|
|
18634
|
+
releaseLink.target = "_blank";
|
|
18635
|
+
releaseLink.rel = "noopener noreferrer";
|
|
18636
|
+
releaseLink.append(
|
|
18637
|
+
messages.updateDownloadFromReleases,
|
|
18638
|
+
createRendererSettingsIcon("external-link", 14)
|
|
18639
|
+
);
|
|
18640
|
+
actions.append(releaseLink);
|
|
18641
|
+
context.content.append(heading, metadata, panel, actions);
|
|
18520
18642
|
let pollTimer;
|
|
18521
18643
|
let pollAttempts = 0;
|
|
18522
18644
|
let pending = false;
|
|
@@ -18535,22 +18657,35 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
18535
18657
|
copy.textContent = detail;
|
|
18536
18658
|
panel.append(title, copy);
|
|
18537
18659
|
};
|
|
18660
|
+
const renderRequestFailure = (error51) => {
|
|
18661
|
+
renderPendingStatus(
|
|
18662
|
+
null,
|
|
18663
|
+
error51 instanceof RendererUpdateRequestTimeoutError ? messages.updateRequestTimeout : error51 instanceof Error ? error51.message : messages.updateFailed,
|
|
18664
|
+
"failed"
|
|
18665
|
+
);
|
|
18666
|
+
};
|
|
18538
18667
|
const scheduleStatusPoll = (client, resetAttempts = false) => {
|
|
18539
18668
|
clearPoll();
|
|
18540
18669
|
if (resetAttempts) pollAttempts = 0;
|
|
18541
|
-
if (pollAttempts >= 320)
|
|
18670
|
+
if (pollAttempts >= 320) {
|
|
18671
|
+
renderPendingStatus(null, messages.updateRequestTimeout, "failed");
|
|
18672
|
+
return;
|
|
18673
|
+
}
|
|
18542
18674
|
pollAttempts += 1;
|
|
18543
18675
|
pollTimer = document2.defaultView?.setTimeout(() => {
|
|
18544
|
-
void context.runLatest(
|
|
18545
|
-
|
|
18546
|
-
|
|
18547
|
-
|
|
18548
|
-
|
|
18549
|
-
|
|
18550
|
-
|
|
18551
|
-
|
|
18676
|
+
void context.runLatest(
|
|
18677
|
+
(signal) => runBoundedRendererUpdateRequest(() => client.readUpdateStatus(), signal),
|
|
18678
|
+
{
|
|
18679
|
+
success(result) {
|
|
18680
|
+
const message = statusMessage(result.status, messages);
|
|
18681
|
+
if (isPendingStatus(result.status)) scheduleStatusPoll(client);
|
|
18682
|
+
if (message) renderPendingStatus(result.status, message);
|
|
18683
|
+
},
|
|
18684
|
+
failure(error51) {
|
|
18685
|
+
renderRequestFailure(error51);
|
|
18686
|
+
}
|
|
18552
18687
|
}
|
|
18553
|
-
|
|
18688
|
+
);
|
|
18554
18689
|
}, 750);
|
|
18555
18690
|
};
|
|
18556
18691
|
const renderPendingStatus = (status, message, viewPhase = status?.phase ?? "pending") => {
|
|
@@ -18559,6 +18694,21 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
18559
18694
|
const state = document2.createElement("strong");
|
|
18560
18695
|
state.textContent = message;
|
|
18561
18696
|
panel.append(state);
|
|
18697
|
+
if (status?.phase === "downloading" && status.totalBytes !== void 0 && status.downloadedBytes !== void 0) {
|
|
18698
|
+
const progress = document2.createElement("progress");
|
|
18699
|
+
progress.className = "settings-update-progress";
|
|
18700
|
+
progress.max = status.totalBytes;
|
|
18701
|
+
progress.value = Math.min(status.downloadedBytes, status.totalBytes);
|
|
18702
|
+
progress.setAttribute("aria-label", messages.updateDownloading);
|
|
18703
|
+
const detail = document2.createElement("span");
|
|
18704
|
+
detail.className = "settings-update-progress-detail";
|
|
18705
|
+
const percent = Math.min(
|
|
18706
|
+
100,
|
|
18707
|
+
Math.round(status.downloadedBytes / status.totalBytes * 1e3) / 10
|
|
18708
|
+
);
|
|
18709
|
+
detail.textContent = `${percent}% \xB7 ${formatUpdateBytes(status.downloadedBytes)} / ${formatUpdateBytes(status.totalBytes)}`;
|
|
18710
|
+
panel.append(progress, detail);
|
|
18711
|
+
}
|
|
18562
18712
|
if (viewPhase === "failed") {
|
|
18563
18713
|
const retry = document2.createElement("button");
|
|
18564
18714
|
retry.type = "button";
|
|
@@ -18572,26 +18722,28 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
18572
18722
|
if (pending) return;
|
|
18573
18723
|
pending = true;
|
|
18574
18724
|
renderPendingStatus(null, messages.updatePreparing);
|
|
18575
|
-
void context.runLatest(
|
|
18576
|
-
|
|
18577
|
-
|
|
18578
|
-
|
|
18579
|
-
|
|
18580
|
-
|
|
18581
|
-
|
|
18582
|
-
|
|
18583
|
-
|
|
18584
|
-
|
|
18585
|
-
|
|
18586
|
-
|
|
18587
|
-
|
|
18588
|
-
error51
|
|
18589
|
-
|
|
18590
|
-
);
|
|
18725
|
+
void context.runLatest(
|
|
18726
|
+
(signal) => runBoundedRendererUpdateRequest(() => client.startUpdate(), signal),
|
|
18727
|
+
{
|
|
18728
|
+
success(result) {
|
|
18729
|
+
pending = false;
|
|
18730
|
+
renderPendingStatus(
|
|
18731
|
+
result.status,
|
|
18732
|
+
statusMessage(result.status, messages) ?? messages.updatePreparing
|
|
18733
|
+
);
|
|
18734
|
+
if (isPendingStatus(result.status)) scheduleStatusPoll(client, true);
|
|
18735
|
+
},
|
|
18736
|
+
failure(error51) {
|
|
18737
|
+
pending = false;
|
|
18738
|
+
renderRequestFailure(error51);
|
|
18739
|
+
}
|
|
18591
18740
|
}
|
|
18592
|
-
|
|
18741
|
+
);
|
|
18593
18742
|
};
|
|
18594
18743
|
const renderCheck = (result, client) => {
|
|
18744
|
+
currentVersionValue.textContent = `v${result.currentVersion}`;
|
|
18745
|
+
installationValue.textContent = installationLabel(result.installation, messages);
|
|
18746
|
+
if (result.releaseNotesUrl) releaseLink.href = result.releaseNotesUrl;
|
|
18595
18747
|
const operationMessage = statusMessage(result.status, messages);
|
|
18596
18748
|
if (isPendingStatus(result.status)) {
|
|
18597
18749
|
renderPendingStatus(result.status, operationMessage ?? messages.updatePreparing);
|
|
@@ -18599,9 +18751,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
18599
18751
|
return;
|
|
18600
18752
|
}
|
|
18601
18753
|
panel.dataset.updateState = result.error ? "error" : result.updateAvailable ? "available" : "current";
|
|
18602
|
-
panel.replaceChildren(
|
|
18603
|
-
versionRow(context, messages.updateCurrentVersion, result.currentVersion)
|
|
18604
|
-
);
|
|
18754
|
+
panel.replaceChildren();
|
|
18605
18755
|
if (result.latestVersion) {
|
|
18606
18756
|
panel.append(versionRow(context, messages.updateLatestVersion, result.latestVersion));
|
|
18607
18757
|
}
|
|
@@ -18629,15 +18779,6 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
18629
18779
|
update.addEventListener("click", () => start(client));
|
|
18630
18780
|
panel.append(update);
|
|
18631
18781
|
}
|
|
18632
|
-
if (result.releaseNotesUrl) {
|
|
18633
|
-
const notes = document2.createElement("a");
|
|
18634
|
-
notes.className = "settings-update-link";
|
|
18635
|
-
notes.href = result.releaseNotesUrl;
|
|
18636
|
-
notes.target = "_blank";
|
|
18637
|
-
notes.rel = "noopener noreferrer";
|
|
18638
|
-
notes.append(messages.updateViewRelease, createRendererSettingsIcon("external-link", 14));
|
|
18639
|
-
panel.append(notes);
|
|
18640
|
-
}
|
|
18641
18782
|
if (result.error) {
|
|
18642
18783
|
const error51 = document2.createElement("p");
|
|
18643
18784
|
error51.className = "settings-update-error";
|
|
@@ -18657,17 +18798,20 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
18657
18798
|
return Promise.resolve();
|
|
18658
18799
|
}
|
|
18659
18800
|
pending = true;
|
|
18660
|
-
renderPendingStatus(null, messages.
|
|
18661
|
-
return context.runLatest(
|
|
18662
|
-
|
|
18663
|
-
|
|
18664
|
-
|
|
18665
|
-
|
|
18666
|
-
|
|
18667
|
-
|
|
18668
|
-
|
|
18801
|
+
renderPendingStatus(null, messages.updateChecking);
|
|
18802
|
+
return context.runLatest(
|
|
18803
|
+
(signal) => runBoundedRendererUpdateRequest(() => client.checkUpdate(), signal),
|
|
18804
|
+
{
|
|
18805
|
+
success(result) {
|
|
18806
|
+
pending = false;
|
|
18807
|
+
renderCheck(result, client);
|
|
18808
|
+
},
|
|
18809
|
+
failure(error51) {
|
|
18810
|
+
pending = false;
|
|
18811
|
+
renderRequestFailure(error51);
|
|
18812
|
+
}
|
|
18669
18813
|
}
|
|
18670
|
-
|
|
18814
|
+
);
|
|
18671
18815
|
};
|
|
18672
18816
|
void load();
|
|
18673
18817
|
return clearPoll;
|
|
@@ -18690,7 +18834,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
18690
18834
|
}
|
|
18691
18835
|
|
|
18692
18836
|
// 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';
|
|
18837
|
+
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';
|
|
18694
18838
|
|
|
18695
18839
|
// src/settings/shell.ts
|
|
18696
18840
|
var SETTINGS_SHELL_ATTRIBUTE = "data-codexhost-settings-shell";
|
|
@@ -19126,6 +19270,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
19126
19270
|
}
|
|
19127
19271
|
|
|
19128
19272
|
// src/renderer-settings-lifecycle.ts
|
|
19273
|
+
var UPDATE_CHECK_TIMEOUT_MS = 5e3;
|
|
19274
|
+
var UPDATE_RETRY_DELAYS_MS = [1e3, 3e3, 1e4, 3e4];
|
|
19129
19275
|
function installRendererSettingsLifecycle(ownerWindow = window, options = {}) {
|
|
19130
19276
|
const lifecycleController = new AbortController();
|
|
19131
19277
|
let locale = resolveRendererSettingsLocale(ownerWindow.navigator.languages);
|
|
@@ -19133,6 +19279,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
19133
19279
|
let trigger = null;
|
|
19134
19280
|
let localeRequest = null;
|
|
19135
19281
|
let checkedUpdateClient = null;
|
|
19282
|
+
let retryUpdateClient = null;
|
|
19283
|
+
let updateRetryTimer = null;
|
|
19284
|
+
let updateRetryAttempt = 0;
|
|
19136
19285
|
let updateCheckGeneration = 0;
|
|
19137
19286
|
let updateAvailable = false;
|
|
19138
19287
|
let openGeneration = 0;
|
|
@@ -19195,16 +19344,65 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
19195
19344
|
localeRequest = request;
|
|
19196
19345
|
return request;
|
|
19197
19346
|
};
|
|
19347
|
+
const clearUpdateRetry = () => {
|
|
19348
|
+
if (updateRetryTimer === null) return;
|
|
19349
|
+
ownerWindow.clearTimeout(updateRetryTimer);
|
|
19350
|
+
updateRetryTimer = null;
|
|
19351
|
+
};
|
|
19352
|
+
const scheduleUpdateRetry = (client) => {
|
|
19353
|
+
if (disposed || updateRetryTimer !== null) return;
|
|
19354
|
+
const delay = UPDATE_RETRY_DELAYS_MS[updateRetryAttempt];
|
|
19355
|
+
if (delay === void 0) return;
|
|
19356
|
+
updateRetryAttempt += 1;
|
|
19357
|
+
updateRetryTimer = ownerWindow.setTimeout(() => {
|
|
19358
|
+
updateRetryTimer = null;
|
|
19359
|
+
if (disposed || options.getUpdateClient?.() !== client) return;
|
|
19360
|
+
refreshUpdateIndicator();
|
|
19361
|
+
}, delay);
|
|
19362
|
+
};
|
|
19363
|
+
const checkUpdateWithTimeout = (client) => new Promise((resolve, reject) => {
|
|
19364
|
+
const timeout = ownerWindow.setTimeout(
|
|
19365
|
+
() => reject(new Error("Update indicator check timed out")),
|
|
19366
|
+
UPDATE_CHECK_TIMEOUT_MS
|
|
19367
|
+
);
|
|
19368
|
+
void client.checkUpdate().then(
|
|
19369
|
+
(result) => {
|
|
19370
|
+
ownerWindow.clearTimeout(timeout);
|
|
19371
|
+
resolve(result);
|
|
19372
|
+
},
|
|
19373
|
+
(error51) => {
|
|
19374
|
+
ownerWindow.clearTimeout(timeout);
|
|
19375
|
+
reject(error51);
|
|
19376
|
+
}
|
|
19377
|
+
);
|
|
19378
|
+
});
|
|
19198
19379
|
const refreshUpdateIndicator = () => {
|
|
19199
19380
|
const client = options.getUpdateClient?.() ?? null;
|
|
19200
19381
|
if (!client || checkedUpdateClient === client) return;
|
|
19382
|
+
if (retryUpdateClient !== client) {
|
|
19383
|
+
clearUpdateRetry();
|
|
19384
|
+
retryUpdateClient = client;
|
|
19385
|
+
updateRetryAttempt = 0;
|
|
19386
|
+
}
|
|
19201
19387
|
checkedUpdateClient = client;
|
|
19202
19388
|
const generation = ++updateCheckGeneration;
|
|
19203
|
-
void client
|
|
19389
|
+
void checkUpdateWithTimeout(client).then((result) => {
|
|
19204
19390
|
if (disposed || generation !== updateCheckGeneration) return;
|
|
19205
19391
|
updateAvailable = result.updateAvailable;
|
|
19206
19392
|
trigger?.setUpdateAvailable(updateAvailable);
|
|
19393
|
+
if (result.error === null) {
|
|
19394
|
+
updateRetryAttempt = 0;
|
|
19395
|
+
clearUpdateRetry();
|
|
19396
|
+
return;
|
|
19397
|
+
}
|
|
19398
|
+
checkedUpdateClient = null;
|
|
19399
|
+
scheduleUpdateRetry(client);
|
|
19207
19400
|
}).catch(() => {
|
|
19401
|
+
if (disposed || generation !== updateCheckGeneration || checkedUpdateClient !== client) {
|
|
19402
|
+
return;
|
|
19403
|
+
}
|
|
19404
|
+
checkedUpdateClient = null;
|
|
19405
|
+
scheduleUpdateRetry(client);
|
|
19208
19406
|
});
|
|
19209
19407
|
};
|
|
19210
19408
|
mount();
|
|
@@ -19225,6 +19423,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
19225
19423
|
openGeneration += 1;
|
|
19226
19424
|
updateCheckGeneration += 1;
|
|
19227
19425
|
lifecycleController.abort();
|
|
19426
|
+
clearUpdateRetry();
|
|
19228
19427
|
trigger?.dispose();
|
|
19229
19428
|
shell?.dispose();
|
|
19230
19429
|
trigger = null;
|
|
@@ -20488,6 +20687,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
20488
20687
|
applyAdapterAgent = applyAgent ?? null;
|
|
20489
20688
|
modelControl = nextModelControl ?? null;
|
|
20490
20689
|
adapterStatus = status;
|
|
20690
|
+
const installedModelControl = modelControl;
|
|
20691
|
+
queueMicrotask(() => {
|
|
20692
|
+
if (disposed || modelControl !== installedModelControl) return;
|
|
20693
|
+
try {
|
|
20694
|
+
settingsLifecycle.refresh();
|
|
20695
|
+
} catch {
|
|
20696
|
+
}
|
|
20697
|
+
});
|
|
20491
20698
|
sidebarAgentIcons.refresh();
|
|
20492
20699
|
void refreshHarnessAvailability();
|
|
20493
20700
|
const connected = connectedComposers();
|
package/bin/codexhost.exe
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|