cxstatusline 0.1.1 → 0.3.0
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 +32 -41
- package/dist/cxstatusline.js +1012 -423
- package/package.json +8 -2
- package/patches/codex-0.154.0.patch +2825 -0
- package/patches/manifest.json +3 -2
package/dist/cxstatusline.js
CHANGED
|
@@ -54793,7 +54793,7 @@ class SessionNameWidget {
|
|
|
54793
54793
|
}
|
|
54794
54794
|
// src/utils/terminal.ts
|
|
54795
54795
|
import { execSync } from "child_process";
|
|
54796
|
-
var __dirname = "/Users/
|
|
54796
|
+
var __dirname = "/Users/runner/work/cxstatusline/cxstatusline/src/utils";
|
|
54797
54797
|
function probeTerminalWidth() {
|
|
54798
54798
|
const overrideRaw = process.env.CCSTATUSLINE_WIDTH;
|
|
54799
54799
|
if (overrideRaw) {
|
|
@@ -57046,10 +57046,9 @@ async function runRender(stdin, deps) {
|
|
|
57046
57046
|
`, code: 2 };
|
|
57047
57047
|
}
|
|
57048
57048
|
}
|
|
57049
|
-
|
|
57050
57049
|
// src/version-info.ts
|
|
57051
|
-
var VERSION = "0.
|
|
57052
|
-
var SOURCE_COMMIT = /^[0-9a-f]{40}$/.test("
|
|
57050
|
+
var VERSION = "0.3.0";
|
|
57051
|
+
var SOURCE_COMMIT = /^[0-9a-f]{40}$/.test("238a373fb9c429871859ab99d013fa69b456b23b") ? "238a373fb9c429871859ab99d013fa69b456b23b" : null;
|
|
57053
57052
|
var SOURCE_DIRTY = false;
|
|
57054
57053
|
|
|
57055
57054
|
// src/context.ts
|
|
@@ -57163,11 +57162,12 @@ function realContext(env3, io) {
|
|
|
57163
57162
|
const deps = realDeps();
|
|
57164
57163
|
const sccache = deps.which("sccache");
|
|
57165
57164
|
const run = (cmd, args, opts) => {
|
|
57165
|
+
const baseEnv = opts?.env ? { ...process.env, ...opts.env } : process.env;
|
|
57166
57166
|
const r = spawnSync2(cmd, args, {
|
|
57167
57167
|
encoding: "utf8",
|
|
57168
57168
|
cwd: opts?.cwd,
|
|
57169
57169
|
stdio: opts?.interactive ? "inherit" : "pipe",
|
|
57170
|
-
env: sccache && cmd === "cargo" ? { ...
|
|
57170
|
+
env: sccache && cmd === "cargo" ? { ...baseEnv, RUSTC_WRAPPER: sccache } : baseEnv,
|
|
57171
57171
|
maxBuffer: 64 * 1024 * 1024,
|
|
57172
57172
|
...opts?.timeoutMs === undefined ? {} : { timeout: opts.timeoutMs, killSignal: "SIGKILL" }
|
|
57173
57173
|
});
|
|
@@ -57190,7 +57190,7 @@ function realContext(env3, io) {
|
|
|
57190
57190
|
|
|
57191
57191
|
// src/patch/run.ts
|
|
57192
57192
|
import { appendFileSync, mkdirSync as mkdirSync7 } from "node:fs";
|
|
57193
|
-
import { join as
|
|
57193
|
+
import { join as join15 } from "node:path";
|
|
57194
57194
|
|
|
57195
57195
|
// src/lock.ts
|
|
57196
57196
|
import { closeSync, existsSync as existsSync4, mkdirSync, openSync, readFileSync as readFileSync2, unlinkSync, writeSync } from "node:fs";
|
|
@@ -57244,89 +57244,10 @@ function acquireLock(file2, isAlive = pidAlive) {
|
|
|
57244
57244
|
return null;
|
|
57245
57245
|
}
|
|
57246
57246
|
|
|
57247
|
-
// src/
|
|
57248
|
-
|
|
57249
|
-
|
|
57250
|
-
|
|
57251
|
-
import { mkdirSync as mkdirSync2, renameSync, writeFileSync } from "node:fs";
|
|
57252
|
-
import { randomBytes } from "node:crypto";
|
|
57253
|
-
import { dirname as dirname5, join as join5 } from "node:path";
|
|
57254
|
-
function writeFileAtomic(file2, text) {
|
|
57255
|
-
mkdirSync2(dirname5(file2), { recursive: true });
|
|
57256
|
-
const tmp = join5(dirname5(file2), `.${process.pid}.${randomBytes(4).toString("hex")}.tmp`);
|
|
57257
|
-
writeFileSync(tmp, text);
|
|
57258
|
-
renameSync(tmp, file2);
|
|
57259
|
-
}
|
|
57260
|
-
|
|
57261
|
-
// src/sh.ts
|
|
57262
|
-
var sq = (s) => `'${s.replace(/'/g, `'"'"'`)}'`;
|
|
57263
|
-
|
|
57264
|
-
// src/hook/install.ts
|
|
57265
|
-
var HOOK_STATUS_MESSAGE = "cxstatusline: checking Codex version";
|
|
57266
|
-
var HOOK_TIMEOUT_SEC = 10;
|
|
57267
|
-
var hookCommand = (cxBin) => `${sq(cxBin)} hook`;
|
|
57268
|
-
function hookEntry(cxBin) {
|
|
57269
|
-
return { hooks: [{ type: "command", command: hookCommand(cxBin), timeout: HOOK_TIMEOUT_SEC, statusMessage: HOOK_STATUS_MESSAGE }] };
|
|
57270
|
-
}
|
|
57271
|
-
var isOurGroup = (g) => g.hooks.some((h) => h.statusMessage === HOOK_STATUS_MESSAGE);
|
|
57272
|
-
var sameJson = (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
|
57273
|
-
function mergeHook(file2, cxBin) {
|
|
57274
|
-
const base2 = file2 ?? { hooks: {} };
|
|
57275
|
-
const entry = hookEntry(cxBin);
|
|
57276
|
-
const groups = base2.hooks.SessionStart ?? [];
|
|
57277
|
-
const idx = groups.findIndex(isOurGroup);
|
|
57278
|
-
if (idx !== -1 && sameJson(groups[idx], entry))
|
|
57279
|
-
return { file: base2, changed: false };
|
|
57280
|
-
const next = idx === -1 ? [...groups, entry] : groups.map((g, i) => i === idx ? entry : g);
|
|
57281
|
-
return { file: { ...base2, hooks: { ...base2.hooks, SessionStart: next } }, changed: true };
|
|
57282
|
-
}
|
|
57283
|
-
function removeHook(file2) {
|
|
57284
|
-
const groups = file2.hooks.SessionStart ?? [];
|
|
57285
|
-
const kept = groups.filter((g) => !isOurGroup(g));
|
|
57286
|
-
if (kept.length === groups.length)
|
|
57287
|
-
return { file: file2, changed: false };
|
|
57288
|
-
const { SessionStart: _dropped, ...rest2 } = file2.hooks;
|
|
57289
|
-
const hooks = kept.length === 0 ? rest2 : { ...rest2, SessionStart: kept };
|
|
57290
|
-
return { file: { ...file2, hooks }, changed: true };
|
|
57291
|
-
}
|
|
57292
|
-
function readHooksFile(path) {
|
|
57293
|
-
if (!existsSync5(path))
|
|
57294
|
-
return null;
|
|
57295
|
-
let raw;
|
|
57296
|
-
try {
|
|
57297
|
-
raw = JSON.parse(readFileSync3(path, "utf8"));
|
|
57298
|
-
} catch {
|
|
57299
|
-
throw new Error(`${path}: hooks.json is not valid JSON; fix it by hand before installing the hook`);
|
|
57300
|
-
}
|
|
57301
|
-
if (typeof raw !== "object" || raw === null || Array.isArray(raw))
|
|
57302
|
-
throw new Error(`${path}: hooks.json must be a JSON object`);
|
|
57303
|
-
const o = raw;
|
|
57304
|
-
if (o.hooks !== undefined && (typeof o.hooks !== "object" || o.hooks === null))
|
|
57305
|
-
throw new Error(`${path}: "hooks" must be an object`);
|
|
57306
|
-
return { ...raw, hooks: o.hooks ?? {} };
|
|
57307
|
-
}
|
|
57308
|
-
function installHook(hooksFile, cxBin) {
|
|
57309
|
-
const { file: file2, changed } = mergeHook(readHooksFile(hooksFile), cxBin);
|
|
57310
|
-
if (!changed)
|
|
57311
|
-
return "unchanged";
|
|
57312
|
-
writeFileAtomic(hooksFile, `${JSON.stringify(file2, null, 2)}
|
|
57313
|
-
`);
|
|
57314
|
-
return "added";
|
|
57315
|
-
}
|
|
57316
|
-
function uninstallHook(hooksFile) {
|
|
57317
|
-
const current = readHooksFile(hooksFile);
|
|
57318
|
-
if (!current)
|
|
57319
|
-
return "absent";
|
|
57320
|
-
const { file: file2, changed } = removeHook(current);
|
|
57321
|
-
if (!changed)
|
|
57322
|
-
return "absent";
|
|
57323
|
-
writeFileAtomic(hooksFile, `${JSON.stringify(file2, null, 2)}
|
|
57324
|
-
`);
|
|
57325
|
-
return "removed";
|
|
57326
|
-
}
|
|
57327
|
-
|
|
57328
|
-
// src/state.ts
|
|
57329
|
-
import { existsSync as existsSync6, readFileSync as readFileSync4 } from "node:fs";
|
|
57247
|
+
// src/distribution/files.ts
|
|
57248
|
+
var GENERATION_EXECUTABLES = ["codex", "codex-code-mode-host"];
|
|
57249
|
+
var GENERATION_LEGAL_FILES = ["LICENSE", "NOTICE", "THIRD_PARTY_NOTICES.md"];
|
|
57250
|
+
var ARTIFACT_FILES = [...GENERATION_EXECUTABLES, ...GENERATION_LEGAL_FILES];
|
|
57330
57251
|
|
|
57331
57252
|
// src/version.ts
|
|
57332
57253
|
var POLICIES = ["every", "stable-minors", "manual"];
|
|
@@ -57376,173 +57297,19 @@ function behindWithinMinor(upstream, patched) {
|
|
|
57376
57297
|
return upstream.major === patched.major && upstream.minor === patched.minor && upstream.pre === null && compareSemver(upstream, patched) === 1;
|
|
57377
57298
|
}
|
|
57378
57299
|
|
|
57379
|
-
// src/state.ts
|
|
57380
|
-
var RELEASE_UNAVAILABLE = "release-unavailable";
|
|
57381
|
-
var RELEASE_RETRY_AFTER_MS = 24 * 60 * 60 * 1000;
|
|
57382
|
-
var DEFAULT_STATE = {
|
|
57383
|
-
version: 1,
|
|
57384
|
-
policy: "stable-minors",
|
|
57385
|
-
patched_from: null,
|
|
57386
|
-
upstream_bin: null,
|
|
57387
|
-
launcher_restore: null,
|
|
57388
|
-
last_attempt: null
|
|
57389
|
-
};
|
|
57390
|
-
var BACKUP_SUFFIX = ".bak";
|
|
57391
|
-
var isObj2 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
57392
|
-
var strOrNull = (v) => v === null || typeof v === "string" ? v : undefined;
|
|
57393
|
-
function restore(v) {
|
|
57394
|
-
if (v === null)
|
|
57395
|
-
return null;
|
|
57396
|
-
if (!isObj2(v))
|
|
57397
|
-
return;
|
|
57398
|
-
if (v.kind === "none")
|
|
57399
|
-
return { kind: "none" };
|
|
57400
|
-
if (v.kind === "symlink" && typeof v.target === "string")
|
|
57401
|
-
return { kind: "symlink", target: v.target };
|
|
57402
|
-
return;
|
|
57403
|
-
}
|
|
57404
|
-
function attempt2(v) {
|
|
57405
|
-
if (v === null)
|
|
57406
|
-
return null;
|
|
57407
|
-
if (!isObj2(v) || typeof v.at !== "string" || typeof v.ok !== "boolean" || typeof v.version !== "string")
|
|
57408
|
-
return;
|
|
57409
|
-
return typeof v.reason === "string" ? { at: v.at, ok: v.ok, version: v.version, reason: v.reason } : { at: v.at, ok: v.ok, version: v.version };
|
|
57410
|
-
}
|
|
57411
|
-
function validate3(raw) {
|
|
57412
|
-
if (!isObj2(raw) || raw.version !== 1)
|
|
57413
|
-
return null;
|
|
57414
|
-
const policy = POLICIES.includes(String(raw.policy)) ? raw.policy : undefined;
|
|
57415
|
-
const patched_from = strOrNull(raw.patched_from);
|
|
57416
|
-
const upstream_bin = strOrNull(raw.upstream_bin);
|
|
57417
|
-
const launcher_restore = restore(raw.launcher_restore);
|
|
57418
|
-
const last_attempt = attempt2(raw.last_attempt);
|
|
57419
|
-
if (policy === undefined || patched_from === undefined || upstream_bin === undefined || launcher_restore === undefined || last_attempt === undefined)
|
|
57420
|
-
return null;
|
|
57421
|
-
return { version: 1, policy, patched_from, upstream_bin, launcher_restore, last_attempt };
|
|
57422
|
-
}
|
|
57423
|
-
function readValidated(file2) {
|
|
57424
|
-
if (!existsSync6(file2))
|
|
57425
|
-
return null;
|
|
57426
|
-
try {
|
|
57427
|
-
return validate3(JSON.parse(readFileSync4(file2, "utf8")));
|
|
57428
|
-
} catch {
|
|
57429
|
-
return null;
|
|
57430
|
-
}
|
|
57431
|
-
}
|
|
57432
|
-
function readState(file2) {
|
|
57433
|
-
if (!existsSync6(file2) && !existsSync6(`${file2}${BACKUP_SUFFIX}`)) {
|
|
57434
|
-
return { state: DEFAULT_STATE, corrupt: false };
|
|
57435
|
-
}
|
|
57436
|
-
const primary = readValidated(file2);
|
|
57437
|
-
if (primary)
|
|
57438
|
-
return { state: primary, corrupt: false };
|
|
57439
|
-
const backup = readValidated(`${file2}${BACKUP_SUFFIX}`);
|
|
57440
|
-
return backup ? { state: backup, corrupt: true } : { state: DEFAULT_STATE, corrupt: true };
|
|
57441
|
-
}
|
|
57442
|
-
function writeState(file2, state) {
|
|
57443
|
-
const text = `${JSON.stringify(state, null, 2)}
|
|
57444
|
-
`;
|
|
57445
|
-
writeFileAtomic(file2, text);
|
|
57446
|
-
writeFileAtomic(`${file2}${BACKUP_SUFFIX}`, text);
|
|
57447
|
-
}
|
|
57448
|
-
|
|
57449
|
-
// src/patch/acquire.ts
|
|
57450
|
-
import { rmSync as rmSync5 } from "node:fs";
|
|
57451
|
-
|
|
57452
|
-
// src/codex/upstream.ts
|
|
57453
|
-
import { accessSync as accessSync2, constants as constants3, lstatSync, readlinkSync, realpathSync as realpathSync2, statSync } from "node:fs";
|
|
57454
|
-
import { dirname as dirname6, isAbsolute, join as join6, resolve as resolve2 } from "node:path";
|
|
57455
|
-
function isExecutable(p) {
|
|
57456
|
-
try {
|
|
57457
|
-
accessSync2(p, constants3.X_OK);
|
|
57458
|
-
return statSync(p).isFile();
|
|
57459
|
-
} catch {
|
|
57460
|
-
return false;
|
|
57461
|
-
}
|
|
57462
|
-
}
|
|
57463
|
-
function isManaged(p, paths, isOurWrapper) {
|
|
57464
|
-
if (resolve2(p) === resolve2(paths.patchedBin) || isOurWrapper(p))
|
|
57465
|
-
return true;
|
|
57466
|
-
try {
|
|
57467
|
-
return realpathSync2(p) === realpathSync2(paths.patchedBin);
|
|
57468
|
-
} catch {
|
|
57469
|
-
return false;
|
|
57470
|
-
}
|
|
57471
|
-
}
|
|
57472
|
-
function inspectLauncher(paths, isOurWrapper) {
|
|
57473
|
-
let st;
|
|
57474
|
-
try {
|
|
57475
|
-
st = lstatSync(paths.wrapperPath);
|
|
57476
|
-
} catch {
|
|
57477
|
-
return null;
|
|
57478
|
-
}
|
|
57479
|
-
if (st.isSymbolicLink()) {
|
|
57480
|
-
const raw = readlinkSync(paths.wrapperPath);
|
|
57481
|
-
const target = isAbsolute(raw) ? raw : resolve2(dirname6(paths.wrapperPath), raw);
|
|
57482
|
-
if (isManaged(target, paths, isOurWrapper))
|
|
57483
|
-
return null;
|
|
57484
|
-
return { kind: "found", bin: target, launcher_restore: { kind: "symlink", target } };
|
|
57485
|
-
}
|
|
57486
|
-
if (isOurWrapper(paths.wrapperPath))
|
|
57487
|
-
return null;
|
|
57488
|
-
return { kind: "foreign", path: paths.wrapperPath };
|
|
57489
|
-
}
|
|
57490
|
-
function walkPath(paths, env3, isOurWrapper) {
|
|
57491
|
-
for (const dir of (env3.PATH ?? "").split(":").filter(Boolean)) {
|
|
57492
|
-
if (resolve2(dir) === resolve2(paths.binDir))
|
|
57493
|
-
continue;
|
|
57494
|
-
const candidate = join6(dir, "codex");
|
|
57495
|
-
if (isExecutable(candidate) && !isManaged(candidate, paths, isOurWrapper))
|
|
57496
|
-
return candidate;
|
|
57497
|
-
}
|
|
57498
|
-
return null;
|
|
57499
|
-
}
|
|
57500
|
-
function resolveUpstream(paths, env3, isOurWrapper, savedBin) {
|
|
57501
|
-
const launcher = inspectLauncher(paths, isOurWrapper);
|
|
57502
|
-
if (launcher)
|
|
57503
|
-
return launcher;
|
|
57504
|
-
const current = walkPath(paths, env3, isOurWrapper);
|
|
57505
|
-
const bin = current ?? (savedBin && isExecutable(savedBin) && !isManaged(savedBin, paths, isOurWrapper) ? savedBin : null);
|
|
57506
|
-
return bin ? { kind: "found", bin, launcher_restore: { kind: "none" } } : { kind: "not-found" };
|
|
57507
|
-
}
|
|
57508
|
-
function describeLookup(l) {
|
|
57509
|
-
switch (l.kind) {
|
|
57510
|
-
case "found":
|
|
57511
|
-
return l.bin;
|
|
57512
|
-
case "foreign":
|
|
57513
|
-
return `${l.path} is a real file we did not write; refusing to overwrite it`;
|
|
57514
|
-
case "not-found":
|
|
57515
|
-
return "no upstream Codex found (nothing named codex on PATH outside ~/.local/bin, and the launcher there is not a symlink)";
|
|
57516
|
-
}
|
|
57517
|
-
}
|
|
57518
|
-
function readUpstreamVersion(bin, run) {
|
|
57519
|
-
const r = run(bin, ["--version"]);
|
|
57520
|
-
if (r.status !== 0)
|
|
57521
|
-
return null;
|
|
57522
|
-
return parseCodexVersionOutput(r.stdout);
|
|
57523
|
-
}
|
|
57524
|
-
function preserveLauncherRestore(recorded, found) {
|
|
57525
|
-
return found.kind === "symlink" ? found : recorded ?? found;
|
|
57526
|
-
}
|
|
57527
|
-
|
|
57528
|
-
// src/distribution/files.ts
|
|
57529
|
-
var GENERATION_EXECUTABLES = ["codex", "codex-code-mode-host"];
|
|
57530
|
-
var GENERATION_LEGAL_FILES = ["LICENSE", "NOTICE", "THIRD_PARTY_NOTICES.md"];
|
|
57531
|
-
var ARTIFACT_FILES = [...GENERATION_EXECUTABLES, ...GENERATION_LEGAL_FILES];
|
|
57532
|
-
|
|
57533
57300
|
// src/distribution/prebuilt.ts
|
|
57534
57301
|
import { createHash as createHash3 } from "node:crypto";
|
|
57535
|
-
import { chmodSync as chmodSync2, mkdirSync as
|
|
57536
|
-
import { join as
|
|
57302
|
+
import { chmodSync as chmodSync2, mkdirSync as mkdirSync3, mkdtempSync, readFileSync as readFileSync4, rmSync as rmSync2 } from "node:fs";
|
|
57303
|
+
import { join as join7 } from "node:path";
|
|
57537
57304
|
|
|
57538
57305
|
// src/patch/generation.ts
|
|
57539
|
-
import { chmodSync, copyFileSync, existsSync as
|
|
57540
|
-
import { createHash, randomBytes
|
|
57541
|
-
import { dirname as
|
|
57306
|
+
import { chmodSync, copyFileSync, existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync3, readdirSync, readlinkSync, realpathSync as realpathSync2, renameSync, rmSync, statSync, symlinkSync, writeFileSync } from "node:fs";
|
|
57307
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
57308
|
+
import { dirname as dirname5, isAbsolute, join as join5, resolve as resolve2, sep } from "node:path";
|
|
57542
57309
|
var INSTALLATION_FILE = "installation.json";
|
|
57543
57310
|
var SAFE_SEGMENT = /^[A-Za-z0-9][A-Za-z0-9._+-]*$/;
|
|
57544
57311
|
function digestOf(file2) {
|
|
57545
|
-
const buf =
|
|
57312
|
+
const buf = readFileSync3(file2);
|
|
57546
57313
|
return { sha256: createHash("sha256").update(buf).digest("hex"), size: buf.length };
|
|
57547
57314
|
}
|
|
57548
57315
|
function stamp(installedAt) {
|
|
@@ -57554,10 +57321,10 @@ function nearestExisting2(p) {
|
|
|
57554
57321
|
let cur = p;
|
|
57555
57322
|
for (;; ) {
|
|
57556
57323
|
try {
|
|
57557
|
-
|
|
57324
|
+
statSync(cur);
|
|
57558
57325
|
return cur;
|
|
57559
57326
|
} catch {
|
|
57560
|
-
const parent =
|
|
57327
|
+
const parent = dirname5(cur);
|
|
57561
57328
|
if (parent === cur)
|
|
57562
57329
|
return cur;
|
|
57563
57330
|
cur = parent;
|
|
@@ -57566,7 +57333,7 @@ function nearestExisting2(p) {
|
|
|
57566
57333
|
}
|
|
57567
57334
|
function realish(p) {
|
|
57568
57335
|
const near = nearestExisting2(p);
|
|
57569
|
-
return
|
|
57336
|
+
return realpathSync2(near) + resolve2(p).slice(resolve2(near).length);
|
|
57570
57337
|
}
|
|
57571
57338
|
function insideGenerationsRoot(paths, candidate) {
|
|
57572
57339
|
return realish(candidate).startsWith(`${realish(paths.generationsDir)}${sep}`);
|
|
@@ -57576,8 +57343,8 @@ function validateStaging(pair) {
|
|
|
57576
57343
|
throw new Error(`prepared pair has an unusable codexVersion "${pair.codexVersion}"`);
|
|
57577
57344
|
}
|
|
57578
57345
|
for (const name of GENERATION_EXECUTABLES) {
|
|
57579
|
-
const file2 =
|
|
57580
|
-
if (!
|
|
57346
|
+
const file2 = join5(pair.directory, name);
|
|
57347
|
+
if (!existsSync5(file2))
|
|
57581
57348
|
throw new Error(`staged pair is missing ${name}`);
|
|
57582
57349
|
const want = pair.provenance.executables[name];
|
|
57583
57350
|
const got = digestOf(file2);
|
|
@@ -57587,7 +57354,7 @@ function validateStaging(pair) {
|
|
|
57587
57354
|
}
|
|
57588
57355
|
if (pair.provenance.source === "prebuilt") {
|
|
57589
57356
|
for (const name of GENERATION_LEGAL_FILES) {
|
|
57590
|
-
if (!
|
|
57357
|
+
if (!existsSync5(join5(pair.directory, name)))
|
|
57591
57358
|
throw new Error(`prebuilt pair is missing ${name}`);
|
|
57592
57359
|
}
|
|
57593
57360
|
}
|
|
@@ -57597,8 +57364,8 @@ function installationRecord(pair) {
|
|
|
57597
57364
|
return record2;
|
|
57598
57365
|
}
|
|
57599
57366
|
function copyInto(from, into, name, mode, expected) {
|
|
57600
|
-
const target =
|
|
57601
|
-
copyFileSync(
|
|
57367
|
+
const target = join5(into, name);
|
|
57368
|
+
copyFileSync(join5(from, name), target);
|
|
57602
57369
|
chmodSync(target, mode);
|
|
57603
57370
|
if (!expected)
|
|
57604
57371
|
return;
|
|
@@ -57608,9 +57375,9 @@ function copyInto(from, into, name, mode, expected) {
|
|
|
57608
57375
|
}
|
|
57609
57376
|
}
|
|
57610
57377
|
function commitJson(file2, value, rename2) {
|
|
57611
|
-
const tmp =
|
|
57378
|
+
const tmp = join5(dirname5(file2), `.${process.pid}.${randomBytes(4).toString("hex")}.tmp`);
|
|
57612
57379
|
try {
|
|
57613
|
-
|
|
57380
|
+
writeFileSync(tmp, `${JSON.stringify(value, null, 2)}
|
|
57614
57381
|
`);
|
|
57615
57382
|
rename2(tmp, file2);
|
|
57616
57383
|
} catch (e) {
|
|
@@ -57619,26 +57386,26 @@ function commitJson(file2, value, rename2) {
|
|
|
57619
57386
|
}
|
|
57620
57387
|
}
|
|
57621
57388
|
function freshDirectory(pair, paths) {
|
|
57622
|
-
|
|
57389
|
+
mkdirSync2(paths.generationsDir, { recursive: true });
|
|
57623
57390
|
for (;; ) {
|
|
57624
|
-
const dir =
|
|
57625
|
-
if (
|
|
57391
|
+
const dir = join5(paths.generationsDir, `${pair.codexVersion}-${stamp(pair.provenance.installedAt)}-${randomBytes(3).toString("hex")}`);
|
|
57392
|
+
if (existsSync5(dir))
|
|
57626
57393
|
continue;
|
|
57627
|
-
|
|
57394
|
+
mkdirSync2(dir);
|
|
57628
57395
|
return dir;
|
|
57629
57396
|
}
|
|
57630
57397
|
}
|
|
57631
|
-
function createGeneration(pair, paths, rename2 =
|
|
57398
|
+
function createGeneration(pair, paths, rename2 = renameSync) {
|
|
57632
57399
|
validateStaging(pair);
|
|
57633
57400
|
const dir = freshDirectory(pair, paths);
|
|
57634
57401
|
try {
|
|
57635
57402
|
for (const name of GENERATION_EXECUTABLES)
|
|
57636
57403
|
copyInto(pair.directory, dir, name, 493, pair.provenance.executables[name]);
|
|
57637
57404
|
for (const name of GENERATION_LEGAL_FILES) {
|
|
57638
|
-
if (
|
|
57405
|
+
if (existsSync5(join5(pair.directory, name)))
|
|
57639
57406
|
copyInto(pair.directory, dir, name, 420);
|
|
57640
57407
|
}
|
|
57641
|
-
commitJson(
|
|
57408
|
+
commitJson(join5(dir, INSTALLATION_FILE), installationRecord(pair), rename2);
|
|
57642
57409
|
} catch (e) {
|
|
57643
57410
|
rmSync(dir, { recursive: true, force: true });
|
|
57644
57411
|
throw e;
|
|
@@ -57646,24 +57413,24 @@ function createGeneration(pair, paths, rename2 = renameSync2) {
|
|
|
57646
57413
|
return dir;
|
|
57647
57414
|
}
|
|
57648
57415
|
function isGenerationDir(dir) {
|
|
57649
|
-
return
|
|
57416
|
+
return existsSync5(join5(dir, INSTALLATION_FILE)) && existsSync5(join5(dir, "codex"));
|
|
57650
57417
|
}
|
|
57651
57418
|
function listGenerations(paths) {
|
|
57652
57419
|
try {
|
|
57653
|
-
return readdirSync(paths.generationsDir).map((name) =>
|
|
57420
|
+
return readdirSync(paths.generationsDir).map((name) => join5(paths.generationsDir, name)).sort();
|
|
57654
57421
|
} catch {
|
|
57655
57422
|
return [];
|
|
57656
57423
|
}
|
|
57657
57424
|
}
|
|
57658
57425
|
function readPointer(paths) {
|
|
57659
57426
|
try {
|
|
57660
|
-
return
|
|
57427
|
+
return readlinkSync(paths.currentGeneration);
|
|
57661
57428
|
} catch {
|
|
57662
57429
|
return null;
|
|
57663
57430
|
}
|
|
57664
57431
|
}
|
|
57665
|
-
function swapPointer(paths, target, rename2 =
|
|
57666
|
-
const staged = `${paths.currentGeneration}.${
|
|
57432
|
+
function swapPointer(paths, target, rename2 = renameSync) {
|
|
57433
|
+
const staged = `${paths.currentGeneration}.${randomBytes(4).toString("hex")}`;
|
|
57667
57434
|
symlinkSync(target, staged);
|
|
57668
57435
|
try {
|
|
57669
57436
|
rename2(staged, paths.currentGeneration);
|
|
@@ -57672,7 +57439,7 @@ function swapPointer(paths, target, rename2 = renameSync2) {
|
|
|
57672
57439
|
throw e;
|
|
57673
57440
|
}
|
|
57674
57441
|
}
|
|
57675
|
-
function restorePointer(paths, previous, rename2 =
|
|
57442
|
+
function restorePointer(paths, previous, rename2 = renameSync) {
|
|
57676
57443
|
if (previous === null) {
|
|
57677
57444
|
rmSync(paths.currentGeneration, { force: true });
|
|
57678
57445
|
return;
|
|
@@ -57683,11 +57450,11 @@ function activeGeneration(paths) {
|
|
|
57683
57450
|
const target = readPointer(paths);
|
|
57684
57451
|
if (target === null)
|
|
57685
57452
|
return null;
|
|
57686
|
-
const abs =
|
|
57453
|
+
const abs = isAbsolute(target) ? target : resolve2(dirname5(paths.currentGeneration), target);
|
|
57687
57454
|
if (!insideGenerationsRoot(paths, abs))
|
|
57688
57455
|
return null;
|
|
57689
57456
|
try {
|
|
57690
|
-
return
|
|
57457
|
+
return statSync(abs).isDirectory() ? abs : null;
|
|
57691
57458
|
} catch {
|
|
57692
57459
|
return null;
|
|
57693
57460
|
}
|
|
@@ -57745,7 +57512,7 @@ function readInstallation(paths) {
|
|
|
57745
57512
|
if (dir === null)
|
|
57746
57513
|
return null;
|
|
57747
57514
|
try {
|
|
57748
|
-
const raw = JSON.parse(
|
|
57515
|
+
const raw = JSON.parse(readFileSync3(join5(dir, INSTALLATION_FILE), "utf8"));
|
|
57749
57516
|
return checkedRecord(raw);
|
|
57750
57517
|
} catch {
|
|
57751
57518
|
return null;
|
|
@@ -57754,7 +57521,7 @@ function readInstallation(paths) {
|
|
|
57754
57521
|
|
|
57755
57522
|
// src/distribution/archive.ts
|
|
57756
57523
|
import { createReadStream, createWriteStream } from "node:fs";
|
|
57757
|
-
import { join as
|
|
57524
|
+
import { join as join6 } from "node:path";
|
|
57758
57525
|
import { createGunzip } from "node:zlib";
|
|
57759
57526
|
|
|
57760
57527
|
// node_modules/tar/dist/esm/index.min.js
|
|
@@ -60985,7 +60752,7 @@ var EXTRACTED_TOTAL_LIMIT = 2 * 1024 * 1024 * 1024;
|
|
|
60985
60752
|
var LEGAL_TOTAL_LIMIT = 16 * 1024 * 1024;
|
|
60986
60753
|
var EXECUTABLE_MODE = 493;
|
|
60987
60754
|
var LEGAL_MODE = 420;
|
|
60988
|
-
function
|
|
60755
|
+
function isExecutable(name) {
|
|
60989
60756
|
return GENERATION_EXECUTABLES.includes(name);
|
|
60990
60757
|
}
|
|
60991
60758
|
function quoteName(name) {
|
|
@@ -61009,7 +60776,7 @@ function rejectionReason(entry, seen, budget) {
|
|
|
61009
60776
|
const size2 = entry.size;
|
|
61010
60777
|
if (!Number.isSafeInteger(size2) || size2 < 0)
|
|
61011
60778
|
return `archive entry ${quoteName(name)} declares an unusable size`;
|
|
61012
|
-
const executable =
|
|
60779
|
+
const executable = isExecutable(name);
|
|
61013
60780
|
if (executable && size2 === 0)
|
|
61014
60781
|
return `archive entry ${quoteName(name)} is an empty executable`;
|
|
61015
60782
|
const mode = entry.mode ?? entry.header.mode ?? 0;
|
|
@@ -61028,9 +60795,9 @@ function rejectionReason(entry, seen, budget) {
|
|
|
61028
60795
|
}
|
|
61029
60796
|
function writeEntry(entry, staging) {
|
|
61030
60797
|
const name = entry.path;
|
|
61031
|
-
const mode =
|
|
61032
|
-
const sink = createWriteStream(
|
|
61033
|
-
const done = new Promise((
|
|
60798
|
+
const mode = isExecutable(name) ? EXECUTABLE_MODE : LEGAL_MODE;
|
|
60799
|
+
const sink = createWriteStream(join6(staging, name), { mode, flags: "wx" });
|
|
60800
|
+
const done = new Promise((resolve3, reject2) => {
|
|
61034
60801
|
sink.on("error", reject2);
|
|
61035
60802
|
entry.on("error", reject2);
|
|
61036
60803
|
sink.on("finish", () => {
|
|
@@ -61038,7 +60805,7 @@ function writeEntry(entry, staging) {
|
|
|
61038
60805
|
reject2(new Error(`archive entry ${quoteName(name)} ended after ${sink.bytesWritten} of ${entry.size} bytes`));
|
|
61039
60806
|
return;
|
|
61040
60807
|
}
|
|
61041
|
-
|
|
60808
|
+
resolve3();
|
|
61042
60809
|
});
|
|
61043
60810
|
entry.pipe(sink);
|
|
61044
60811
|
});
|
|
@@ -61053,7 +60820,7 @@ function writeEntry(entry, staging) {
|
|
|
61053
60820
|
function parseArchive(archivePath, staging, writes) {
|
|
61054
60821
|
const seen = new Set;
|
|
61055
60822
|
const budget = { total: 0, legal: 0 };
|
|
61056
|
-
return new Promise((
|
|
60823
|
+
return new Promise((resolve3, reject2) => {
|
|
61057
60824
|
const source = createReadStream(archivePath);
|
|
61058
60825
|
const gunzip = createGunzip();
|
|
61059
60826
|
let settled = false;
|
|
@@ -61095,7 +60862,7 @@ function parseArchive(archivePath, staging, writes) {
|
|
|
61095
60862
|
reject2(new Error(`archive is missing ${missing.join(", ")}`));
|
|
61096
60863
|
return;
|
|
61097
60864
|
}
|
|
61098
|
-
|
|
60865
|
+
resolve3();
|
|
61099
60866
|
});
|
|
61100
60867
|
source.pipe(gunzip).pipe(parser);
|
|
61101
60868
|
});
|
|
@@ -61113,9 +60880,9 @@ async function extractArchive(archivePath, staging) {
|
|
|
61113
60880
|
|
|
61114
60881
|
// src/distribution/transport.ts
|
|
61115
60882
|
import { createHash as createHash2 } from "node:crypto";
|
|
61116
|
-
import { createReadStream as createReadStream2, existsSync as
|
|
60883
|
+
import { createReadStream as createReadStream2, existsSync as existsSync6 } from "node:fs";
|
|
61117
60884
|
import { open as open2 } from "node:fs/promises";
|
|
61118
|
-
import { dirname as
|
|
60885
|
+
import { dirname as dirname6 } from "node:path";
|
|
61119
60886
|
var PUBLIC_BASE = "https://github.com/adrijshikhar/cxstatusline/releases/download";
|
|
61120
60887
|
var REPO = "adrijshikhar/cxstatusline";
|
|
61121
60888
|
var MAX_REDIRECTS = 5;
|
|
@@ -61157,7 +60924,7 @@ function nextUrl(current, location, allowHttp, asset) {
|
|
|
61157
60924
|
}
|
|
61158
60925
|
return resolved.toString();
|
|
61159
60926
|
}
|
|
61160
|
-
async function streamToFile(response, dest, maxBytes, asset) {
|
|
60927
|
+
async function streamToFile(response, dest, maxBytes, asset, onProgress) {
|
|
61161
60928
|
const declared = response.headers.get("content-length");
|
|
61162
60929
|
const expected = declared === null ? null : Number(declared);
|
|
61163
60930
|
if (expected !== null && (!Number.isSafeInteger(expected) || expected < 0 || expected > maxBytes)) {
|
|
@@ -61180,6 +60947,7 @@ async function streamToFile(response, dest, maxBytes, asset) {
|
|
|
61180
60947
|
throw new Error(`${asset} is larger than the ${maxBytes}-byte limit`);
|
|
61181
60948
|
hash2.update(value);
|
|
61182
60949
|
await handle.write(value);
|
|
60950
|
+
onProgress?.(size2, expected);
|
|
61183
60951
|
}
|
|
61184
60952
|
} finally {
|
|
61185
60953
|
await handle.close();
|
|
@@ -61210,7 +60978,7 @@ async function httpDownload(start, asset, dest, maxBytes, opts) {
|
|
|
61210
60978
|
return "not-found";
|
|
61211
60979
|
if (!response.ok)
|
|
61212
60980
|
throw new Error(`download of ${asset} failed with HTTP ${response.status}`);
|
|
61213
|
-
return await streamToFile(response, dest, maxBytes, asset);
|
|
60981
|
+
return await streamToFile(response, dest, maxBytes, asset, opts.onProgress);
|
|
61214
60982
|
}
|
|
61215
60983
|
throw new Error(`download of ${asset} exceeded ${MAX_REDIRECTS} redirects`);
|
|
61216
60984
|
}
|
|
@@ -61230,7 +60998,7 @@ async function ghDownload(ctx, tag, asset, dest, maxBytes) {
|
|
|
61230
60998
|
if (ctx.which("gh") === null) {
|
|
61231
60999
|
throw new GhMissingError(`${asset} is not public for release ${tag} and GitHub CLI (gh) is not installed`);
|
|
61232
61000
|
}
|
|
61233
|
-
const result2 = ctx.run("gh", ["release", "download", tag, "--repo", REPO, "--pattern", asset, "--dir",
|
|
61001
|
+
const result2 = ctx.run("gh", ["release", "download", tag, "--repo", REPO, "--pattern", asset, "--dir", dirname6(dest)], { timeoutMs: GH_TIMEOUT_MS });
|
|
61234
61002
|
if (result2.status !== 0) {
|
|
61235
61003
|
const detail = sanitize(result2.stderr || result2.stdout);
|
|
61236
61004
|
if (/auth|logged in|log in|login|credential/i.test(detail)) {
|
|
@@ -61238,7 +61006,7 @@ async function ghDownload(ctx, tag, asset, dest, maxBytes) {
|
|
|
61238
61006
|
}
|
|
61239
61007
|
throw new ReleaseUnavailableError(`release ${tag} not found or access denied: ${detail}`);
|
|
61240
61008
|
}
|
|
61241
|
-
if (!
|
|
61009
|
+
if (!existsSync6(dest))
|
|
61242
61010
|
throw new ReleaseUnavailableError(`release ${tag} not found or access denied: gh downloaded no ${asset}`);
|
|
61243
61011
|
return await hashFile(dest, maxBytes, asset);
|
|
61244
61012
|
}
|
|
@@ -61254,15 +61022,15 @@ async function downloadAsset(ctx, tag, asset, dest, maxBytes, opts = {}) {
|
|
|
61254
61022
|
var MANIFEST_ASSET = "manifest.json";
|
|
61255
61023
|
var PROBE_TIMEOUT_MS = 30000;
|
|
61256
61024
|
function digestOf2(file2) {
|
|
61257
|
-
const bytes =
|
|
61025
|
+
const bytes = readFileSync4(file2);
|
|
61258
61026
|
return { sha256: createHash3("sha256").update(bytes).digest("hex"), size: bytes.length };
|
|
61259
61027
|
}
|
|
61260
61028
|
function sameDigest(a, b2) {
|
|
61261
61029
|
return a.sha256 === b2.sha256 && a.size === b2.size;
|
|
61262
61030
|
}
|
|
61263
61031
|
function privateTemp(ctx, prefix) {
|
|
61264
|
-
|
|
61265
|
-
const dir = mkdtempSync(
|
|
61032
|
+
mkdirSync3(ctx.paths.libexecDir, { recursive: true });
|
|
61033
|
+
const dir = mkdtempSync(join7(ctx.paths.libexecDir, prefix));
|
|
61266
61034
|
chmodSync2(dir, 448);
|
|
61267
61035
|
return dir;
|
|
61268
61036
|
}
|
|
@@ -61288,7 +61056,7 @@ function unchangedPair(ctx, manifest, artifact, tag) {
|
|
|
61288
61056
|
return null;
|
|
61289
61057
|
for (const name of ARTIFACT_FILES) {
|
|
61290
61058
|
try {
|
|
61291
|
-
if (!sameDigest(digestOf2(
|
|
61059
|
+
if (!sameDigest(digestOf2(join7(directory, name)), artifact.files[name]))
|
|
61292
61060
|
return null;
|
|
61293
61061
|
} catch {
|
|
61294
61062
|
return null;
|
|
@@ -61299,7 +61067,7 @@ function unchangedPair(ctx, manifest, artifact, tag) {
|
|
|
61299
61067
|
function verifyStaged(staging, artifact) {
|
|
61300
61068
|
const digests = {};
|
|
61301
61069
|
for (const name of ARTIFACT_FILES) {
|
|
61302
|
-
const got = digestOf2(
|
|
61070
|
+
const got = digestOf2(join7(staging, name));
|
|
61303
61071
|
if (!sameDigest(got, artifact.files[name])) {
|
|
61304
61072
|
throw new Error(`staged ${name} does not match the release manifest sha256`);
|
|
61305
61073
|
}
|
|
@@ -61311,7 +61079,7 @@ function verifyStaged(staging, artifact) {
|
|
|
61311
61079
|
};
|
|
61312
61080
|
}
|
|
61313
61081
|
function probeVersion(ctx, staging, codexVersion) {
|
|
61314
|
-
const probe = ctx.run(
|
|
61082
|
+
const probe = ctx.run(join7(staging, "codex"), ["--version"], { timeoutMs: PROBE_TIMEOUT_MS });
|
|
61315
61083
|
const reported = sanitize((probe.stdout || probe.stderr).slice(0, 512));
|
|
61316
61084
|
if (probe.status !== 0 || reported !== `codex-cli ${codexVersion}`) {
|
|
61317
61085
|
throw new Error(`staged codex reported version "${reported}" instead of "codex-cli ${codexVersion}"`);
|
|
@@ -61338,15 +61106,20 @@ function stagedPair(ctx, staging, manifest, artifact, tag) {
|
|
|
61338
61106
|
};
|
|
61339
61107
|
}
|
|
61340
61108
|
async function stageArchive(ctx, download, manifest, artifact, tag, opts) {
|
|
61341
|
-
const archive =
|
|
61109
|
+
const archive = join7(download, artifact.filename);
|
|
61110
|
+
opts.onStatus?.("download", `Downloading prebuilt archive (${artifact.filename})...`);
|
|
61342
61111
|
const got = await downloadAsset(ctx, tag, artifact.filename, archive, ARCHIVE_MAX_BYTES, opts);
|
|
61343
61112
|
if (got.sha256 !== artifact.sha256 || got.size !== artifact.size) {
|
|
61344
61113
|
throw new Error(`${artifact.filename} does not match the release manifest sha256`);
|
|
61345
61114
|
}
|
|
61115
|
+
opts.onStatus?.("download-done", `Downloaded ${artifact.filename}`);
|
|
61346
61116
|
const staging = privateTemp(ctx, "staging-");
|
|
61347
61117
|
try {
|
|
61118
|
+
opts.onStatus?.("extract", "Extracting and verifying executables...");
|
|
61348
61119
|
await extractArchive(archive, staging);
|
|
61349
|
-
|
|
61120
|
+
const pair = stagedPair(ctx, staging, manifest, artifact, tag);
|
|
61121
|
+
opts.onStatus?.("extract-done", "Verified executables (codex, codex-code-mode-host)");
|
|
61122
|
+
return pair;
|
|
61350
61123
|
} catch (e) {
|
|
61351
61124
|
rmSync2(staging, { recursive: true, force: true });
|
|
61352
61125
|
throw e;
|
|
@@ -61354,12 +61127,14 @@ async function stageArchive(ctx, download, manifest, artifact, tag, opts) {
|
|
|
61354
61127
|
}
|
|
61355
61128
|
async function preparePrebuilt(ctx, expected, opts = {}) {
|
|
61356
61129
|
const tag = releaseTag(expected.cxVersion, expected.codexVersion);
|
|
61130
|
+
opts.onStatus?.("manifest", `Checking release ${tag} for ${expected.platform}...`);
|
|
61357
61131
|
const download = privateTemp(ctx, "download-");
|
|
61358
61132
|
try {
|
|
61359
|
-
const manifestFile =
|
|
61133
|
+
const manifestFile = join7(download, MANIFEST_ASSET);
|
|
61360
61134
|
await downloadAsset(ctx, tag, MANIFEST_ASSET, manifestFile, MANIFEST_MAX_BYTES, opts);
|
|
61361
|
-
const manifest = validateManifest(JSON.parse(
|
|
61135
|
+
const manifest = validateManifest(JSON.parse(readFileSync4(manifestFile, "utf8")), expected);
|
|
61362
61136
|
const artifact = artifactFor(manifest, expected);
|
|
61137
|
+
opts.onStatus?.("manifest-done", `Found release for Codex ${manifest.codexVersion} (${artifact.platform})`);
|
|
61363
61138
|
const unchanged = unchangedPair(ctx, manifest, artifact, tag);
|
|
61364
61139
|
if (unchanged !== null)
|
|
61365
61140
|
return { kind: "unchanged", pair: unchanged };
|
|
@@ -61474,67 +61249,354 @@ function validateManifest(raw, expected) {
|
|
|
61474
61249
|
return structural.data;
|
|
61475
61250
|
}
|
|
61476
61251
|
|
|
61477
|
-
// src/
|
|
61478
|
-
import {
|
|
61479
|
-
import {
|
|
61480
|
-
|
|
61481
|
-
|
|
61482
|
-
|
|
61483
|
-
|
|
61484
|
-
|
|
61485
|
-
|
|
61486
|
-
class BuildError extends Error {
|
|
61487
|
-
step;
|
|
61488
|
-
name = "BuildError";
|
|
61489
|
-
constructor(step, detail) {
|
|
61490
|
-
super(`${step}: ${detail.trim() || "failed"}`);
|
|
61491
|
-
this.step = step;
|
|
61252
|
+
// src/codex/upstream.ts
|
|
61253
|
+
import { accessSync as accessSync2, constants as constants3, lstatSync, readlinkSync as readlinkSync2, realpathSync as realpathSync3, statSync as statSync2 } from "node:fs";
|
|
61254
|
+
import { dirname as dirname7, isAbsolute as isAbsolute2, join as join8, resolve as resolve3 } from "node:path";
|
|
61255
|
+
function isExecutable2(p2) {
|
|
61256
|
+
try {
|
|
61257
|
+
accessSync2(p2, constants3.X_OK);
|
|
61258
|
+
return statSync2(p2).isFile();
|
|
61259
|
+
} catch {
|
|
61260
|
+
return false;
|
|
61492
61261
|
}
|
|
61493
61262
|
}
|
|
61494
|
-
|
|
61495
|
-
|
|
61496
|
-
|
|
61497
|
-
|
|
61498
|
-
|
|
61499
|
-
|
|
61500
|
-
|
|
61501
|
-
...["status-0", "status-1", "status-2", "esc esc to edit previous message"].map((s3) => `" ${s3.padEnd(78)}"`),
|
|
61502
|
-
""
|
|
61503
|
-
].join(`
|
|
61504
|
-
`);
|
|
61505
|
-
var TARGETS = ["codex", "codex-code-mode-host"];
|
|
61506
|
-
var HEX403 = /^[0-9a-f]{40}$/;
|
|
61507
|
-
function must(step, run, log, cmd, args, cwd2) {
|
|
61508
|
-
log(`$ ${[cmd, ...args].join(" ")}`);
|
|
61509
|
-
const r = run(cmd, args, cwd2 ? { cwd: cwd2 } : undefined);
|
|
61510
|
-
for (const line of `${r.stdout}${r.stderr}`.split(`
|
|
61511
|
-
`).filter(Boolean))
|
|
61512
|
-
log(line);
|
|
61513
|
-
if (r.status !== 0)
|
|
61514
|
-
throw new BuildError(step, r.stderr || r.stdout);
|
|
61515
|
-
}
|
|
61516
|
-
function runFocusedTests(run, log, which, crateDir) {
|
|
61517
|
-
if (which("just")) {
|
|
61518
|
-
log("running the focused Rust tests with just");
|
|
61519
|
-
must("just test", run, log, "just", ["test", "--release", "-p", "codex-tui", "cxstatusline", "--retries", "0"], crateDir);
|
|
61520
|
-
return;
|
|
61263
|
+
function isManaged(p2, paths, isOurWrapper) {
|
|
61264
|
+
if (resolve3(p2) === resolve3(paths.patchedBin) || isOurWrapper(p2))
|
|
61265
|
+
return true;
|
|
61266
|
+
try {
|
|
61267
|
+
return realpathSync3(p2) === realpathSync3(paths.patchedBin);
|
|
61268
|
+
} catch {
|
|
61269
|
+
return false;
|
|
61521
61270
|
}
|
|
61522
|
-
log("just is not on PATH; running the focused Rust tests with cargo");
|
|
61523
|
-
must("cargo test", run, log, "cargo", ["test", "--release", "-p", "codex-tui", "cxstatusline"], crateDir);
|
|
61524
61271
|
}
|
|
61525
|
-
function
|
|
61526
|
-
|
|
61527
|
-
|
|
61528
|
-
|
|
61529
|
-
|
|
61272
|
+
function inspectLauncher(paths, isOurWrapper) {
|
|
61273
|
+
let st2;
|
|
61274
|
+
try {
|
|
61275
|
+
st2 = lstatSync(paths.wrapperPath);
|
|
61276
|
+
} catch {
|
|
61277
|
+
return null;
|
|
61530
61278
|
}
|
|
61531
|
-
|
|
61532
|
-
|
|
61533
|
-
|
|
61279
|
+
if (st2.isSymbolicLink()) {
|
|
61280
|
+
const raw = readlinkSync2(paths.wrapperPath);
|
|
61281
|
+
const target = isAbsolute2(raw) ? raw : resolve3(dirname7(paths.wrapperPath), raw);
|
|
61282
|
+
if (isManaged(target, paths, isOurWrapper))
|
|
61283
|
+
return null;
|
|
61284
|
+
return { kind: "found", bin: target, launcher_restore: { kind: "symlink", target } };
|
|
61285
|
+
}
|
|
61286
|
+
if (isOurWrapper(paths.wrapperPath))
|
|
61287
|
+
return null;
|
|
61288
|
+
return { kind: "foreign", path: paths.wrapperPath };
|
|
61289
|
+
}
|
|
61290
|
+
function walkPath(paths, env3, isOurWrapper) {
|
|
61291
|
+
for (const dir of (env3.PATH ?? "").split(":").filter(Boolean)) {
|
|
61292
|
+
if (resolve3(dir) === resolve3(paths.binDir))
|
|
61293
|
+
continue;
|
|
61294
|
+
const candidate = join8(dir, "codex");
|
|
61295
|
+
if (isExecutable2(candidate) && !isManaged(candidate, paths, isOurWrapper))
|
|
61296
|
+
return candidate;
|
|
61297
|
+
}
|
|
61298
|
+
return null;
|
|
61299
|
+
}
|
|
61300
|
+
function resolveUpstream(paths, env3, isOurWrapper, savedBin) {
|
|
61301
|
+
const launcher = inspectLauncher(paths, isOurWrapper);
|
|
61302
|
+
if (launcher)
|
|
61303
|
+
return launcher;
|
|
61304
|
+
const current = walkPath(paths, env3, isOurWrapper);
|
|
61305
|
+
const bin = current ?? (savedBin && isExecutable2(savedBin) && !isManaged(savedBin, paths, isOurWrapper) ? savedBin : null);
|
|
61306
|
+
return bin ? { kind: "found", bin, launcher_restore: { kind: "none" } } : { kind: "not-found" };
|
|
61307
|
+
}
|
|
61308
|
+
function describeLookup(l) {
|
|
61309
|
+
switch (l.kind) {
|
|
61310
|
+
case "found":
|
|
61311
|
+
return l.bin;
|
|
61312
|
+
case "foreign":
|
|
61313
|
+
return `${l.path} is a real file we did not write; refusing to overwrite it`;
|
|
61314
|
+
case "not-found":
|
|
61315
|
+
return "no upstream Codex found (nothing named codex on PATH outside ~/.local/bin, and the launcher there is not a symlink)";
|
|
61316
|
+
}
|
|
61317
|
+
}
|
|
61318
|
+
function readUpstreamVersion(bin, run) {
|
|
61319
|
+
const r = run(bin, ["--version"]);
|
|
61320
|
+
if (r.status !== 0)
|
|
61321
|
+
return null;
|
|
61322
|
+
return parseCodexVersionOutput(r.stdout);
|
|
61323
|
+
}
|
|
61324
|
+
function preserveLauncherRestore(recorded, found) {
|
|
61325
|
+
return found.kind === "symlink" ? found : recorded ?? found;
|
|
61326
|
+
}
|
|
61327
|
+
|
|
61328
|
+
// src/hook/install.ts
|
|
61329
|
+
import { existsSync as existsSync7, readFileSync as readFileSync5 } from "node:fs";
|
|
61330
|
+
|
|
61331
|
+
// src/atomic.ts
|
|
61332
|
+
import { mkdirSync as mkdirSync4, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
61333
|
+
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
61334
|
+
import { dirname as dirname8, join as join9 } from "node:path";
|
|
61335
|
+
function writeFileAtomic(file2, text) {
|
|
61336
|
+
mkdirSync4(dirname8(file2), { recursive: true });
|
|
61337
|
+
const tmp = join9(dirname8(file2), `.${process.pid}.${randomBytes2(4).toString("hex")}.tmp`);
|
|
61338
|
+
writeFileSync2(tmp, text);
|
|
61339
|
+
renameSync2(tmp, file2);
|
|
61340
|
+
}
|
|
61341
|
+
|
|
61342
|
+
// src/sh.ts
|
|
61343
|
+
var sq = (s3) => `'${s3.replace(/'/g, `'"'"'`)}'`;
|
|
61344
|
+
|
|
61345
|
+
// src/hook/install.ts
|
|
61346
|
+
var HOOK_STATUS_MESSAGE = "cxstatusline: checking Codex version";
|
|
61347
|
+
var HOOK_TIMEOUT_SEC = 10;
|
|
61348
|
+
var hookCommand = (cxBin) => `${sq(cxBin)} hook`;
|
|
61349
|
+
function hookEntry(cxBin) {
|
|
61350
|
+
return { hooks: [{ type: "command", command: hookCommand(cxBin), timeout: HOOK_TIMEOUT_SEC, statusMessage: HOOK_STATUS_MESSAGE }] };
|
|
61351
|
+
}
|
|
61352
|
+
var isOurGroup = (g2) => g2.hooks.some((h) => h.statusMessage === HOOK_STATUS_MESSAGE);
|
|
61353
|
+
var sameJson = (a, b2) => JSON.stringify(a) === JSON.stringify(b2);
|
|
61354
|
+
function mergeHook(file2, cxBin) {
|
|
61355
|
+
const base2 = file2 ?? { hooks: {} };
|
|
61356
|
+
const entry = hookEntry(cxBin);
|
|
61357
|
+
const groups = base2.hooks.SessionStart ?? [];
|
|
61358
|
+
const idx = groups.findIndex(isOurGroup);
|
|
61359
|
+
if (idx !== -1 && sameJson(groups[idx], entry))
|
|
61360
|
+
return { file: base2, changed: false };
|
|
61361
|
+
const next = idx === -1 ? [...groups, entry] : groups.map((g2, i) => i === idx ? entry : g2);
|
|
61362
|
+
return { file: { ...base2, hooks: { ...base2.hooks, SessionStart: next } }, changed: true };
|
|
61363
|
+
}
|
|
61364
|
+
function removeHook(file2) {
|
|
61365
|
+
const groups = file2.hooks.SessionStart ?? [];
|
|
61366
|
+
const kept = groups.filter((g2) => !isOurGroup(g2));
|
|
61367
|
+
if (kept.length === groups.length)
|
|
61368
|
+
return { file: file2, changed: false };
|
|
61369
|
+
const { SessionStart: _dropped, ...rest2 } = file2.hooks;
|
|
61370
|
+
const hooks = kept.length === 0 ? rest2 : { ...rest2, SessionStart: kept };
|
|
61371
|
+
return { file: { ...file2, hooks }, changed: true };
|
|
61372
|
+
}
|
|
61373
|
+
function readHooksFile(path) {
|
|
61374
|
+
if (!existsSync7(path))
|
|
61375
|
+
return null;
|
|
61376
|
+
let raw;
|
|
61377
|
+
try {
|
|
61378
|
+
raw = JSON.parse(readFileSync5(path, "utf8"));
|
|
61379
|
+
} catch {
|
|
61380
|
+
throw new Error(`${path}: hooks.json is not valid JSON; fix it by hand before installing the hook`);
|
|
61381
|
+
}
|
|
61382
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw))
|
|
61383
|
+
throw new Error(`${path}: hooks.json must be a JSON object`);
|
|
61384
|
+
const o = raw;
|
|
61385
|
+
if (o.hooks !== undefined && (typeof o.hooks !== "object" || o.hooks === null))
|
|
61386
|
+
throw new Error(`${path}: "hooks" must be an object`);
|
|
61387
|
+
return { ...raw, hooks: o.hooks ?? {} };
|
|
61388
|
+
}
|
|
61389
|
+
function installHook(hooksFile, cxBin) {
|
|
61390
|
+
const { file: file2, changed } = mergeHook(readHooksFile(hooksFile), cxBin);
|
|
61391
|
+
if (!changed)
|
|
61392
|
+
return "unchanged";
|
|
61393
|
+
writeFileAtomic(hooksFile, `${JSON.stringify(file2, null, 2)}
|
|
61394
|
+
`);
|
|
61395
|
+
return "added";
|
|
61396
|
+
}
|
|
61397
|
+
function uninstallHook(hooksFile) {
|
|
61398
|
+
const current = readHooksFile(hooksFile);
|
|
61399
|
+
if (!current)
|
|
61400
|
+
return "absent";
|
|
61401
|
+
const { file: file2, changed } = removeHook(current);
|
|
61402
|
+
if (!changed)
|
|
61403
|
+
return "absent";
|
|
61404
|
+
writeFileAtomic(hooksFile, `${JSON.stringify(file2, null, 2)}
|
|
61405
|
+
`);
|
|
61406
|
+
return "removed";
|
|
61407
|
+
}
|
|
61408
|
+
|
|
61409
|
+
// src/state.ts
|
|
61410
|
+
import { existsSync as existsSync8, readFileSync as readFileSync6 } from "node:fs";
|
|
61411
|
+
var RELEASE_UNAVAILABLE = "release-unavailable";
|
|
61412
|
+
var RELEASE_RETRY_AFTER_MS = 24 * 60 * 60 * 1000;
|
|
61413
|
+
var DEFAULT_STATE = {
|
|
61414
|
+
version: 1,
|
|
61415
|
+
policy: "stable-minors",
|
|
61416
|
+
patched_from: null,
|
|
61417
|
+
upstream_bin: null,
|
|
61418
|
+
launcher_restore: null,
|
|
61419
|
+
last_attempt: null
|
|
61420
|
+
};
|
|
61421
|
+
var BACKUP_SUFFIX = ".bak";
|
|
61422
|
+
var isObj2 = (v2) => typeof v2 === "object" && v2 !== null && !Array.isArray(v2);
|
|
61423
|
+
var strOrNull = (v2) => v2 === null || typeof v2 === "string" ? v2 : undefined;
|
|
61424
|
+
function restore(v2) {
|
|
61425
|
+
if (v2 === null)
|
|
61426
|
+
return null;
|
|
61427
|
+
if (!isObj2(v2))
|
|
61428
|
+
return;
|
|
61429
|
+
if (v2.kind === "none")
|
|
61430
|
+
return { kind: "none" };
|
|
61431
|
+
if (v2.kind === "symlink" && typeof v2.target === "string")
|
|
61432
|
+
return { kind: "symlink", target: v2.target };
|
|
61433
|
+
return;
|
|
61434
|
+
}
|
|
61435
|
+
function attempt2(v2) {
|
|
61436
|
+
if (v2 === null)
|
|
61437
|
+
return null;
|
|
61438
|
+
if (!isObj2(v2) || typeof v2.at !== "string" || typeof v2.ok !== "boolean" || typeof v2.version !== "string")
|
|
61439
|
+
return;
|
|
61440
|
+
return typeof v2.reason === "string" ? { at: v2.at, ok: v2.ok, version: v2.version, reason: v2.reason } : { at: v2.at, ok: v2.ok, version: v2.version };
|
|
61441
|
+
}
|
|
61442
|
+
function validate3(raw) {
|
|
61443
|
+
if (!isObj2(raw) || raw.version !== 1)
|
|
61444
|
+
return null;
|
|
61445
|
+
const policy = POLICIES.includes(String(raw.policy)) ? raw.policy : undefined;
|
|
61446
|
+
const patched_from = strOrNull(raw.patched_from);
|
|
61447
|
+
const upstream_bin = strOrNull(raw.upstream_bin);
|
|
61448
|
+
const launcher_restore = restore(raw.launcher_restore);
|
|
61449
|
+
const last_attempt = attempt2(raw.last_attempt);
|
|
61450
|
+
if (policy === undefined || patched_from === undefined || upstream_bin === undefined || launcher_restore === undefined || last_attempt === undefined)
|
|
61451
|
+
return null;
|
|
61452
|
+
return { version: 1, policy, patched_from, upstream_bin, launcher_restore, last_attempt };
|
|
61453
|
+
}
|
|
61454
|
+
function readValidated(file2) {
|
|
61455
|
+
if (!existsSync8(file2))
|
|
61456
|
+
return null;
|
|
61457
|
+
try {
|
|
61458
|
+
return validate3(JSON.parse(readFileSync6(file2, "utf8")));
|
|
61459
|
+
} catch {
|
|
61460
|
+
return null;
|
|
61461
|
+
}
|
|
61462
|
+
}
|
|
61463
|
+
function readState(file2) {
|
|
61464
|
+
if (!existsSync8(file2) && !existsSync8(`${file2}${BACKUP_SUFFIX}`)) {
|
|
61465
|
+
return { state: DEFAULT_STATE, corrupt: false };
|
|
61466
|
+
}
|
|
61467
|
+
const primary = readValidated(file2);
|
|
61468
|
+
if (primary)
|
|
61469
|
+
return { state: primary, corrupt: false };
|
|
61470
|
+
const backup = readValidated(`${file2}${BACKUP_SUFFIX}`);
|
|
61471
|
+
return backup ? { state: backup, corrupt: true } : { state: DEFAULT_STATE, corrupt: true };
|
|
61472
|
+
}
|
|
61473
|
+
function writeState(file2, state) {
|
|
61474
|
+
const text = `${JSON.stringify(state, null, 2)}
|
|
61475
|
+
`;
|
|
61476
|
+
writeFileAtomic(file2, text);
|
|
61477
|
+
writeFileAtomic(`${file2}${BACKUP_SUFFIX}`, text);
|
|
61478
|
+
}
|
|
61479
|
+
|
|
61480
|
+
// src/patch/acquire.ts
|
|
61481
|
+
import { rmSync as rmSync5 } from "node:fs";
|
|
61482
|
+
|
|
61483
|
+
// src/patch/compile.ts
|
|
61484
|
+
import { chmodSync as chmodSync3, copyFileSync as copyFileSync2, mkdirSync as mkdirSync5, mkdtempSync as mkdtempSync2, readFileSync as readFileSync8, rmSync as rmSync3, statSync as statSync4 } from "node:fs";
|
|
61485
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
61486
|
+
import { join as join12 } from "node:path";
|
|
61487
|
+
|
|
61488
|
+
// src/patch/build.ts
|
|
61489
|
+
import { existsSync as existsSync10, lstatSync as lstatSync2, readFileSync as readFileSync7, statSync as statSync3 } from "node:fs";
|
|
61490
|
+
import { join as join11 } from "node:path";
|
|
61491
|
+
|
|
61492
|
+
// src/patch/v8.ts
|
|
61493
|
+
import { existsSync as existsSync9 } from "node:fs";
|
|
61494
|
+
import { join as join10 } from "node:path";
|
|
61495
|
+
function defaultV8Target() {
|
|
61496
|
+
const isArm = process.arch === "arm64";
|
|
61497
|
+
if (process.platform === "darwin")
|
|
61498
|
+
return isArm ? "aarch64-apple-darwin" : "x86_64-apple-darwin";
|
|
61499
|
+
if (process.platform === "linux")
|
|
61500
|
+
return isArm ? "aarch64-unknown-linux-gnu" : "x86_64-unknown-linux-gnu";
|
|
61501
|
+
return isArm ? "aarch64-pc-windows-msvc" : "x86_64-pc-windows-msvc";
|
|
61502
|
+
}
|
|
61503
|
+
var PYTHON_RESOLVE_SCRIPT = [
|
|
61504
|
+
"import json, os, sys",
|
|
61505
|
+
"repo = sys.argv[1]",
|
|
61506
|
+
"target = sys.argv[2]",
|
|
61507
|
+
"os.environ['CODEX_REPO_ROOT'] = repo",
|
|
61508
|
+
"sys.path.insert(0, repo)",
|
|
61509
|
+
"from scripts.codex_package.targets import TARGET_SPECS",
|
|
61510
|
+
"from scripts.codex_package.v8 import resolve_codex_v8_cargo_env",
|
|
61511
|
+
"spec = TARGET_SPECS.get(target)",
|
|
61512
|
+
"if spec:",
|
|
61513
|
+
" print(json.dumps(resolve_codex_v8_cargo_env(spec)))",
|
|
61514
|
+
"else:",
|
|
61515
|
+
" print('{}')"
|
|
61516
|
+
].join(`
|
|
61517
|
+
`);
|
|
61518
|
+
function resolveV8Env(sourceDir, run, log) {
|
|
61519
|
+
if (process.env.RUSTY_V8_ARCHIVE && process.env.RUSTY_V8_SRC_BINDING_PATH) {
|
|
61520
|
+
return {
|
|
61521
|
+
RUSTY_V8_ARCHIVE: process.env.RUSTY_V8_ARCHIVE,
|
|
61522
|
+
RUSTY_V8_SRC_BINDING_PATH: process.env.RUSTY_V8_SRC_BINDING_PATH
|
|
61523
|
+
};
|
|
61524
|
+
}
|
|
61525
|
+
const v8Script = join10(sourceDir, "scripts", "codex_package", "v8.py");
|
|
61526
|
+
if (!existsSync9(v8Script)) {
|
|
61527
|
+
return {};
|
|
61528
|
+
}
|
|
61529
|
+
const target = defaultV8Target();
|
|
61530
|
+
log(`resolving Codex V8 dependencies for ${target}...`);
|
|
61531
|
+
for (const py of ["python3", "python"]) {
|
|
61532
|
+
const r = run(py, ["-c", PYTHON_RESOLVE_SCRIPT, sourceDir, target], { cwd: sourceDir });
|
|
61533
|
+
if (r.status === 0 && r.stdout.trim()) {
|
|
61534
|
+
try {
|
|
61535
|
+
const parsed = JSON.parse(r.stdout.trim());
|
|
61536
|
+
if (parsed.RUSTY_V8_ARCHIVE && parsed.RUSTY_V8_SRC_BINDING_PATH) {
|
|
61537
|
+
log(`using Codex V8 archive: ${parsed.RUSTY_V8_ARCHIVE}`);
|
|
61538
|
+
return parsed;
|
|
61539
|
+
}
|
|
61540
|
+
} catch {}
|
|
61541
|
+
}
|
|
61542
|
+
}
|
|
61543
|
+
log("warning: could not resolve Codex V8 dependencies via python; build may fail if V8 prebuilts are needed");
|
|
61544
|
+
return {};
|
|
61545
|
+
}
|
|
61546
|
+
|
|
61547
|
+
// src/patch/build.ts
|
|
61548
|
+
class BuildError extends Error {
|
|
61549
|
+
step;
|
|
61550
|
+
name = "BuildError";
|
|
61551
|
+
constructor(step, detail) {
|
|
61552
|
+
super(`${step}: ${detail.trim() || "failed"}`);
|
|
61553
|
+
this.step = step;
|
|
61554
|
+
}
|
|
61555
|
+
}
|
|
61556
|
+
var REPO2 = "https://github.com/openai/codex";
|
|
61557
|
+
var SNAPSHOT = "codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__footer__tests__cxstatusline_block_preserves_instruction_footer.snap";
|
|
61558
|
+
var SNAPSHOT_CONTENT = [
|
|
61559
|
+
"---",
|
|
61560
|
+
"source: tui/src/bottom_pane/footer.rs",
|
|
61561
|
+
"expression: terminal.backend()",
|
|
61562
|
+
"---",
|
|
61563
|
+
...["status-0", "status-1", "status-2", "esc esc to edit previous message"].map((s3) => `" ${s3.padEnd(78)}"`),
|
|
61564
|
+
""
|
|
61565
|
+
].join(`
|
|
61566
|
+
`);
|
|
61567
|
+
var TARGETS = ["codex", "codex-code-mode-host"];
|
|
61568
|
+
var HEX403 = /^[0-9a-f]{40}$/;
|
|
61569
|
+
function must(step, run, log, cmd, args, cwd2, env3) {
|
|
61570
|
+
log(`$ ${[cmd, ...args].join(" ")}`);
|
|
61571
|
+
const r = run(cmd, args, { cwd: cwd2, env: env3 });
|
|
61572
|
+
for (const line of `${r.stdout}${r.stderr}`.split(`
|
|
61573
|
+
`).filter(Boolean))
|
|
61574
|
+
log(line);
|
|
61575
|
+
if (r.status !== 0)
|
|
61576
|
+
throw new BuildError(step, r.stderr || r.stdout);
|
|
61577
|
+
}
|
|
61578
|
+
function runFocusedTests(run, log, which, crateDir, env3) {
|
|
61579
|
+
if (which("just")) {
|
|
61580
|
+
log("running the focused Rust tests with just");
|
|
61581
|
+
must("just test", run, log, "just", ["test", "--release", "-p", "codex-tui", "cxstatusline", "--retries", "0"], crateDir, env3);
|
|
61582
|
+
return;
|
|
61583
|
+
}
|
|
61584
|
+
log("just is not on PATH; running the focused Rust tests with cargo");
|
|
61585
|
+
must("cargo test", run, log, "cargo", ["test", "--release", "-p", "codex-tui", "cxstatusline"], crateDir, env3);
|
|
61586
|
+
}
|
|
61587
|
+
function headCommit(plan, run) {
|
|
61588
|
+
const r = run("git", ["-C", plan.sourceDir, "rev-parse", "HEAD"]);
|
|
61589
|
+
const commit = r.stdout.trim();
|
|
61590
|
+
if (r.status !== 0 || !HEX403.test(commit)) {
|
|
61591
|
+
throw new BuildError("rev-parse", `${plan.sourceDir} did not report a commit for ${plan.tag}`);
|
|
61592
|
+
}
|
|
61593
|
+
return commit;
|
|
61594
|
+
}
|
|
61595
|
+
function prepareCheckout(plan, run, log) {
|
|
61534
61596
|
const git = (step, ...args) => must(step, run, log, "git", ["-C", plan.sourceDir, ...args]);
|
|
61535
|
-
if (
|
|
61597
|
+
if (existsSync10(join11(plan.sourceDir, ".git"))) {
|
|
61536
61598
|
git("fetch", "fetch", "--tags", "--filter=blob:none", "origin");
|
|
61537
|
-
const snapshot =
|
|
61599
|
+
const snapshot = join11(plan.sourceDir, SNAPSHOT);
|
|
61538
61600
|
const st2 = lstatSync2(snapshot, { throwIfNoEntry: false });
|
|
61539
61601
|
if (st2) {
|
|
61540
61602
|
const tracked = run("git", ["-C", plan.sourceDir, "ls-files", "--error-unmatch", "--", SNAPSHOT]);
|
|
@@ -61551,22 +61613,38 @@ function prepareCheckout(plan, run, log) {
|
|
|
61551
61613
|
}
|
|
61552
61614
|
git("checkout", "checkout", "--detach", plan.tag);
|
|
61553
61615
|
}
|
|
61554
|
-
function buildPatched(plan, run, log, which) {
|
|
61616
|
+
function buildPatched(plan, run, log, which, onStatus) {
|
|
61555
61617
|
const git = (step, ...args) => must(step, run, log, "git", ["-C", plan.sourceDir, ...args]);
|
|
61618
|
+
onStatus?.("checkout", `Preparing checkout for ${plan.tag}...`);
|
|
61556
61619
|
prepareCheckout(plan, run, log);
|
|
61557
61620
|
const upstreamCommit = headCommit(plan, run);
|
|
61621
|
+
onStatus?.("checkout-done", `Upstream source ready at ${upstreamCommit.slice(0, 10)}`);
|
|
61622
|
+
const patchBase = plan.patchFile.split("/").pop() ?? "patch";
|
|
61623
|
+
onStatus?.("patch", `Applying ${patchBase}...`);
|
|
61558
61624
|
git("apply --check", "apply", "--index", "--check", plan.patchFile);
|
|
61559
61625
|
git("apply", "apply", "--index", plan.patchFile);
|
|
61560
|
-
|
|
61561
|
-
|
|
61626
|
+
onStatus?.("patch-done", `Applied ${patchBase} cleanly`);
|
|
61627
|
+
const crateDir = join11(plan.sourceDir, "codex-rs");
|
|
61628
|
+
const v8Env = resolveV8Env(plan.sourceDir, run, log);
|
|
61629
|
+
onStatus?.("build", "Compiling release binaries (cargo build --release)... Note: this full compile typically takes 10 to 20 minutes.");
|
|
61630
|
+
const buildStart = Date.now();
|
|
61631
|
+
must("cargo build", run, log, "cargo", ["build", "--release", "-p", "codex-cli", "--bin", "codex", "-p", "codex-code-mode-host", "--bin", "codex-code-mode-host"], crateDir, v8Env);
|
|
61632
|
+
const buildElapsed = Math.round((Date.now() - buildStart) / 1000);
|
|
61633
|
+
const buildElapsedStr = buildElapsed >= 60 ? `${Math.floor(buildElapsed / 60)}m ${buildElapsed % 60}s` : `${buildElapsed}s`;
|
|
61634
|
+
onStatus?.("build-done", `Release binaries compiled (codex, codex-code-mode-host in ${buildElapsedStr})`);
|
|
61562
61635
|
const [codex, codexCodeModeHost] = TARGETS.map((name) => {
|
|
61563
|
-
const bin =
|
|
61564
|
-
if (!
|
|
61636
|
+
const bin = join11(crateDir, "target", "release", name);
|
|
61637
|
+
if (!existsSync10(bin) || statSync3(bin).size === 0) {
|
|
61565
61638
|
throw new BuildError("cargo build", `cargo exited 0 but ${bin} is missing or empty`);
|
|
61566
61639
|
}
|
|
61567
61640
|
return bin;
|
|
61568
61641
|
});
|
|
61569
|
-
|
|
61642
|
+
onStatus?.("test", "Running focused regression tests...");
|
|
61643
|
+
const testStart = Date.now();
|
|
61644
|
+
runFocusedTests(run, log, which, crateDir, v8Env);
|
|
61645
|
+
const testElapsed = Math.round((Date.now() - testStart) / 1000);
|
|
61646
|
+
const testElapsedStr = testElapsed >= 60 ? `${Math.floor(testElapsed / 60)}m ${testElapsed % 60}s` : `${testElapsed}s`;
|
|
61647
|
+
onStatus?.("test-done", `Focused regression tests passed (in ${testElapsedStr})`);
|
|
61570
61648
|
return { codex, codexCodeModeHost, upstreamCommit };
|
|
61571
61649
|
}
|
|
61572
61650
|
|
|
@@ -61584,7 +61662,7 @@ function platformLabel() {
|
|
|
61584
61662
|
}
|
|
61585
61663
|
function stage(ctx, built) {
|
|
61586
61664
|
mkdirSync5(ctx.paths.libexecDir, { recursive: true });
|
|
61587
|
-
const directory = mkdtempSync2(
|
|
61665
|
+
const directory = mkdtempSync2(join12(ctx.paths.libexecDir, STAGING_PREFIX));
|
|
61588
61666
|
chmodSync3(directory, 448);
|
|
61589
61667
|
const sources = {
|
|
61590
61668
|
codex: built.codex,
|
|
@@ -61593,7 +61671,7 @@ function stage(ctx, built) {
|
|
|
61593
61671
|
const executables = {};
|
|
61594
61672
|
try {
|
|
61595
61673
|
for (const name of GENERATION_EXECUTABLES) {
|
|
61596
|
-
const target =
|
|
61674
|
+
const target = join12(directory, name);
|
|
61597
61675
|
copyFileSync2(sources[name], target);
|
|
61598
61676
|
chmodSync3(target, 493);
|
|
61599
61677
|
executables[name] = digestOf3(target);
|
|
@@ -61610,11 +61688,13 @@ function stage(ctx, built) {
|
|
|
61610
61688
|
}
|
|
61611
61689
|
};
|
|
61612
61690
|
}
|
|
61613
|
-
function prepareCompiled(ctx, upstream, ref) {
|
|
61614
|
-
const patchFile =
|
|
61691
|
+
function prepareCompiled(ctx, upstream, ref, onStatus) {
|
|
61692
|
+
const patchFile = join12(ctx.patchesDir, ref.file);
|
|
61615
61693
|
const patchSha256 = digestOf3(patchFile).sha256;
|
|
61616
|
-
const built = buildPatched({ tag: ref.tag, sourceDir: ctx.paths.sourceDir, patchFile }, ctx.run, ctx.log, ctx.which);
|
|
61694
|
+
const built = buildPatched({ tag: ref.tag, sourceDir: ctx.paths.sourceDir, patchFile }, ctx.run, ctx.log, ctx.which, onStatus);
|
|
61695
|
+
onStatus?.("stage", "Staging generation and verifying binaries...");
|
|
61617
61696
|
const staged = stage(ctx, built);
|
|
61697
|
+
onStatus?.("stage-done", "Generation staged and binaries verified");
|
|
61618
61698
|
return {
|
|
61619
61699
|
directory: staged.directory,
|
|
61620
61700
|
codexVersion: upstream.raw,
|
|
@@ -61634,7 +61714,7 @@ function prepareCompiled(ctx, upstream, ref) {
|
|
|
61634
61714
|
|
|
61635
61715
|
// src/patch/manifest.ts
|
|
61636
61716
|
import { readFileSync as readFileSync9 } from "node:fs";
|
|
61637
|
-
import { join as
|
|
61717
|
+
import { join as join13 } from "node:path";
|
|
61638
61718
|
class ManifestError extends Error {
|
|
61639
61719
|
name = "ManifestError";
|
|
61640
61720
|
}
|
|
@@ -61653,7 +61733,7 @@ var isCandidate = (c) => {
|
|
|
61653
61733
|
return parsed !== null && parsed.pre === null;
|
|
61654
61734
|
};
|
|
61655
61735
|
function loadManifest(patchesDir) {
|
|
61656
|
-
const file2 =
|
|
61736
|
+
const file2 = join13(patchesDir, "manifest.json");
|
|
61657
61737
|
try {
|
|
61658
61738
|
const raw = JSON.parse(readFileSync9(file2, "utf8"));
|
|
61659
61739
|
const m2 = raw;
|
|
@@ -61679,9 +61759,9 @@ function resolvePatch(m2, v2) {
|
|
|
61679
61759
|
}
|
|
61680
61760
|
|
|
61681
61761
|
// src/patch/wrapper.ts
|
|
61682
|
-
import { chmodSync as chmodSync4, closeSync as closeSync2, existsSync as
|
|
61762
|
+
import { chmodSync as chmodSync4, closeSync as closeSync2, existsSync as existsSync11, lstatSync as lstatSync3, mkdirSync as mkdirSync6, openSync as openSync2, readFileSync as readFileSync10, readSync, renameSync as renameSync3, rmSync as rmSync4, statSync as statSync5, writeFileSync as writeFileSync3 } from "node:fs";
|
|
61683
61763
|
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
61684
|
-
import { join as
|
|
61764
|
+
import { join as join14 } from "node:path";
|
|
61685
61765
|
var WRAPPER_MARKER = "# cxstatusline-wrapper v1";
|
|
61686
61766
|
var WRAPPER_MARKER_V2 = "# cxstatusline-wrapper v2";
|
|
61687
61767
|
var WRAPPER_MARKERS = [WRAPPER_MARKER, WRAPPER_MARKER_V2];
|
|
@@ -61740,7 +61820,7 @@ function isSymlink(p2) {
|
|
|
61740
61820
|
}
|
|
61741
61821
|
}
|
|
61742
61822
|
function stageExecutable(target, write) {
|
|
61743
|
-
mkdirSync6(
|
|
61823
|
+
mkdirSync6(join14(target, ".."), { recursive: true });
|
|
61744
61824
|
const tmp = `${target}.tmp-${process.pid}`;
|
|
61745
61825
|
try {
|
|
61746
61826
|
write(tmp);
|
|
@@ -61757,7 +61837,7 @@ function placeExecutable(target, write) {
|
|
|
61757
61837
|
renameSync3(stageExecutable(target, write), target);
|
|
61758
61838
|
}
|
|
61759
61839
|
function foreignLauncher(target) {
|
|
61760
|
-
return
|
|
61840
|
+
return existsSync11(target) && !isSymlink(target) && !isOurWrapper(target) ? `${target} is a real file we did not write (not a symlink, no cxstatusline marker); refusing to replace it. Move it aside and re-run, or point PATH at a different bin dir.` : null;
|
|
61761
61841
|
}
|
|
61762
61842
|
function assertLauncherReplaceable(paths) {
|
|
61763
61843
|
const reason = foreignLauncher(paths.wrapperPath);
|
|
@@ -61895,7 +61975,7 @@ async function acquireLocked(ctx, initial2, opts, transport) {
|
|
|
61895
61975
|
recordFailure(ctx, state, upstream.raw, reason);
|
|
61896
61976
|
return { kind: "refused", reason };
|
|
61897
61977
|
}
|
|
61898
|
-
return opts.source === "compiled" ? compiledAcquisition(ctx, state, upstream) : prebuiltAcquisition(ctx, state, upstream, transport);
|
|
61978
|
+
return opts.source === "compiled" ? compiledAcquisition(ctx, state, upstream, transport.onStatus) : prebuiltAcquisition(ctx, state, upstream, transport);
|
|
61899
61979
|
}
|
|
61900
61980
|
function install(ctx, state, upstream, source, pair) {
|
|
61901
61981
|
try {
|
|
@@ -61910,7 +61990,7 @@ function install(ctx, state, upstream, source, pair) {
|
|
|
61910
61990
|
rmSync5(pair.directory, { recursive: true, force: true });
|
|
61911
61991
|
}
|
|
61912
61992
|
}
|
|
61913
|
-
function compiledAcquisition(ctx, state, upstream) {
|
|
61993
|
+
function compiledAcquisition(ctx, state, upstream, onStatus) {
|
|
61914
61994
|
let ref;
|
|
61915
61995
|
try {
|
|
61916
61996
|
ref = resolvePatch(loadManifest(ctx.patchesDir), upstream);
|
|
@@ -61932,7 +62012,7 @@ function compiledAcquisition(ctx, state, upstream) {
|
|
|
61932
62012
|
}
|
|
61933
62013
|
let pair;
|
|
61934
62014
|
try {
|
|
61935
|
-
pair = prepareCompiled(ctx, upstream, ref);
|
|
62015
|
+
pair = prepareCompiled(ctx, upstream, ref, onStatus);
|
|
61936
62016
|
} catch (e) {
|
|
61937
62017
|
const reason = reasonOf(e);
|
|
61938
62018
|
recordFailure(ctx, state, upstream.raw, reason);
|
|
@@ -62004,6 +62084,288 @@ function describeOutcome(o) {
|
|
|
62004
62084
|
}
|
|
62005
62085
|
}
|
|
62006
62086
|
|
|
62087
|
+
// src/ui/box.ts
|
|
62088
|
+
var symbols = {
|
|
62089
|
+
ok: source_default.green("✔"),
|
|
62090
|
+
warn: source_default.yellow("▲"),
|
|
62091
|
+
fail: source_default.red("✖"),
|
|
62092
|
+
info: source_default.cyan("ℹ"),
|
|
62093
|
+
bullet: source_default.dim("●"),
|
|
62094
|
+
activeBullet: source_default.green("●"),
|
|
62095
|
+
dimBullet: source_default.dim("○"),
|
|
62096
|
+
pointer: source_default.cyan("▸"),
|
|
62097
|
+
diamond: source_default.magenta("◇")
|
|
62098
|
+
};
|
|
62099
|
+
function splitLines(lines) {
|
|
62100
|
+
return lines.flatMap((l) => l.split(`
|
|
62101
|
+
`));
|
|
62102
|
+
}
|
|
62103
|
+
function renderBox(lines, options = {}) {
|
|
62104
|
+
const border = options.borderColor ?? source_default.dim;
|
|
62105
|
+
const flatLines = splitLines(lines);
|
|
62106
|
+
const minWidth = options.minWidth ?? 60;
|
|
62107
|
+
const contentWidth = flatLines.reduce((max2, l) => Math.max(max2, getVisibleWidth(l)), 0);
|
|
62108
|
+
const titleWidth = options.title ? getVisibleWidth(options.title) + (options.badge ? getVisibleWidth(options.badge) + 2 : 0) : 0;
|
|
62109
|
+
const innerWidth = Math.max(minWidth, contentWidth, titleWidth);
|
|
62110
|
+
const topBorder = `${border("╭─")}${border("─".repeat(innerWidth + 2))}${border("─╮")}`;
|
|
62111
|
+
const bottomBorder = `${border("╰─")}${border("─".repeat(innerWidth + 2))}${border("─╯")}`;
|
|
62112
|
+
const renderedLines = [topBorder];
|
|
62113
|
+
if (options.title) {
|
|
62114
|
+
const title = options.title;
|
|
62115
|
+
const badge = options.badge ? ` ${options.badge}` : "";
|
|
62116
|
+
const headerVisible = getVisibleWidth(title) + getVisibleWidth(badge);
|
|
62117
|
+
const rightPad = " ".repeat(Math.max(0, innerWidth - headerVisible));
|
|
62118
|
+
renderedLines.push(`${border("│")} ${title}${rightPad}${badge} ${border("│")}`);
|
|
62119
|
+
renderedLines.push(`${border("├─")}${border("─".repeat(innerWidth + 2))}${border("─┤")}`);
|
|
62120
|
+
}
|
|
62121
|
+
for (const line of flatLines) {
|
|
62122
|
+
const pad3 = " ".repeat(Math.max(0, innerWidth - getVisibleWidth(line)));
|
|
62123
|
+
renderedLines.push(`${border("│")} ${line}${pad3} ${border("│")}`);
|
|
62124
|
+
}
|
|
62125
|
+
renderedLines.push(bottomBorder);
|
|
62126
|
+
return renderedLines.join(`
|
|
62127
|
+
`);
|
|
62128
|
+
}
|
|
62129
|
+
function renderHeader(title, subtitle, badge, minWidth = 68) {
|
|
62130
|
+
const border = source_default.cyan;
|
|
62131
|
+
const titleVis = getVisibleWidth(title);
|
|
62132
|
+
const badgeVis = badge ? getVisibleWidth(badge) : 0;
|
|
62133
|
+
const subVis = subtitle ? getVisibleWidth(subtitle) : 0;
|
|
62134
|
+
const innerWidth = Math.max(minWidth, titleVis + (badge ? badgeVis + 4 : 0), subVis);
|
|
62135
|
+
const topBorder = `${border("╭─")}${border("─".repeat(innerWidth + 2))}${border("─╮")}`;
|
|
62136
|
+
const bottomBorder = `${border("╰─")}${border("─".repeat(innerWidth + 2))}${border("─╯")}`;
|
|
62137
|
+
const lines = [topBorder];
|
|
62138
|
+
if (badge) {
|
|
62139
|
+
const space = " ".repeat(Math.max(2, innerWidth - titleVis - badgeVis));
|
|
62140
|
+
lines.push(`${border("│")} ${source_default.bold.white(title)}${space}${source_default.dim(badge)} ${border("│")}`);
|
|
62141
|
+
} else {
|
|
62142
|
+
const space = " ".repeat(Math.max(0, innerWidth - titleVis));
|
|
62143
|
+
lines.push(`${border("│")} ${source_default.bold.white(title)}${space} ${border("│")}`);
|
|
62144
|
+
}
|
|
62145
|
+
if (subtitle) {
|
|
62146
|
+
const space = " ".repeat(Math.max(0, innerWidth - subVis));
|
|
62147
|
+
lines.push(`${border("│")} ${source_default.dim(subtitle)}${space} ${border("│")}`);
|
|
62148
|
+
}
|
|
62149
|
+
lines.push(bottomBorder);
|
|
62150
|
+
return lines.join(`
|
|
62151
|
+
`);
|
|
62152
|
+
}
|
|
62153
|
+
function renderSectionTitle(title) {
|
|
62154
|
+
return ` ${symbols.pointer} ${source_default.bold.white(title)}`;
|
|
62155
|
+
}
|
|
62156
|
+
|
|
62157
|
+
// src/ui/install-format.ts
|
|
62158
|
+
function renderInstallHeader(compile3) {
|
|
62159
|
+
const subtitle = compile3 ? "Compiling patched Codex from source" : "Acquiring prebuilt statusline integration for OpenAI Codex";
|
|
62160
|
+
return renderHeader("cxstatusline install", subtitle, `v${VERSION}`);
|
|
62161
|
+
}
|
|
62162
|
+
function renderInstallSuccess(opts) {
|
|
62163
|
+
const sourceDesc = opts.source === "prebuilt" ? opts.reused ? "prebuilt release (reused existing generation)" : "prebuilt release" : "source build";
|
|
62164
|
+
const hookDesc = `hook ${opts.hookAction} in ${opts.hookFile}`;
|
|
62165
|
+
const lines = [
|
|
62166
|
+
`${symbols.ok} ${source_default.bold.green("Installation Complete")}`,
|
|
62167
|
+
"",
|
|
62168
|
+
` ${source_default.dim("Codex Target:")} ${source_default.bold.white(opts.version)}`,
|
|
62169
|
+
` ${source_default.dim("Source:")} ${source_default.cyan(sourceDesc)}`,
|
|
62170
|
+
` ${source_default.dim("Hook:")} ${source_default.white(hookDesc)}`,
|
|
62171
|
+
"",
|
|
62172
|
+
source_default.white("Start Codex once and accept the cxstatusline hook when prompted.")
|
|
62173
|
+
];
|
|
62174
|
+
return renderBox(lines, { borderColor: source_default.green, minWidth: 68 });
|
|
62175
|
+
}
|
|
62176
|
+
function renderInstallHookError(opts) {
|
|
62177
|
+
const lines = [
|
|
62178
|
+
`${symbols.warn} ${source_default.bold.yellow("Codex Installed (Hook Notice)")}`,
|
|
62179
|
+
"",
|
|
62180
|
+
`Codex ${opts.version} is installed, but the SessionStart hook could not be written: ${opts.error}`,
|
|
62181
|
+
"",
|
|
62182
|
+
`Fix ${opts.hookFile} by hand, then run \`cxstatusline hook install\`.`
|
|
62183
|
+
];
|
|
62184
|
+
return renderBox(lines, { borderColor: source_default.yellow, minWidth: 68 });
|
|
62185
|
+
}
|
|
62186
|
+
function renderInstallFailure(outcome, advice) {
|
|
62187
|
+
const desc = describeOutcome(outcome);
|
|
62188
|
+
const lines = [
|
|
62189
|
+
`${symbols.fail} ${source_default.bold.red("Installation Incomplete")}`,
|
|
62190
|
+
"",
|
|
62191
|
+
source_default.white(desc)
|
|
62192
|
+
];
|
|
62193
|
+
if (advice.length > 0) {
|
|
62194
|
+
lines.push("");
|
|
62195
|
+
lines.push(source_default.bold.cyan("Next Steps:"));
|
|
62196
|
+
for (const a of advice) {
|
|
62197
|
+
lines.push(` ${symbols.pointer} ${a}`);
|
|
62198
|
+
}
|
|
62199
|
+
}
|
|
62200
|
+
return renderBox(lines, { borderColor: source_default.red, minWidth: 68 });
|
|
62201
|
+
}
|
|
62202
|
+
// src/ui/progress.ts
|
|
62203
|
+
function formatBytes2(bytes) {
|
|
62204
|
+
if (bytes <= 0)
|
|
62205
|
+
return "0 B";
|
|
62206
|
+
if (bytes < 1024)
|
|
62207
|
+
return `${bytes} B`;
|
|
62208
|
+
if (bytes < 1024 * 1024)
|
|
62209
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
62210
|
+
if (bytes < 1024 * 1024 * 1024)
|
|
62211
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
62212
|
+
return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;
|
|
62213
|
+
}
|
|
62214
|
+
function formatDurationMs(ms2) {
|
|
62215
|
+
if (ms2 < 1000)
|
|
62216
|
+
return `${ms2}ms`;
|
|
62217
|
+
const sec = Math.round(ms2 / 1000);
|
|
62218
|
+
if (sec < 60)
|
|
62219
|
+
return `${(ms2 / 1000).toFixed(1)}s`;
|
|
62220
|
+
const min2 = Math.floor(sec / 60);
|
|
62221
|
+
const remSec = sec % 60;
|
|
62222
|
+
return `${min2}m ${remSec}s`;
|
|
62223
|
+
}
|
|
62224
|
+
function renderProgressBar(ratio, width = 24) {
|
|
62225
|
+
const clamped = Math.max(0, Math.min(1, Number.isFinite(ratio) ? ratio : 0));
|
|
62226
|
+
const filled = Math.round(clamped * width);
|
|
62227
|
+
const empty = Math.max(0, width - filled);
|
|
62228
|
+
return `[${source_default.cyan("█".repeat(filled))}${source_default.dim("░".repeat(empty))}]`;
|
|
62229
|
+
}
|
|
62230
|
+
function createInstallProgressTracker(io2, baseTransport = {}) {
|
|
62231
|
+
const isTTY = io2.isTTY ?? (typeof process !== "undefined" && Boolean(process.stdout?.isTTY));
|
|
62232
|
+
let downloadStart = 0;
|
|
62233
|
+
let lastDownloadUpdate = 0;
|
|
62234
|
+
let hasProgressBar = false;
|
|
62235
|
+
let lastReportedPct = -1;
|
|
62236
|
+
const clearProgressLine = () => {
|
|
62237
|
+
if (hasProgressBar && isTTY) {
|
|
62238
|
+
io2.write("\r\x1B[2K");
|
|
62239
|
+
hasProgressBar = false;
|
|
62240
|
+
}
|
|
62241
|
+
};
|
|
62242
|
+
const onProgress = (loaded, total) => {
|
|
62243
|
+
const now2 = Date.now();
|
|
62244
|
+
if (!downloadStart)
|
|
62245
|
+
downloadStart = now2;
|
|
62246
|
+
if (isTTY && now2 - lastDownloadUpdate < 50 && total !== null && loaded < total) {
|
|
62247
|
+
return;
|
|
62248
|
+
}
|
|
62249
|
+
lastDownloadUpdate = now2;
|
|
62250
|
+
const elapsedSec = Math.max(0.001, (now2 - downloadStart) / 1000);
|
|
62251
|
+
const speed = loaded / elapsedSec;
|
|
62252
|
+
const speedStr = `${formatBytes2(speed)}/s`;
|
|
62253
|
+
if (total !== null && total > 0) {
|
|
62254
|
+
const ratio = Math.min(1, loaded / total);
|
|
62255
|
+
const pct = Math.floor(ratio * 100);
|
|
62256
|
+
if (isTTY) {
|
|
62257
|
+
const bar = renderProgressBar(ratio, 24);
|
|
62258
|
+
const loadedStr = formatBytes2(loaded);
|
|
62259
|
+
const totalStr = formatBytes2(total);
|
|
62260
|
+
const text = `\r ${bar} ${source_default.bold(String(pct).padStart(3))}% ${loadedStr} / ${totalStr} (${source_default.dim(speedStr)})`;
|
|
62261
|
+
io2.write(text);
|
|
62262
|
+
hasProgressBar = true;
|
|
62263
|
+
} else {
|
|
62264
|
+
const milestone = Math.floor(pct / 25) * 25;
|
|
62265
|
+
if (milestone > lastReportedPct && milestone > 0) {
|
|
62266
|
+
lastReportedPct = milestone;
|
|
62267
|
+
io2.say(` ${symbols.dimBullet} Downloaded ${milestone}% (${formatBytes2(loaded)} / ${formatBytes2(total)})`);
|
|
62268
|
+
}
|
|
62269
|
+
}
|
|
62270
|
+
} else {
|
|
62271
|
+
if (isTTY) {
|
|
62272
|
+
io2.write(`\r ${symbols.activeBullet} ${formatBytes2(loaded)} downloaded (${source_default.dim(speedStr)})`);
|
|
62273
|
+
hasProgressBar = true;
|
|
62274
|
+
}
|
|
62275
|
+
}
|
|
62276
|
+
};
|
|
62277
|
+
const onStatus = (phase, message) => {
|
|
62278
|
+
clearProgressLine();
|
|
62279
|
+
switch (phase) {
|
|
62280
|
+
case "manifest":
|
|
62281
|
+
io2.say(`
|
|
62282
|
+
${symbols.pointer} ${source_default.bold("Release Metadata")}`);
|
|
62283
|
+
io2.say(` ${symbols.dimBullet} ${source_default.dim(message)}`);
|
|
62284
|
+
break;
|
|
62285
|
+
case "manifest-done":
|
|
62286
|
+
io2.say(` ${symbols.ok} ${source_default.white(message)}`);
|
|
62287
|
+
break;
|
|
62288
|
+
case "download":
|
|
62289
|
+
io2.say(`
|
|
62290
|
+
${symbols.pointer} ${source_default.bold("Downloading Prebuilt Archive")}`);
|
|
62291
|
+
downloadStart = Date.now();
|
|
62292
|
+
lastDownloadUpdate = 0;
|
|
62293
|
+
lastReportedPct = -1;
|
|
62294
|
+
break;
|
|
62295
|
+
case "download-done":
|
|
62296
|
+
clearProgressLine();
|
|
62297
|
+
const duration3 = downloadStart ? ` in ${formatDurationMs(Date.now() - downloadStart)}` : "";
|
|
62298
|
+
io2.say(` ${symbols.ok} ${source_default.white(message)}${source_default.dim(duration3)}`);
|
|
62299
|
+
break;
|
|
62300
|
+
case "extract":
|
|
62301
|
+
io2.say(`
|
|
62302
|
+
${symbols.pointer} ${source_default.bold("Verification & Staging")}`);
|
|
62303
|
+
io2.say(` ${symbols.dimBullet} ${source_default.dim(message)}`);
|
|
62304
|
+
break;
|
|
62305
|
+
case "extract-done":
|
|
62306
|
+
io2.say(` ${symbols.ok} ${source_default.white(message)}`);
|
|
62307
|
+
break;
|
|
62308
|
+
case "checkout":
|
|
62309
|
+
io2.say(`
|
|
62310
|
+
${symbols.pointer} ${source_default.bold("Upstream Source")}`);
|
|
62311
|
+
io2.say(` ${symbols.dimBullet} ${source_default.dim(message)}`);
|
|
62312
|
+
break;
|
|
62313
|
+
case "checkout-done":
|
|
62314
|
+
io2.say(` ${symbols.ok} ${source_default.white(message)}`);
|
|
62315
|
+
break;
|
|
62316
|
+
case "patch":
|
|
62317
|
+
io2.say(`
|
|
62318
|
+
${symbols.pointer} ${source_default.bold("Statusline Patch")}`);
|
|
62319
|
+
io2.say(` ${symbols.dimBullet} ${source_default.dim(message)}`);
|
|
62320
|
+
break;
|
|
62321
|
+
case "patch-done":
|
|
62322
|
+
io2.say(` ${symbols.ok} ${source_default.white(message)}`);
|
|
62323
|
+
break;
|
|
62324
|
+
case "build":
|
|
62325
|
+
io2.say(`
|
|
62326
|
+
${symbols.pointer} ${source_default.bold("Compiling Release Binaries")}`);
|
|
62327
|
+
io2.say(` ${symbols.dimBullet} ${source_default.dim(message)}`);
|
|
62328
|
+
break;
|
|
62329
|
+
case "build-done":
|
|
62330
|
+
io2.say(` ${symbols.ok} ${source_default.white(message)}`);
|
|
62331
|
+
break;
|
|
62332
|
+
case "test":
|
|
62333
|
+
io2.say(`
|
|
62334
|
+
${symbols.pointer} ${source_default.bold("Regression Tests")}`);
|
|
62335
|
+
io2.say(` ${symbols.dimBullet} ${source_default.dim(message)}`);
|
|
62336
|
+
break;
|
|
62337
|
+
case "test-done":
|
|
62338
|
+
io2.say(` ${symbols.ok} ${source_default.white(message)}`);
|
|
62339
|
+
break;
|
|
62340
|
+
case "stage":
|
|
62341
|
+
io2.say(`
|
|
62342
|
+
${symbols.pointer} ${source_default.bold("Staging & Activation")}`);
|
|
62343
|
+
io2.say(` ${symbols.ok} ${source_default.white(message)}`);
|
|
62344
|
+
break;
|
|
62345
|
+
default:
|
|
62346
|
+
io2.say(` ${symbols.info} ${message}`);
|
|
62347
|
+
break;
|
|
62348
|
+
}
|
|
62349
|
+
};
|
|
62350
|
+
const transport = {
|
|
62351
|
+
...baseTransport,
|
|
62352
|
+
onProgress: (loaded, total) => {
|
|
62353
|
+
onProgress(loaded, total);
|
|
62354
|
+
baseTransport.onProgress?.(loaded, total);
|
|
62355
|
+
},
|
|
62356
|
+
onStatus: (phase, msg) => {
|
|
62357
|
+
onStatus(phase, msg);
|
|
62358
|
+
baseTransport.onStatus?.(phase, msg);
|
|
62359
|
+
}
|
|
62360
|
+
};
|
|
62361
|
+
return {
|
|
62362
|
+
transport,
|
|
62363
|
+
finish: () => {
|
|
62364
|
+
clearProgressLine();
|
|
62365
|
+
}
|
|
62366
|
+
};
|
|
62367
|
+
}
|
|
62368
|
+
|
|
62007
62369
|
// src/patch/run.ts
|
|
62008
62370
|
var REPO3 = "adrijshikhar/cxstatusline";
|
|
62009
62371
|
function simulateDrift(ctx, version2) {
|
|
@@ -62065,51 +62427,143 @@ function report(ctx, outcome) {
|
|
|
62065
62427
|
for (const line of fallbackAdvice(ctx, outcome.version))
|
|
62066
62428
|
ctx.say(line);
|
|
62067
62429
|
}
|
|
62068
|
-
function runPatch(ctx, opts) {
|
|
62069
|
-
|
|
62430
|
+
function runPatch(ctx, opts, transport = {}) {
|
|
62431
|
+
ctx.say(renderInstallHeader(true));
|
|
62432
|
+
const progress = createInstallProgressTracker({
|
|
62433
|
+
isTTY: process.stdout?.isTTY,
|
|
62434
|
+
write: (s3) => process.stdout.write(s3),
|
|
62435
|
+
say: (l) => ctx.say(l)
|
|
62436
|
+
}, transport);
|
|
62437
|
+
return runAcquisition(ctx, { source: "compiled", force: opts.force }, progress.transport).finally(() => {
|
|
62438
|
+
progress.finish();
|
|
62439
|
+
});
|
|
62070
62440
|
}
|
|
62071
62441
|
async function runInstall(ctx, opts, transport = {}) {
|
|
62072
|
-
|
|
62073
|
-
|
|
62074
|
-
|
|
62442
|
+
ctx.say(renderInstallHeader(opts.compile));
|
|
62443
|
+
const progress = createInstallProgressTracker({
|
|
62444
|
+
isTTY: process.stdout?.isTTY,
|
|
62445
|
+
write: (s3) => process.stdout.write(s3),
|
|
62446
|
+
say: (l) => ctx.say(l)
|
|
62447
|
+
}, transport);
|
|
62448
|
+
let outcome;
|
|
62449
|
+
try {
|
|
62450
|
+
outcome = await runAcquisition(ctx, { source: opts.compile ? "compiled" : "prebuilt", force: true }, progress.transport);
|
|
62451
|
+
} finally {
|
|
62452
|
+
progress.finish();
|
|
62453
|
+
}
|
|
62454
|
+
if (outcome.kind !== "installed") {
|
|
62455
|
+
const advice = outcome.kind === "unavailable" ? fallbackAdvice(ctx, outcome.version) : [];
|
|
62456
|
+
ctx.say(renderInstallFailure(outcome, advice));
|
|
62075
62457
|
return 1;
|
|
62458
|
+
}
|
|
62076
62459
|
try {
|
|
62077
62460
|
const r = installHook(ctx.paths.hooksFile, ctx.cxBin);
|
|
62078
|
-
ctx.say(
|
|
62079
|
-
|
|
62080
|
-
|
|
62461
|
+
ctx.say(renderInstallSuccess({
|
|
62462
|
+
version: outcome.version,
|
|
62463
|
+
source: outcome.source,
|
|
62464
|
+
reused: outcome.reused,
|
|
62465
|
+
hookAction: r,
|
|
62466
|
+
hookFile: ctx.paths.hooksFile
|
|
62467
|
+
}));
|
|
62081
62468
|
return 0;
|
|
62082
62469
|
} catch (e) {
|
|
62083
|
-
ctx.say(
|
|
62084
|
-
|
|
62470
|
+
ctx.say(renderInstallHookError({
|
|
62471
|
+
version: outcome.version,
|
|
62472
|
+
hookFile: ctx.paths.hooksFile,
|
|
62473
|
+
error: String(e)
|
|
62474
|
+
}));
|
|
62085
62475
|
return 1;
|
|
62086
62476
|
}
|
|
62087
62477
|
}
|
|
62088
|
-
async function
|
|
62478
|
+
async function probeUpstreamLatest(fetchFn) {
|
|
62479
|
+
try {
|
|
62480
|
+
const headers = { accept: "application/vnd.github+json", "user-agent": "cxstatusline" };
|
|
62481
|
+
if (process.env.GITHUB_TOKEN)
|
|
62482
|
+
headers.authorization = `Bearer ${process.env.GITHUB_TOKEN}`;
|
|
62483
|
+
const res = await fetchFn("https://api.github.com/repos/openai/codex/releases/latest", {
|
|
62484
|
+
headers,
|
|
62485
|
+
signal: AbortSignal.timeout(5000)
|
|
62486
|
+
});
|
|
62487
|
+
if (!res.ok)
|
|
62488
|
+
return null;
|
|
62489
|
+
const data = await res.json();
|
|
62490
|
+
if (typeof data.tag_name !== "string")
|
|
62491
|
+
return null;
|
|
62492
|
+
return data.tag_name.replace(/^rust-v/, "");
|
|
62493
|
+
} catch {
|
|
62494
|
+
return null;
|
|
62495
|
+
}
|
|
62496
|
+
}
|
|
62497
|
+
async function probePrebuiltExists(targetCodexVersion, cxVersion, fetchFn, baseUrl) {
|
|
62498
|
+
try {
|
|
62499
|
+
const tag = releaseTag(cxVersion, targetCodexVersion);
|
|
62500
|
+
const url2 = baseUrl ? `${baseUrl}/${tag}/manifest.json` : `https://github.com/adrijshikhar/cxstatusline/releases/download/${tag}/manifest.json`;
|
|
62501
|
+
const res = await fetchFn(url2, { method: "HEAD", signal: AbortSignal.timeout(5000) });
|
|
62502
|
+
return res.ok || res.status === 302 || res.status === 301;
|
|
62503
|
+
} catch {
|
|
62504
|
+
return false;
|
|
62505
|
+
}
|
|
62506
|
+
}
|
|
62507
|
+
async function runUpdate(ctx, optsOrTransport = {}, maybeTransport) {
|
|
62508
|
+
const opts = "compile" in optsOrTransport || "force" in optsOrTransport ? optsOrTransport : {};
|
|
62509
|
+
const transport = "baseUrl" in optsOrTransport || "fetch" in optsOrTransport ? optsOrTransport : maybeTransport ?? {};
|
|
62089
62510
|
const state = loadState(ctx);
|
|
62090
62511
|
const located = upstreamFor(ctx, state);
|
|
62091
62512
|
if ("reason" in located) {
|
|
62092
62513
|
ctx.say(`no upstream Codex to update: ${located.reason}`);
|
|
62093
62514
|
return 1;
|
|
62094
62515
|
}
|
|
62516
|
+
const current = readUpstreamVersion(located.bin, ctx.run);
|
|
62517
|
+
const fetchFn = transport.fetch ?? fetch;
|
|
62518
|
+
if (current && !opts.force && !opts.compile) {
|
|
62519
|
+
const latest = await probeUpstreamLatest(fetchFn);
|
|
62520
|
+
if (latest && latest !== current.raw) {
|
|
62521
|
+
const available = await probePrebuiltExists(latest, VERSION, fetchFn, transport.baseUrl);
|
|
62522
|
+
if (!available) {
|
|
62523
|
+
ctx.say(`Warning: Upstream Codex update available: ${current.raw} -> ${latest}.`);
|
|
62524
|
+
ctx.say(`However, cxstatusline has not yet published prebuilt binaries for Codex ${latest}.`);
|
|
62525
|
+
ctx.say("Updating now will replace your patched launcher with stock Codex.");
|
|
62526
|
+
ctx.say("");
|
|
62527
|
+
ctx.say("Options:");
|
|
62528
|
+
ctx.say(" - Wait until cxstatusline publishes prebuilt binaries for this version.");
|
|
62529
|
+
ctx.say(" - Update and compile from source: cxstatusline update --compile");
|
|
62530
|
+
ctx.say(" - Update to stock Codex anyway: cxstatusline update --force");
|
|
62531
|
+
return 1;
|
|
62532
|
+
}
|
|
62533
|
+
} else if (latest && latest === current.raw) {
|
|
62534
|
+
ctx.say(`Codex is already at the latest version (${current.raw}).`);
|
|
62535
|
+
return 0;
|
|
62536
|
+
}
|
|
62537
|
+
}
|
|
62095
62538
|
ctx.say(`running upstream updater: ${located.bin} update`);
|
|
62096
62539
|
const r = ctx.run(located.bin, ["update"], { interactive: true });
|
|
62097
62540
|
if (r.status !== 0) {
|
|
62098
62541
|
ctx.say(`upstream updater exited ${String(r.status)}; see its output above. Not installing.`);
|
|
62099
62542
|
return 1;
|
|
62100
62543
|
}
|
|
62101
|
-
const
|
|
62544
|
+
const source = opts.compile ? "compiled" : "prebuilt";
|
|
62545
|
+
const progress = createInstallProgressTracker({
|
|
62546
|
+
isTTY: process.stdout?.isTTY,
|
|
62547
|
+
write: (s3) => process.stdout.write(s3),
|
|
62548
|
+
say: (l) => ctx.say(l)
|
|
62549
|
+
}, transport);
|
|
62550
|
+
let outcome;
|
|
62551
|
+
try {
|
|
62552
|
+
outcome = await runAcquisition(ctx, { source, force: true }, progress.transport);
|
|
62553
|
+
} finally {
|
|
62554
|
+
progress.finish();
|
|
62555
|
+
}
|
|
62102
62556
|
report(ctx, outcome);
|
|
62103
62557
|
return outcome.kind === "installed" ? 0 : 1;
|
|
62104
62558
|
}
|
|
62105
62559
|
function appendLog(file2, line) {
|
|
62106
|
-
mkdirSync7(
|
|
62560
|
+
mkdirSync7(join15(file2, ".."), { recursive: true });
|
|
62107
62561
|
appendFileSync(file2, `${new Date().toISOString()} ${line}
|
|
62108
62562
|
`);
|
|
62109
62563
|
}
|
|
62110
62564
|
|
|
62111
62565
|
// src/hook/run.ts
|
|
62112
|
-
import { appendFileSync as appendFileSync2, closeSync as closeSync3, existsSync as
|
|
62566
|
+
import { appendFileSync as appendFileSync2, closeSync as closeSync3, existsSync as existsSync12, mkdirSync as mkdirSync8, openSync as openSync3 } from "node:fs";
|
|
62113
62567
|
import { spawn } from "node:child_process";
|
|
62114
62568
|
import { dirname as dirname9 } from "node:path";
|
|
62115
62569
|
var HOOK_SOURCES = ["startup", "resume", "clear"];
|
|
@@ -62147,11 +62601,11 @@ function locateUpstream(ctx, state) {
|
|
|
62147
62601
|
}
|
|
62148
62602
|
function maintainWrapper(ctx, messages) {
|
|
62149
62603
|
if (readInstallation(ctx.paths) === null) {
|
|
62150
|
-
if (!
|
|
62604
|
+
if (!existsSync12(ctx.paths.patchedBin)) {
|
|
62151
62605
|
messages.push(`cxstatusline: the patched binary ${ctx.paths.patchedBin} is missing; Codex is running unpatched. Run \`cxstatusline install\`.`);
|
|
62152
62606
|
return;
|
|
62153
62607
|
}
|
|
62154
|
-
if (!
|
|
62608
|
+
if (!existsSync12(ctx.paths.patchedCodeModeHost)) {
|
|
62155
62609
|
messages.push(`cxstatusline: the required Code Mode host ${ctx.paths.patchedCodeModeHost} is missing; run \`cxstatusline install\` to restore it.`);
|
|
62156
62610
|
return;
|
|
62157
62611
|
}
|
|
@@ -62248,12 +62702,12 @@ function realHookDeps() {
|
|
|
62248
62702
|
}
|
|
62249
62703
|
|
|
62250
62704
|
// src/commands/doctor.ts
|
|
62251
|
-
import { existsSync as
|
|
62705
|
+
import { existsSync as existsSync14, lstatSync as lstatSync4, readFileSync as readFileSync12, readlinkSync as readlinkSync3 } from "node:fs";
|
|
62252
62706
|
|
|
62253
62707
|
// src/commands/doctor-generation.ts
|
|
62254
62708
|
import { createHash as createHash5 } from "node:crypto";
|
|
62255
|
-
import { existsSync as
|
|
62256
|
-
import { dirname as dirname10, isAbsolute as isAbsolute3, join as
|
|
62709
|
+
import { existsSync as existsSync13, readFileSync as readFileSync11 } from "node:fs";
|
|
62710
|
+
import { dirname as dirname10, isAbsolute as isAbsolute3, join as join16, resolve as resolve4 } from "node:path";
|
|
62257
62711
|
var line = (key, value, ok = null) => ({ key, value, ok });
|
|
62258
62712
|
var NO_GENERATION = "n/a (no active generation)";
|
|
62259
62713
|
function resolvePointerTarget(paths, raw) {
|
|
@@ -62298,7 +62752,9 @@ function cxVersionLine(record2) {
|
|
|
62298
62752
|
if (!record2)
|
|
62299
62753
|
return line("cx_version", NO_GENERATION, null);
|
|
62300
62754
|
const match = record2.provenance.cxVersion === VERSION;
|
|
62301
|
-
|
|
62755
|
+
if (match)
|
|
62756
|
+
return line("cx_version", VERSION, true);
|
|
62757
|
+
return line("cx_version", `cli ${VERSION} vs generation ${record2.provenance.cxVersion}`, false);
|
|
62302
62758
|
}
|
|
62303
62759
|
function releaseLine(record2) {
|
|
62304
62760
|
if (!record2)
|
|
@@ -62330,8 +62786,8 @@ function upstreamCommitLine(record2) {
|
|
|
62330
62786
|
function digestLine(key, label, record2, dir) {
|
|
62331
62787
|
if (!record2 || !dir)
|
|
62332
62788
|
return line(label, NO_GENERATION, null);
|
|
62333
|
-
const file2 =
|
|
62334
|
-
if (!
|
|
62789
|
+
const file2 = join16(dir, key);
|
|
62790
|
+
if (!existsSync13(file2))
|
|
62335
62791
|
return line(label, "missing", false);
|
|
62336
62792
|
let buf;
|
|
62337
62793
|
try {
|
|
@@ -62348,8 +62804,8 @@ function digestLine(key, label, record2, dir) {
|
|
|
62348
62804
|
function codexVersionLine(ctx, record2, dir) {
|
|
62349
62805
|
if (!record2 || !dir)
|
|
62350
62806
|
return line("codex_version", NO_GENERATION, null);
|
|
62351
|
-
const bin =
|
|
62352
|
-
if (!
|
|
62807
|
+
const bin = join16(dir, "codex");
|
|
62808
|
+
if (!existsSync13(bin))
|
|
62353
62809
|
return line("codex_version", "missing", false);
|
|
62354
62810
|
let result2;
|
|
62355
62811
|
try {
|
|
@@ -62371,7 +62827,7 @@ function legalLine(record2, dir) {
|
|
|
62371
62827
|
return line("legal", "n/a (compiled build)", null);
|
|
62372
62828
|
if (!dir)
|
|
62373
62829
|
return line("legal", NO_GENERATION, null);
|
|
62374
|
-
const missing = GENERATION_LEGAL_FILES.filter((f2) => !
|
|
62830
|
+
const missing = GENERATION_LEGAL_FILES.filter((f2) => !existsSync13(join16(dir, f2)));
|
|
62375
62831
|
return missing.length === 0 ? line("legal", "present", true) : line("legal", `missing: ${missing.join(", ")}`, false);
|
|
62376
62832
|
}
|
|
62377
62833
|
function generationDetailLines(ctx, status) {
|
|
@@ -62404,11 +62860,136 @@ function bookkeepingLine(state, record2) {
|
|
|
62404
62860
|
function legacyLine(paths, record2) {
|
|
62405
62861
|
if (record2 !== null)
|
|
62406
62862
|
return null;
|
|
62407
|
-
if (!
|
|
62863
|
+
if (!existsSync13(paths.patchedBin) && !existsSync13(paths.patchedCodeModeHost))
|
|
62408
62864
|
return null;
|
|
62409
62865
|
return line("legacy", "legacy layout: run cxstatusline revert then cxstatusline install", false);
|
|
62410
62866
|
}
|
|
62411
62867
|
|
|
62868
|
+
// src/commands/doctor-format.ts
|
|
62869
|
+
var SECTIONS = [
|
|
62870
|
+
{
|
|
62871
|
+
title: "Core & Environment",
|
|
62872
|
+
keys: ["renderer", "settings", "platform", "toolchain"]
|
|
62873
|
+
},
|
|
62874
|
+
{
|
|
62875
|
+
title: "Codex Integration",
|
|
62876
|
+
keys: ["upstream", "wrapper", "hook", "policy", "drift"]
|
|
62877
|
+
},
|
|
62878
|
+
{
|
|
62879
|
+
title: "Active Generation & Binaries",
|
|
62880
|
+
keys: [
|
|
62881
|
+
"active",
|
|
62882
|
+
"generation",
|
|
62883
|
+
"cx_version",
|
|
62884
|
+
"release",
|
|
62885
|
+
"patch",
|
|
62886
|
+
"source_commit",
|
|
62887
|
+
"upstream_commit",
|
|
62888
|
+
"codex_digest",
|
|
62889
|
+
"host_digest",
|
|
62890
|
+
"codex_version",
|
|
62891
|
+
"legal",
|
|
62892
|
+
"bookkeeping",
|
|
62893
|
+
"legacy"
|
|
62894
|
+
]
|
|
62895
|
+
},
|
|
62896
|
+
{
|
|
62897
|
+
title: "State & Locks",
|
|
62898
|
+
keys: ["state", "patched_from", "last_attempt", "lock"]
|
|
62899
|
+
}
|
|
62900
|
+
];
|
|
62901
|
+
function formatValue(raw, ok) {
|
|
62902
|
+
const value = String(raw ?? "");
|
|
62903
|
+
if (ok === false)
|
|
62904
|
+
return source_default.red(value);
|
|
62905
|
+
if (value === "absent" || value === "none" || value === "never" || value.startsWith("n/a")) {
|
|
62906
|
+
return source_default.dim(value);
|
|
62907
|
+
}
|
|
62908
|
+
if (value === "free" || value === "ours" || value === "darwin-arm64" || value === "darwin-x64") {
|
|
62909
|
+
return source_default.green(value);
|
|
62910
|
+
}
|
|
62911
|
+
return source_default.white(value);
|
|
62912
|
+
}
|
|
62913
|
+
function statusBullet(ok) {
|
|
62914
|
+
if (ok === true)
|
|
62915
|
+
return symbols.ok;
|
|
62916
|
+
if (ok === false)
|
|
62917
|
+
return symbols.fail;
|
|
62918
|
+
return symbols.dimBullet;
|
|
62919
|
+
}
|
|
62920
|
+
function renderSummary(lines) {
|
|
62921
|
+
const failures = lines.filter((l) => l.ok === false);
|
|
62922
|
+
const driftLine = lines.find((l) => l.key === "drift");
|
|
62923
|
+
if (failures.length > 0) {
|
|
62924
|
+
const count = failures.length;
|
|
62925
|
+
const word = count === 1 ? "issue" : "issues";
|
|
62926
|
+
const detail = driftLine && driftLine.ok === false ? "Run `cxstatusline install` to update to the current Codex version." : "Check the failed items above for instructions.";
|
|
62927
|
+
return renderBox([
|
|
62928
|
+
`${symbols.fail} ${source_default.bold.red(`${count} ${word} detected`)}`,
|
|
62929
|
+
` ${source_default.dim(detail)}`
|
|
62930
|
+
], { borderColor: source_default.red, minWidth: 68 });
|
|
62931
|
+
}
|
|
62932
|
+
return renderBox([
|
|
62933
|
+
`${symbols.ok} ${source_default.bold.green("All systems operational")}`,
|
|
62934
|
+
` ${source_default.dim("Statusline is configured and active for OpenAI Codex.")}`
|
|
62935
|
+
], { borderColor: source_default.green, minWidth: 68 });
|
|
62936
|
+
}
|
|
62937
|
+
function singleLineSummary(text) {
|
|
62938
|
+
const lines = text.split(`
|
|
62939
|
+
`).map((l) => l.trim()).filter(Boolean);
|
|
62940
|
+
if (lines.length <= 1)
|
|
62941
|
+
return text;
|
|
62942
|
+
const match = /^(failed\s+\S+\s+at\s+[0-9T:.-]+Z?):\s*(.*)/.exec(lines[0]);
|
|
62943
|
+
const prefix = match ? match[1] : lines[0].split(":")[0] ?? "failed";
|
|
62944
|
+
const errorLine = lines.find((l) => /^error(\[[A-Z0-9]+\])?:/i.test(l)) ?? lines.find((l) => /^failed to/i.test(l)) ?? lines.find((l) => /panic/i.test(l)) ?? lines[lines.length - 1];
|
|
62945
|
+
return `${prefix}: ${errorLine}`;
|
|
62946
|
+
}
|
|
62947
|
+
function formatDiagnosticLine(item, maxKeyWidth) {
|
|
62948
|
+
const bullet = statusBullet(item.ok);
|
|
62949
|
+
const key = source_default.cyan(item.key.padEnd(maxKeyWidth));
|
|
62950
|
+
const summary = singleLineSummary(String(item.value ?? ""));
|
|
62951
|
+
const val = formatValue(summary, item.ok);
|
|
62952
|
+
return ` ${bullet} ${key} ${val}`;
|
|
62953
|
+
}
|
|
62954
|
+
function formatDoctorPretty(lines) {
|
|
62955
|
+
const lineMap = new Map(lines.map((l) => [l.key, l]));
|
|
62956
|
+
const seen = new Set;
|
|
62957
|
+
const maxKeyWidth = lines.reduce((max2, l) => Math.max(max2, l.key.length), 0);
|
|
62958
|
+
const parts = [
|
|
62959
|
+
renderHeader("cxstatusline doctor", "Diagnostics & System Health", `v${VERSION}`),
|
|
62960
|
+
""
|
|
62961
|
+
];
|
|
62962
|
+
for (const section of SECTIONS) {
|
|
62963
|
+
const sectionLines = [];
|
|
62964
|
+
for (const key of section.keys) {
|
|
62965
|
+
const entry = lineMap.get(key);
|
|
62966
|
+
if (entry) {
|
|
62967
|
+
sectionLines.push(entry);
|
|
62968
|
+
seen.add(key);
|
|
62969
|
+
}
|
|
62970
|
+
}
|
|
62971
|
+
if (sectionLines.length === 0)
|
|
62972
|
+
continue;
|
|
62973
|
+
parts.push(renderSectionTitle(section.title));
|
|
62974
|
+
for (const item of sectionLines) {
|
|
62975
|
+
parts.push(formatDiagnosticLine(item, maxKeyWidth));
|
|
62976
|
+
}
|
|
62977
|
+
parts.push("");
|
|
62978
|
+
}
|
|
62979
|
+
const extra = lines.filter((l) => !seen.has(l.key));
|
|
62980
|
+
if (extra.length > 0) {
|
|
62981
|
+
parts.push(renderSectionTitle("Other Diagnostics"));
|
|
62982
|
+
for (const item of extra) {
|
|
62983
|
+
parts.push(formatDiagnosticLine(item, maxKeyWidth));
|
|
62984
|
+
}
|
|
62985
|
+
parts.push("");
|
|
62986
|
+
}
|
|
62987
|
+
parts.push(renderSummary(lines));
|
|
62988
|
+
return `${parts.join(`
|
|
62989
|
+
`)}
|
|
62990
|
+
`;
|
|
62991
|
+
}
|
|
62992
|
+
|
|
62412
62993
|
// src/commands/doctor.ts
|
|
62413
62994
|
var line2 = (key, value, ok = null) => ({ key, value, ok });
|
|
62414
62995
|
function wrapperLine(ctx) {
|
|
@@ -62424,7 +63005,7 @@ function wrapperLine(ctx) {
|
|
|
62424
63005
|
return isOurWrapper(p2) ? line2("wrapper", "ours", true) : line2("wrapper", "foreign file! not ours, not a symlink", false);
|
|
62425
63006
|
}
|
|
62426
63007
|
function hookLine(ctx) {
|
|
62427
|
-
if (!
|
|
63008
|
+
if (!existsSync14(ctx.paths.hooksFile))
|
|
62428
63009
|
return line2("hook", "absent");
|
|
62429
63010
|
try {
|
|
62430
63011
|
const f2 = JSON.parse(readFileSync12(ctx.paths.hooksFile, "utf8"));
|
|
@@ -62480,7 +63061,7 @@ function doctorReport(ctx) {
|
|
|
62480
63061
|
};
|
|
62481
63062
|
const lines = [
|
|
62482
63063
|
line2("renderer", `${ctx.cxBin} (${VERSION})`),
|
|
62483
|
-
line2("settings", `${ctx.paths.settingsFile} ${
|
|
63064
|
+
line2("settings", `${ctx.paths.settingsFile} ${existsSync14(ctx.paths.settingsFile) ? "present" : "absent (written on first render)"}`),
|
|
62484
63065
|
upstreamLine(ctx, upstreamBin, upstream?.raw ?? null, lookupNote),
|
|
62485
63066
|
line2("state", corrupt ? `${ctx.paths.stateFile} CORRUPT (recovered from ${ctx.paths.stateBackupFile} where possible)` : ctx.paths.stateFile, corrupt ? false : null),
|
|
62486
63067
|
line2("patched_from", state.patched_from ?? "never"),
|
|
@@ -62500,16 +63081,12 @@ function doctorReport(ctx) {
|
|
|
62500
63081
|
return lines.filter((l) => l !== null);
|
|
62501
63082
|
}
|
|
62502
63083
|
function formatDoctor(lines) {
|
|
62503
|
-
|
|
62504
|
-
const width = Math.max(...lines.map((l) => l.key.length));
|
|
62505
|
-
return `${lines.map((l) => `${mark(l.ok)} ${l.key.padEnd(width)} ${l.value}`).join(`
|
|
62506
|
-
`)}
|
|
62507
|
-
`;
|
|
63084
|
+
return formatDoctorPretty(lines);
|
|
62508
63085
|
}
|
|
62509
63086
|
|
|
62510
63087
|
// src/commands/revert.ts
|
|
62511
|
-
import { existsSync as
|
|
62512
|
-
import { join as
|
|
63088
|
+
import { existsSync as existsSync15, lstatSync as lstatSync5, readdirSync as readdirSync2, rmSync as rmSync6, symlinkSync as symlinkSync2 } from "node:fs";
|
|
63089
|
+
import { join as join17 } from "node:path";
|
|
62513
63090
|
function safeIsSymlink(p2) {
|
|
62514
63091
|
try {
|
|
62515
63092
|
return lstatSync5(p2).isSymbolicLink();
|
|
@@ -62530,11 +63107,11 @@ function revert(ctx) {
|
|
|
62530
63107
|
}
|
|
62531
63108
|
function removeGenerations(ctx, actions) {
|
|
62532
63109
|
const { currentGeneration, generationsDir } = ctx.paths;
|
|
62533
|
-
if (
|
|
63110
|
+
if (existsSync15(currentGeneration) || safeIsSymlink(currentGeneration)) {
|
|
62534
63111
|
rmSync6(currentGeneration, { recursive: true, force: true });
|
|
62535
63112
|
actions.push(`removed generation pointer ${currentGeneration}`);
|
|
62536
63113
|
}
|
|
62537
|
-
if (!
|
|
63114
|
+
if (!existsSync15(generationsDir))
|
|
62538
63115
|
return;
|
|
62539
63116
|
let removed = 0;
|
|
62540
63117
|
for (const dir of listGenerations(ctx.paths)) {
|
|
@@ -62552,11 +63129,11 @@ function removeGenerations(ctx, actions) {
|
|
|
62552
63129
|
var OWNED_LIBEXEC_PREFIXES = ["current.", "staging-", "download-", "compiled-"];
|
|
62553
63130
|
function removeStagingDebris(ctx, actions) {
|
|
62554
63131
|
const { libexecDir } = ctx.paths;
|
|
62555
|
-
if (!
|
|
63132
|
+
if (!existsSync15(libexecDir))
|
|
62556
63133
|
return;
|
|
62557
63134
|
const debris = readdirSync2(libexecDir).filter((n) => OWNED_LIBEXEC_PREFIXES.some((p2) => n.startsWith(p2)));
|
|
62558
63135
|
for (const name of debris)
|
|
62559
|
-
rmSync6(
|
|
63136
|
+
rmSync6(join17(libexecDir, name), { recursive: true, force: true });
|
|
62560
63137
|
if (debris.length > 0) {
|
|
62561
63138
|
actions.push(`removed ${debris.length} leftover staging entr${debris.length === 1 ? "y" : "ies"} from ${libexecDir}`);
|
|
62562
63139
|
}
|
|
@@ -62568,7 +63145,7 @@ function revertLocked(ctx) {
|
|
|
62568
63145
|
if (corrupt)
|
|
62569
63146
|
actions.push(`state.json was corrupt; used ${ctx.paths.stateBackupFile} where possible`);
|
|
62570
63147
|
const w2 = ctx.paths.wrapperPath;
|
|
62571
|
-
if (
|
|
63148
|
+
if (existsSync15(w2) || safeIsSymlink(w2)) {
|
|
62572
63149
|
if (isOurWrapper(w2)) {
|
|
62573
63150
|
rmSync6(w2);
|
|
62574
63151
|
actions.push(`removed wrapper ${w2}`);
|
|
@@ -62584,11 +63161,11 @@ function revertLocked(ctx) {
|
|
|
62584
63161
|
}
|
|
62585
63162
|
removeGenerations(ctx, actions);
|
|
62586
63163
|
removeStagingDebris(ctx, actions);
|
|
62587
|
-
if (
|
|
63164
|
+
if (existsSync15(ctx.paths.patchedBin)) {
|
|
62588
63165
|
rmSync6(ctx.paths.patchedBin);
|
|
62589
63166
|
actions.push(`removed patched binary ${ctx.paths.patchedBin}`);
|
|
62590
63167
|
}
|
|
62591
|
-
if (
|
|
63168
|
+
if (existsSync15(ctx.paths.patchedCodeModeHost)) {
|
|
62592
63169
|
rmSync6(ctx.paths.patchedCodeModeHost);
|
|
62593
63170
|
actions.push(`removed Code Mode host ${ctx.paths.patchedCodeModeHost}`);
|
|
62594
63171
|
}
|
|
@@ -64038,9 +64615,9 @@ function MainMenu({ onSelect, initialSelection = 0, hasChanges = false }) {
|
|
|
64038
64615
|
}
|
|
64039
64616
|
|
|
64040
64617
|
// src/tui/components/PowerlineSetup.tsx
|
|
64041
|
-
import { existsSync as
|
|
64618
|
+
import { existsSync as existsSync16, readdirSync as readdirSync3 } from "node:fs";
|
|
64042
64619
|
import { homedir as homedir2, platform as platform2 } from "node:os";
|
|
64043
|
-
import { join as
|
|
64620
|
+
import { join as join18 } from "node:path";
|
|
64044
64621
|
var import_react40 = __toESM(require_react(), 1);
|
|
64045
64622
|
|
|
64046
64623
|
// src/utils/powerline-settings.ts
|
|
@@ -64425,9 +65002,9 @@ function buildPowerlineSetupMenuItems(powerline) {
|
|
|
64425
65002
|
];
|
|
64426
65003
|
}
|
|
64427
65004
|
function detectPowerlineFont() {
|
|
64428
|
-
const dirs = platform2() === "darwin" ? [
|
|
65005
|
+
const dirs = platform2() === "darwin" ? [join18(homedir2(), "Library", "Fonts"), "/Library/Fonts"] : platform2() === "win32" ? [join18(homedir2(), "AppData", "Local", "Microsoft", "Windows", "Fonts"), "C:\\Windows\\Fonts"] : [join18(homedir2(), ".local", "share", "fonts"), join18(homedir2(), ".fonts"), "/usr/share/fonts"];
|
|
64429
65006
|
try {
|
|
64430
|
-
return dirs.some((dir) =>
|
|
65007
|
+
return dirs.some((dir) => existsSync16(dir) && readdirSync3(dir).some((file2) => /powerline|nerd font|meslo.*lg/i.test(file2)));
|
|
64431
65008
|
} catch {
|
|
64432
65009
|
return false;
|
|
64433
65010
|
}
|
|
@@ -64950,7 +65527,7 @@ var USAGE = `usage: cxstatusline [command]
|
|
|
64950
65527
|
install [--compile] install the published Codex pair (--compile builds it from source)
|
|
64951
65528
|
patch [--force] build and install the patched Codex from source
|
|
64952
65529
|
patch --simulate-drift <v> record <v> as the installed version so the next session sees drift
|
|
64953
|
-
update
|
|
65530
|
+
update [--compile|--force] run upstream's own updater, then install the pair for it
|
|
64954
65531
|
hook [install|uninstall] manage the SessionStart entry; bare 'hook' is what Codex runs
|
|
64955
65532
|
doctor report toolchain, drift, hook and wrapper state
|
|
64956
65533
|
revert restore stock Codex; keep settings
|
|
@@ -64999,7 +65576,19 @@ async function installCommand(argv, io2, deps) {
|
|
|
64999
65576
|
io2.stderr(USAGE);
|
|
65000
65577
|
return 2;
|
|
65001
65578
|
}
|
|
65002
|
-
return runInstall(contextFor(io2, deps), { compile: flags[0] === "--compile" });
|
|
65579
|
+
return runInstall(contextFor(io2, deps), { compile: flags[0] === "--compile" }, deps.transport);
|
|
65580
|
+
}
|
|
65581
|
+
async function updateCommand(argv, io2, deps) {
|
|
65582
|
+
const flags = argv.slice(1);
|
|
65583
|
+
const allowed = new Set(["--compile", "--force", "-y", "--yes"]);
|
|
65584
|
+
if (flags.some((f2) => !allowed.has(f2))) {
|
|
65585
|
+
io2.stderr(USAGE);
|
|
65586
|
+
return 2;
|
|
65587
|
+
}
|
|
65588
|
+
return runUpdate(contextFor(io2, deps), {
|
|
65589
|
+
compile: flags.includes("--compile"),
|
|
65590
|
+
force: flags.includes("--force") || flags.includes("-y") || flags.includes("--yes")
|
|
65591
|
+
}, deps.transport);
|
|
65003
65592
|
}
|
|
65004
65593
|
async function hookAcquireCommand(io2, deps) {
|
|
65005
65594
|
const ctx = contextFor(io2, deps);
|
|
@@ -65058,7 +65647,7 @@ async function main(argv, io2, deps = {}) {
|
|
|
65058
65647
|
if (cmd === "patch")
|
|
65059
65648
|
return patchCommand(argv, io2, deps);
|
|
65060
65649
|
if (cmd === "update")
|
|
65061
|
-
return
|
|
65650
|
+
return updateCommand(argv, io2, deps);
|
|
65062
65651
|
if (cmd === "install")
|
|
65063
65652
|
return installCommand(argv, io2, deps);
|
|
65064
65653
|
if (cmd === "hook" && (argv[1] === "install" || argv[1] === "uninstall")) {
|