@roamcode.ai/server 1.0.19 → 1.0.21
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/dist/index.d.ts +6 -7
- package/dist/index.js +68 -89
- package/dist/start.js +64 -85
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -2466,12 +2466,12 @@ type CodexExecutableProbe = {
|
|
|
2466
2466
|
state: "failed";
|
|
2467
2467
|
};
|
|
2468
2468
|
interface CodexExecutableResolution {
|
|
2469
|
-
/**
|
|
2469
|
+
/** Stable user-selected command used by Codex terminals and auxiliary services. */
|
|
2470
2470
|
executable: string;
|
|
2471
|
-
/**
|
|
2471
|
+
/** Resolved source installation inspected during boot. */
|
|
2472
2472
|
sourceExecutable: string;
|
|
2473
2473
|
provenance: CodexInstallProvenance;
|
|
2474
|
-
/** True only when
|
|
2474
|
+
/** True only when a blocked OpenAI-signed Homebrew executable was atomically repaired in place. */
|
|
2475
2475
|
recovered: boolean;
|
|
2476
2476
|
}
|
|
2477
2477
|
interface CodexExecutableDeps {
|
|
@@ -2489,10 +2489,9 @@ interface ResolveCodexExecutableOptions {
|
|
|
2489
2489
|
}
|
|
2490
2490
|
declare function defaultProbeCodexExecutable(executable: string, env: NodeJS.ProcessEnv): Promise<CodexExecutableProbe>;
|
|
2491
2491
|
/**
|
|
2492
|
-
*
|
|
2493
|
-
*
|
|
2494
|
-
*
|
|
2495
|
-
* It never modifies the user's Codex installation and never applies the workaround to an unsigned binary.
|
|
2492
|
+
* Probe the configured Codex CLI once at boot. Only a timed-out, officially signed Homebrew installation is
|
|
2493
|
+
* repaired, and the configured command remains the stable launch path so future Homebrew upgrades are not pinned
|
|
2494
|
+
* to an old Caskroom version.
|
|
2496
2495
|
*/
|
|
2497
2496
|
declare function resolveCodexExecutable(options: ResolveCodexExecutableOptions): Promise<CodexExecutableResolution>;
|
|
2498
2497
|
|
package/dist/index.js
CHANGED
|
@@ -2268,16 +2268,16 @@ async function smokeServer(serverEntry, dataDir, nodePath, log) {
|
|
|
2268
2268
|
void dataDir;
|
|
2269
2269
|
}
|
|
2270
2270
|
}
|
|
2271
|
-
function replaceSymlink(
|
|
2272
|
-
const temp = `${
|
|
2271
|
+
function replaceSymlink(link2, target) {
|
|
2272
|
+
const temp = `${link2}.${process.pid}.${randomUUID2()}.new`;
|
|
2273
2273
|
try {
|
|
2274
2274
|
unlinkSync(temp);
|
|
2275
2275
|
} catch {
|
|
2276
2276
|
}
|
|
2277
|
-
const parent = realpathSync(dirname2(
|
|
2277
|
+
const parent = realpathSync(dirname2(link2));
|
|
2278
2278
|
const canonicalTarget = realpathSync(target);
|
|
2279
2279
|
symlinkSync(relative(parent, canonicalTarget), temp, "dir");
|
|
2280
|
-
renameSync(temp,
|
|
2280
|
+
renameSync(temp, link2);
|
|
2281
2281
|
}
|
|
2282
2282
|
function trimLog(log) {
|
|
2283
2283
|
return log.split("\n").slice(-20).join("\n").slice(-8e3);
|
|
@@ -2429,7 +2429,7 @@ async function installManagedRelease(opts) {
|
|
|
2429
2429
|
}
|
|
2430
2430
|
|
|
2431
2431
|
// src/updater.ts
|
|
2432
|
-
var RUNNING_VERSION = "1.0.
|
|
2432
|
+
var RUNNING_VERSION = "1.0.21" ? "1.0.21".replace(/^v/, "") : packageVersion();
|
|
2433
2433
|
var RUNNING_BUILD = RUNNING_VERSION;
|
|
2434
2434
|
var RELEASES_API = "https://api.github.com/repos/burakgon/roamcode/releases?per_page=100";
|
|
2435
2435
|
var RELEASE_MANIFEST_ASSET = "roamcode-release.json";
|
|
@@ -8588,29 +8588,16 @@ var CodexLatestService = class {
|
|
|
8588
8588
|
// src/providers/codex-executable.ts
|
|
8589
8589
|
import { execFile } from "child_process";
|
|
8590
8590
|
import { constants as constants2 } from "fs";
|
|
8591
|
-
import {
|
|
8592
|
-
access,
|
|
8593
|
-
chmod,
|
|
8594
|
-
copyFile,
|
|
8595
|
-
lstat as lstat2,
|
|
8596
|
-
mkdir as mkdir2,
|
|
8597
|
-
readFile as readFile3,
|
|
8598
|
-
realpath as realpath3,
|
|
8599
|
-
rename as rename2,
|
|
8600
|
-
rm,
|
|
8601
|
-
stat as stat3,
|
|
8602
|
-
writeFile
|
|
8603
|
-
} from "fs/promises";
|
|
8591
|
+
import { access, chmod, copyFile, link, realpath as realpath3, rename as rename2, rm, rmdir as rmdir2, stat as stat3 } from "fs/promises";
|
|
8604
8592
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
8605
|
-
import { delimiter, isAbsolute as isAbsolute5, join as join12, sep as sep5 } from "path";
|
|
8593
|
+
import { basename as basename3, delimiter, dirname as dirname5, isAbsolute as isAbsolute5, join as join12, sep as sep5 } from "path";
|
|
8606
8594
|
var CODEX_EXECUTABLE_PROBE_TIMEOUT_MS = 5e3;
|
|
8607
8595
|
var OPENAI_CODE_SIGNING_TEAM_ID = "2DC432GLL2";
|
|
8608
|
-
var
|
|
8609
|
-
var MAX_MANAGED_CODEX_BYTES = 1024 * 1024 * 1024;
|
|
8610
|
-
var MANAGED_DIRECTORY = "provider-bin";
|
|
8611
|
-
var MANAGED_EXECUTABLE = "codex-macos";
|
|
8612
|
-
var STATE_FILE = "codex-macos-source.json";
|
|
8596
|
+
var MAX_CODEX_BYTES = 1024 * 1024 * 1024;
|
|
8613
8597
|
var MAX_PROCESS_OUTPUT_BYTES = 16 * 1024;
|
|
8598
|
+
var LEGACY_MANAGED_DIRECTORY = "provider-bin";
|
|
8599
|
+
var LEGACY_MANAGED_EXECUTABLE = "codex-macos";
|
|
8600
|
+
var LEGACY_MANAGED_STATE = "codex-macos-source.json";
|
|
8614
8601
|
function runBounded(executable, args, options) {
|
|
8615
8602
|
return new Promise((resolve7) => {
|
|
8616
8603
|
execFile(
|
|
@@ -8696,37 +8683,60 @@ function provenanceFor(executable) {
|
|
|
8696
8683
|
if (/\/node_modules\/(?:@openai\/codex|@openai\/codex-[^/]+)\//i.test(normalized)) return "npm";
|
|
8697
8684
|
return "unknown";
|
|
8698
8685
|
}
|
|
8699
|
-
function
|
|
8700
|
-
return
|
|
8701
|
-
sourcePath,
|
|
8702
|
-
device: String(sourceStat.dev),
|
|
8703
|
-
inode: String(sourceStat.ino),
|
|
8704
|
-
size: sourceStat.size,
|
|
8705
|
-
modifiedAtMs: sourceStat.mtimeMs
|
|
8706
|
-
};
|
|
8686
|
+
function validSource(sourceStat) {
|
|
8687
|
+
return sourceStat.isFile() && sourceStat.size > 0 && sourceStat.size <= MAX_CODEX_BYTES;
|
|
8707
8688
|
}
|
|
8708
|
-
function
|
|
8709
|
-
|
|
8710
|
-
const value = JSON.parse(raw);
|
|
8711
|
-
if (value.schemaVersion !== STATE_SCHEMA_VERSION || typeof value.sourcePath !== "string" || typeof value.device !== "string" || typeof value.inode !== "string" || typeof value.size !== "number" || !Number.isSafeInteger(value.size) || typeof value.modifiedAtMs !== "number" || !Number.isFinite(value.modifiedAtMs)) {
|
|
8712
|
-
return void 0;
|
|
8713
|
-
}
|
|
8714
|
-
return value;
|
|
8715
|
-
} catch {
|
|
8716
|
-
return void 0;
|
|
8717
|
-
}
|
|
8689
|
+
function sameSource(left, right) {
|
|
8690
|
+
return left.dev === right.dev && left.ino === right.ino && left.size === right.size && left.mtimeMs === right.mtimeMs;
|
|
8718
8691
|
}
|
|
8719
|
-
function
|
|
8720
|
-
|
|
8692
|
+
async function removeLegacyManagedCopy(dataDir) {
|
|
8693
|
+
const directory = join12(dataDir, LEGACY_MANAGED_DIRECTORY);
|
|
8694
|
+
await Promise.all([
|
|
8695
|
+
rm(join12(directory, LEGACY_MANAGED_EXECUTABLE), { force: true }).catch(() => void 0),
|
|
8696
|
+
rm(join12(directory, LEGACY_MANAGED_STATE), { force: true }).catch(() => void 0)
|
|
8697
|
+
]);
|
|
8698
|
+
await rmdir2(directory).catch(() => void 0);
|
|
8721
8699
|
}
|
|
8722
|
-
async function
|
|
8700
|
+
async function repairHomebrewExecutable(source, sourceStat, env, deps) {
|
|
8701
|
+
if (!await deps.verifyOfficialSignature(source)) return false;
|
|
8702
|
+
const nonce = randomUUID7();
|
|
8703
|
+
const directory = dirname5(source);
|
|
8704
|
+
const name = basename3(source);
|
|
8705
|
+
const temporary = join12(directory, `.${name}.roamcode-repair-${nonce}`);
|
|
8706
|
+
const backup = join12(directory, `.${name}.roamcode-backup-${nonce}`);
|
|
8707
|
+
let backupCreated = false;
|
|
8708
|
+
let sourceReplaced = false;
|
|
8709
|
+
let committed = false;
|
|
8710
|
+
let preserveBackup = false;
|
|
8723
8711
|
try {
|
|
8724
|
-
|
|
8725
|
-
|
|
8726
|
-
if (!await deps.
|
|
8727
|
-
|
|
8712
|
+
await copyFile(source, temporary, constants2.COPYFILE_EXCL);
|
|
8713
|
+
await chmod(temporary, sourceStat.mode & 511);
|
|
8714
|
+
if (!await deps.clearExtendedAttributes(temporary)) return false;
|
|
8715
|
+
if (!await deps.verifyOfficialSignature(temporary)) return false;
|
|
8716
|
+
if ((await deps.probe(temporary, env)).state !== "ready") return false;
|
|
8717
|
+
const currentStat = await stat3(source);
|
|
8718
|
+
if (!sameSource(sourceStat, currentStat)) return false;
|
|
8719
|
+
await link(source, backup);
|
|
8720
|
+
backupCreated = true;
|
|
8721
|
+
await rename2(temporary, source);
|
|
8722
|
+
sourceReplaced = true;
|
|
8723
|
+
if (!await deps.verifyOfficialSignature(source)) return false;
|
|
8724
|
+
if ((await deps.probe(source, env)).state !== "ready") return false;
|
|
8725
|
+
committed = true;
|
|
8726
|
+
return true;
|
|
8728
8727
|
} catch {
|
|
8729
8728
|
return false;
|
|
8729
|
+
} finally {
|
|
8730
|
+
if (sourceReplaced && !committed && backupCreated) {
|
|
8731
|
+
try {
|
|
8732
|
+
await rename2(backup, source);
|
|
8733
|
+
backupCreated = false;
|
|
8734
|
+
} catch {
|
|
8735
|
+
preserveBackup = true;
|
|
8736
|
+
}
|
|
8737
|
+
}
|
|
8738
|
+
await rm(temporary, { force: true }).catch(() => void 0);
|
|
8739
|
+
if (!preserveBackup) await rm(backup, { force: true }).catch(() => void 0);
|
|
8730
8740
|
}
|
|
8731
8741
|
}
|
|
8732
8742
|
async function resolveCodexExecutable(options) {
|
|
@@ -8743,7 +8753,7 @@ async function resolveCodexExecutable(options) {
|
|
|
8743
8753
|
if (!source) return unresolved;
|
|
8744
8754
|
const provenance = provenanceFor(source);
|
|
8745
8755
|
const ordinary = {
|
|
8746
|
-
executable:
|
|
8756
|
+
executable: options.codexBin,
|
|
8747
8757
|
sourceExecutable: source,
|
|
8748
8758
|
provenance,
|
|
8749
8759
|
recovered: false
|
|
@@ -8754,47 +8764,16 @@ async function resolveCodexExecutable(options) {
|
|
|
8754
8764
|
} catch {
|
|
8755
8765
|
return ordinary;
|
|
8756
8766
|
}
|
|
8757
|
-
if (!
|
|
8758
|
-
const identity = identityFor(source, sourceStat);
|
|
8759
|
-
const managedDir = join12(options.dataDir, MANAGED_DIRECTORY);
|
|
8760
|
-
const target = join12(managedDir, MANAGED_EXECUTABLE);
|
|
8761
|
-
const statePath = join12(managedDir, STATE_FILE);
|
|
8762
|
-
try {
|
|
8763
|
-
const state = parseManagedState(await readFile3(statePath, "utf8"));
|
|
8764
|
-
if (state && stateMatches(state, identity) && await usableManagedExecutable(target, env, deps)) {
|
|
8765
|
-
return { executable: target, sourceExecutable: source, provenance, recovered: true };
|
|
8766
|
-
}
|
|
8767
|
-
} catch {
|
|
8768
|
-
}
|
|
8767
|
+
if (!validSource(sourceStat)) return ordinary;
|
|
8769
8768
|
const sourceProbe = await deps.probe(source, env);
|
|
8770
|
-
if (sourceProbe.state
|
|
8771
|
-
|
|
8772
|
-
const nonce = randomUUID7();
|
|
8773
|
-
const temporaryExecutable = join12(managedDir, `.codex-${nonce}.tmp`);
|
|
8774
|
-
const temporaryState = join12(managedDir, `.codex-state-${nonce}.tmp`);
|
|
8775
|
-
try {
|
|
8776
|
-
await mkdir2(managedDir, { recursive: true, mode: 448 });
|
|
8777
|
-
await chmod(managedDir, 448);
|
|
8778
|
-
await copyFile(source, temporaryExecutable, constants2.COPYFILE_EXCL);
|
|
8779
|
-
await chmod(temporaryExecutable, 448);
|
|
8780
|
-
if (!await deps.clearExtendedAttributes(temporaryExecutable)) return ordinary;
|
|
8781
|
-
if (!await deps.verifyOfficialSignature(temporaryExecutable)) return ordinary;
|
|
8782
|
-
if ((await deps.probe(temporaryExecutable, env)).state !== "ready") return ordinary;
|
|
8783
|
-
await rename2(temporaryExecutable, target);
|
|
8784
|
-
if (!await usableManagedExecutable(target, env, deps)) return ordinary;
|
|
8785
|
-
const state = { schemaVersion: STATE_SCHEMA_VERSION, ...identity };
|
|
8786
|
-
await writeFile(temporaryState, `${JSON.stringify(state)}
|
|
8787
|
-
`, { encoding: "utf8", mode: 384, flag: "wx" });
|
|
8788
|
-
await rename2(temporaryState, statePath);
|
|
8789
|
-
return { executable: target, sourceExecutable: source, provenance, recovered: true };
|
|
8790
|
-
} catch {
|
|
8769
|
+
if (sourceProbe.state === "ready") {
|
|
8770
|
+
await removeLegacyManagedCopy(options.dataDir);
|
|
8791
8771
|
return ordinary;
|
|
8792
|
-
} finally {
|
|
8793
|
-
await Promise.all([
|
|
8794
|
-
rm(temporaryExecutable, { force: true }).catch(() => void 0),
|
|
8795
|
-
rm(temporaryState, { force: true }).catch(() => void 0)
|
|
8796
|
-
]);
|
|
8797
8772
|
}
|
|
8773
|
+
if (sourceProbe.state !== "timeout" || provenance !== "homebrew") return ordinary;
|
|
8774
|
+
if (!await repairHomebrewExecutable(source, sourceStat, env, deps)) return ordinary;
|
|
8775
|
+
await removeLegacyManagedCopy(options.dataDir);
|
|
8776
|
+
return { ...ordinary, recovered: true };
|
|
8798
8777
|
}
|
|
8799
8778
|
|
|
8800
8779
|
// src/start.ts
|
|
@@ -8857,7 +8836,7 @@ async function startServer(env = process.env) {
|
|
|
8857
8836
|
const codexBin = codexExecutable.executable;
|
|
8858
8837
|
if (codexExecutable.recovered) {
|
|
8859
8838
|
console.warn(
|
|
8860
|
-
"[roamcode]
|
|
8839
|
+
"[roamcode] Repaired a macOS-blocked Homebrew Codex CLI in place using a verified, byte-identical OpenAI-signed replacement; no private binary was retained."
|
|
8861
8840
|
);
|
|
8862
8841
|
}
|
|
8863
8842
|
const store = openSessionStore({ dbPath: join13(config.dataDir, "sessions.db") });
|
package/dist/start.js
CHANGED
|
@@ -871,7 +871,7 @@ function readPreviousVersion(root) {
|
|
|
871
871
|
}
|
|
872
872
|
|
|
873
873
|
// src/updater.ts
|
|
874
|
-
var RUNNING_VERSION = "1.0.
|
|
874
|
+
var RUNNING_VERSION = "1.0.21" ? "1.0.21".replace(/^v/, "") : packageVersion();
|
|
875
875
|
var RELEASES_API = "https://api.github.com/repos/burakgon/roamcode/releases?per_page=100";
|
|
876
876
|
var RELEASE_MANIFEST_ASSET = "roamcode-release.json";
|
|
877
877
|
var CHECK_CACHE_MS = 15 * 6e4;
|
|
@@ -8049,29 +8049,16 @@ var CodexLatestService = class {
|
|
|
8049
8049
|
// src/providers/codex-executable.ts
|
|
8050
8050
|
import { execFile } from "child_process";
|
|
8051
8051
|
import { constants as constants2 } from "fs";
|
|
8052
|
-
import {
|
|
8053
|
-
access,
|
|
8054
|
-
chmod,
|
|
8055
|
-
copyFile,
|
|
8056
|
-
lstat as lstat2,
|
|
8057
|
-
mkdir as mkdir2,
|
|
8058
|
-
readFile as readFile3,
|
|
8059
|
-
realpath as realpath3,
|
|
8060
|
-
rename as rename2,
|
|
8061
|
-
rm,
|
|
8062
|
-
stat as stat3,
|
|
8063
|
-
writeFile
|
|
8064
|
-
} from "fs/promises";
|
|
8052
|
+
import { access, chmod, copyFile, link, realpath as realpath3, rename as rename2, rm, rmdir as rmdir2, stat as stat3 } from "fs/promises";
|
|
8065
8053
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
8066
|
-
import { delimiter, isAbsolute as isAbsolute5, join as join12, sep as sep5 } from "path";
|
|
8054
|
+
import { basename as basename3, delimiter, dirname as dirname5, isAbsolute as isAbsolute5, join as join12, sep as sep5 } from "path";
|
|
8067
8055
|
var CODEX_EXECUTABLE_PROBE_TIMEOUT_MS = 5e3;
|
|
8068
8056
|
var OPENAI_CODE_SIGNING_TEAM_ID = "2DC432GLL2";
|
|
8069
|
-
var
|
|
8070
|
-
var MAX_MANAGED_CODEX_BYTES = 1024 * 1024 * 1024;
|
|
8071
|
-
var MANAGED_DIRECTORY = "provider-bin";
|
|
8072
|
-
var MANAGED_EXECUTABLE = "codex-macos";
|
|
8073
|
-
var STATE_FILE = "codex-macos-source.json";
|
|
8057
|
+
var MAX_CODEX_BYTES = 1024 * 1024 * 1024;
|
|
8074
8058
|
var MAX_PROCESS_OUTPUT_BYTES = 16 * 1024;
|
|
8059
|
+
var LEGACY_MANAGED_DIRECTORY = "provider-bin";
|
|
8060
|
+
var LEGACY_MANAGED_EXECUTABLE = "codex-macos";
|
|
8061
|
+
var LEGACY_MANAGED_STATE = "codex-macos-source.json";
|
|
8075
8062
|
function runBounded(executable, args, options) {
|
|
8076
8063
|
return new Promise((resolve7) => {
|
|
8077
8064
|
execFile(
|
|
@@ -8157,37 +8144,60 @@ function provenanceFor(executable) {
|
|
|
8157
8144
|
if (/\/node_modules\/(?:@openai\/codex|@openai\/codex-[^/]+)\//i.test(normalized)) return "npm";
|
|
8158
8145
|
return "unknown";
|
|
8159
8146
|
}
|
|
8160
|
-
function
|
|
8161
|
-
return
|
|
8162
|
-
sourcePath,
|
|
8163
|
-
device: String(sourceStat.dev),
|
|
8164
|
-
inode: String(sourceStat.ino),
|
|
8165
|
-
size: sourceStat.size,
|
|
8166
|
-
modifiedAtMs: sourceStat.mtimeMs
|
|
8167
|
-
};
|
|
8147
|
+
function validSource(sourceStat) {
|
|
8148
|
+
return sourceStat.isFile() && sourceStat.size > 0 && sourceStat.size <= MAX_CODEX_BYTES;
|
|
8168
8149
|
}
|
|
8169
|
-
function
|
|
8170
|
-
|
|
8171
|
-
const value = JSON.parse(raw);
|
|
8172
|
-
if (value.schemaVersion !== STATE_SCHEMA_VERSION || typeof value.sourcePath !== "string" || typeof value.device !== "string" || typeof value.inode !== "string" || typeof value.size !== "number" || !Number.isSafeInteger(value.size) || typeof value.modifiedAtMs !== "number" || !Number.isFinite(value.modifiedAtMs)) {
|
|
8173
|
-
return void 0;
|
|
8174
|
-
}
|
|
8175
|
-
return value;
|
|
8176
|
-
} catch {
|
|
8177
|
-
return void 0;
|
|
8178
|
-
}
|
|
8150
|
+
function sameSource(left, right) {
|
|
8151
|
+
return left.dev === right.dev && left.ino === right.ino && left.size === right.size && left.mtimeMs === right.mtimeMs;
|
|
8179
8152
|
}
|
|
8180
|
-
function
|
|
8181
|
-
|
|
8153
|
+
async function removeLegacyManagedCopy(dataDir) {
|
|
8154
|
+
const directory = join12(dataDir, LEGACY_MANAGED_DIRECTORY);
|
|
8155
|
+
await Promise.all([
|
|
8156
|
+
rm(join12(directory, LEGACY_MANAGED_EXECUTABLE), { force: true }).catch(() => void 0),
|
|
8157
|
+
rm(join12(directory, LEGACY_MANAGED_STATE), { force: true }).catch(() => void 0)
|
|
8158
|
+
]);
|
|
8159
|
+
await rmdir2(directory).catch(() => void 0);
|
|
8182
8160
|
}
|
|
8183
|
-
async function
|
|
8161
|
+
async function repairHomebrewExecutable(source, sourceStat, env, deps) {
|
|
8162
|
+
if (!await deps.verifyOfficialSignature(source)) return false;
|
|
8163
|
+
const nonce = randomUUID7();
|
|
8164
|
+
const directory = dirname5(source);
|
|
8165
|
+
const name = basename3(source);
|
|
8166
|
+
const temporary = join12(directory, `.${name}.roamcode-repair-${nonce}`);
|
|
8167
|
+
const backup = join12(directory, `.${name}.roamcode-backup-${nonce}`);
|
|
8168
|
+
let backupCreated = false;
|
|
8169
|
+
let sourceReplaced = false;
|
|
8170
|
+
let committed = false;
|
|
8171
|
+
let preserveBackup = false;
|
|
8184
8172
|
try {
|
|
8185
|
-
|
|
8186
|
-
|
|
8187
|
-
if (!await deps.
|
|
8188
|
-
|
|
8173
|
+
await copyFile(source, temporary, constants2.COPYFILE_EXCL);
|
|
8174
|
+
await chmod(temporary, sourceStat.mode & 511);
|
|
8175
|
+
if (!await deps.clearExtendedAttributes(temporary)) return false;
|
|
8176
|
+
if (!await deps.verifyOfficialSignature(temporary)) return false;
|
|
8177
|
+
if ((await deps.probe(temporary, env)).state !== "ready") return false;
|
|
8178
|
+
const currentStat = await stat3(source);
|
|
8179
|
+
if (!sameSource(sourceStat, currentStat)) return false;
|
|
8180
|
+
await link(source, backup);
|
|
8181
|
+
backupCreated = true;
|
|
8182
|
+
await rename2(temporary, source);
|
|
8183
|
+
sourceReplaced = true;
|
|
8184
|
+
if (!await deps.verifyOfficialSignature(source)) return false;
|
|
8185
|
+
if ((await deps.probe(source, env)).state !== "ready") return false;
|
|
8186
|
+
committed = true;
|
|
8187
|
+
return true;
|
|
8189
8188
|
} catch {
|
|
8190
8189
|
return false;
|
|
8190
|
+
} finally {
|
|
8191
|
+
if (sourceReplaced && !committed && backupCreated) {
|
|
8192
|
+
try {
|
|
8193
|
+
await rename2(backup, source);
|
|
8194
|
+
backupCreated = false;
|
|
8195
|
+
} catch {
|
|
8196
|
+
preserveBackup = true;
|
|
8197
|
+
}
|
|
8198
|
+
}
|
|
8199
|
+
await rm(temporary, { force: true }).catch(() => void 0);
|
|
8200
|
+
if (!preserveBackup) await rm(backup, { force: true }).catch(() => void 0);
|
|
8191
8201
|
}
|
|
8192
8202
|
}
|
|
8193
8203
|
async function resolveCodexExecutable(options) {
|
|
@@ -8204,7 +8214,7 @@ async function resolveCodexExecutable(options) {
|
|
|
8204
8214
|
if (!source) return unresolved;
|
|
8205
8215
|
const provenance = provenanceFor(source);
|
|
8206
8216
|
const ordinary = {
|
|
8207
|
-
executable:
|
|
8217
|
+
executable: options.codexBin,
|
|
8208
8218
|
sourceExecutable: source,
|
|
8209
8219
|
provenance,
|
|
8210
8220
|
recovered: false
|
|
@@ -8215,47 +8225,16 @@ async function resolveCodexExecutable(options) {
|
|
|
8215
8225
|
} catch {
|
|
8216
8226
|
return ordinary;
|
|
8217
8227
|
}
|
|
8218
|
-
if (!
|
|
8219
|
-
const identity = identityFor(source, sourceStat);
|
|
8220
|
-
const managedDir = join12(options.dataDir, MANAGED_DIRECTORY);
|
|
8221
|
-
const target = join12(managedDir, MANAGED_EXECUTABLE);
|
|
8222
|
-
const statePath = join12(managedDir, STATE_FILE);
|
|
8223
|
-
try {
|
|
8224
|
-
const state = parseManagedState(await readFile3(statePath, "utf8"));
|
|
8225
|
-
if (state && stateMatches(state, identity) && await usableManagedExecutable(target, env, deps)) {
|
|
8226
|
-
return { executable: target, sourceExecutable: source, provenance, recovered: true };
|
|
8227
|
-
}
|
|
8228
|
-
} catch {
|
|
8229
|
-
}
|
|
8228
|
+
if (!validSource(sourceStat)) return ordinary;
|
|
8230
8229
|
const sourceProbe = await deps.probe(source, env);
|
|
8231
|
-
if (sourceProbe.state
|
|
8232
|
-
|
|
8233
|
-
const nonce = randomUUID7();
|
|
8234
|
-
const temporaryExecutable = join12(managedDir, `.codex-${nonce}.tmp`);
|
|
8235
|
-
const temporaryState = join12(managedDir, `.codex-state-${nonce}.tmp`);
|
|
8236
|
-
try {
|
|
8237
|
-
await mkdir2(managedDir, { recursive: true, mode: 448 });
|
|
8238
|
-
await chmod(managedDir, 448);
|
|
8239
|
-
await copyFile(source, temporaryExecutable, constants2.COPYFILE_EXCL);
|
|
8240
|
-
await chmod(temporaryExecutable, 448);
|
|
8241
|
-
if (!await deps.clearExtendedAttributes(temporaryExecutable)) return ordinary;
|
|
8242
|
-
if (!await deps.verifyOfficialSignature(temporaryExecutable)) return ordinary;
|
|
8243
|
-
if ((await deps.probe(temporaryExecutable, env)).state !== "ready") return ordinary;
|
|
8244
|
-
await rename2(temporaryExecutable, target);
|
|
8245
|
-
if (!await usableManagedExecutable(target, env, deps)) return ordinary;
|
|
8246
|
-
const state = { schemaVersion: STATE_SCHEMA_VERSION, ...identity };
|
|
8247
|
-
await writeFile(temporaryState, `${JSON.stringify(state)}
|
|
8248
|
-
`, { encoding: "utf8", mode: 384, flag: "wx" });
|
|
8249
|
-
await rename2(temporaryState, statePath);
|
|
8250
|
-
return { executable: target, sourceExecutable: source, provenance, recovered: true };
|
|
8251
|
-
} catch {
|
|
8230
|
+
if (sourceProbe.state === "ready") {
|
|
8231
|
+
await removeLegacyManagedCopy(options.dataDir);
|
|
8252
8232
|
return ordinary;
|
|
8253
|
-
} finally {
|
|
8254
|
-
await Promise.all([
|
|
8255
|
-
rm(temporaryExecutable, { force: true }).catch(() => void 0),
|
|
8256
|
-
rm(temporaryState, { force: true }).catch(() => void 0)
|
|
8257
|
-
]);
|
|
8258
8233
|
}
|
|
8234
|
+
if (sourceProbe.state !== "timeout" || provenance !== "homebrew") return ordinary;
|
|
8235
|
+
if (!await repairHomebrewExecutable(source, sourceStat, env, deps)) return ordinary;
|
|
8236
|
+
await removeLegacyManagedCopy(options.dataDir);
|
|
8237
|
+
return { ...ordinary, recovered: true };
|
|
8259
8238
|
}
|
|
8260
8239
|
|
|
8261
8240
|
// src/start.ts
|
|
@@ -8318,7 +8297,7 @@ async function startServer(env = process.env) {
|
|
|
8318
8297
|
const codexBin = codexExecutable.executable;
|
|
8319
8298
|
if (codexExecutable.recovered) {
|
|
8320
8299
|
console.warn(
|
|
8321
|
-
"[roamcode]
|
|
8300
|
+
"[roamcode] Repaired a macOS-blocked Homebrew Codex CLI in place using a verified, byte-identical OpenAI-signed replacement; no private binary was retained."
|
|
8322
8301
|
);
|
|
8323
8302
|
}
|
|
8324
8303
|
const store = openSessionStore({ dbPath: join13(config.dataDir, "sessions.db") });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@roamcode.ai/server",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.21",
|
|
4
4
|
"description": "Host-native server for RoamCode",
|
|
5
5
|
"homepage": "https://roamcode.ai",
|
|
6
6
|
"bugs": "https://github.com/burakgon/roamcode/issues",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"node-pty": "1.1.0",
|
|
41
41
|
"web-push": "^3.6.7",
|
|
42
42
|
"zod": "^4.4.3",
|
|
43
|
-
"@roamcode.ai/web": "1.0.
|
|
43
|
+
"@roamcode.ai/web": "1.0.21"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@types/better-sqlite3": "^7.6.13",
|