openmausbot 0.1.67 → 0.1.69
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/assets/{index-BwpNqgCm.js → index-BmHupgVJ.js} +1 -1
- package/dist/assets/index-COp5lMnv.js +279 -0
- package/dist/assets/index-Jk7TIeyW.css +1 -0
- package/dist/index.html +2 -2
- package/dist-server/container-mcp.js +40 -2
- package/dist-server/drivers/agents-proxy.js +112 -7
- package/dist-server/enterprise/server/index.js +14587 -0
- package/dist-server/index.js +1732 -681
- package/dist-server/openmausbot.js +939 -381
- package/dist-server/pair-cli.js +939 -381
- package/dist-server/server/avatar-image.js +86 -34
- package/dist-server/server/bot-package.js +60 -14
- package/dist-server/server/brand.js +7 -0
- package/dist-server/server/cli.js +23 -1
- package/dist-server/server/config.js +30 -3
- package/dist-server/server/delegations.js +56 -11
- package/dist-server/server/drivers/acp/qwen.js +142 -5
- package/dist-server/server/drivers/agents-proxy.js +135 -8
- package/dist-server/server/drivers/codex-device-auth.js +102 -3
- package/dist-server/server/drivers/codex-identity.js +115 -0
- package/dist-server/server/drivers/codex.js +6 -0
- package/dist-server/server/harness/registry.js +2 -0
- package/dist-server/server/index.js +220 -65
- package/dist-server/server/package-export.js +7 -0
- package/dist-server/server/provider-auth-sessions.js +24 -0
- package/dist-server/server/routine-requests.js +270 -25
- package/dist-server/server/routines.js +215 -21
- package/dist-server/server/service-cli.js +63 -0
- package/dist-server/server/service-unit.js +129 -0
- package/dist-server/server/steer-queue.js +30 -1
- package/dist-server/server/store.js +30 -4
- package/dist-server/server/system-prompt.js +1 -0
- package/dist-server/server/turn-dispatch-guard.js +6 -0
- package/dist-server/shared/image-generation.js +28 -0
- package/dist-server/vps-container-mcp.js +40 -2
- package/enterprise/LICENSE +32 -0
- package/enterprise/README.md +89 -0
- package/enterprise/server/index.js +14587 -0
- package/package.json +2 -1
- package/dist/assets/index-A3CBTxwl.css +0 -1
- package/dist/assets/index-CDuyoVPJ.js +0 -278
|
@@ -2298,7 +2298,7 @@ function displayText(value, multiline = false) {
|
|
|
2298
2298
|
}
|
|
2299
2299
|
function plainText(question, hidden, context) {
|
|
2300
2300
|
const { input, output, signal } = context;
|
|
2301
|
-
return new Promise((
|
|
2301
|
+
return new Promise((resolve13, reject) => {
|
|
2302
2302
|
input.setRawMode?.(hidden);
|
|
2303
2303
|
const rl = createInterface({ input, terminal: hidden });
|
|
2304
2304
|
let finished = false;
|
|
@@ -2309,7 +2309,7 @@ function plainText(question, hidden, context) {
|
|
|
2309
2309
|
rl.close();
|
|
2310
2310
|
output.write("\n");
|
|
2311
2311
|
if (error51) reject(error51);
|
|
2312
|
-
else
|
|
2312
|
+
else resolve13(answer ?? "");
|
|
2313
2313
|
};
|
|
2314
2314
|
const cancel = () => finish(void 0, signal.reason ?? new SetupCancelled());
|
|
2315
2315
|
signal.addEventListener("abort", cancel, { once: true });
|
|
@@ -17526,6 +17526,30 @@ var init_zod = __esm({
|
|
|
17526
17526
|
}
|
|
17527
17527
|
});
|
|
17528
17528
|
|
|
17529
|
+
// shared/image-generation.ts
|
|
17530
|
+
function normalizeImageGenerationUrl(value) {
|
|
17531
|
+
const message2 = "Use an HTTPS API base URL, or HTTP for a local router, without passwords, query parameters or fragments";
|
|
17532
|
+
let url2;
|
|
17533
|
+
try {
|
|
17534
|
+
url2 = new URL(value.trim());
|
|
17535
|
+
} catch {
|
|
17536
|
+
throw new Error(message2);
|
|
17537
|
+
}
|
|
17538
|
+
if (value.length > 2048 || url2.username || url2.password || url2.search || url2.hash) throw new Error(message2);
|
|
17539
|
+
const host = url2.hostname.toLowerCase();
|
|
17540
|
+
const ipv43 = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/.exec(host);
|
|
17541
|
+
const local = host === "localhost" || host.endsWith(".localhost") || host.endsWith(".local") || host === "host.docker.internal" || host === "host.containers.internal" || host === "[::1]" || /^\[f[cd][0-9a-f]{2}:/.test(host) || ipv43 && (Number(ipv43[1]) === 127 || Number(ipv43[1]) === 10 || Number(ipv43[1]) === 192 && Number(ipv43[2]) === 168 || Number(ipv43[1]) === 172 && Number(ipv43[2]) >= 16 && Number(ipv43[2]) <= 31);
|
|
17542
|
+
if (url2.protocol !== "https:" && !(url2.protocol === "http:" && local)) throw new Error(message2);
|
|
17543
|
+
if (ipv43 && (Number(ipv43[1]) === 0 || Number(ipv43[1]) === 169 && Number(ipv43[2]) === 254)) throw new Error(message2);
|
|
17544
|
+
url2.pathname = url2.pathname.replace(/\/+$/, "").replace(/\/images\/generations$/, "");
|
|
17545
|
+
return url2.toString().replace(/\/+$/, "");
|
|
17546
|
+
}
|
|
17547
|
+
var init_image_generation = __esm({
|
|
17548
|
+
"shared/image-generation.ts"() {
|
|
17549
|
+
"use strict";
|
|
17550
|
+
}
|
|
17551
|
+
});
|
|
17552
|
+
|
|
17529
17553
|
// server/contracts.ts
|
|
17530
17554
|
var EFFORT_LEVELS, eventCounter, newEventId, newId;
|
|
17531
17555
|
var init_contracts = __esm({
|
|
@@ -17577,9 +17601,9 @@ var init_schema = __esm({
|
|
|
17577
17601
|
});
|
|
17578
17602
|
|
|
17579
17603
|
// server/config.ts
|
|
17580
|
-
import { readFileSync as readFileSync2, mkdirSync as
|
|
17581
|
-
import { homedir as
|
|
17582
|
-
import { join as
|
|
17604
|
+
import { readFileSync as readFileSync2, mkdirSync as mkdirSync4, existsSync as existsSync3, renameSync as renameSync3 } from "node:fs";
|
|
17605
|
+
import { homedir as homedir4 } from "node:os";
|
|
17606
|
+
import { join as join5 } from "node:path";
|
|
17583
17607
|
function isValidSshAlias(value) {
|
|
17584
17608
|
return typeof value === "string" && SSH_ALIAS.test(value);
|
|
17585
17609
|
}
|
|
@@ -17712,7 +17736,7 @@ function parseStoredConfig(value) {
|
|
|
17712
17736
|
function loadConfig() {
|
|
17713
17737
|
let cfg = {};
|
|
17714
17738
|
try {
|
|
17715
|
-
cfg = parseStoredConfig(parseJson(readFileSync2(
|
|
17739
|
+
cfg = parseStoredConfig(parseJson(readFileSync2(join5(DATA_DIR, "config.json"), "utf8")));
|
|
17716
17740
|
} catch {
|
|
17717
17741
|
}
|
|
17718
17742
|
cfg.xai = { ...cfg.xai };
|
|
@@ -17732,6 +17756,7 @@ function loadConfig() {
|
|
|
17732
17756
|
if (process.env.OMB_TTS_KEY !== void 0) cfg.tts.key = process.env.OMB_TTS_KEY;
|
|
17733
17757
|
cfg.imageGen = { ...cfg.imageGen };
|
|
17734
17758
|
if (process.env.OMB_OPENAI_IMAGE_KEY !== void 0) cfg.imageGen.key = process.env.OMB_OPENAI_IMAGE_KEY;
|
|
17759
|
+
if (process.env.OMB_CUSTOM_IMAGE_KEY !== void 0) cfg.imageGen.customApiKey = process.env.OMB_CUSTOM_IMAGE_KEY;
|
|
17735
17760
|
const splitEmails = (value) => value.split(/[,\s]+/).map((entry) => entry.trim().toLowerCase()).filter(Boolean);
|
|
17736
17761
|
if (process.env.OMB_SIGNIN_EMAILS !== void 0 || process.env.OMB_SIGNIN_MEMBER_EMAILS !== void 0) {
|
|
17737
17762
|
cfg.signIn = { ...cfg.signIn };
|
|
@@ -17744,7 +17769,7 @@ function stripWorkspaceCredentialEnv(env) {
|
|
|
17744
17769
|
for (const key of WORKSPACE_CREDENTIAL_ENV) delete env[key];
|
|
17745
17770
|
}
|
|
17746
17771
|
function saveConfig(patch, options = {}) {
|
|
17747
|
-
const p =
|
|
17772
|
+
const p = join5(DATA_DIR, "config.json");
|
|
17748
17773
|
let disk = {};
|
|
17749
17774
|
try {
|
|
17750
17775
|
const parsed = jsonObjectSchema.safeParse(parseJson(readFileSync2(p, "utf8")));
|
|
@@ -17754,7 +17779,7 @@ function saveConfig(patch, options = {}) {
|
|
|
17754
17779
|
const checkedPatch = appConfigSchema.partial().parse(patch);
|
|
17755
17780
|
const storedProfiles = storedBrowserProfilesSchema.safeParse(disk.browserProfiles);
|
|
17756
17781
|
if (storedProfiles.success) disk.browserProfiles = storedProfiles.data;
|
|
17757
|
-
for (const key of ["xai", "openaiCompat", "composio", "box", "opencodeGo", "tts", "imageGen", "profile", "rooms", "localVm", "features"]) {
|
|
17782
|
+
for (const key of ["xai", "openaiCompat", "composio", "box", "opencodeGo", "tts", "imageGen", "profile", "rooms", "threads", "localVm", "features"]) {
|
|
17758
17783
|
const section = checkedPatch[key];
|
|
17759
17784
|
if (!section) continue;
|
|
17760
17785
|
const current = jsonObjectSchema.safeParse(disk[key]);
|
|
@@ -17803,7 +17828,7 @@ function saveConfig(patch, options = {}) {
|
|
|
17803
17828
|
}
|
|
17804
17829
|
disk.instances = diskInstances;
|
|
17805
17830
|
}
|
|
17806
|
-
|
|
17831
|
+
mkdirSync4(DATA_DIR, { recursive: true });
|
|
17807
17832
|
writeFileAtomic(p, JSON.stringify(disk, null, 2), { mode: 384 });
|
|
17808
17833
|
}
|
|
17809
17834
|
function injectedEnvironment(cfg, driver) {
|
|
@@ -17875,11 +17900,12 @@ function instanceConfigs(cfg) {
|
|
|
17875
17900
|
}
|
|
17876
17901
|
return map3;
|
|
17877
17902
|
}
|
|
17878
|
-
var optionalText, SSH_ALIAS, LEGACY_BROWSER_PROFILE_ID, BROWSER_PROFILE_ID, MIN_ROOM_TURN_TIMEOUT_MINUTES, MAX_ROOM_TURN_TIMEOUT_MINUTES, MIN_LOCAL_VM_MAX_INSTANCES, MAX_LOCAL_VM_MAX_INSTANCES, vpsConfigSchema, roomConfigSchema, localVmConfigSchema, browserProfileSchema, legacyBrowserProfileSchema, legacyBrowserProfilesSchema, storedBrowserProfilesSchema, browserProfilesSchema, featureConfigSchema, instanceConfigSchema, instanceConfigMapSchema, defaultModelSelectionSchema, appConfigSchema, storedAppConfigSchema, appConfigPatchSchema, jsonObjectSchema, DATA_DIR, LEGACY_DATA_DIR, EVENTS_DIR, NATIVE_DIR, WORKSPACE_CREDENTIAL_ENV, PROVIDER_CREDENTIAL_ENV;
|
|
17903
|
+
var optionalText, SSH_ALIAS, LEGACY_BROWSER_PROFILE_ID, BROWSER_PROFILE_ID, MIN_ROOM_TURN_TIMEOUT_MINUTES, MAX_ROOM_TURN_TIMEOUT_MINUTES, MAX_CONCURRENT_BOT_THREADS, MIN_LOCAL_VM_MAX_INSTANCES, MAX_LOCAL_VM_MAX_INSTANCES, vpsConfigSchema, roomConfigSchema, localVmConfigSchema, browserProfileSchema, legacyBrowserProfileSchema, legacyBrowserProfilesSchema, storedBrowserProfilesSchema, browserProfilesSchema, featureConfigSchema, instanceConfigSchema, instanceConfigMapSchema, defaultModelSelectionSchema, appConfigSchema, storedAppConfigSchema, appConfigPatchSchema, jsonObjectSchema, DATA_DIR, LEGACY_DATA_DIR, EVENTS_DIR, NATIVE_DIR, WORKSPACE_CREDENTIAL_ENV, PROVIDER_CREDENTIAL_ENV;
|
|
17879
17904
|
var init_config = __esm({
|
|
17880
17905
|
"server/config.ts"() {
|
|
17881
17906
|
"use strict";
|
|
17882
17907
|
init_zod();
|
|
17908
|
+
init_image_generation();
|
|
17883
17909
|
init_atomic();
|
|
17884
17910
|
init_contracts();
|
|
17885
17911
|
init_mcp_registry();
|
|
@@ -17890,6 +17916,7 @@ var init_config = __esm({
|
|
|
17890
17916
|
BROWSER_PROFILE_ID = /^[a-z0-9_-]{1,40}$/;
|
|
17891
17917
|
MIN_ROOM_TURN_TIMEOUT_MINUTES = 1;
|
|
17892
17918
|
MAX_ROOM_TURN_TIMEOUT_MINUTES = 1440;
|
|
17919
|
+
MAX_CONCURRENT_BOT_THREADS = 10;
|
|
17893
17920
|
MIN_LOCAL_VM_MAX_INSTANCES = 1;
|
|
17894
17921
|
MAX_LOCAL_VM_MAX_INSTANCES = 4;
|
|
17895
17922
|
vpsConfigSchema = external_exports.object({
|
|
@@ -17987,14 +18014,32 @@ var init_config = __esm({
|
|
|
17987
18014
|
* engine: "elevenlabs" (default; needs a key) or "system" (the Mac's
|
|
17988
18015
|
* built-in voices, no key). */
|
|
17989
18016
|
tts: external_exports.object({ key: optionalText, voice: optionalText, provider: external_exports.enum(["elevenlabs", "system"]).optional() }).optional(),
|
|
17990
|
-
/**
|
|
17991
|
-
imageGen: external_exports.object({
|
|
18017
|
+
/** Avatar provider credentials stay separate; choosing a router never reuses a cloud key. */
|
|
18018
|
+
imageGen: external_exports.object({
|
|
18019
|
+
provider: external_exports.enum(["openai", "xai", "custom"]).optional(),
|
|
18020
|
+
key: optionalText,
|
|
18021
|
+
customApiKey: optionalText,
|
|
18022
|
+
customUrl: external_exports.string().trim().max(2048).transform((value, ctx) => {
|
|
18023
|
+
if (!value) return "";
|
|
18024
|
+
try {
|
|
18025
|
+
return normalizeImageGenerationUrl(value);
|
|
18026
|
+
} catch (error51) {
|
|
18027
|
+
ctx.addIssue({ code: "custom", message: error51.message });
|
|
18028
|
+
return external_exports.NEVER;
|
|
18029
|
+
}
|
|
18030
|
+
}).optional(),
|
|
18031
|
+
customModel: external_exports.string().trim().max(200).refine(
|
|
18032
|
+
(value) => !["\r", "\n", "\0"].some((character) => value.includes(character)),
|
|
18033
|
+
"Use a model ID without control characters"
|
|
18034
|
+
).optional()
|
|
18035
|
+
}).optional(),
|
|
17992
18036
|
/** Non-secret profile details shown in the sidebar. */
|
|
17993
18037
|
profile: external_exports.object({ name: optionalText, email: optionalText }).optional(),
|
|
17994
18038
|
/** UI language override (BCP-47, lowercase). Empty/absent = follow the
|
|
17995
18039
|
* system language. Unknown tags degrade to English in the renderer. */
|
|
17996
18040
|
language: optionalText,
|
|
17997
18041
|
rooms: roomConfigSchema.optional(),
|
|
18042
|
+
threads: external_exports.object({ maxConcurrentPerBot: external_exports.number().int().min(1).max(MAX_CONCURRENT_BOT_THREADS) }).strict().optional(),
|
|
17998
18043
|
localVm: localVmConfigSchema.optional(),
|
|
17999
18044
|
features: featureConfigSchema.optional(),
|
|
18000
18045
|
browserProfiles: browserProfilesSchema.optional(),
|
|
@@ -18010,10 +18055,10 @@ var init_config = __esm({
|
|
|
18010
18055
|
});
|
|
18011
18056
|
appConfigPatchSchema = appConfigSchema.omit({ instances: true, mcpServers: true, cliStartup: true, customDomain: true });
|
|
18012
18057
|
jsonObjectSchema = external_exports.record(external_exports.string(), external_exports.json());
|
|
18013
|
-
DATA_DIR = process.env.OMB_DATA_DIR ??
|
|
18014
|
-
LEGACY_DATA_DIR =
|
|
18015
|
-
EVENTS_DIR =
|
|
18016
|
-
NATIVE_DIR =
|
|
18058
|
+
DATA_DIR = process.env.OMB_DATA_DIR ?? join5(homedir4(), ".openmausbot");
|
|
18059
|
+
LEGACY_DATA_DIR = join5(homedir4(), ".opengrokbot");
|
|
18060
|
+
EVENTS_DIR = join5(DATA_DIR, "events");
|
|
18061
|
+
NATIVE_DIR = join5(DATA_DIR, "native");
|
|
18017
18062
|
WORKSPACE_CREDENTIAL_ENV = [
|
|
18018
18063
|
"XAI_API_KEY",
|
|
18019
18064
|
"OPENAI_COMPAT_API_KEY",
|
|
@@ -18022,6 +18067,7 @@ var init_config = __esm({
|
|
|
18022
18067
|
"OPENCODE_API_KEY",
|
|
18023
18068
|
"OMB_TTS_KEY",
|
|
18024
18069
|
"OMB_OPENAI_IMAGE_KEY",
|
|
18070
|
+
"OMB_CUSTOM_IMAGE_KEY",
|
|
18025
18071
|
"COMPOSIO_API_KEY",
|
|
18026
18072
|
"OMB_COMPOSIO_BROKER_TOKEN",
|
|
18027
18073
|
// Harness-private filesystem hints are not credentials themselves, but
|
|
@@ -18050,9 +18096,9 @@ var init_config = __esm({
|
|
|
18050
18096
|
// electron/data-dir-lease.mjs
|
|
18051
18097
|
import { execFileSync } from "node:child_process";
|
|
18052
18098
|
import { createHash as createHash2, randomUUID as randomUUID5 } from "node:crypto";
|
|
18053
|
-
import { existsSync as existsSync4, linkSync, mkdirSync as
|
|
18099
|
+
import { existsSync as existsSync4, linkSync, mkdirSync as mkdirSync5, readFileSync as readFileSync3, renameSync as renameSync4, unlinkSync as unlinkSync2, writeFileSync as writeFileSync4 } from "node:fs";
|
|
18054
18100
|
import { hostname as hostname4, uptime } from "node:os";
|
|
18055
|
-
import { join as
|
|
18101
|
+
import { join as join6 } from "node:path";
|
|
18056
18102
|
function leaseError(message2, cause) {
|
|
18057
18103
|
return Object.assign(new DataDirLeaseError(message2), { cause });
|
|
18058
18104
|
}
|
|
@@ -18157,7 +18203,7 @@ function unlinkExact(path3, message2) {
|
|
|
18157
18203
|
function publishRecord(path3, record3, prepareMessage, acquireMessage) {
|
|
18158
18204
|
const candidatePath = `${path3}.candidate-${record3.pid}-${record3.token}`;
|
|
18159
18205
|
try {
|
|
18160
|
-
|
|
18206
|
+
writeFileSync4(candidatePath, `${JSON.stringify(record3)}
|
|
18161
18207
|
`, { flag: "wx", mode: 384, flush: true });
|
|
18162
18208
|
} catch (error51) {
|
|
18163
18209
|
throw leaseError(prepareMessage, error51);
|
|
@@ -18240,14 +18286,14 @@ function prepareDataDir(dataDir, legacyDataDir) {
|
|
|
18240
18286
|
}
|
|
18241
18287
|
}
|
|
18242
18288
|
try {
|
|
18243
|
-
|
|
18289
|
+
mkdirSync5(dataDir, { recursive: true, mode: 448 });
|
|
18244
18290
|
} catch (error51) {
|
|
18245
18291
|
throw leaseError("OpenMausBot cannot create its data directory.", error51);
|
|
18246
18292
|
}
|
|
18247
|
-
return
|
|
18293
|
+
return join6(dataDir, LEASE_NAME);
|
|
18248
18294
|
}
|
|
18249
18295
|
function assertNoLiveDelegatedChild(dataDir) {
|
|
18250
|
-
const childLeasePath =
|
|
18296
|
+
const childLeasePath = join6(dataDir, DELEGATED_CHILD_DIR, LEASE_NAME);
|
|
18251
18297
|
const child = readOwner(childLeasePath);
|
|
18252
18298
|
if (!child) return;
|
|
18253
18299
|
if (child.host !== hostname4()) {
|
|
@@ -18278,7 +18324,7 @@ function acquireDataDirLeaseInternal(dataDir, options = {}) {
|
|
|
18278
18324
|
};
|
|
18279
18325
|
const candidatePath = `${leasePath}.candidate-${owner.pid}-${owner.token}`;
|
|
18280
18326
|
try {
|
|
18281
|
-
|
|
18327
|
+
writeFileSync4(candidatePath, `${JSON.stringify(owner)}
|
|
18282
18328
|
`, { flag: "wx", mode: 384, flush: true });
|
|
18283
18329
|
} catch (error51) {
|
|
18284
18330
|
throw leaseError("OpenMausBot cannot prepare its data-directory lease.", error51);
|
|
@@ -18371,62 +18417,62 @@ var init_data_dir_lease2 = __esm({
|
|
|
18371
18417
|
// server/env-path.ts
|
|
18372
18418
|
import { execFile as execFile2 } from "node:child_process";
|
|
18373
18419
|
import { closeSync as closeSync2, existsSync as existsSync5, openSync as openSync2, readFileSync as readFileSync4, readSync, statSync as statSync2, readdirSync } from "node:fs";
|
|
18374
|
-
import { homedir as
|
|
18375
|
-
import { basename, delimiter as delimiter3, dirname as
|
|
18420
|
+
import { homedir as homedir5 } from "node:os";
|
|
18421
|
+
import { basename as basename2, delimiter as delimiter3, dirname as dirname3, extname, join as join7 } from "node:path";
|
|
18376
18422
|
function nvmBinDirs() {
|
|
18377
18423
|
try {
|
|
18378
|
-
const base2 =
|
|
18379
|
-
return readdirSync(base2).filter((v) => v.startsWith("v")).sort((a2, b) => b.localeCompare(a2, void 0, { numeric: true })).map((v) =>
|
|
18424
|
+
const base2 = join7(homedir5(), ".nvm", "versions", "node");
|
|
18425
|
+
return readdirSync(base2).filter((v) => v.startsWith("v")).sort((a2, b) => b.localeCompare(a2, void 0, { numeric: true })).map((v) => join7(base2, v, "bin"));
|
|
18380
18426
|
} catch {
|
|
18381
18427
|
return [];
|
|
18382
18428
|
}
|
|
18383
18429
|
}
|
|
18384
18430
|
function knownDirs() {
|
|
18385
|
-
const home =
|
|
18431
|
+
const home = homedir5();
|
|
18386
18432
|
return [
|
|
18387
|
-
|
|
18433
|
+
join7(home, ".local", "bin"),
|
|
18388
18434
|
// claude installer default
|
|
18389
|
-
|
|
18435
|
+
join7(home, ".npm-global", "bin"),
|
|
18390
18436
|
// npm prefix ~/.npm-global (claude, opencode)
|
|
18391
|
-
|
|
18437
|
+
join7(home, ".kimi-code", "bin"),
|
|
18392
18438
|
// kimi-code installer
|
|
18393
|
-
|
|
18439
|
+
join7(home, ".grok", "bin"),
|
|
18394
18440
|
// x.ai installer
|
|
18395
|
-
|
|
18441
|
+
join7(home, ".opencode", "bin"),
|
|
18396
18442
|
// opencode installer
|
|
18397
|
-
|
|
18443
|
+
join7(home, ".claude", "local"),
|
|
18398
18444
|
// claude "local install"
|
|
18399
18445
|
"/opt/homebrew/bin",
|
|
18400
18446
|
// brew, Apple silicon
|
|
18401
18447
|
"/usr/local/bin",
|
|
18402
18448
|
// brew Intel / classic installs
|
|
18403
|
-
|
|
18404
|
-
|
|
18405
|
-
|
|
18406
|
-
|
|
18407
|
-
|
|
18449
|
+
join7(home, ".volta", "bin"),
|
|
18450
|
+
join7(home, ".bun", "bin"),
|
|
18451
|
+
join7(home, ".asdf", "shims"),
|
|
18452
|
+
join7(home, ".deno", "bin"),
|
|
18453
|
+
join7(home, "bin"),
|
|
18408
18454
|
...nvmBinDirs()
|
|
18409
18455
|
];
|
|
18410
18456
|
}
|
|
18411
18457
|
function windowsKnownDirs() {
|
|
18412
|
-
const home =
|
|
18413
|
-
const appData = process.env.APPDATA ??
|
|
18414
|
-
const localAppData = process.env.LOCALAPPDATA ??
|
|
18458
|
+
const home = homedir5();
|
|
18459
|
+
const appData = process.env.APPDATA ?? join7(home, "AppData", "Roaming");
|
|
18460
|
+
const localAppData = process.env.LOCALAPPDATA ?? join7(home, "AppData", "Local");
|
|
18415
18461
|
return [
|
|
18416
|
-
|
|
18462
|
+
join7(appData, "npm"),
|
|
18417
18463
|
// npm -g shims: claude, codex
|
|
18418
|
-
|
|
18464
|
+
join7(home, ".grok", "bin"),
|
|
18419
18465
|
// x.ai installer
|
|
18420
|
-
|
|
18466
|
+
join7(localAppData, "agy", "bin"),
|
|
18421
18467
|
// Antigravity installer
|
|
18422
|
-
|
|
18468
|
+
join7(home, ".local", "bin"),
|
|
18423
18469
|
// claude native installer
|
|
18424
|
-
|
|
18425
|
-
|
|
18470
|
+
join7(home, ".claude", "local"),
|
|
18471
|
+
join7(home, "bin"),
|
|
18426
18472
|
// Factory droid installer (%USERPROFILE%\bin)
|
|
18427
|
-
|
|
18428
|
-
|
|
18429
|
-
|
|
18473
|
+
join7(home, ".bun", "bin"),
|
|
18474
|
+
join7(home, ".deno", "bin"),
|
|
18475
|
+
join7(home, "go", "bin")
|
|
18430
18476
|
];
|
|
18431
18477
|
}
|
|
18432
18478
|
function resetPathCache() {
|
|
@@ -18480,7 +18526,7 @@ function findCliCandidates(name) {
|
|
|
18480
18526
|
for (const dir of augmentedPath().split(delimiter3)) {
|
|
18481
18527
|
if (!dir) continue;
|
|
18482
18528
|
for (const ext of exts) {
|
|
18483
|
-
const p =
|
|
18529
|
+
const p = join7(dir, name + ext);
|
|
18484
18530
|
if (existsSync5(p)) {
|
|
18485
18531
|
out.push(p);
|
|
18486
18532
|
break;
|
|
@@ -18525,13 +18571,13 @@ function whichWin(cli) {
|
|
|
18525
18571
|
if (/[\\/]/.test(cli) || /^[a-zA-Z]:/.test(cli)) return probe(cli);
|
|
18526
18572
|
for (const dir of augmentedPath().split(delimiter3)) {
|
|
18527
18573
|
if (!dir) continue;
|
|
18528
|
-
const hit = probe(
|
|
18574
|
+
const hit = probe(join7(dir, cli));
|
|
18529
18575
|
if (hit) return hit;
|
|
18530
18576
|
}
|
|
18531
18577
|
return null;
|
|
18532
18578
|
}
|
|
18533
18579
|
function nodeExe(near) {
|
|
18534
|
-
const local =
|
|
18580
|
+
const local = join7(near, "node.exe");
|
|
18535
18581
|
if (isFile(local)) return local;
|
|
18536
18582
|
const onPath2 = whichWin("node.exe");
|
|
18537
18583
|
if (onPath2 && extname(onPath2).toLowerCase() === ".exe") return onPath2;
|
|
@@ -18544,8 +18590,8 @@ function parseCmdShim(shim) {
|
|
|
18544
18590
|
} catch {
|
|
18545
18591
|
return null;
|
|
18546
18592
|
}
|
|
18547
|
-
const dir =
|
|
18548
|
-
const targets = [...text2.matchAll(/"%~?dp0%?\\?([^"]+)"/g)].map((m) =>
|
|
18593
|
+
const dir = dirname3(shim);
|
|
18594
|
+
const targets = [...text2.matchAll(/"%~?dp0%?\\?([^"]+)"/g)].map((m) => join7(dir, m[1])).filter((p) => isFile(p) && basename2(p).toLowerCase() !== "node.exe");
|
|
18549
18595
|
const script = targets.find((p) => /\.[cm]?js$/i.test(p));
|
|
18550
18596
|
if (script) {
|
|
18551
18597
|
const node = nodeExe(dir);
|
|
@@ -18573,7 +18619,7 @@ function parseNodeShebang(file2) {
|
|
|
18573
18619
|
}
|
|
18574
18620
|
}
|
|
18575
18621
|
if (!/^#!.*\bnode(\.exe)?\b/.test(head)) return null;
|
|
18576
|
-
const node = nodeExe(
|
|
18622
|
+
const node = nodeExe(dirname3(file2));
|
|
18577
18623
|
return node ? { command: node, args: [file2] } : null;
|
|
18578
18624
|
}
|
|
18579
18625
|
function resolveWord(cli, args) {
|
|
@@ -18615,7 +18661,7 @@ import {
|
|
|
18615
18661
|
spawn as spawn4,
|
|
18616
18662
|
execFile as execFile3
|
|
18617
18663
|
} from "node:child_process";
|
|
18618
|
-
import { join as
|
|
18664
|
+
import { join as join8 } from "node:path";
|
|
18619
18665
|
function resolveCli(cli, args = []) {
|
|
18620
18666
|
return resolveCliSpawn(cli, args);
|
|
18621
18667
|
}
|
|
@@ -18677,12 +18723,12 @@ function describeSpawnFailure(err, cli) {
|
|
|
18677
18723
|
function killCliTree(child, timeoutMs = 5e3) {
|
|
18678
18724
|
const pid = child.pid;
|
|
18679
18725
|
if (!pid || child.exitCode !== null || child.signalCode !== null) return Promise.resolve(true);
|
|
18680
|
-
return new Promise((
|
|
18726
|
+
return new Promise((resolve13) => {
|
|
18681
18727
|
let timer;
|
|
18682
18728
|
const done = (stopped) => {
|
|
18683
18729
|
clearTimeout(timer);
|
|
18684
18730
|
child.off("close", closed);
|
|
18685
|
-
|
|
18731
|
+
resolve13(stopped);
|
|
18686
18732
|
};
|
|
18687
18733
|
const closed = () => done(true);
|
|
18688
18734
|
child.once("close", closed);
|
|
@@ -18709,7 +18755,7 @@ function killCliTree(child, timeoutMs = 5e3) {
|
|
|
18709
18755
|
});
|
|
18710
18756
|
}
|
|
18711
18757
|
function brokerSocketPath(dataDir, tag) {
|
|
18712
|
-
return process.platform === "win32" ? `\\\\.\\pipe\\openmausbot-perm-${process.pid}-${tag}` :
|
|
18758
|
+
return process.platform === "win32" ? `\\\\.\\pipe\\openmausbot-perm-${process.pid}-${tag}` : join8(dataDir, `perm-${tag}.sock`);
|
|
18713
18759
|
}
|
|
18714
18760
|
var WINDOWS_SAFE_COMMAND_LINE_CHARS;
|
|
18715
18761
|
var init_procs = __esm({
|
|
@@ -18907,8 +18953,10 @@ var init_registry = __esm({
|
|
|
18907
18953
|
access: driver?.metadata.access ?? "subscription",
|
|
18908
18954
|
install: driver?.install,
|
|
18909
18955
|
authentication: inst.startAuthentication ? {
|
|
18910
|
-
method: inst.getAuthentication && inst.completeAuthentication ? "paste-code" : inst.getAuthentication ? "device-code" : "browser"
|
|
18956
|
+
method: inst.getAuthentication && inst.completeAuthentication ? "paste-code" : inst.getAuthentication ? "device-code" : "browser",
|
|
18911
18957
|
// a link and a callback URL (managed engines)
|
|
18958
|
+
// the browser may remove the stored sign-in to switch accounts
|
|
18959
|
+
signOut: inst.signOut !== void 0
|
|
18912
18960
|
} : void 0,
|
|
18913
18961
|
cli: this.cliByInstance.get(inst.instanceId),
|
|
18914
18962
|
cliDefault: cliDefaultOf(driver),
|
|
@@ -18937,8 +18985,8 @@ var init_registry = __esm({
|
|
|
18937
18985
|
|
|
18938
18986
|
// server/drivers/local-inject.ts
|
|
18939
18987
|
import { readFileSync as readFileSync5 } from "node:fs";
|
|
18940
|
-
import { homedir as
|
|
18941
|
-
import { join as
|
|
18988
|
+
import { homedir as homedir6 } from "node:os";
|
|
18989
|
+
import { join as join9 } from "node:path";
|
|
18942
18990
|
function contextWindowsFromPs(extra) {
|
|
18943
18991
|
const out = /* @__PURE__ */ new Map();
|
|
18944
18992
|
const rec = extra && typeof extra === "object" ? extra : null;
|
|
@@ -19021,9 +19069,9 @@ function firstUnslothToken(row) {
|
|
|
19021
19069
|
return null;
|
|
19022
19070
|
}
|
|
19023
19071
|
function readUnslothKey(env) {
|
|
19024
|
-
const home = env.HOME || env.USERPROFILE ||
|
|
19072
|
+
const home = env.HOME || env.USERPROFILE || homedir6();
|
|
19025
19073
|
try {
|
|
19026
|
-
const raw = JSON.parse(readFileSync5(
|
|
19074
|
+
const raw = JSON.parse(readFileSync5(join9(home, ".unsloth", "studio", "auth", "agent_api_key.json"), "utf8"));
|
|
19027
19075
|
if (raw.servers && typeof raw.servers === "object") {
|
|
19028
19076
|
const servers = raw.servers;
|
|
19029
19077
|
for (const url2 of ["http://127.0.0.1:8888", "http://localhost:8888"]) {
|
|
@@ -19225,17 +19273,17 @@ var init_local_inject = __esm({
|
|
|
19225
19273
|
|
|
19226
19274
|
// server/proxy-paths.ts
|
|
19227
19275
|
import { existsSync as existsSync6 } from "node:fs";
|
|
19228
|
-
import { dirname as
|
|
19276
|
+
import { dirname as dirname4, join as join10 } from "node:path";
|
|
19229
19277
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
19230
19278
|
function resolveProxy(relative2) {
|
|
19231
|
-
const source =
|
|
19232
|
-
return existsSync6(source) ? source :
|
|
19279
|
+
const source = join10(SERVER_ROOT, `${relative2}.ts`);
|
|
19280
|
+
return existsSync6(source) ? source : join10(SERVER_ROOT, `${relative2}.js`);
|
|
19233
19281
|
}
|
|
19234
19282
|
var SERVER_ROOT, SPAWNED_PROXIES;
|
|
19235
19283
|
var init_proxy_paths = __esm({
|
|
19236
19284
|
"server/proxy-paths.ts"() {
|
|
19237
19285
|
"use strict";
|
|
19238
|
-
SERVER_ROOT =
|
|
19286
|
+
SERVER_ROOT = dirname4(fileURLToPath2(import.meta.url));
|
|
19239
19287
|
SPAWNED_PROXIES = {
|
|
19240
19288
|
browser: resolveProxy("browser-proxy"),
|
|
19241
19289
|
computer: resolveProxy("computer-proxy"),
|
|
@@ -19257,7 +19305,7 @@ var init_proxy_paths = __esm({
|
|
|
19257
19305
|
|
|
19258
19306
|
// server/container-computer.ts
|
|
19259
19307
|
import { execFile as execFile4 } from "node:child_process";
|
|
19260
|
-
import { join as
|
|
19308
|
+
import { join as join11, resolve as resolve3 } from "node:path";
|
|
19261
19309
|
import { promisify } from "node:util";
|
|
19262
19310
|
function computerProxyEnv(computer) {
|
|
19263
19311
|
return {
|
|
@@ -19281,7 +19329,7 @@ var init_container_computer = __esm({
|
|
|
19281
19329
|
IMAGE_REPOSITORY = "localhost/openmausbot/cua-local-vm";
|
|
19282
19330
|
IMAGE_LAYER_VERSION = "5";
|
|
19283
19331
|
IMAGE = `${IMAGE_REPOSITORY}:driver-${CUA_DRIVER_VERSION}-v${IMAGE_LAYER_VERSION}`;
|
|
19284
|
-
VM_WORKSPACE_DIR =
|
|
19332
|
+
VM_WORKSPACE_DIR = join11(DATA_DIR, "vm-home");
|
|
19285
19333
|
MEMORY_BYTES = 4 * 1024 * 1024 * 1024;
|
|
19286
19334
|
SHM_BYTES = 512 * 1024 * 1024;
|
|
19287
19335
|
containerMcpPath = SPAWNED_PROXIES.containerMcp;
|
|
@@ -19372,11 +19420,11 @@ var init_redact = __esm({
|
|
|
19372
19420
|
|
|
19373
19421
|
// server/drivers/native.ts
|
|
19374
19422
|
import { appendFileSync } from "node:fs";
|
|
19375
|
-
import { join as
|
|
19423
|
+
import { join as join12 } from "node:path";
|
|
19376
19424
|
function appendNative(threadId, entry) {
|
|
19377
19425
|
try {
|
|
19378
19426
|
appendFileSync(
|
|
19379
|
-
|
|
19427
|
+
join12(NATIVE_DIR, `${threadId}.ndjson`),
|
|
19380
19428
|
JSON.stringify({ at: (/* @__PURE__ */ new Date()).toISOString(), ...entry, msg: redactSecrets(entry.msg) }) + "\n",
|
|
19381
19429
|
{ mode: 384 }
|
|
19382
19430
|
);
|
|
@@ -19392,9 +19440,9 @@ var init_native = __esm({
|
|
|
19392
19440
|
});
|
|
19393
19441
|
|
|
19394
19442
|
// server/drivers/acp/core.ts
|
|
19395
|
-
import { homedir as
|
|
19443
|
+
import { homedir as homedir7 } from "node:os";
|
|
19396
19444
|
import { lstat, mkdir, readFile, realpath, stat, writeFile } from "node:fs/promises";
|
|
19397
|
-
import { basename as
|
|
19445
|
+
import { basename as basename3, dirname as dirname5, isAbsolute, relative, resolve as resolve4 } from "node:path";
|
|
19398
19446
|
function skipSubscriptionAuthForLocalInject(model) {
|
|
19399
19447
|
return Boolean(decodeInjectId(model));
|
|
19400
19448
|
}
|
|
@@ -19579,7 +19627,7 @@ function createAcpDriver(support11) {
|
|
|
19579
19627
|
throw new Error("local computer control requires interactive provider approvals");
|
|
19580
19628
|
}
|
|
19581
19629
|
const turnId = newId();
|
|
19582
|
-
const cwd = turn.cwd ?? turnConfig.workspace ??
|
|
19630
|
+
const cwd = turn.cwd ?? turnConfig.workspace ?? homedir7();
|
|
19583
19631
|
const env = childEnv(turnConfig);
|
|
19584
19632
|
if (support11.requireAuthenticationBeforeSpawn && !skipSubscriptionAuthForLocalInject(turn.model) && !await support11.isAuthenticated(env, turnConfig, instanceId)) {
|
|
19585
19633
|
emit({ ...base2(threadId, turnId), type: "turn.started" });
|
|
@@ -19623,7 +19671,7 @@ function createAcpDriver(support11) {
|
|
|
19623
19671
|
}
|
|
19624
19672
|
appendNative(threadId, { dir: "out", source: SOURCE, msg: nativeLogMessage(obj) });
|
|
19625
19673
|
};
|
|
19626
|
-
const request = (method, params, timeoutMs) => new Promise((
|
|
19674
|
+
const request = (method, params, timeoutMs) => new Promise((resolve13, reject) => {
|
|
19627
19675
|
const id = nextId++;
|
|
19628
19676
|
let timer = null;
|
|
19629
19677
|
if (timeoutMs) {
|
|
@@ -19633,7 +19681,7 @@ function createAcpDriver(support11) {
|
|
|
19633
19681
|
}, timeoutMs);
|
|
19634
19682
|
timer.unref?.();
|
|
19635
19683
|
}
|
|
19636
|
-
rpcPending.set(id, { resolve:
|
|
19684
|
+
rpcPending.set(id, { resolve: resolve13, reject, timer });
|
|
19637
19685
|
send({ jsonrpc: "2.0", id, method, params });
|
|
19638
19686
|
});
|
|
19639
19687
|
const stop = () => killCliTree(child);
|
|
@@ -19647,12 +19695,12 @@ function createAcpDriver(support11) {
|
|
|
19647
19695
|
if (lexical === ".." || lexical.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) || isAbsolute(lexical)) {
|
|
19648
19696
|
throw new Error("ACP file path is outside the session workspace.");
|
|
19649
19697
|
}
|
|
19650
|
-
const suffix = [
|
|
19651
|
-
let ancestor =
|
|
19698
|
+
const suffix = [basename3(requested)];
|
|
19699
|
+
let ancestor = dirname5(requested);
|
|
19652
19700
|
while (!await lstat(ancestor).catch(() => null)) {
|
|
19653
|
-
const parent =
|
|
19701
|
+
const parent = dirname5(ancestor);
|
|
19654
19702
|
if (parent === ancestor) throw new Error("ACP file path has no accessible parent.");
|
|
19655
|
-
suffix.unshift(
|
|
19703
|
+
suffix.unshift(basename3(ancestor));
|
|
19656
19704
|
ancestor = parent;
|
|
19657
19705
|
}
|
|
19658
19706
|
const candidate = resolve4(await realpath(ancestor), ...suffix);
|
|
@@ -19698,7 +19746,7 @@ function createAcpDriver(support11) {
|
|
|
19698
19746
|
if (typeof params.content !== "string" || Buffer.byteLength(params.content) > CLIENT_FILE_MAX_BYTES) {
|
|
19699
19747
|
throw new Error(`ACP can only write text files under ${CLIENT_FILE_MAX_BYTES} bytes.`);
|
|
19700
19748
|
}
|
|
19701
|
-
await mkdir(
|
|
19749
|
+
await mkdir(dirname5(path3), { recursive: true });
|
|
19702
19750
|
await writeFile(path3, params.content, "utf8");
|
|
19703
19751
|
send({ jsonrpc: "2.0", id: msg.id, result: {} });
|
|
19704
19752
|
} catch (error51) {
|
|
@@ -20069,12 +20117,12 @@ ${turn.text}` : turn.text;
|
|
|
20069
20117
|
const snapshot = async () => {
|
|
20070
20118
|
const env = childEnv();
|
|
20071
20119
|
if (support11.snapshot) return support11.snapshot(env, config2, instanceId);
|
|
20072
|
-
const version2 = await new Promise((
|
|
20120
|
+
const version2 = await new Promise((resolve13) => {
|
|
20073
20121
|
execCli(
|
|
20074
20122
|
config2.cli,
|
|
20075
20123
|
["--version"],
|
|
20076
20124
|
{ timeout: 8e3, env },
|
|
20077
|
-
(err, stdout2) =>
|
|
20125
|
+
(err, stdout2) => resolve13(err ? null : stdout2.trim())
|
|
20078
20126
|
);
|
|
20079
20127
|
});
|
|
20080
20128
|
if (!version2) return { state: "unavailable", reason: `\`${config2.cli}\` CLI not found` };
|
|
@@ -20162,7 +20210,7 @@ import { createHash as createHash3, randomUUID as randomUUID6 } from "node:crypt
|
|
|
20162
20210
|
import { mkdir as mkdir2, mkdtemp, readFile as readFile2, rm, stat as stat2 } from "node:fs/promises";
|
|
20163
20211
|
import { request as httpRequest } from "node:http";
|
|
20164
20212
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
20165
|
-
import { delimiter as delimiter4, join as
|
|
20213
|
+
import { delimiter as delimiter4, join as join13, resolve as resolve5 } from "node:path";
|
|
20166
20214
|
function quoteBrowserArgument(value) {
|
|
20167
20215
|
return `'${value.replaceAll("'", `'"'"'`)}'`;
|
|
20168
20216
|
}
|
|
@@ -20197,11 +20245,11 @@ function authorizationUrlFromLine(line) {
|
|
|
20197
20245
|
}
|
|
20198
20246
|
}
|
|
20199
20247
|
function antigravityProfileDirectory(instanceId, baseDir = DATA_DIR) {
|
|
20200
|
-
return
|
|
20248
|
+
return join13(baseDir, "providers", "antigravity", createHash3("sha256").update(instanceId).digest("hex"));
|
|
20201
20249
|
}
|
|
20202
20250
|
async function prepareAntigravityProfile(input) {
|
|
20203
20251
|
const directory = resolve5(input.profileDirectory ?? antigravityProfileDirectory(input.instanceId, input.baseDir));
|
|
20204
|
-
const acpDirectory =
|
|
20252
|
+
const acpDirectory = join13(directory, "antigravity-acp");
|
|
20205
20253
|
await mkdir2(acpDirectory, { recursive: true, mode: 448 });
|
|
20206
20254
|
if (process.platform !== "win32") {
|
|
20207
20255
|
const { chmod: chmod2 } = await import("node:fs/promises");
|
|
@@ -20209,7 +20257,7 @@ async function prepareAntigravityProfile(input) {
|
|
|
20209
20257
|
await chmod2(acpDirectory, 448);
|
|
20210
20258
|
}
|
|
20211
20259
|
writeFileAtomic(
|
|
20212
|
-
|
|
20260
|
+
join13(acpDirectory, "settings.json"),
|
|
20213
20261
|
`${JSON.stringify({ auth: { type: "oauth-personal" } })}
|
|
20214
20262
|
`,
|
|
20215
20263
|
{ mode: 384 }
|
|
@@ -20232,7 +20280,7 @@ async function prepareAntigravityProfile(input) {
|
|
|
20232
20280
|
PYTHONUNBUFFERED: "1",
|
|
20233
20281
|
ELECTRON_RUN_AS_NODE: "1"
|
|
20234
20282
|
});
|
|
20235
|
-
return { directory, tokenPath:
|
|
20283
|
+
return { directory, tokenPath: join13(acpDirectory, "acp_token.json"), environment };
|
|
20236
20284
|
}
|
|
20237
20285
|
async function antigravityProfileAuthenticated(profile) {
|
|
20238
20286
|
try {
|
|
@@ -20361,7 +20409,7 @@ function isValidAntigravityInitializeResult(initialized, expectedVersion) {
|
|
|
20361
20409
|
return true;
|
|
20362
20410
|
}
|
|
20363
20411
|
async function validateAntigravityRuntime(runtime, expectedVersion) {
|
|
20364
|
-
const profileDirectory = await mkdtemp(
|
|
20412
|
+
const profileDirectory = await mkdtemp(join13(tmpdir2(), "openmaus-antigravity-verify-"));
|
|
20365
20413
|
let client;
|
|
20366
20414
|
let failed = false;
|
|
20367
20415
|
let failure;
|
|
@@ -20464,14 +20512,14 @@ var init_antigravity_acp = __esm({
|
|
|
20464
20512
|
this.child.stderr.setEncoding("utf8");
|
|
20465
20513
|
this.child.stderr.on("data", (chunk) => this.consumeDiagnostics(chunk));
|
|
20466
20514
|
this.child.once("error", (error51) => this.failAll(error51));
|
|
20467
|
-
this.exited = new Promise((
|
|
20515
|
+
this.exited = new Promise((resolve13) => {
|
|
20468
20516
|
this.child.once("close", (code, signal) => {
|
|
20469
20517
|
this.noteStartupDiagnostic(this.diagnosticBuffer);
|
|
20470
20518
|
this.diagnosticBuffer = "";
|
|
20471
20519
|
if (!this.closed) this.failAll(new Error(
|
|
20472
20520
|
`Antigravity ACP exited ${code ?? signal ?? "unexpectedly"}.${this.nativeStartupHint ? ` ${this.nativeStartupHint}` : ""}`
|
|
20473
20521
|
));
|
|
20474
|
-
|
|
20522
|
+
resolve13();
|
|
20475
20523
|
});
|
|
20476
20524
|
});
|
|
20477
20525
|
}
|
|
@@ -20577,8 +20625,8 @@ var init_antigravity_acp = __esm({
|
|
|
20577
20625
|
async closeAndWait(timeoutMs = 5e3) {
|
|
20578
20626
|
this.close();
|
|
20579
20627
|
let timer;
|
|
20580
|
-
const timedOut = new Promise((
|
|
20581
|
-
timer = setTimeout(() =>
|
|
20628
|
+
const timedOut = new Promise((resolve13) => {
|
|
20629
|
+
timer = setTimeout(() => resolve13(false), timeoutMs);
|
|
20582
20630
|
timer.unref?.();
|
|
20583
20631
|
});
|
|
20584
20632
|
try {
|
|
@@ -20750,7 +20798,7 @@ import {
|
|
|
20750
20798
|
writeFile as writeFile2
|
|
20751
20799
|
} from "node:fs/promises";
|
|
20752
20800
|
import { constants } from "node:fs";
|
|
20753
|
-
import { delimiter as delimiter5, dirname as
|
|
20801
|
+
import { delimiter as delimiter5, dirname as dirname6, isAbsolute as isAbsolute2, join as join14, resolve as resolve6 } from "node:path";
|
|
20754
20802
|
import { Transform } from "node:stream";
|
|
20755
20803
|
import { pipeline } from "node:stream/promises";
|
|
20756
20804
|
import { createInflateRaw } from "node:zlib";
|
|
@@ -20771,7 +20819,7 @@ async function retryOnWindowsFileLock(step, options = {}) {
|
|
|
20771
20819
|
}
|
|
20772
20820
|
}
|
|
20773
20821
|
function runtimeRoot(baseDir = DATA_DIR) {
|
|
20774
|
-
return
|
|
20822
|
+
return join14(baseDir, "tools", "antigravity-acp", `${process.platform}-${process.arch}`);
|
|
20775
20823
|
}
|
|
20776
20824
|
function executableNames(platform = process.platform) {
|
|
20777
20825
|
return platform === "win32" ? { executable: "agy_acp_server.exe", harness: "localharness_external.exe" } : { executable: "agy_acp_server.par", harness: "localharness_external" };
|
|
@@ -20788,10 +20836,10 @@ async function executableFile(path3, bytes) {
|
|
|
20788
20836
|
}
|
|
20789
20837
|
async function completedRelease(directory, asset) {
|
|
20790
20838
|
try {
|
|
20791
|
-
const record3 = JSON.parse(await readFile3(
|
|
20839
|
+
const record3 = JSON.parse(await readFile3(join14(directory, INSTALL_RECORD), "utf8"));
|
|
20792
20840
|
if (record3.sha256 !== asset.sha256 || record3.version !== asset.version || record3.executable.name !== asset.executable.name || record3.executable.bytes !== asset.executable.bytes || record3.harness.name !== asset.harness.name || record3.harness.bytes !== asset.harness.bytes) return null;
|
|
20793
|
-
const executablePath =
|
|
20794
|
-
const harnessPath =
|
|
20841
|
+
const executablePath = join14(directory, asset.executable.name);
|
|
20842
|
+
const harnessPath = join14(directory, asset.harness.name);
|
|
20795
20843
|
if (!await executableFile(executablePath, asset.executable.bytes)) return null;
|
|
20796
20844
|
if (!await executableFile(harnessPath, asset.harness.bytes)) return null;
|
|
20797
20845
|
return { executablePath, harnessPath, source: "managed", version: asset.version };
|
|
@@ -20807,7 +20855,7 @@ function pathCandidates(binary2, env) {
|
|
|
20807
20855
|
async function externalRuntime(candidate, source) {
|
|
20808
20856
|
const names = executableNames();
|
|
20809
20857
|
const executablePath = resolve6(candidate);
|
|
20810
|
-
const harnessPath =
|
|
20858
|
+
const harnessPath = join14(dirname6(executablePath), names.harness);
|
|
20811
20859
|
if (!await executableFile(executablePath) || !await executableFile(harnessPath)) return null;
|
|
20812
20860
|
return { executablePath, harnessPath, source, version: null };
|
|
20813
20861
|
}
|
|
@@ -20827,7 +20875,7 @@ async function resolveAntigravityRuntime(binaryPath, env = process.env, baseDir
|
|
|
20827
20875
|
}
|
|
20828
20876
|
const asset = resolveAntigravityReleaseAsset();
|
|
20829
20877
|
if (asset) {
|
|
20830
|
-
const managed = await completedRelease(
|
|
20878
|
+
const managed = await completedRelease(join14(runtimeRoot(baseDir), "versions", asset.sha256), asset);
|
|
20831
20879
|
if (managed) return managed;
|
|
20832
20880
|
}
|
|
20833
20881
|
const names = executableNames();
|
|
@@ -20949,7 +20997,7 @@ async function extractPinnedArchive(archivePath, outputDirectory, asset) {
|
|
|
20949
20997
|
start: dataOffset,
|
|
20950
20998
|
end: dataOffset + entry.compressedBytes - 1
|
|
20951
20999
|
});
|
|
20952
|
-
const destination = createWriteStream(
|
|
21000
|
+
const destination = createWriteStream(join14(outputDirectory, entry.name), { flags: "wx", mode: 448 });
|
|
20953
21001
|
if (entry.compression === 8) await pipeline(source, createInflateRaw(), counter, destination);
|
|
20954
21002
|
else await pipeline(source, counter, destination);
|
|
20955
21003
|
if (bytes !== expectedBytes) throw new Error("An extracted file was truncated.");
|
|
@@ -20960,8 +21008,8 @@ async function installOnce(options) {
|
|
|
20960
21008
|
const asset = options.asset === void 0 ? resolveAntigravityReleaseAsset() : options.asset;
|
|
20961
21009
|
if (!asset) throw new Error(`Google does not publish an Antigravity runtime for ${process.platform}-${process.arch}.`);
|
|
20962
21010
|
const root = runtimeRoot(options.baseDir);
|
|
20963
|
-
const versions =
|
|
20964
|
-
const destination =
|
|
21011
|
+
const versions = join14(root, "versions");
|
|
21012
|
+
const destination = join14(versions, asset.sha256);
|
|
20965
21013
|
await mkdir3(versions, { recursive: true, mode: 448 });
|
|
20966
21014
|
const existing = await completedRelease(destination, asset);
|
|
20967
21015
|
if (existing) {
|
|
@@ -20977,11 +21025,11 @@ async function installOnce(options) {
|
|
|
20977
21025
|
} catch (error51) {
|
|
20978
21026
|
if (error51 instanceof Error && error51.message.includes("Antigravity needs")) throw error51;
|
|
20979
21027
|
}
|
|
20980
|
-
const staging = await mkdtemp2(
|
|
21028
|
+
const staging = await mkdtemp2(join14(versions, `${STAGING_PREFIX}${randomUUID7()}-`));
|
|
20981
21029
|
let failed = false;
|
|
20982
21030
|
try {
|
|
20983
|
-
const archivePath =
|
|
20984
|
-
const runtimeDirectory =
|
|
21031
|
+
const archivePath = join14(staging, "download.zip");
|
|
21032
|
+
const runtimeDirectory = join14(staging, "runtime");
|
|
20985
21033
|
await mkdir3(runtimeDirectory, { mode: 448 });
|
|
20986
21034
|
const controller = new AbortController();
|
|
20987
21035
|
const timeout = setTimeout(() => controller.abort(), DOWNLOAD_TIMEOUT_MS2);
|
|
@@ -21027,12 +21075,12 @@ async function installOnce(options) {
|
|
|
21027
21075
|
}
|
|
21028
21076
|
await extractPinnedArchive(archivePath, runtimeDirectory, asset);
|
|
21029
21077
|
if (process.platform !== "win32") {
|
|
21030
|
-
await chmod(
|
|
21031
|
-
await chmod(
|
|
21078
|
+
await chmod(join14(runtimeDirectory, asset.executable.name), 493);
|
|
21079
|
+
await chmod(join14(runtimeDirectory, asset.harness.name), 493);
|
|
21032
21080
|
}
|
|
21033
21081
|
const candidate = {
|
|
21034
|
-
executablePath:
|
|
21035
|
-
harnessPath:
|
|
21082
|
+
executablePath: join14(runtimeDirectory, asset.executable.name),
|
|
21083
|
+
harnessPath: join14(runtimeDirectory, asset.harness.name),
|
|
21036
21084
|
source: "managed",
|
|
21037
21085
|
version: asset.version
|
|
21038
21086
|
};
|
|
@@ -21043,7 +21091,7 @@ async function installOnce(options) {
|
|
|
21043
21091
|
executable: asset.executable,
|
|
21044
21092
|
harness: asset.harness
|
|
21045
21093
|
};
|
|
21046
|
-
await writeFile2(
|
|
21094
|
+
await writeFile2(join14(runtimeDirectory, INSTALL_RECORD), `${JSON.stringify(record3)}
|
|
21047
21095
|
`, { flag: "wx", mode: 384 });
|
|
21048
21096
|
try {
|
|
21049
21097
|
await retryOnWindowsFileLock(() => rename(runtimeDirectory, destination));
|
|
@@ -21087,7 +21135,7 @@ var init_antigravity_runtime = __esm({
|
|
|
21087
21135
|
FREE_SPACE_MARGIN = 256 * 1024 * 1024;
|
|
21088
21136
|
DOWNLOAD_TIMEOUT_MS2 = 45 * 6e4;
|
|
21089
21137
|
STAGING_PREFIX = ".install-";
|
|
21090
|
-
wait = (ms) => new Promise((
|
|
21138
|
+
wait = (ms) => new Promise((resolve13) => setTimeout(resolve13, ms));
|
|
21091
21139
|
INSTALL_RECORD = ".install-complete.json";
|
|
21092
21140
|
AntigravitySetupError = class extends Error {
|
|
21093
21141
|
status = 409;
|
|
@@ -21482,15 +21530,15 @@ var init_boxagent = __esm({
|
|
|
21482
21530
|
// server/drivers/claude-login-auth.ts
|
|
21483
21531
|
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
21484
21532
|
import { realpathSync } from "node:fs";
|
|
21485
|
-
import { homedir as
|
|
21486
|
-
import { basename as
|
|
21533
|
+
import { homedir as homedir8 } from "node:os";
|
|
21534
|
+
import { basename as basename4, dirname as dirname7, isAbsolute as isAbsolute3, join as join15, resolve as resolve7 } from "node:path";
|
|
21487
21535
|
import { stripVTControlCharacters as stripVTControlCharacters3 } from "node:util";
|
|
21488
21536
|
function canonicalPath(path3) {
|
|
21489
21537
|
try {
|
|
21490
21538
|
return realpathSync(path3);
|
|
21491
21539
|
} catch {
|
|
21492
|
-
const parent =
|
|
21493
|
-
return parent === path3 ? path3 :
|
|
21540
|
+
const parent = dirname7(path3);
|
|
21541
|
+
return parent === path3 ? path3 : join15(canonicalPath(parent), basename4(path3));
|
|
21494
21542
|
}
|
|
21495
21543
|
}
|
|
21496
21544
|
function claudeSignInLink(value) {
|
|
@@ -21542,11 +21590,11 @@ var init_claude_login_auth = __esm({
|
|
|
21542
21590
|
await this.flow?.stopping;
|
|
21543
21591
|
if (this.disposed) throw new Error("This provider was removed. Refresh Settings before signing in.");
|
|
21544
21592
|
const env = this.options.environment();
|
|
21545
|
-
const home = env.HOME || env.USERPROFILE ||
|
|
21593
|
+
const home = env.HOME || env.USERPROFILE || homedir8();
|
|
21546
21594
|
if (!isAbsolute3(home) || env.CLAUDE_CONFIG_DIR && !isAbsolute3(env.CLAUDE_CONFIG_DIR)) {
|
|
21547
21595
|
throw new Error("Use an absolute HOME and CLAUDE_CONFIG_DIR path for this server's Claude provider before signing in.");
|
|
21548
21596
|
}
|
|
21549
|
-
const homeKey = canonicalPath(resolve7(env.CLAUDE_CONFIG_DIR ||
|
|
21597
|
+
const homeKey = canonicalPath(resolve7(env.CLAUDE_CONFIG_DIR || join15(home, ".claude")));
|
|
21550
21598
|
if (authenticatingHomes.has(homeKey)) {
|
|
21551
21599
|
throw new Error("A Claude sign-in is already running for this server account. Finish or cancel it before starting another.");
|
|
21552
21600
|
}
|
|
@@ -21801,13 +21849,13 @@ function computeBackoff(attempt, random = Math.random) {
|
|
|
21801
21849
|
function interruptibleDelay(ms, signal) {
|
|
21802
21850
|
let timer = null;
|
|
21803
21851
|
let onCancel = null;
|
|
21804
|
-
const promise2 = new Promise((
|
|
21805
|
-
timer = setTimeout(() =>
|
|
21852
|
+
const promise2 = new Promise((resolve13) => {
|
|
21853
|
+
timer = setTimeout(() => resolve13("elapsed"), Math.max(1, ms));
|
|
21806
21854
|
timer.unref?.();
|
|
21807
|
-
if (signal?.aborted) return
|
|
21855
|
+
if (signal?.aborted) return resolve13("cancelled");
|
|
21808
21856
|
onCancel = () => {
|
|
21809
21857
|
clearTimeout(timer);
|
|
21810
|
-
|
|
21858
|
+
resolve13("cancelled");
|
|
21811
21859
|
};
|
|
21812
21860
|
signal?.addEventListener("abort", onCancel, { once: true });
|
|
21813
21861
|
});
|
|
@@ -21856,37 +21904,37 @@ var init_retry = __esm({
|
|
|
21856
21904
|
|
|
21857
21905
|
// server/drivers/claude.ts
|
|
21858
21906
|
import { createHash as createHash5, randomBytes as randomBytes2 } from "node:crypto";
|
|
21859
|
-
import { chmodSync as chmodSync3, mkdtempSync as mkdtempSync2, readFileSync as readFileSync6, rmSync as rmSync2, unlinkSync as unlinkSync3, writeFileSync as
|
|
21907
|
+
import { chmodSync as chmodSync3, mkdtempSync as mkdtempSync2, readFileSync as readFileSync6, rmSync as rmSync2, unlinkSync as unlinkSync3, writeFileSync as writeFileSync5 } from "node:fs";
|
|
21860
21908
|
import { createServer as createNetServer } from "node:net";
|
|
21861
|
-
import { homedir as
|
|
21862
|
-
import { join as
|
|
21909
|
+
import { homedir as homedir9, tmpdir as tmpdir3 } from "node:os";
|
|
21910
|
+
import { join as join16, dirname as dirname8, isAbsolute as isAbsolute4, normalize } from "node:path";
|
|
21863
21911
|
function claudeAuthStatus(cli, env, run3 = execCli) {
|
|
21864
|
-
return new Promise((
|
|
21912
|
+
return new Promise((resolve13) => {
|
|
21865
21913
|
run3(cli, ["auth", "status", "--json"], { timeout: 8e3, maxBuffer: 65536, env }, (_error, stdout2) => {
|
|
21866
21914
|
try {
|
|
21867
21915
|
const status = JSON.parse(stdout2);
|
|
21868
21916
|
if (!status || typeof status !== "object" || !("loggedIn" in status) || status.loggedIn !== true) {
|
|
21869
|
-
return
|
|
21917
|
+
return resolve13({ authenticated: false });
|
|
21870
21918
|
}
|
|
21871
21919
|
const identity = status;
|
|
21872
21920
|
const boundedText = (value, max) => typeof value === "string" && value.trim().length > 0 && value.length <= max && !/[\p{Cc}\p{Cf}]/u.test(value) ? value.trim() : void 0;
|
|
21873
21921
|
const candidateEmail = boundedText(identity.email, 254);
|
|
21874
21922
|
const email3 = candidateEmail && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(candidateEmail) ? candidateEmail : void 0;
|
|
21875
21923
|
const organization = boundedText(identity.orgName, 160);
|
|
21876
|
-
|
|
21924
|
+
resolve13({
|
|
21877
21925
|
authenticated: true,
|
|
21878
21926
|
...email3 || organization ? { account: { ...email3 ? { email: email3 } : {}, ...organization ? { organization } : {} } } : {}
|
|
21879
21927
|
});
|
|
21880
21928
|
} catch {
|
|
21881
|
-
|
|
21929
|
+
resolve13({ authenticated: false });
|
|
21882
21930
|
}
|
|
21883
21931
|
});
|
|
21884
21932
|
});
|
|
21885
21933
|
}
|
|
21886
21934
|
function resolveClaudeConfigDir(configDir, env = process.env) {
|
|
21887
|
-
const home = env.HOME || env.USERPROFILE ||
|
|
21888
|
-
const configured = configDir?.trim() || env.CLAUDE_CONFIG_DIR?.trim() ||
|
|
21889
|
-
const expanded = configured === "~" ? home : configured.startsWith("~/") ?
|
|
21935
|
+
const home = env.HOME || env.USERPROFILE || homedir9();
|
|
21936
|
+
const configured = configDir?.trim() || env.CLAUDE_CONFIG_DIR?.trim() || join16(home, ".claude");
|
|
21937
|
+
const expanded = configured === "~" ? home : configured.startsWith("~/") ? join16(home, configured.slice(2)) : configured;
|
|
21890
21938
|
if (!isAbsolute4(expanded) || /[\p{Cc}\p{Cf}]/u.test(expanded)) {
|
|
21891
21939
|
throw new Error("claude: configDir must be an absolute path or start with ~/");
|
|
21892
21940
|
}
|
|
@@ -21938,7 +21986,7 @@ function extrasFromUnknown(value) {
|
|
|
21938
21986
|
function readClaudeModelCatalog(env = process.env) {
|
|
21939
21987
|
let settings2 = {};
|
|
21940
21988
|
try {
|
|
21941
|
-
settings2 = JSON.parse(readFileSync6(
|
|
21989
|
+
settings2 = JSON.parse(readFileSync6(join16(resolveClaudeConfigDir(void 0, env), "settings.json"), "utf8"));
|
|
21942
21990
|
} catch {
|
|
21943
21991
|
return STATIC_CLAUDE_MODELS;
|
|
21944
21992
|
}
|
|
@@ -21962,7 +22010,7 @@ function readClaudeModelCatalog(env = process.env) {
|
|
|
21962
22010
|
function removePrivateTempDir(filePath) {
|
|
21963
22011
|
if (!filePath) return true;
|
|
21964
22012
|
try {
|
|
21965
|
-
rmSync2(
|
|
22013
|
+
rmSync2(dirname8(filePath), { recursive: true, force: true, maxRetries: 3, retryDelay: 50 });
|
|
21966
22014
|
return true;
|
|
21967
22015
|
} catch {
|
|
21968
22016
|
return false;
|
|
@@ -21988,7 +22036,7 @@ function brokerSocketCandidates(threadId) {
|
|
|
21988
22036
|
const base2 = permissionSocketPath(threadId);
|
|
21989
22037
|
if (process.platform !== "win32") {
|
|
21990
22038
|
const scope = createHash5("sha256").update(`${DATA_DIR}\0${process.pid}\0${threadId}`).digest("hex").slice(0, 16);
|
|
21991
|
-
return [base2,
|
|
22039
|
+
return [base2, join16(tmpdir3(), `omb-perm-${scope}.sock`)];
|
|
21992
22040
|
}
|
|
21993
22041
|
return [
|
|
21994
22042
|
base2,
|
|
@@ -22069,9 +22117,9 @@ async function createPermissionBroker(opts) {
|
|
|
22069
22117
|
unlinkSync3(candidate);
|
|
22070
22118
|
} catch {
|
|
22071
22119
|
}
|
|
22072
|
-
let outcome = await new Promise((
|
|
22073
|
-
attempt.once("listening", () =>
|
|
22074
|
-
attempt.once("error", (error51) =>
|
|
22120
|
+
let outcome = await new Promise((resolve13) => {
|
|
22121
|
+
attempt.once("listening", () => resolve13("listening"));
|
|
22122
|
+
attempt.once("error", (error51) => resolve13(error51));
|
|
22075
22123
|
attempt.listen(candidate);
|
|
22076
22124
|
});
|
|
22077
22125
|
if (outcome === "listening" && process.platform !== "win32") {
|
|
@@ -22328,19 +22376,19 @@ var init_claude = __esm({
|
|
|
22328
22376
|
};
|
|
22329
22377
|
const writeUser = (s, threadId, promptMsg) => {
|
|
22330
22378
|
if (!s.child.stdin.writable || s.child.stdin.destroyed) return Promise.resolve(false);
|
|
22331
|
-
return new Promise((
|
|
22379
|
+
return new Promise((resolve13) => {
|
|
22332
22380
|
try {
|
|
22333
22381
|
s.child.stdin.write(JSON.stringify(promptMsg) + "\n", (error51) => {
|
|
22334
|
-
if (error51) return
|
|
22382
|
+
if (error51) return resolve13(false);
|
|
22335
22383
|
appendNative(threadId, {
|
|
22336
22384
|
dir: "out",
|
|
22337
22385
|
source: "claude.sdk.message",
|
|
22338
22386
|
msg: diagnosticClaudeUserMessage(promptMsg)
|
|
22339
22387
|
});
|
|
22340
|
-
|
|
22388
|
+
resolve13(true);
|
|
22341
22389
|
});
|
|
22342
22390
|
} catch {
|
|
22343
|
-
|
|
22391
|
+
resolve13(false);
|
|
22344
22392
|
}
|
|
22345
22393
|
});
|
|
22346
22394
|
};
|
|
@@ -22454,13 +22502,13 @@ var init_claude = __esm({
|
|
|
22454
22502
|
allowed.push("mcp__ogb");
|
|
22455
22503
|
let mcpConfigPath = null;
|
|
22456
22504
|
if (Object.keys(mcpServers).length) {
|
|
22457
|
-
mcpConfigPath =
|
|
22505
|
+
mcpConfigPath = join16(mkdtempSync2(join16(tmpdir3(), "omb-mcp-")), "mcp.json");
|
|
22458
22506
|
args.push("--mcp-config", mcpConfigPath);
|
|
22459
22507
|
args.push("--allowedTools", allowed.join(","));
|
|
22460
22508
|
}
|
|
22461
22509
|
const env = environment(turnModel);
|
|
22462
22510
|
env.CLAUDE_CODE_DISABLE_BACKGROUND_TASKS = "1";
|
|
22463
|
-
const cwd = turn.cwd ??
|
|
22511
|
+
const cwd = turn.cwd ?? homedir9();
|
|
22464
22512
|
const privateFileFlags = /* @__PURE__ */ new Set(["--mcp-config"]);
|
|
22465
22513
|
const keyArgs = args.filter((a2, i2) => !privateFileFlags.has(a2) && !privateFileFlags.has(args[i2 - 1] ?? ""));
|
|
22466
22514
|
const argsKey = JSON.stringify({
|
|
@@ -22489,7 +22537,7 @@ var init_claude = __esm({
|
|
|
22489
22537
|
retryState.delete(threadId);
|
|
22490
22538
|
if (mcpConfigPath) {
|
|
22491
22539
|
try {
|
|
22492
|
-
rmSync2(
|
|
22540
|
+
rmSync2(dirname8(mcpConfigPath), { recursive: true, force: true });
|
|
22493
22541
|
} catch {
|
|
22494
22542
|
}
|
|
22495
22543
|
}
|
|
@@ -22497,7 +22545,7 @@ var init_claude = __esm({
|
|
|
22497
22545
|
}
|
|
22498
22546
|
if (mcpConfigPath) {
|
|
22499
22547
|
try {
|
|
22500
|
-
rmSync2(
|
|
22548
|
+
rmSync2(dirname8(mcpConfigPath), { recursive: true, force: true });
|
|
22501
22549
|
} catch {
|
|
22502
22550
|
}
|
|
22503
22551
|
}
|
|
@@ -22509,7 +22557,7 @@ var init_claude = __esm({
|
|
|
22509
22557
|
broker = void 0;
|
|
22510
22558
|
if (mcpConfigPath) {
|
|
22511
22559
|
try {
|
|
22512
|
-
rmSync2(
|
|
22560
|
+
rmSync2(dirname8(mcpConfigPath), { recursive: true, force: true });
|
|
22513
22561
|
} catch {
|
|
22514
22562
|
}
|
|
22515
22563
|
mcpConfigPath = null;
|
|
@@ -22522,8 +22570,8 @@ var init_claude = __esm({
|
|
|
22522
22570
|
};
|
|
22523
22571
|
try {
|
|
22524
22572
|
if (turn.system) {
|
|
22525
|
-
systemPromptPath =
|
|
22526
|
-
|
|
22573
|
+
systemPromptPath = join16(mkdtempSync2(join16(tmpdir3(), "omb-system-")), "prompt.txt");
|
|
22574
|
+
writeFileSync5(systemPromptPath, turn.system, { mode: 384 });
|
|
22527
22575
|
args.push("--append-system-prompt-file", systemPromptPath);
|
|
22528
22576
|
}
|
|
22529
22577
|
if (socketPath) {
|
|
@@ -22563,7 +22611,7 @@ var init_claude = __esm({
|
|
|
22563
22611
|
}
|
|
22564
22612
|
}
|
|
22565
22613
|
if (mcpConfigPath) {
|
|
22566
|
-
|
|
22614
|
+
writeFileSync5(mcpConfigPath, JSON.stringify({ mcpServers }), { mode: 384 });
|
|
22567
22615
|
}
|
|
22568
22616
|
if (sessionId) args.push("--resume", sessionId);
|
|
22569
22617
|
else args.push("--session-id", newSessionId);
|
|
@@ -22602,7 +22650,7 @@ var init_claude = __esm({
|
|
|
22602
22650
|
session.broker?.pause();
|
|
22603
22651
|
if (session.mcpConfigPath) {
|
|
22604
22652
|
try {
|
|
22605
|
-
rmSync2(
|
|
22653
|
+
rmSync2(dirname8(session.mcpConfigPath), { recursive: true, force: true });
|
|
22606
22654
|
} catch {
|
|
22607
22655
|
}
|
|
22608
22656
|
session.mcpConfigPath = null;
|
|
@@ -22730,7 +22778,7 @@ var init_claude = __esm({
|
|
|
22730
22778
|
failedBroker?.close();
|
|
22731
22779
|
if (session.mcpConfigPath) {
|
|
22732
22780
|
try {
|
|
22733
|
-
rmSync2(
|
|
22781
|
+
rmSync2(dirname8(session.mcpConfigPath), { recursive: true, force: true });
|
|
22734
22782
|
} catch {
|
|
22735
22783
|
}
|
|
22736
22784
|
session.mcpConfigPath = null;
|
|
@@ -22799,7 +22847,7 @@ var init_claude = __esm({
|
|
|
22799
22847
|
session.broker?.close();
|
|
22800
22848
|
if (session.mcpConfigPath) {
|
|
22801
22849
|
try {
|
|
22802
|
-
rmSync2(
|
|
22850
|
+
rmSync2(dirname8(session.mcpConfigPath), { recursive: true, force: true });
|
|
22803
22851
|
} catch {
|
|
22804
22852
|
}
|
|
22805
22853
|
}
|
|
@@ -22830,19 +22878,19 @@ var init_claude = __esm({
|
|
|
22830
22878
|
} });
|
|
22831
22879
|
const snapshot = async () => {
|
|
22832
22880
|
const env = environment();
|
|
22833
|
-
const version2 = await new Promise((
|
|
22881
|
+
const version2 = await new Promise((resolve13) => {
|
|
22834
22882
|
execCli(
|
|
22835
22883
|
config2.cli,
|
|
22836
22884
|
["--version"],
|
|
22837
22885
|
{ timeout: 8e3, env },
|
|
22838
|
-
(err, stdout2) =>
|
|
22886
|
+
(err, stdout2) => resolve13(err ? null : stdout2.trim())
|
|
22839
22887
|
);
|
|
22840
22888
|
});
|
|
22841
22889
|
if (!version2) return { state: "unavailable", reason: `\`${config2.cli}\` CLI not found` };
|
|
22842
22890
|
const auth = await claudeAuthStatus(config2.cli, env);
|
|
22843
22891
|
return { state: "available", version: version2, ...auth, billing: "subscription" };
|
|
22844
22892
|
};
|
|
22845
|
-
const generateReview = (prompt, signal) => new Promise((
|
|
22893
|
+
const generateReview = (prompt, signal) => new Promise((resolve13, reject) => {
|
|
22846
22894
|
const child = spawnCli(
|
|
22847
22895
|
config2.cli,
|
|
22848
22896
|
["-p", "--model", "claude-haiku-4-5", "--output-format", "text"],
|
|
@@ -22860,7 +22908,7 @@ var init_claude = __esm({
|
|
|
22860
22908
|
clearTimeout(timer);
|
|
22861
22909
|
signal?.removeEventListener("abort", onAbort);
|
|
22862
22910
|
if (error51) reject(error51);
|
|
22863
|
-
else
|
|
22911
|
+
else resolve13(stdout2.trim());
|
|
22864
22912
|
};
|
|
22865
22913
|
const onAbort = () => {
|
|
22866
22914
|
killCliTree(child);
|
|
@@ -22961,8 +23009,8 @@ var init_claude = __esm({
|
|
|
22961
23009
|
|
|
22962
23010
|
// server/drivers/codex-catalog.ts
|
|
22963
23011
|
import { readdirSync as readdirSync2, readFileSync as readFileSync7 } from "node:fs";
|
|
22964
|
-
import { homedir as
|
|
22965
|
-
import { basename as
|
|
23012
|
+
import { homedir as homedir10 } from "node:os";
|
|
23013
|
+
import { basename as basename5, join as join17 } from "node:path";
|
|
22966
23014
|
function encodeCodexSelection(provider, model) {
|
|
22967
23015
|
return `${provider}${SEP}${model}`;
|
|
22968
23016
|
}
|
|
@@ -22975,9 +23023,9 @@ function decodeCodexSelection(id) {
|
|
|
22975
23023
|
return { model: id, modelProvider: MODEL_ID2.test(id) ? OFFICIAL_CODEX_PROVIDER : null };
|
|
22976
23024
|
}
|
|
22977
23025
|
function readCodexAppServerModelCatalog(cli, env, timeoutMs = 8e3) {
|
|
22978
|
-
return new Promise((
|
|
23026
|
+
return new Promise((resolve13) => {
|
|
22979
23027
|
const child = spawnCli(cli, ["app-server"], {
|
|
22980
|
-
cwd:
|
|
23028
|
+
cwd: homedir10(),
|
|
22981
23029
|
env,
|
|
22982
23030
|
stdio: ["pipe", "pipe", "pipe"]
|
|
22983
23031
|
});
|
|
@@ -22992,7 +23040,7 @@ function readCodexAppServerModelCatalog(cli, env, timeoutMs = 8e3) {
|
|
|
22992
23040
|
settled = true;
|
|
22993
23041
|
clearTimeout(timer);
|
|
22994
23042
|
killCliTree(child);
|
|
22995
|
-
|
|
23043
|
+
resolve13(catalog);
|
|
22996
23044
|
};
|
|
22997
23045
|
const request = (method, params, kind) => {
|
|
22998
23046
|
const id = nextId++;
|
|
@@ -23078,7 +23126,7 @@ function readCodexAppServerModelCatalog(cli, env, timeoutMs = 8e3) {
|
|
|
23078
23126
|
}
|
|
23079
23127
|
function codexHome(env) {
|
|
23080
23128
|
if (env.CODEX_HOME) return env.CODEX_HOME;
|
|
23081
|
-
return
|
|
23129
|
+
return join17(env.HOME || env.USERPROFILE || homedir10(), ".codex");
|
|
23082
23130
|
}
|
|
23083
23131
|
function unquote(raw) {
|
|
23084
23132
|
let value = raw.trim();
|
|
@@ -23164,11 +23212,11 @@ function niceLabel(model, provider, known, named) {
|
|
|
23164
23212
|
}
|
|
23165
23213
|
function collectCatalogNames(home) {
|
|
23166
23214
|
const named = /* @__PURE__ */ new Map();
|
|
23167
|
-
for (const file2 of listDir(
|
|
23215
|
+
for (const file2 of listDir(join17(home, "model-catalogs"))) {
|
|
23168
23216
|
if (!file2.endsWith(".json")) continue;
|
|
23169
|
-
const provider =
|
|
23217
|
+
const provider = basename5(file2, ".json").replace(/-models$/, "");
|
|
23170
23218
|
if (!PROVIDER_ID.test(provider)) continue;
|
|
23171
|
-
const raw = readText(
|
|
23219
|
+
const raw = readText(join17(home, "model-catalogs", file2));
|
|
23172
23220
|
if (!raw) continue;
|
|
23173
23221
|
let parsed;
|
|
23174
23222
|
try {
|
|
@@ -23220,7 +23268,7 @@ async function probeProviderModels(provider, env, fetchImpl) {
|
|
|
23220
23268
|
async function readCodexModelCatalog(env = process.env, fetchImpl = fetch, cli) {
|
|
23221
23269
|
const official = (cli ? await readCodexAppServerModelCatalog(cli, env) : null) ?? STATIC_CODEX_MODELS;
|
|
23222
23270
|
const home = codexHome(env);
|
|
23223
|
-
const mainText = readText(
|
|
23271
|
+
const mainText = readText(join17(home, "config.toml"));
|
|
23224
23272
|
if (!mainText) return mergeLocalInject(official, env, fetchImpl);
|
|
23225
23273
|
const main2 = parseCodexToml(mainText);
|
|
23226
23274
|
const known = new Map(main2.providers.map((provider) => [provider.id, provider]));
|
|
@@ -23235,7 +23283,7 @@ async function readCodexModelCatalog(env = process.env, fetchImpl = fetch, cli)
|
|
|
23235
23283
|
remember(main2.modelProvider, main2.model);
|
|
23236
23284
|
for (const file2 of listDir(home)) {
|
|
23237
23285
|
if (!file2.endsWith(".config.toml")) continue;
|
|
23238
|
-
const profile = parseCodexToml(readText(
|
|
23286
|
+
const profile = parseCodexToml(readText(join17(home, file2)) ?? "");
|
|
23239
23287
|
for (const provider of profile.providers) {
|
|
23240
23288
|
if (!known.has(provider.id)) known.set(provider.id, provider);
|
|
23241
23289
|
}
|
|
@@ -23301,8 +23349,8 @@ var init_codex_catalog = __esm({
|
|
|
23301
23349
|
|
|
23302
23350
|
// server/drivers/codex-instructions.ts
|
|
23303
23351
|
import { createHash as createHash6 } from "node:crypto";
|
|
23304
|
-
import { mkdirSync as
|
|
23305
|
-
import { join as
|
|
23352
|
+
import { mkdirSync as mkdirSync6, readFileSync as readFileSync8 } from "node:fs";
|
|
23353
|
+
import { join as join18 } from "node:path";
|
|
23306
23354
|
function codexDeveloperInstructions(config2, botInstructions) {
|
|
23307
23355
|
if (!config2 || typeof config2 !== "object" || Array.isArray(config2)) {
|
|
23308
23356
|
throw new Error("Codex returned no effective configuration; cannot safely update bot instructions.");
|
|
@@ -23316,8 +23364,8 @@ function codexDeveloperInstructions(config2, botInstructions) {
|
|
|
23316
23364
|
${configured}` : botInstructions;
|
|
23317
23365
|
}
|
|
23318
23366
|
async function syncCodexInstructions(key, nativeThreadId, instructions, resumed, request) {
|
|
23319
|
-
const directory =
|
|
23320
|
-
const path3 =
|
|
23367
|
+
const directory = join18(DATA_DIR, "codex-instructions");
|
|
23368
|
+
const path3 = join18(directory, `${digest(JSON.stringify([key, nativeThreadId]))}.sha256`);
|
|
23321
23369
|
const fingerprint = digest(instructions);
|
|
23322
23370
|
let previous;
|
|
23323
23371
|
try {
|
|
@@ -23346,7 +23394,7 @@ async function syncCodexInstructions(key, nativeThreadId, instructions, resumed,
|
|
|
23346
23394
|
}
|
|
23347
23395
|
}
|
|
23348
23396
|
if (!resumed || previous !== fingerprint) {
|
|
23349
|
-
|
|
23397
|
+
mkdirSync6(directory, { recursive: true });
|
|
23350
23398
|
writeFileAtomic(path3, fingerprint, { mode: 384 });
|
|
23351
23399
|
}
|
|
23352
23400
|
}
|
|
@@ -23363,15 +23411,15 @@ var init_codex_instructions = __esm({
|
|
|
23363
23411
|
// server/drivers/codex-device-auth.ts
|
|
23364
23412
|
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
23365
23413
|
import { realpathSync as realpathSync2 } from "node:fs";
|
|
23366
|
-
import { homedir as
|
|
23367
|
-
import { basename as
|
|
23414
|
+
import { homedir as homedir11 } from "node:os";
|
|
23415
|
+
import { basename as basename6, dirname as dirname9, isAbsolute as isAbsolute5, join as join19, resolve as resolve8 } from "node:path";
|
|
23368
23416
|
import { stripVTControlCharacters as stripVTControlCharacters4 } from "node:util";
|
|
23369
23417
|
function canonicalPath2(path3) {
|
|
23370
23418
|
try {
|
|
23371
23419
|
return realpathSync2(path3);
|
|
23372
23420
|
} catch {
|
|
23373
|
-
const parent =
|
|
23374
|
-
return parent === path3 ? path3 :
|
|
23421
|
+
const parent = dirname9(path3);
|
|
23422
|
+
return parent === path3 ? path3 : join19(canonicalPath2(parent), basename6(path3));
|
|
23375
23423
|
}
|
|
23376
23424
|
}
|
|
23377
23425
|
function codexDevicePrompt(output) {
|
|
@@ -23403,6 +23451,7 @@ var init_codex_device_auth = __esm({
|
|
|
23403
23451
|
authenticatingHomes2 = /* @__PURE__ */ new Set();
|
|
23404
23452
|
CodexDeviceAuthController = class {
|
|
23405
23453
|
flow = null;
|
|
23454
|
+
command = null;
|
|
23406
23455
|
disposed = false;
|
|
23407
23456
|
options;
|
|
23408
23457
|
constructor(options) {
|
|
@@ -23417,11 +23466,11 @@ var init_codex_device_auth = __esm({
|
|
|
23417
23466
|
await this.flow?.stopping;
|
|
23418
23467
|
if (this.disposed) throw new Error("This provider was removed. Refresh Settings before signing in.");
|
|
23419
23468
|
const env = this.options.environment();
|
|
23420
|
-
const home = env.HOME || env.USERPROFILE ||
|
|
23469
|
+
const home = env.HOME || env.USERPROFILE || homedir11();
|
|
23421
23470
|
if (!isAbsolute5(home) || env.CODEX_HOME && !isAbsolute5(env.CODEX_HOME)) {
|
|
23422
23471
|
throw new Error("Use an absolute HOME and CODEX_HOME path for this server's Codex provider before signing in.");
|
|
23423
23472
|
}
|
|
23424
|
-
const homeKey = canonicalPath2(resolve8(env.CODEX_HOME ||
|
|
23473
|
+
const homeKey = canonicalPath2(resolve8(env.CODEX_HOME || join19(home, ".codex")));
|
|
23425
23474
|
if (authenticatingHomes2.has(homeKey)) {
|
|
23426
23475
|
throw new Error("A ChatGPT sign-in is already running for this server account. Finish or cancel it before starting another.");
|
|
23427
23476
|
}
|
|
@@ -23478,12 +23527,92 @@ var init_codex_device_auth = __esm({
|
|
|
23478
23527
|
if (this.flow?.status.phase === "waiting") this.finish(this.flow, "cancelled", "ChatGPT sign-in cancelled.");
|
|
23479
23528
|
await this.flow?.stopping;
|
|
23480
23529
|
if (this.flow?.terminationFailed) throw new Error(this.flow.status.message);
|
|
23530
|
+
if (this.command && !await this.stopChild(this.command)) {
|
|
23531
|
+
throw new Error("Codex could not be stopped on this server. Ask the server administrator to stop the account command before trying again.");
|
|
23532
|
+
}
|
|
23481
23533
|
}
|
|
23482
23534
|
async dispose() {
|
|
23483
23535
|
this.disposed = true;
|
|
23484
23536
|
await this.cancel();
|
|
23485
23537
|
this.flow = null;
|
|
23486
23538
|
}
|
|
23539
|
+
/** Remove the ChatGPT sign-in Codex stores for this server account so a
|
|
23540
|
+
* different account can connect. A sign-in in progress is never pulled
|
|
23541
|
+
* away underneath the browser completing it. */
|
|
23542
|
+
async signOut() {
|
|
23543
|
+
if (this.disposed) throw new Error("This provider was removed. Refresh Settings before signing out.");
|
|
23544
|
+
if (this.flow?.status.phase === "waiting") throw new Error("Finish or cancel the ChatGPT sign-in in progress before signing out.");
|
|
23545
|
+
await this.flow?.stopping;
|
|
23546
|
+
if (this.disposed) throw new Error("This provider was removed. Refresh Settings before signing out.");
|
|
23547
|
+
const env = this.options.environment();
|
|
23548
|
+
const home = env.HOME || env.USERPROFILE || homedir11();
|
|
23549
|
+
if (!isAbsolute5(home) || env.CODEX_HOME && !isAbsolute5(env.CODEX_HOME)) {
|
|
23550
|
+
throw new Error("Use an absolute HOME and CODEX_HOME path for this server's Codex provider before signing out.");
|
|
23551
|
+
}
|
|
23552
|
+
const homeKey = canonicalPath2(resolve8(env.CODEX_HOME || join19(home, ".codex")));
|
|
23553
|
+
if (authenticatingHomes2.has(homeKey)) {
|
|
23554
|
+
throw new Error("A ChatGPT sign-in is running for this server account. Finish or cancel it before signing out.");
|
|
23555
|
+
}
|
|
23556
|
+
authenticatingHomes2.add(homeKey);
|
|
23557
|
+
try {
|
|
23558
|
+
const before = await this.exec(["login", "status"], env, home);
|
|
23559
|
+
if (before.code === 1 && /^not logged in\b/im.test(before.output)) return;
|
|
23560
|
+
if (before.code !== 0 || !/^logged in.*chatgpt\b/im.test(before.output)) {
|
|
23561
|
+
throw new Error("Codex did not confirm a ChatGPT sign-in. Other authentication methods will not be removed; ask the server administrator to check the account.");
|
|
23562
|
+
}
|
|
23563
|
+
const logout = await this.exec(["logout"], env, home);
|
|
23564
|
+
if (logout.code !== 0) throw new Error("Codex could not remove the sign-in on this server. Check the server's Codex installation and try again.");
|
|
23565
|
+
const status = await this.exec(["login", "status"], env, home);
|
|
23566
|
+
if (status.code !== 1 || !/^not logged in\b/im.test(status.output)) {
|
|
23567
|
+
throw new Error("Codex still reports a sign-in on this server. Update Codex and check its login status before trying again.");
|
|
23568
|
+
}
|
|
23569
|
+
} finally {
|
|
23570
|
+
const child = this.command;
|
|
23571
|
+
if (child && child.exitCode === null && child.signalCode === null) {
|
|
23572
|
+
child.once("close", () => authenticatingHomes2.delete(homeKey));
|
|
23573
|
+
} else authenticatingHomes2.delete(homeKey);
|
|
23574
|
+
}
|
|
23575
|
+
}
|
|
23576
|
+
/** One bounded, non-interactive Codex command. Its output stays here;
|
|
23577
|
+
* callers see an exit code and a status-line match, never the text. */
|
|
23578
|
+
exec(args, env, cwd) {
|
|
23579
|
+
return new Promise((resolveExec, rejectExec) => {
|
|
23580
|
+
if (this.disposed) {
|
|
23581
|
+
rejectExec(new Error("This provider was removed. Refresh Settings before signing out."));
|
|
23582
|
+
return;
|
|
23583
|
+
}
|
|
23584
|
+
let child;
|
|
23585
|
+
try {
|
|
23586
|
+
child = spawnCli(this.options.cli, args, { env: { ...env, NO_COLOR: "1" }, cwd, stdio: ["pipe", "pipe", "pipe"] });
|
|
23587
|
+
} catch {
|
|
23588
|
+
rejectExec(new Error("Codex could not start on this server. Install or update the configured Codex CLI, then try again."));
|
|
23589
|
+
return;
|
|
23590
|
+
}
|
|
23591
|
+
this.command = child;
|
|
23592
|
+
child.stdin.end();
|
|
23593
|
+
let output = "";
|
|
23594
|
+
const receive = (chunk) => {
|
|
23595
|
+
if (output.length < MAX_OUTPUT2) output += chunk.toString("utf8").slice(0, MAX_OUTPUT2 - output.length);
|
|
23596
|
+
};
|
|
23597
|
+
child.stdout.on("data", receive);
|
|
23598
|
+
child.stderr.on("data", receive);
|
|
23599
|
+
const timer = setTimeout(() => {
|
|
23600
|
+
void this.stopChild(child).catch(() => false).then((stopped) => {
|
|
23601
|
+
if (!stopped) rejectExec(new Error("Codex could not be stopped on this server. Ask the server administrator to stop the account command before trying again."));
|
|
23602
|
+
});
|
|
23603
|
+
}, this.options.startupTimeoutMs ?? 3e4);
|
|
23604
|
+
timer.unref();
|
|
23605
|
+
child.once("error", (error51) => {
|
|
23606
|
+
clearTimeout(timer);
|
|
23607
|
+
rejectExec(new Error(error51.code === "ENOENT" ? "Codex is not installed on this server. Run npm install -g @openai/codex@latest on the server, then try again." : "Codex could not start on this server. Check the configured CLI path and its executable permissions."));
|
|
23608
|
+
});
|
|
23609
|
+
child.once("close", (code) => {
|
|
23610
|
+
clearTimeout(timer);
|
|
23611
|
+
if (this.command === child) this.command = null;
|
|
23612
|
+
resolveExec({ code, output: stripVTControlCharacters4(output) });
|
|
23613
|
+
});
|
|
23614
|
+
});
|
|
23615
|
+
}
|
|
23487
23616
|
run(flow, args, env, cwd, done, parsePrompt = false) {
|
|
23488
23617
|
if (flow.status.phase !== "waiting") return;
|
|
23489
23618
|
let child;
|
|
@@ -23538,7 +23667,7 @@ var init_codex_device_auth = __esm({
|
|
|
23538
23667
|
if (phase === "succeeded") flow.resolve({ ...flow.status, phase });
|
|
23539
23668
|
else flow.reject(new Error(message2 ?? "ChatGPT sign-in did not finish."));
|
|
23540
23669
|
}
|
|
23541
|
-
flow.stopping = this.stopChild(flow).catch(() => false).then((stopped) => {
|
|
23670
|
+
flow.stopping = this.stopChild(flow.child).catch(() => false).then((stopped) => {
|
|
23542
23671
|
const release = () => authenticatingHomes2.delete(flow.homeKey);
|
|
23543
23672
|
if (stopped) {
|
|
23544
23673
|
release();
|
|
@@ -23553,8 +23682,7 @@ var init_codex_device_auth = __esm({
|
|
|
23553
23682
|
if (phase === "succeeded") void this.options.onAuthenticated?.().catch(() => {
|
|
23554
23683
|
});
|
|
23555
23684
|
}
|
|
23556
|
-
async stopChild(
|
|
23557
|
-
const child = flow.child;
|
|
23685
|
+
async stopChild(child) {
|
|
23558
23686
|
if (!child || await killCliTree(child, this.options.terminateTimeoutMs ?? 1500)) return true;
|
|
23559
23687
|
if (process.platform !== "win32" && child.pid) {
|
|
23560
23688
|
try {
|
|
@@ -23578,9 +23706,122 @@ var init_codex_device_auth = __esm({
|
|
|
23578
23706
|
}
|
|
23579
23707
|
});
|
|
23580
23708
|
|
|
23709
|
+
// server/drivers/codex-identity.ts
|
|
23710
|
+
import { homedir as homedir12 } from "node:os";
|
|
23711
|
+
import { isAbsolute as isAbsolute6, join as join20, resolve as resolve9 } from "node:path";
|
|
23712
|
+
function codexHome2(env) {
|
|
23713
|
+
if (env.CODEX_HOME) return isAbsolute6(env.CODEX_HOME) ? resolve9(env.CODEX_HOME) : null;
|
|
23714
|
+
const home = env.HOME || env.USERPROFILE || homedir12();
|
|
23715
|
+
return isAbsolute6(home) ? join20(home, ".codex") : null;
|
|
23716
|
+
}
|
|
23717
|
+
async function codexAccountEmail(cli, env, timeoutMs = 3e3) {
|
|
23718
|
+
const cwd = env.HOME || env.USERPROFILE || homedir12();
|
|
23719
|
+
if (!isAbsolute6(cwd) || !codexHome2(env)) return null;
|
|
23720
|
+
return new Promise((resolveEmail) => {
|
|
23721
|
+
let child;
|
|
23722
|
+
try {
|
|
23723
|
+
child = spawnCli(cli, ["app-server"], { cwd, env, stdio: ["pipe", "pipe", "pipe"] });
|
|
23724
|
+
} catch {
|
|
23725
|
+
resolveEmail(null);
|
|
23726
|
+
return;
|
|
23727
|
+
}
|
|
23728
|
+
let finishing = false;
|
|
23729
|
+
let buffer = "";
|
|
23730
|
+
let outputBytes = 0;
|
|
23731
|
+
let initialized = false;
|
|
23732
|
+
const finish = async (email3) => {
|
|
23733
|
+
if (finishing) return;
|
|
23734
|
+
finishing = true;
|
|
23735
|
+
clearTimeout(timer);
|
|
23736
|
+
let stopped = await killCliTree(child, 1e3);
|
|
23737
|
+
if (!stopped && child.pid) {
|
|
23738
|
+
try {
|
|
23739
|
+
if (process.platform === "win32") child.kill("SIGKILL");
|
|
23740
|
+
else process.kill(-child.pid, "SIGKILL");
|
|
23741
|
+
} catch {
|
|
23742
|
+
try {
|
|
23743
|
+
child.kill("SIGKILL");
|
|
23744
|
+
} catch {
|
|
23745
|
+
}
|
|
23746
|
+
}
|
|
23747
|
+
stopped = await killCliTree(child, 1e3);
|
|
23748
|
+
}
|
|
23749
|
+
resolveEmail(stopped ? email3 : null);
|
|
23750
|
+
};
|
|
23751
|
+
const timer = setTimeout(() => {
|
|
23752
|
+
void finish(null);
|
|
23753
|
+
}, timeoutMs);
|
|
23754
|
+
timer.unref();
|
|
23755
|
+
const send = (message2) => {
|
|
23756
|
+
try {
|
|
23757
|
+
child.stdin.write(`${JSON.stringify(message2)}
|
|
23758
|
+
`);
|
|
23759
|
+
} catch {
|
|
23760
|
+
void finish(null);
|
|
23761
|
+
}
|
|
23762
|
+
};
|
|
23763
|
+
child.stdin.on("error", () => {
|
|
23764
|
+
void finish(null);
|
|
23765
|
+
});
|
|
23766
|
+
child.stderr.resume();
|
|
23767
|
+
child.on("error", () => {
|
|
23768
|
+
void finish(null);
|
|
23769
|
+
});
|
|
23770
|
+
child.on("close", () => {
|
|
23771
|
+
void finish(null);
|
|
23772
|
+
});
|
|
23773
|
+
child.stdout.setEncoding("utf8");
|
|
23774
|
+
child.stdout.on("data", (chunk) => {
|
|
23775
|
+
if (finishing) return;
|
|
23776
|
+
outputBytes += Buffer.byteLength(chunk);
|
|
23777
|
+
if (outputBytes > MAX_OUTPUT3) {
|
|
23778
|
+
void finish(null);
|
|
23779
|
+
return;
|
|
23780
|
+
}
|
|
23781
|
+
buffer += chunk;
|
|
23782
|
+
let newline;
|
|
23783
|
+
while (!finishing && (newline = buffer.indexOf("\n")) !== -1) {
|
|
23784
|
+
const line = buffer.slice(0, newline);
|
|
23785
|
+
buffer = buffer.slice(newline + 1);
|
|
23786
|
+
if (!line.trim()) continue;
|
|
23787
|
+
let message2;
|
|
23788
|
+
try {
|
|
23789
|
+
message2 = JSON.parse(line);
|
|
23790
|
+
} catch {
|
|
23791
|
+
void finish(null);
|
|
23792
|
+
return;
|
|
23793
|
+
}
|
|
23794
|
+
if (!initialized && message2?.id === 1) {
|
|
23795
|
+
if (message2.error || !message2.result) {
|
|
23796
|
+
void finish(null);
|
|
23797
|
+
return;
|
|
23798
|
+
}
|
|
23799
|
+
initialized = true;
|
|
23800
|
+
send({ method: "initialized", params: {} });
|
|
23801
|
+
send({ id: 2, method: "account/read", params: { refreshToken: false } });
|
|
23802
|
+
} else if (initialized && message2?.id === 2) {
|
|
23803
|
+
const account = message2.error ? null : message2.result?.account;
|
|
23804
|
+
const email3 = account?.type === "chatgpt" ? account.email : null;
|
|
23805
|
+
void finish(typeof email3 === "string" && email3.length <= 254 && EMAIL.test(email3) && !/[\p{Cc}\p{Cf}]/u.test(email3) ? email3 : null);
|
|
23806
|
+
}
|
|
23807
|
+
}
|
|
23808
|
+
});
|
|
23809
|
+
send({ id: 1, method: "initialize", params: { clientInfo: { name: "openmausbot", version: "1" } } });
|
|
23810
|
+
});
|
|
23811
|
+
}
|
|
23812
|
+
var MAX_OUTPUT3, EMAIL;
|
|
23813
|
+
var init_codex_identity = __esm({
|
|
23814
|
+
"server/drivers/codex-identity.ts"() {
|
|
23815
|
+
"use strict";
|
|
23816
|
+
init_procs();
|
|
23817
|
+
MAX_OUTPUT3 = 16384;
|
|
23818
|
+
EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
23819
|
+
}
|
|
23820
|
+
});
|
|
23821
|
+
|
|
23581
23822
|
// server/drivers/codex.ts
|
|
23582
23823
|
import { existsSync as existsSync7 } from "node:fs";
|
|
23583
|
-
import { homedir as
|
|
23824
|
+
import { homedir as homedir13 } from "node:os";
|
|
23584
23825
|
function codexPredatesAstra(version2) {
|
|
23585
23826
|
const value = version2.trim();
|
|
23586
23827
|
const match = /\bcodex-cli\s+v?(\d+)\.(\d+)\.(\d+)(?:[-+][0-9a-z.-]+)?(?![\d.])\b/i.exec(value) ?? /^v?(\d+)\.(\d+)\.(\d+)(?:[-+][0-9a-z.-]+)?$/i.exec(value);
|
|
@@ -23850,6 +24091,7 @@ var init_codex = __esm({
|
|
|
23850
24091
|
init_native();
|
|
23851
24092
|
init_codex_instructions();
|
|
23852
24093
|
init_codex_device_auth();
|
|
24094
|
+
init_codex_identity();
|
|
23853
24095
|
init_codex_catalog();
|
|
23854
24096
|
DRIVER_KIND3 = "codex";
|
|
23855
24097
|
ASTRA_MODEL_ID = "gpt-6-astra";
|
|
@@ -23983,7 +24225,7 @@ var init_codex = __esm({
|
|
|
23983
24225
|
);
|
|
23984
24226
|
}
|
|
23985
24227
|
const child = spawnCli(config2.cli, appServerArgs, {
|
|
23986
|
-
cwd: turn.cwd ??
|
|
24228
|
+
cwd: turn.cwd ?? homedir13(),
|
|
23987
24229
|
env,
|
|
23988
24230
|
stdio: ["pipe", "pipe", "pipe"]
|
|
23989
24231
|
});
|
|
@@ -24011,7 +24253,7 @@ var init_codex = __esm({
|
|
|
24011
24253
|
msg: codexNativeLogMessage(obj)
|
|
24012
24254
|
});
|
|
24013
24255
|
};
|
|
24014
|
-
const request = (method, params, timeoutMs = 6e4) => new Promise((
|
|
24256
|
+
const request = (method, params, timeoutMs = 6e4) => new Promise((resolve13, reject) => {
|
|
24015
24257
|
const id = nextId++;
|
|
24016
24258
|
if (method === "config/read") sensitiveResponseIds.add(id);
|
|
24017
24259
|
const timer = setTimeout(() => {
|
|
@@ -24021,7 +24263,7 @@ var init_codex = __esm({
|
|
|
24021
24263
|
rpcPending.set(id, {
|
|
24022
24264
|
resolve: (v) => {
|
|
24023
24265
|
clearTimeout(timer);
|
|
24024
|
-
|
|
24266
|
+
resolve13(v);
|
|
24025
24267
|
},
|
|
24026
24268
|
reject: (e) => {
|
|
24027
24269
|
clearTimeout(timer);
|
|
@@ -24289,7 +24531,7 @@ var init_codex = __esm({
|
|
|
24289
24531
|
let effectiveConfig;
|
|
24290
24532
|
try {
|
|
24291
24533
|
const configured = await request("config/read", {
|
|
24292
|
-
cwd: turn.cwd ??
|
|
24534
|
+
cwd: turn.cwd ?? homedir13(),
|
|
24293
24535
|
includeLayers: false
|
|
24294
24536
|
});
|
|
24295
24537
|
effectiveConfig = configured?.config;
|
|
@@ -24333,7 +24575,7 @@ var init_codex = __esm({
|
|
|
24333
24575
|
const selection = decodeCodexSelection(turn.model);
|
|
24334
24576
|
const startThread = () => request("thread/start", {
|
|
24335
24577
|
developerInstructions,
|
|
24336
|
-
cwd: turn.cwd ??
|
|
24578
|
+
cwd: turn.cwd ?? homedir13(),
|
|
24337
24579
|
model: selection.model,
|
|
24338
24580
|
...selection.modelProvider ? { modelProvider: selection.modelProvider } : {},
|
|
24339
24581
|
...approvalParams.thread,
|
|
@@ -24400,8 +24642,8 @@ var init_codex = __esm({
|
|
|
24400
24642
|
void settle(false, "shutdown_timeout");
|
|
24401
24643
|
return;
|
|
24402
24644
|
}
|
|
24403
|
-
await new Promise((
|
|
24404
|
-
const timer = setTimeout(
|
|
24645
|
+
await new Promise((resolve13) => {
|
|
24646
|
+
const timer = setTimeout(resolve13, Math.max(1, Math.round(delayMs * retryScale)));
|
|
24405
24647
|
timer.unref?.();
|
|
24406
24648
|
});
|
|
24407
24649
|
if (!stopRequested) {
|
|
@@ -24429,28 +24671,30 @@ var init_codex = __esm({
|
|
|
24429
24671
|
};
|
|
24430
24672
|
const snapshot = async () => {
|
|
24431
24673
|
const env = childEnv();
|
|
24432
|
-
const version2 = await new Promise((
|
|
24674
|
+
const version2 = await new Promise((resolve13) => {
|
|
24433
24675
|
execCli(
|
|
24434
24676
|
config2.cli,
|
|
24435
24677
|
["--version"],
|
|
24436
24678
|
{ timeout: 8e3, env },
|
|
24437
|
-
(err, stdout2) =>
|
|
24679
|
+
(err, stdout2) => resolve13(err ? null : stdout2.trim())
|
|
24438
24680
|
);
|
|
24439
24681
|
});
|
|
24440
24682
|
if (!version2) return { state: "unavailable", reason: `\`${config2.cli}\` CLI not found` };
|
|
24441
|
-
const authenticated = await new Promise((
|
|
24683
|
+
const authenticated = await new Promise((resolve13) => {
|
|
24442
24684
|
execCli(
|
|
24443
24685
|
config2.cli,
|
|
24444
24686
|
["login", "status"],
|
|
24445
24687
|
{ timeout: 8e3, env },
|
|
24446
|
-
(err, stdout2, stderr) =>
|
|
24688
|
+
(err, stdout2, stderr) => resolve13(!err && /^logged in\b/im.test(`${stdout2}
|
|
24447
24689
|
${stderr ?? ""}`))
|
|
24448
24690
|
);
|
|
24449
24691
|
});
|
|
24692
|
+
const email3 = authenticated ? await codexAccountEmail(config2.cli, env) : null;
|
|
24450
24693
|
return {
|
|
24451
24694
|
state: "available",
|
|
24452
24695
|
version: version2,
|
|
24453
24696
|
authenticated,
|
|
24697
|
+
...email3 ? { account: { email: email3 } } : {},
|
|
24454
24698
|
update: codexAstraUpdate(version2, models, config2.cli),
|
|
24455
24699
|
billing: "subscription"
|
|
24456
24700
|
};
|
|
@@ -24467,6 +24711,7 @@ ${stderr ?? ""}`))
|
|
|
24467
24711
|
startAuthentication: () => authentication.start(),
|
|
24468
24712
|
getAuthentication: (flowId) => authentication.get(flowId),
|
|
24469
24713
|
cancelAuthentication: () => authentication.cancel(),
|
|
24714
|
+
signOut: () => authentication.signOut(),
|
|
24470
24715
|
snapshot,
|
|
24471
24716
|
adapter: {
|
|
24472
24717
|
provider: DRIVER_KIND3,
|
|
@@ -24790,12 +25035,12 @@ var init_grok = __esm({
|
|
|
24790
25035
|
});
|
|
24791
25036
|
|
|
24792
25037
|
// server/drivers/acp/grok.ts
|
|
24793
|
-
import { existsSync as existsSync8, readFileSync as readFileSync9, writeFileSync as
|
|
24794
|
-
import { homedir as
|
|
24795
|
-
import { join as
|
|
25038
|
+
import { existsSync as existsSync8, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "node:fs";
|
|
25039
|
+
import { homedir as homedir14 } from "node:os";
|
|
25040
|
+
import { join as join21 } from "node:path";
|
|
24796
25041
|
function grokHome(env) {
|
|
24797
25042
|
if (env.GROK_HOME) return env.GROK_HOME;
|
|
24798
|
-
return
|
|
25043
|
+
return join21(env.HOME || env.USERPROFILE || homedir14(), ".grok");
|
|
24799
25044
|
}
|
|
24800
25045
|
function unquote2(raw) {
|
|
24801
25046
|
const value = raw.trim();
|
|
@@ -24805,7 +25050,7 @@ function unquote2(raw) {
|
|
|
24805
25050
|
return value;
|
|
24806
25051
|
}
|
|
24807
25052
|
function readGrokModelCatalog(env = process.env) {
|
|
24808
|
-
const path3 =
|
|
25053
|
+
const path3 = join21(grokHome(env), "config.toml");
|
|
24809
25054
|
let text2 = "";
|
|
24810
25055
|
try {
|
|
24811
25056
|
text2 = readFileSync9(path3, "utf8");
|
|
@@ -24878,7 +25123,7 @@ function ensureGrokInjectSlug(modelId, env = process.env) {
|
|
|
24878
25123
|
if (!inject) return modelId;
|
|
24879
25124
|
const host = localHost(inject.host);
|
|
24880
25125
|
if (!host) return modelId;
|
|
24881
|
-
const path3 =
|
|
25126
|
+
const path3 = join21(grokHome(env), "config.toml");
|
|
24882
25127
|
let text2 = "";
|
|
24883
25128
|
try {
|
|
24884
25129
|
text2 = readFileSync9(path3, "utf8");
|
|
@@ -24932,7 +25177,7 @@ function ensureGrokInjectSlug(modelId, env = process.env) {
|
|
|
24932
25177
|
const next = text2 && !text2.endsWith("\n") ? `${text2}
|
|
24933
25178
|
|
|
24934
25179
|
${block2}` : `${text2}${text2 ? "\n" : ""}${block2}`;
|
|
24935
|
-
|
|
25180
|
+
writeFileSync6(path3, next);
|
|
24936
25181
|
return slug;
|
|
24937
25182
|
}
|
|
24938
25183
|
var STATIC_GROK_MODELS, SLUG, support2, GrokAgentDriver;
|
|
@@ -25013,7 +25258,7 @@ var init_grok2 = __esm({
|
|
|
25013
25258
|
// an unauthenticated CLI is a user action, not something to paper over.
|
|
25014
25259
|
pickAuthMethod: (methods) => methods.some((m) => m.id === "cached_token") ? "cached_token" : null,
|
|
25015
25260
|
authFailure: "fail",
|
|
25016
|
-
isAuthenticated: () => existsSync8(
|
|
25261
|
+
isAuthenticated: () => existsSync8(join21(homedir14(), ".grok", "auth.json")),
|
|
25017
25262
|
// `--append-system-prompt`/`--rules` are accepted by the CLI but do NOT
|
|
25018
25263
|
// reach the agent-stdio system prompt (verified against 1.0.0), so the
|
|
25019
25264
|
// persona is prepended codex-style.
|
|
@@ -25027,11 +25272,11 @@ ${turn.text}` : turn.text
|
|
|
25027
25272
|
|
|
25028
25273
|
// server/drivers/acp/gemini.ts
|
|
25029
25274
|
import { existsSync as existsSync9, readFileSync as readFileSync10 } from "node:fs";
|
|
25030
|
-
import { homedir as
|
|
25031
|
-
import { join as
|
|
25275
|
+
import { homedir as homedir15 } from "node:os";
|
|
25276
|
+
import { join as join22 } from "node:path";
|
|
25032
25277
|
function liveOauthCredential() {
|
|
25033
25278
|
try {
|
|
25034
|
-
const creds = JSON.parse(readFileSync10(
|
|
25279
|
+
const creds = JSON.parse(readFileSync10(join22(homedir15(), ".gemini", "oauth_creds.json"), "utf8"));
|
|
25035
25280
|
if (typeof creds.access_token !== "string" || creds.access_token.trim().length === 0) return false;
|
|
25036
25281
|
const hasRefresh = typeof creds.refresh_token === "string" && creds.refresh_token.trim().length > 0;
|
|
25037
25282
|
if (creds.expiry_date !== void 0) {
|
|
@@ -25044,7 +25289,7 @@ function liveOauthCredential() {
|
|
|
25044
25289
|
}
|
|
25045
25290
|
}
|
|
25046
25291
|
function geminiIsAuthenticated(env) {
|
|
25047
|
-
return nonBlank(env.GEMINI_API_KEY) || nonBlank(env.GOOGLE_API_KEY) || existsSync9(
|
|
25292
|
+
return nonBlank(env.GEMINI_API_KEY) || nonBlank(env.GOOGLE_API_KEY) || existsSync9(join22(homedir15(), ".gemini", "oauth_creds.json")) && liveOauthCredential();
|
|
25048
25293
|
}
|
|
25049
25294
|
var AUTH_PREFERENCE, nonBlank, support3, GeminiAgentDriver;
|
|
25050
25295
|
var init_gemini = __esm({
|
|
@@ -25086,17 +25331,17 @@ ${turn.text}` : turn.text
|
|
|
25086
25331
|
});
|
|
25087
25332
|
|
|
25088
25333
|
// server/drivers/acp/kimi.ts
|
|
25089
|
-
import { existsSync as existsSync10, mkdirSync as
|
|
25090
|
-
import { homedir as
|
|
25091
|
-
import { join as
|
|
25334
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync7, readFileSync as readFileSync11, writeFileSync as writeFileSync7 } from "node:fs";
|
|
25335
|
+
import { homedir as homedir16 } from "node:os";
|
|
25336
|
+
import { join as join23 } from "node:path";
|
|
25092
25337
|
function isLocalInjectAlias(slug) {
|
|
25093
25338
|
return LOCAL_PROVIDER_PREFIXES.some((prefix) => slug.startsWith(prefix));
|
|
25094
25339
|
}
|
|
25095
25340
|
function kimiDataRoot(env) {
|
|
25096
|
-
return env.KIMI_CODE_HOME ||
|
|
25341
|
+
return env.KIMI_CODE_HOME || join23(env.HOME || env.USERPROFILE || homedir16(), ".kimi-code");
|
|
25097
25342
|
}
|
|
25098
25343
|
function credentialsPath(env) {
|
|
25099
|
-
return
|
|
25344
|
+
return join23(kimiDataRoot(env), "credentials", "kimi-code.json");
|
|
25100
25345
|
}
|
|
25101
25346
|
function quoteToml2(value) {
|
|
25102
25347
|
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
@@ -25383,8 +25628,8 @@ function ensureKimiInjectAlias(modelId, env = process.env) {
|
|
|
25383
25628
|
if (!host) return modelId;
|
|
25384
25629
|
const alias = `${inject.host}/${inject.model.replace(/\//g, "-")}`;
|
|
25385
25630
|
const dataRoot = kimiDataRoot(env);
|
|
25386
|
-
|
|
25387
|
-
const path3 =
|
|
25631
|
+
mkdirSync7(dataRoot, { recursive: true });
|
|
25632
|
+
const path3 = join23(dataRoot, "config.toml");
|
|
25388
25633
|
let text2 = "";
|
|
25389
25634
|
try {
|
|
25390
25635
|
text2 = readFileSync11(path3, "utf8");
|
|
@@ -25425,9 +25670,9 @@ function ensureKimiInjectAlias(modelId, env = process.env) {
|
|
|
25425
25670
|
|
|
25426
25671
|
` : text2 ? `${text2}
|
|
25427
25672
|
` : "";
|
|
25428
|
-
|
|
25673
|
+
writeFileSync7(path3, `${prefix}${blocks.join("\n")}`);
|
|
25429
25674
|
} else if (text2 !== original) {
|
|
25430
|
-
|
|
25675
|
+
writeFileSync7(path3, text2);
|
|
25431
25676
|
}
|
|
25432
25677
|
return alias;
|
|
25433
25678
|
}
|
|
@@ -25449,7 +25694,7 @@ function readKimiModelCatalog(env) {
|
|
|
25449
25694
|
const dataRoot = kimiDataRoot(env);
|
|
25450
25695
|
let text2 = "";
|
|
25451
25696
|
try {
|
|
25452
|
-
text2 = readFileSync11(
|
|
25697
|
+
text2 = readFileSync11(join23(dataRoot, "config.toml"), "utf8");
|
|
25453
25698
|
} catch {
|
|
25454
25699
|
return STATIC_KIMI_MODELS;
|
|
25455
25700
|
}
|
|
@@ -25568,19 +25813,19 @@ ${turn.text}` : turn.text
|
|
|
25568
25813
|
});
|
|
25569
25814
|
|
|
25570
25815
|
// server/drivers/acp/droid.ts
|
|
25571
|
-
import { existsSync as existsSync11, mkdirSync as
|
|
25572
|
-
import { homedir as
|
|
25573
|
-
import { join as
|
|
25816
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync8, readFileSync as readFileSync12, writeFileSync as writeFileSync8 } from "node:fs";
|
|
25817
|
+
import { homedir as homedir17 } from "node:os";
|
|
25818
|
+
import { join as join24 } from "node:path";
|
|
25574
25819
|
function authFilePaths(env) {
|
|
25575
|
-
const home = env.FACTORY_HOME_OVERRIDE || env.HOME ||
|
|
25576
|
-
return AUTH_FILES.map((name) =>
|
|
25820
|
+
const home = env.FACTORY_HOME_OVERRIDE || env.HOME || homedir17();
|
|
25821
|
+
return AUTH_FILES.map((name) => join24(home, ".factory", name));
|
|
25577
25822
|
}
|
|
25578
25823
|
function droidInjectId(host, model) {
|
|
25579
25824
|
const safe = `${host}-${model}`.replace(/[^a-zA-Z0-9._+-]+/g, "-").replace(/-+/g, "-");
|
|
25580
25825
|
return `${INJECT_ID_PREFIX}${safe}`;
|
|
25581
25826
|
}
|
|
25582
25827
|
function factoryHome(env) {
|
|
25583
|
-
return env.FACTORY_HOME_OVERRIDE || env.HOME || env.USERPROFILE ||
|
|
25828
|
+
return env.FACTORY_HOME_OVERRIDE || env.HOME || env.USERPROFILE || homedir17();
|
|
25584
25829
|
}
|
|
25585
25830
|
function ensureDroidInjectModel(modelId, env = process.env) {
|
|
25586
25831
|
const inject = decodeInjectId(modelId);
|
|
@@ -25588,9 +25833,9 @@ function ensureDroidInjectModel(modelId, env = process.env) {
|
|
|
25588
25833
|
const host = localHost(inject.host);
|
|
25589
25834
|
if (!host) return modelId;
|
|
25590
25835
|
const id = droidInjectId(inject.host, inject.model);
|
|
25591
|
-
const dir =
|
|
25592
|
-
|
|
25593
|
-
const path3 =
|
|
25836
|
+
const dir = join24(factoryHome(env), ".factory");
|
|
25837
|
+
mkdirSync8(dir, { recursive: true });
|
|
25838
|
+
const path3 = join24(dir, "settings.json");
|
|
25594
25839
|
let settings2 = {};
|
|
25595
25840
|
try {
|
|
25596
25841
|
settings2 = JSON.parse(readFileSync12(path3, "utf8"));
|
|
@@ -25605,7 +25850,7 @@ function ensureDroidInjectModel(modelId, env = process.env) {
|
|
|
25605
25850
|
if (!match.id) {
|
|
25606
25851
|
match.id = id;
|
|
25607
25852
|
settings2.customModels = custom2;
|
|
25608
|
-
|
|
25853
|
+
writeFileSync8(path3, `${JSON.stringify(settings2, null, 2)}
|
|
25609
25854
|
`);
|
|
25610
25855
|
}
|
|
25611
25856
|
return match.id;
|
|
@@ -25619,7 +25864,7 @@ function ensureDroidInjectModel(modelId, env = process.env) {
|
|
|
25619
25864
|
provider: "generic-chat-completion-api"
|
|
25620
25865
|
});
|
|
25621
25866
|
settings2.customModels = custom2;
|
|
25622
|
-
|
|
25867
|
+
writeFileSync8(path3, `${JSON.stringify(settings2, null, 2)}
|
|
25623
25868
|
`);
|
|
25624
25869
|
return id;
|
|
25625
25870
|
}
|
|
@@ -25630,7 +25875,7 @@ function applyDroidLocalAuthEnv(env, modelId) {
|
|
|
25630
25875
|
env.FACTORY_API_KEY = "openmausbot-local";
|
|
25631
25876
|
}
|
|
25632
25877
|
function readSettings(env) {
|
|
25633
|
-
return JSON.parse(readFileSync12(
|
|
25878
|
+
return JSON.parse(readFileSync12(join24(factoryHome(env), ".factory", "settings.json"), "utf8"));
|
|
25634
25879
|
}
|
|
25635
25880
|
async function resolveModels(env) {
|
|
25636
25881
|
let catalog = MODELS3;
|
|
@@ -25899,10 +26144,10 @@ function decodeCursorAuthText(text2) {
|
|
|
25899
26144
|
return null;
|
|
25900
26145
|
}
|
|
25901
26146
|
function execText(run3, cli, args, env) {
|
|
25902
|
-
return new Promise((
|
|
26147
|
+
return new Promise((resolve13) => {
|
|
25903
26148
|
run3(cli, args, { timeout: EXEC_TIMEOUT_MS, env }, (err, stdout2) => {
|
|
25904
|
-
if (err) return
|
|
25905
|
-
|
|
26149
|
+
if (err) return resolve13(null);
|
|
26150
|
+
resolve13(String(stdout2 ?? ""));
|
|
25906
26151
|
});
|
|
25907
26152
|
});
|
|
25908
26153
|
}
|
|
@@ -26020,9 +26265,9 @@ ${turn.text}` : turn.text
|
|
|
26020
26265
|
});
|
|
26021
26266
|
|
|
26022
26267
|
// server/drivers/acp/opencode-go.ts
|
|
26023
|
-
import { existsSync as existsSync12, mkdirSync as
|
|
26024
|
-
import { homedir as
|
|
26025
|
-
import { join as
|
|
26268
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync9, readFileSync as readFileSync13, writeFileSync as writeFileSync9 } from "node:fs";
|
|
26269
|
+
import { homedir as homedir18 } from "node:os";
|
|
26270
|
+
import { join as join25 } from "node:path";
|
|
26026
26271
|
function labelForModel(id) {
|
|
26027
26272
|
return id.split(/[-_.]+/g).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
|
|
26028
26273
|
}
|
|
@@ -26096,7 +26341,7 @@ function parseOpenCodeModelsOutput(stdout2) {
|
|
|
26096
26341
|
return { default: (preferred ?? options[0]).id, options };
|
|
26097
26342
|
}
|
|
26098
26343
|
function runOpenCodeModels(cli, environment, verbose) {
|
|
26099
|
-
return new Promise((
|
|
26344
|
+
return new Promise((resolve13, reject) => {
|
|
26100
26345
|
execCli(
|
|
26101
26346
|
cli,
|
|
26102
26347
|
["models", ...verbose ? ["--verbose"] : []],
|
|
@@ -26106,7 +26351,7 @@ function runOpenCodeModels(cli, environment, verbose) {
|
|
|
26106
26351
|
reject(new Error(stderr?.trim() || error51.message, { cause: error51 }));
|
|
26107
26352
|
return;
|
|
26108
26353
|
}
|
|
26109
|
-
|
|
26354
|
+
resolve13(stdout2);
|
|
26110
26355
|
}
|
|
26111
26356
|
);
|
|
26112
26357
|
});
|
|
@@ -26122,8 +26367,8 @@ async function discoverOpenCodeModels(environment, cli = "opencode") {
|
|
|
26122
26367
|
}
|
|
26123
26368
|
}
|
|
26124
26369
|
function opencodeConfigDir(env) {
|
|
26125
|
-
const home = env.HOME || env.USERPROFILE ||
|
|
26126
|
-
return
|
|
26370
|
+
const home = env.HOME || env.USERPROFILE || homedir18();
|
|
26371
|
+
return join25(env.XDG_CONFIG_HOME || join25(home, ".config"), "opencode");
|
|
26127
26372
|
}
|
|
26128
26373
|
function ensureOpenCodeInjectModel(modelId, env = process.env) {
|
|
26129
26374
|
const inject = decodeInjectId(modelId);
|
|
@@ -26132,8 +26377,8 @@ function ensureOpenCodeInjectModel(modelId, env = process.env) {
|
|
|
26132
26377
|
if (!host) return modelId;
|
|
26133
26378
|
const native = `${inject.host}/${inject.model}`;
|
|
26134
26379
|
const dir = opencodeConfigDir(env);
|
|
26135
|
-
|
|
26136
|
-
const path3 =
|
|
26380
|
+
mkdirSync9(dir, { recursive: true });
|
|
26381
|
+
const path3 = join25(dir, "opencode.json");
|
|
26137
26382
|
let config2 = { $schema: "https://opencode.ai/config.json" };
|
|
26138
26383
|
if (existsSync12(path3)) {
|
|
26139
26384
|
try {
|
|
@@ -26164,17 +26409,17 @@ function ensureOpenCodeInjectModel(modelId, env = process.env) {
|
|
|
26164
26409
|
models
|
|
26165
26410
|
};
|
|
26166
26411
|
config2.provider = providers;
|
|
26167
|
-
|
|
26412
|
+
writeFileSync9(path3, `${JSON.stringify(config2, null, 2)}
|
|
26168
26413
|
`);
|
|
26169
26414
|
return native;
|
|
26170
26415
|
}
|
|
26171
26416
|
function storedAuthPaths(env) {
|
|
26172
|
-
const home = env.HOME || env.USERPROFILE ||
|
|
26417
|
+
const home = env.HOME || env.USERPROFILE || homedir18();
|
|
26173
26418
|
const roots = [
|
|
26174
|
-
env.XDG_DATA_HOME ||
|
|
26175
|
-
process.platform === "darwin" ?
|
|
26419
|
+
env.XDG_DATA_HOME || join25(home, ".local", "share"),
|
|
26420
|
+
process.platform === "darwin" ? join25(home, "Library", "Application Support") : process.platform === "win32" ? env.LOCALAPPDATA || join25(home, "AppData", "Local") : ""
|
|
26176
26421
|
].filter(Boolean);
|
|
26177
|
-
return [...new Set(roots)].map((root) =>
|
|
26422
|
+
return [...new Set(roots)].map((root) => join25(root, "opencode", "auth.json"));
|
|
26178
26423
|
}
|
|
26179
26424
|
function usableAuthEntry(parsed) {
|
|
26180
26425
|
return Object.values(parsed).some((auth) => {
|
|
@@ -26304,11 +26549,97 @@ ${turn.text}` : turn.text
|
|
|
26304
26549
|
});
|
|
26305
26550
|
|
|
26306
26551
|
// server/drivers/acp/qwen.ts
|
|
26307
|
-
import { chmodSync as chmodSync4, existsSync as existsSync13, mkdirSync as
|
|
26308
|
-
import {
|
|
26309
|
-
import {
|
|
26552
|
+
import { chmodSync as chmodSync4, existsSync as existsSync13, mkdirSync as mkdirSync10, readFileSync as readFileSync14, writeFileSync as writeFileSync10 } from "node:fs";
|
|
26553
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
26554
|
+
import { homedir as homedir19 } from "node:os";
|
|
26555
|
+
import { join as join26 } from "node:path";
|
|
26310
26556
|
function qwenHome(env) {
|
|
26311
|
-
|
|
26557
|
+
const home = process.platform === "win32" ? env.USERPROFILE || env.HOME || homedir19() : env.HOME || env.USERPROFILE || homedir19();
|
|
26558
|
+
return join26(home, ".qwen");
|
|
26559
|
+
}
|
|
26560
|
+
function isRecord(value) {
|
|
26561
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
26562
|
+
}
|
|
26563
|
+
function qwenModelLabel(id, name) {
|
|
26564
|
+
if (!name || name.toLocaleLowerCase().endsWith(id.toLocaleLowerCase())) return id;
|
|
26565
|
+
return `${id} \u2014 ${name}`;
|
|
26566
|
+
}
|
|
26567
|
+
function readQwenRoutes(env) {
|
|
26568
|
+
let settings2;
|
|
26569
|
+
try {
|
|
26570
|
+
settings2 = JSON.parse(readFileSync14(join26(qwenHome(env), "settings.json"), "utf8"));
|
|
26571
|
+
} catch {
|
|
26572
|
+
return [];
|
|
26573
|
+
}
|
|
26574
|
+
if (!isRecord(settings2) || !isRecord(settings2.modelProviders)) return [];
|
|
26575
|
+
const routes = [];
|
|
26576
|
+
const seen = /* @__PURE__ */ new Set();
|
|
26577
|
+
const mappings = isRecord(settings2.providerProtocol) ? settings2.providerProtocol : {};
|
|
26578
|
+
for (const [provider, rows] of Object.entries(settings2.modelProviders)) {
|
|
26579
|
+
const protocol = Object.hasOwn(mappings, provider) ? mappings[provider] : provider;
|
|
26580
|
+
if (typeof protocol !== "string" || !PROTOCOLS.has(protocol) || !Array.isArray(rows)) continue;
|
|
26581
|
+
for (const row of rows) {
|
|
26582
|
+
if (!isRecord(row) || typeof row.id !== "string") continue;
|
|
26583
|
+
const model = row.id;
|
|
26584
|
+
if (!model.trim()) continue;
|
|
26585
|
+
if (row.baseUrl !== void 0 && typeof row.baseUrl !== "string") continue;
|
|
26586
|
+
const baseUrl = typeof row.baseUrl === "string" && row.baseUrl ? row.baseUrl : void 0;
|
|
26587
|
+
if (baseUrl) {
|
|
26588
|
+
try {
|
|
26589
|
+
new URL(baseUrl);
|
|
26590
|
+
} catch {
|
|
26591
|
+
throw new Error("A Qwen model has an invalid endpoint. Fix its baseUrl in Qwen settings and refresh models.");
|
|
26592
|
+
}
|
|
26593
|
+
}
|
|
26594
|
+
const identity = JSON.stringify([protocol, model, baseUrl ?? null]);
|
|
26595
|
+
if (seen.has(identity)) continue;
|
|
26596
|
+
seen.add(identity);
|
|
26597
|
+
if (row.imageOnly === true || row.voiceOnly === true || row.fastOnly === true) continue;
|
|
26598
|
+
routes.push({
|
|
26599
|
+
id: `${model}(${protocol})`,
|
|
26600
|
+
model,
|
|
26601
|
+
provider,
|
|
26602
|
+
protocol,
|
|
26603
|
+
baseUrl,
|
|
26604
|
+
label: typeof row.name === "string" && row.name ? row.name : model,
|
|
26605
|
+
envKey: typeof row.envKey === "string" ? row.envKey : void 0
|
|
26606
|
+
});
|
|
26607
|
+
}
|
|
26608
|
+
}
|
|
26609
|
+
const counts = /* @__PURE__ */ new Map();
|
|
26610
|
+
for (const route of routes) counts.set(route.id, (counts.get(route.id) ?? 0) + 1);
|
|
26611
|
+
for (const route of routes) {
|
|
26612
|
+
if (counts.get(route.id) === 1) continue;
|
|
26613
|
+
const endpoint = route.baseUrl ?? (route.protocol === "openai" ? "https://api.openai.com/v1" : "");
|
|
26614
|
+
let publicEndpoint = null;
|
|
26615
|
+
if (endpoint) {
|
|
26616
|
+
try {
|
|
26617
|
+
const url2 = new URL(endpoint);
|
|
26618
|
+
url2.username = "";
|
|
26619
|
+
url2.password = "";
|
|
26620
|
+
url2.search = "";
|
|
26621
|
+
url2.hash = "";
|
|
26622
|
+
publicEndpoint = url2.href;
|
|
26623
|
+
} catch {
|
|
26624
|
+
throw new Error("A Qwen model has an invalid endpoint. Fix its baseUrl in Qwen settings and refresh models.");
|
|
26625
|
+
}
|
|
26626
|
+
}
|
|
26627
|
+
const identity = [route.id, route.label, route.envKey ?? null, route.baseUrl === void 0, publicEndpoint];
|
|
26628
|
+
route.id = `qwen-route:v1:${createHash7("sha256").update(JSON.stringify(identity)).digest("base64url").slice(0, 16)}`;
|
|
26629
|
+
}
|
|
26630
|
+
if (new Set(routes.map((route) => route.id)).size !== routes.length) {
|
|
26631
|
+
throw new Error("Qwen has indistinguishable model routes. Give them distinct names, envKey values, or public endpoints in Qwen settings.");
|
|
26632
|
+
}
|
|
26633
|
+
return routes;
|
|
26634
|
+
}
|
|
26635
|
+
function readQwenModelCatalog(env = process.env) {
|
|
26636
|
+
const options = readQwenRoutes(env).map(({ id, model, label, provider }) => ({
|
|
26637
|
+
id,
|
|
26638
|
+
label: qwenModelLabel(model, label),
|
|
26639
|
+
custom: true,
|
|
26640
|
+
provider
|
|
26641
|
+
}));
|
|
26642
|
+
return { default: options[0]?.id ?? "", options };
|
|
26312
26643
|
}
|
|
26313
26644
|
function envKeyFor(hostId) {
|
|
26314
26645
|
return `OPENMAUSBOT_QWEN_${hostId.toUpperCase().replace(/[^A-Z0-9]+/g, "_")}_API_KEY`;
|
|
@@ -26319,8 +26650,8 @@ function ensureQwenInjectModel(modelId, env = process.env) {
|
|
|
26319
26650
|
const host = localHost(inject.host);
|
|
26320
26651
|
if (!host) return modelId;
|
|
26321
26652
|
const dir = qwenHome(env);
|
|
26322
|
-
|
|
26323
|
-
const path3 =
|
|
26653
|
+
mkdirSync10(dir, { recursive: true });
|
|
26654
|
+
const path3 = join26(dir, "settings.json");
|
|
26324
26655
|
let settings2 = {};
|
|
26325
26656
|
if (existsSync13(path3)) {
|
|
26326
26657
|
try {
|
|
@@ -26348,7 +26679,7 @@ function ensureQwenInjectModel(modelId, env = process.env) {
|
|
|
26348
26679
|
providers.openai = openai;
|
|
26349
26680
|
settings2.modelProviders = providers;
|
|
26350
26681
|
}
|
|
26351
|
-
|
|
26682
|
+
writeFileSync10(path3, `${JSON.stringify(settings2, null, 2)}
|
|
26352
26683
|
`, { mode: 384 });
|
|
26353
26684
|
try {
|
|
26354
26685
|
chmodSync4(path3, 384);
|
|
@@ -26357,23 +26688,54 @@ function ensureQwenInjectModel(modelId, env = process.env) {
|
|
|
26357
26688
|
return inject.model;
|
|
26358
26689
|
}
|
|
26359
26690
|
async function resolveModels2(env) {
|
|
26360
|
-
const catalog = await mergeLocalInject(
|
|
26361
|
-
|
|
26362
|
-
|
|
26363
|
-
|
|
26691
|
+
const catalog = await mergeLocalInject(readQwenModelCatalog(env), env);
|
|
26692
|
+
const routes = readQwenRoutes(env);
|
|
26693
|
+
const replacements = /* @__PURE__ */ new Map();
|
|
26694
|
+
for (const option of catalog.options) {
|
|
26695
|
+
const injected = decodeInjectId(option.id);
|
|
26696
|
+
if (!injected) continue;
|
|
26697
|
+
const endpoint = localHost(injected.host)?.baseUrl;
|
|
26698
|
+
for (const route of routes) {
|
|
26699
|
+
if (route.protocol === "openai" && route.model === injected.model && route.baseUrl === endpoint) {
|
|
26700
|
+
replacements.set(route.id, option.id);
|
|
26701
|
+
}
|
|
26702
|
+
}
|
|
26703
|
+
}
|
|
26704
|
+
const options = catalog.options.filter((option) => !replacements.has(option.id));
|
|
26705
|
+
const preferred = replacements.get(catalog.default) ?? catalog.default;
|
|
26706
|
+
return { default: options.some((option) => option.id === preferred) ? preferred : options[0]?.id ?? "", options };
|
|
26707
|
+
}
|
|
26708
|
+
function resolveQwenTurnModel(model, env) {
|
|
26709
|
+
if (!model) return model;
|
|
26710
|
+
const injected = decodeInjectId(model);
|
|
26711
|
+
if (injected) ensureQwenInjectModel(model, env);
|
|
26712
|
+
const routes = readQwenRoutes(env);
|
|
26713
|
+
if (injected) {
|
|
26714
|
+
const route = routes.find((row) => row.protocol === "openai" && row.model === injected.model && row.baseUrl === localHost(injected.host)?.baseUrl);
|
|
26715
|
+
if (!route) throw new Error("Qwen could not configure this local model. Refresh models and select it again.");
|
|
26716
|
+
return route.id;
|
|
26717
|
+
}
|
|
26718
|
+
if (routes.some((route) => route.id === model)) return model;
|
|
26719
|
+
const matches = routes.filter((route) => route.model === model);
|
|
26720
|
+
if (matches.length > 1) throw new Error("This Qwen model has multiple providers. Refresh models and select the intended provider again.");
|
|
26721
|
+
if (!matches.length) throw new Error("This Qwen model is no longer configured. Refresh models and select it again.");
|
|
26722
|
+
return matches[0].id;
|
|
26723
|
+
}
|
|
26724
|
+
var EMPTY, PROTOCOLS, support8, QwenAgentDriver;
|
|
26364
26725
|
var init_qwen = __esm({
|
|
26365
26726
|
"server/drivers/acp/qwen.ts"() {
|
|
26366
26727
|
"use strict";
|
|
26367
26728
|
init_local_inject();
|
|
26368
26729
|
init_core3();
|
|
26369
26730
|
EMPTY = { default: "", options: [] };
|
|
26731
|
+
PROTOCOLS = /* @__PURE__ */ new Set(["openai", "anthropic", "gemini", "vertex-ai"]);
|
|
26370
26732
|
support8 = {
|
|
26371
26733
|
driverKind: "qwenAgent",
|
|
26372
26734
|
displayName: "Qwen",
|
|
26373
26735
|
access: "custom",
|
|
26374
26736
|
models: EMPTY,
|
|
26375
26737
|
resolveModels: resolveModels2,
|
|
26376
|
-
resolveTurnModel:
|
|
26738
|
+
resolveTurnModel: resolveQwenTurnModel,
|
|
26377
26739
|
defaultCli: "qwen",
|
|
26378
26740
|
nativeSource: "qwen.acp",
|
|
26379
26741
|
loginNote: "Qwen Code CLI is not installed",
|
|
@@ -26385,7 +26747,10 @@ var init_qwen = __esm({
|
|
|
26385
26747
|
},
|
|
26386
26748
|
docsUrl: "https://qwenlm.github.io/qwen-code-docs/en/users/overview/"
|
|
26387
26749
|
},
|
|
26388
|
-
|
|
26750
|
+
// A raw -m only changes the model within the saved provider. ACP switches
|
|
26751
|
+
// the complete route and confirms it before any prompt leaves OMB.
|
|
26752
|
+
spawnArgs: () => ["--acp"],
|
|
26753
|
+
selectModel: { configId: "model" },
|
|
26389
26754
|
pickAuthMethod: () => null,
|
|
26390
26755
|
authFailure: "continue",
|
|
26391
26756
|
isAuthenticated: () => true,
|
|
@@ -33285,9 +33650,9 @@ var init_browser = __esm({
|
|
|
33285
33650
|
|
|
33286
33651
|
// server/drivers/acp/hermes.ts
|
|
33287
33652
|
import { spawn as spawn5 } from "node:child_process";
|
|
33288
|
-
import { mkdirSync as
|
|
33289
|
-
import { homedir as
|
|
33290
|
-
import { join as
|
|
33653
|
+
import { mkdirSync as mkdirSync11, readFileSync as readFileSync15, writeFileSync as writeFileSync11 } from "node:fs";
|
|
33654
|
+
import { homedir as homedir20 } from "node:os";
|
|
33655
|
+
import { join as join27 } from "node:path";
|
|
33291
33656
|
function bindHermesScreenshotCompat(env, modelId) {
|
|
33292
33657
|
delete env[HERMES_OPENMAUS_SCREENSHOT_COMPAT];
|
|
33293
33658
|
delete env[HERMES_OPENMAUS_SCREENSHOT_COMPAT_MODEL];
|
|
@@ -33297,7 +33662,7 @@ function bindHermesScreenshotCompat(env, modelId) {
|
|
|
33297
33662
|
env[HERMES_OPENMAUS_SCREENSHOT_COMPAT_MODEL] = inject.model;
|
|
33298
33663
|
}
|
|
33299
33664
|
function hermesHome(env) {
|
|
33300
|
-
return env.HERMES_HOME ||
|
|
33665
|
+
return env.HERMES_HOME || join27(env.HOME || env.USERPROFILE || homedir20(), ".hermes");
|
|
33301
33666
|
}
|
|
33302
33667
|
function quoteYaml(value) {
|
|
33303
33668
|
if (/^[\w./:+-]+$/.test(value)) return value;
|
|
@@ -33338,8 +33703,8 @@ function ensureHermesInjectProvider(modelId, env = process.env) {
|
|
|
33338
33703
|
const host = localHost(inject.host);
|
|
33339
33704
|
if (!host) return modelId;
|
|
33340
33705
|
const dir = hermesHome(env);
|
|
33341
|
-
|
|
33342
|
-
const path3 =
|
|
33706
|
+
mkdirSync11(dir, { recursive: true });
|
|
33707
|
+
const path3 = join27(dir, "config.yaml");
|
|
33343
33708
|
let text2 = "";
|
|
33344
33709
|
try {
|
|
33345
33710
|
text2 = readFileSync15(path3, "utf8");
|
|
@@ -33347,7 +33712,7 @@ function ensureHermesInjectProvider(modelId, env = process.env) {
|
|
|
33347
33712
|
text2 = "";
|
|
33348
33713
|
}
|
|
33349
33714
|
const next = upsertHermesProvider(text2, inject.host, host.baseUrl, hostApiKey(host, env));
|
|
33350
|
-
if (next !== text2)
|
|
33715
|
+
if (next !== text2) writeFileSync11(path3, next);
|
|
33351
33716
|
return hermesAcpModelId(modelId) ?? modelId;
|
|
33352
33717
|
}
|
|
33353
33718
|
function hermesAcpModelId(modelId) {
|
|
@@ -33410,13 +33775,13 @@ function hermesConfiguredModel(env = process.env) {
|
|
|
33410
33775
|
const dir = hermesHome(env);
|
|
33411
33776
|
let secrets = "";
|
|
33412
33777
|
try {
|
|
33413
|
-
secrets = readFileSync15(
|
|
33778
|
+
secrets = readFileSync15(join27(dir, ".env"), "utf8");
|
|
33414
33779
|
} catch {
|
|
33415
33780
|
}
|
|
33416
33781
|
const hasHostedProviderKey = HERMES_HOSTED_PROVIDER_KEYS.some((name) => nonEmptyDotenvValue(secrets, name));
|
|
33417
33782
|
let configuredDefault = null;
|
|
33418
33783
|
try {
|
|
33419
|
-
configuredDefault = hermesConfigDefault(readFileSync15(
|
|
33784
|
+
configuredDefault = hermesConfigDefault(readFileSync15(join27(dir, "config.yaml"), "utf8"));
|
|
33420
33785
|
} catch {
|
|
33421
33786
|
}
|
|
33422
33787
|
const configuredProvider = configuredDefault?.provider.toLowerCase() ?? "";
|
|
@@ -33432,12 +33797,12 @@ function hermesConfiguredModel(env = process.env) {
|
|
|
33432
33797
|
};
|
|
33433
33798
|
}
|
|
33434
33799
|
async function fetchHermesAcpModels(cli, env) {
|
|
33435
|
-
return await new Promise((
|
|
33800
|
+
return await new Promise((resolve13) => {
|
|
33436
33801
|
let child;
|
|
33437
33802
|
try {
|
|
33438
33803
|
child = spawn5(cli, ["acp"], { stdio: ["pipe", "pipe", "ignore"], env });
|
|
33439
33804
|
} catch {
|
|
33440
|
-
return
|
|
33805
|
+
return resolve13([]);
|
|
33441
33806
|
}
|
|
33442
33807
|
let settled = false;
|
|
33443
33808
|
let timer;
|
|
@@ -33458,7 +33823,7 @@ async function fetchHermesAcpModels(cli, env) {
|
|
|
33458
33823
|
}
|
|
33459
33824
|
} catch {
|
|
33460
33825
|
}
|
|
33461
|
-
|
|
33826
|
+
resolve13(out);
|
|
33462
33827
|
};
|
|
33463
33828
|
timer = setTimeout(() => done([]), 5e3);
|
|
33464
33829
|
child.once("error", () => done([]));
|
|
@@ -33501,7 +33866,7 @@ async function fetchHermesAcpModels(cli, env) {
|
|
|
33501
33866
|
}
|
|
33502
33867
|
if (msg?.id === initId) {
|
|
33503
33868
|
if (!msg.result) return done([]);
|
|
33504
|
-
sessionId = send("session/new", { cwd: env.HOME || env.USERPROFILE ||
|
|
33869
|
+
sessionId = send("session/new", { cwd: env.HOME || env.USERPROFILE || homedir20(), mcpServers: [] });
|
|
33505
33870
|
} else if (sessionId && msg?.id === sessionId) {
|
|
33506
33871
|
const list = Array.isArray(msg.result?.models?.availableModels) ? msg.result.models.availableModels : [];
|
|
33507
33872
|
done(
|
|
@@ -33736,9 +34101,9 @@ var init_openai_compat = __esm({
|
|
|
33736
34101
|
});
|
|
33737
34102
|
|
|
33738
34103
|
// server/drivers/pi.ts
|
|
33739
|
-
import { chmodSync as chmodSync5, existsSync as existsSync14, mkdirSync as
|
|
33740
|
-
import { homedir as
|
|
33741
|
-
import { join as
|
|
34104
|
+
import { chmodSync as chmodSync5, existsSync as existsSync14, mkdirSync as mkdirSync12, mkdtempSync as mkdtempSync3, readFileSync as readFileSync16, rmSync as rmSync3, writeFileSync as writeFileSync12 } from "node:fs";
|
|
34105
|
+
import { homedir as homedir21, tmpdir as tmpdir4 } from "node:os";
|
|
34106
|
+
import { join as join28 } from "node:path";
|
|
33742
34107
|
function readPiPromptImages(turn) {
|
|
33743
34108
|
return (turn.images ?? []).map((image) => ({
|
|
33744
34109
|
type: "image",
|
|
@@ -33845,7 +34210,7 @@ async function applyPiLocalCatalog(catalog, env = process.env, fetchImpl = fetch
|
|
|
33845
34210
|
return preferPiInjectRows(await mergeLocalInject(catalog, env, fetchImpl));
|
|
33846
34211
|
}
|
|
33847
34212
|
function piAgentDir(env) {
|
|
33848
|
-
return
|
|
34213
|
+
return join28(env.HOME || env.USERPROFILE || homedir21(), ".pi", "agent");
|
|
33849
34214
|
}
|
|
33850
34215
|
function ensurePiInjectModel(modelId, env = process.env) {
|
|
33851
34216
|
const split = splitPiModel(modelId);
|
|
@@ -33855,8 +34220,8 @@ function ensurePiInjectModel(modelId, env = process.env) {
|
|
|
33855
34220
|
const host = localHost(inject.host);
|
|
33856
34221
|
if (!host) return split;
|
|
33857
34222
|
const dir = piAgentDir(env);
|
|
33858
|
-
|
|
33859
|
-
const path3 =
|
|
34223
|
+
mkdirSync12(dir, { recursive: true });
|
|
34224
|
+
const path3 = join28(dir, "models.json");
|
|
33860
34225
|
let root = { providers: {} };
|
|
33861
34226
|
if (existsSync14(path3)) {
|
|
33862
34227
|
try {
|
|
@@ -33901,7 +34266,7 @@ function ensurePiInjectModel(modelId, env = process.env) {
|
|
|
33901
34266
|
existing.models = models;
|
|
33902
34267
|
providers[inject.host] = existing;
|
|
33903
34268
|
root.providers = providers;
|
|
33904
|
-
|
|
34269
|
+
writeFileSync12(path3, `${JSON.stringify(root, null, 2)}
|
|
33905
34270
|
`, { mode: 384 });
|
|
33906
34271
|
try {
|
|
33907
34272
|
chmodSync5(path3, 384);
|
|
@@ -33910,7 +34275,7 @@ function ensurePiInjectModel(modelId, env = process.env) {
|
|
|
33910
34275
|
return split;
|
|
33911
34276
|
}
|
|
33912
34277
|
function readPiDefaultModel(env) {
|
|
33913
|
-
const home = env.HOME || env.USERPROFILE ||
|
|
34278
|
+
const home = env.HOME || env.USERPROFILE || homedir21();
|
|
33914
34279
|
try {
|
|
33915
34280
|
const s = JSON.parse(readFileSync16(`${home}/.pi/agent/settings.json`, "utf8"));
|
|
33916
34281
|
return s.defaultProvider && s.defaultModel ? `${s.defaultProvider}/${s.defaultModel}` : "";
|
|
@@ -33920,7 +34285,7 @@ function readPiDefaultModel(env) {
|
|
|
33920
34285
|
}
|
|
33921
34286
|
async function fetchPiModels(cli, env) {
|
|
33922
34287
|
const child = spawnCli(cli, PI_ARGS, { stdio: ["pipe", "pipe", "pipe"], env });
|
|
33923
|
-
return new Promise((
|
|
34288
|
+
return new Promise((resolve13) => {
|
|
33924
34289
|
let buf = "";
|
|
33925
34290
|
let done = false;
|
|
33926
34291
|
const fallbackDefault = readPiDefaultModel(env);
|
|
@@ -33931,7 +34296,7 @@ async function fetchPiModels(cli, env) {
|
|
|
33931
34296
|
killCliTree(child);
|
|
33932
34297
|
} catch {
|
|
33933
34298
|
}
|
|
33934
|
-
|
|
34299
|
+
resolve13(catalog);
|
|
33935
34300
|
};
|
|
33936
34301
|
const timer = setTimeout(() => finish({ default: "", options: [] }), 15e3);
|
|
33937
34302
|
timer.unref?.();
|
|
@@ -34058,9 +34423,9 @@ var init_pi = __esm({
|
|
|
34058
34423
|
const mcpServers = buildMcpServers(turn);
|
|
34059
34424
|
let mcpTempDir = null;
|
|
34060
34425
|
if (mcpServers) {
|
|
34061
|
-
mcpTempDir = mkdtempSync3(
|
|
34426
|
+
mcpTempDir = mkdtempSync3(join28(tmpdir4(), "omb-pi-mcp-"));
|
|
34062
34427
|
try {
|
|
34063
|
-
|
|
34428
|
+
writeFileSync12(join28(mcpTempDir, "mcp.json"), JSON.stringify({ mcpServers }), { mode: 384 });
|
|
34064
34429
|
} catch (err) {
|
|
34065
34430
|
try {
|
|
34066
34431
|
rmSync3(mcpTempDir, { recursive: true, force: true });
|
|
@@ -34078,7 +34443,7 @@ var init_pi = __esm({
|
|
|
34078
34443
|
env: piEnvironment({
|
|
34079
34444
|
...process.env,
|
|
34080
34445
|
...input.environment,
|
|
34081
|
-
...mcpServers && mcpTempDir ? { OMB_MCP_CONFIG:
|
|
34446
|
+
...mcpServers && mcpTempDir ? { OMB_MCP_CONFIG: join28(mcpTempDir, "mcp.json") } : {}
|
|
34082
34447
|
})
|
|
34083
34448
|
});
|
|
34084
34449
|
} catch (err) {
|
|
@@ -34101,13 +34466,13 @@ var init_pi = __esm({
|
|
|
34101
34466
|
}
|
|
34102
34467
|
responseWaiters.clear();
|
|
34103
34468
|
};
|
|
34104
|
-
const awaitResponse = (command, timeoutMs = 2e4) => new Promise((
|
|
34469
|
+
const awaitResponse = (command, timeoutMs = 2e4) => new Promise((resolve13, reject) => {
|
|
34105
34470
|
const timer = setTimeout(() => {
|
|
34106
34471
|
responseWaiters.delete(command);
|
|
34107
34472
|
reject(new Error(`pi ${command} timed out`));
|
|
34108
34473
|
}, timeoutMs);
|
|
34109
34474
|
timer.unref?.();
|
|
34110
|
-
responseWaiters.set(command, { resolve:
|
|
34475
|
+
responseWaiters.set(command, { resolve: resolve13, reject, timer });
|
|
34111
34476
|
});
|
|
34112
34477
|
child.stdin.on("error", () => rejectWaiters(new Error("pi stdin closed")));
|
|
34113
34478
|
const send = (obj) => {
|
|
@@ -34315,7 +34680,7 @@ ${turn.text}` : turn.text;
|
|
|
34315
34680
|
return { turnId };
|
|
34316
34681
|
};
|
|
34317
34682
|
const snapshot = async () => {
|
|
34318
|
-
const version2 = await new Promise((
|
|
34683
|
+
const version2 = await new Promise((resolve13) => {
|
|
34319
34684
|
const child = spawnCli(config2.cli, ["--version"], {
|
|
34320
34685
|
stdio: ["ignore", "pipe", "pipe"],
|
|
34321
34686
|
env: piEnvironment({ ...process.env, ...input.environment })
|
|
@@ -34328,16 +34693,16 @@ ${turn.text}` : turn.text;
|
|
|
34328
34693
|
killCliTree(child);
|
|
34329
34694
|
} catch {
|
|
34330
34695
|
}
|
|
34331
|
-
|
|
34696
|
+
resolve13(null);
|
|
34332
34697
|
}, 8e3);
|
|
34333
34698
|
timer.unref?.();
|
|
34334
34699
|
child.on("error", () => {
|
|
34335
34700
|
clearTimeout(timer);
|
|
34336
|
-
|
|
34701
|
+
resolve13(null);
|
|
34337
34702
|
});
|
|
34338
34703
|
child.on("close", () => {
|
|
34339
34704
|
clearTimeout(timer);
|
|
34340
|
-
|
|
34705
|
+
resolve13(out.trim() || null);
|
|
34341
34706
|
});
|
|
34342
34707
|
});
|
|
34343
34708
|
if (!version2) return { state: "unavailable", reason: `\`${config2.cli}\` CLI not found` };
|
|
@@ -34416,15 +34781,15 @@ ${turn.text}` : turn.text;
|
|
|
34416
34781
|
|
|
34417
34782
|
// server/drivers/minimax.ts
|
|
34418
34783
|
import { readFileSync as readFileSync17 } from "node:fs";
|
|
34419
|
-
import { homedir as
|
|
34420
|
-
import { join as
|
|
34784
|
+
import { homedir as homedir22 } from "node:os";
|
|
34785
|
+
import { join as join29 } from "node:path";
|
|
34421
34786
|
function normalizedApiUrl(value) {
|
|
34422
34787
|
const root = value.trim().replace(/\/+$/, "");
|
|
34423
34788
|
return root.endsWith("/v1") ? root : `${root}/v1`;
|
|
34424
34789
|
}
|
|
34425
|
-
function loadLocalMiniMaxConfig(home =
|
|
34790
|
+
function loadLocalMiniMaxConfig(home = homedir22()) {
|
|
34426
34791
|
try {
|
|
34427
|
-
const raw = localConfigSchema.parse(JSON.parse(readFileSync17(
|
|
34792
|
+
const raw = localConfigSchema.parse(JSON.parse(readFileSync17(join29(home, ".mmx", "config.json"), "utf8")));
|
|
34428
34793
|
const configuredUrl = raw.base_url?.trim() ? raw.base_url : raw.region === "cn" ? CN_URL : DEFAULT_URL2;
|
|
34429
34794
|
return {
|
|
34430
34795
|
apiKey: raw.api_key?.trim() ?? "",
|
|
@@ -34692,7 +35057,7 @@ __export(cli_setup_exports, {
|
|
|
34692
35057
|
});
|
|
34693
35058
|
import { spawn as spawn6 } from "node:child_process";
|
|
34694
35059
|
import { readFileSync as readFileSync18 } from "node:fs";
|
|
34695
|
-
import { join as
|
|
35060
|
+
import { join as join30, resolve as resolve10 } from "node:path";
|
|
34696
35061
|
import { randomUUID as randomUUID10 } from "node:crypto";
|
|
34697
35062
|
async function inspect(id, entry) {
|
|
34698
35063
|
const registry2 = new ProviderRegistry(BUILT_IN_DRIVERS);
|
|
@@ -34725,11 +35090,11 @@ async function runSetupCli(cli, args, environment = {}) {
|
|
|
34725
35090
|
resetPathCache();
|
|
34726
35091
|
}
|
|
34727
35092
|
function assertDataDir(dataDir) {
|
|
34728
|
-
if (
|
|
35093
|
+
if (resolve10(dataDir) !== resolve10(DATA_DIR)) throw new Error("Setup data directory mismatch. Restart the CLI with --data-dir.");
|
|
34729
35094
|
}
|
|
34730
35095
|
function checkStoredConfig(dataDir) {
|
|
34731
35096
|
try {
|
|
34732
|
-
parseStoredConfig(JSON.parse(readFileSync18(
|
|
35097
|
+
parseStoredConfig(JSON.parse(readFileSync18(join30(dataDir, "config.json"), "utf8")));
|
|
34733
35098
|
} catch (error51) {
|
|
34734
35099
|
if (error51.code === "ENOENT") return;
|
|
34735
35100
|
throw new Error("Existing config.json could not be read or validated. Setup has not changed it; repair it before continuing.");
|
|
@@ -35007,7 +35372,7 @@ var init_browser_engine_release = __esm({
|
|
|
35007
35372
|
});
|
|
35008
35373
|
|
|
35009
35374
|
// server/browser-bundle-release.ts
|
|
35010
|
-
import { join as
|
|
35375
|
+
import { join as join31 } from "node:path";
|
|
35011
35376
|
function browserBundleSpec(target) {
|
|
35012
35377
|
if (!Object.hasOwn(CHROME_ASSETS, target)) throw new Error(`Unsupported desktop browser target: ${target}`);
|
|
35013
35378
|
const pinned = CHROME_ASSETS[target];
|
|
@@ -35043,10 +35408,10 @@ function browserBundlePaths(bundleDirectory, target) {
|
|
|
35043
35408
|
const spec = browserBundleSpec(target);
|
|
35044
35409
|
return {
|
|
35045
35410
|
directory: bundleDirectory,
|
|
35046
|
-
manifest:
|
|
35047
|
-
engine:
|
|
35048
|
-
chrome:
|
|
35049
|
-
licenses:
|
|
35411
|
+
manifest: join31(bundleDirectory, "manifest.json"),
|
|
35412
|
+
engine: join31(bundleDirectory, spec.engine.executable),
|
|
35413
|
+
chrome: join31(bundleDirectory, spec.chrome.executable),
|
|
35414
|
+
licenses: join31(bundleDirectory, "licenses")
|
|
35050
35415
|
};
|
|
35051
35416
|
}
|
|
35052
35417
|
var CHROME_VERSION, CHROME_ASSETS;
|
|
@@ -35100,29 +35465,29 @@ __export(browser_engine_exports, {
|
|
|
35100
35465
|
resolveAgentBrowserBinary: () => resolveAgentBrowserBinary
|
|
35101
35466
|
});
|
|
35102
35467
|
import { spawn as spawn7 } from "node:child_process";
|
|
35103
|
-
import { createHash as
|
|
35104
|
-
import { chmodSync as chmodSync6, constants as constants2, copyFileSync, existsSync as existsSync15, mkdirSync as
|
|
35105
|
-
import { homedir as
|
|
35106
|
-
import { delimiter as delimiter6, dirname as
|
|
35468
|
+
import { createHash as createHash8, randomBytes as randomBytes3, randomUUID as randomUUID11 } from "node:crypto";
|
|
35469
|
+
import { chmodSync as chmodSync6, constants as constants2, copyFileSync, existsSync as existsSync15, mkdirSync as mkdirSync13, readFileSync as readFileSync19, readdirSync as readdirSync3, renameSync as renameSync5, rmSync as rmSync4, statSync as statSync3, unlinkSync as unlinkSync4, writeFileSync as writeFileSync13 } from "node:fs";
|
|
35470
|
+
import { homedir as homedir23, tmpdir as tmpdir5 } from "node:os";
|
|
35471
|
+
import { delimiter as delimiter6, dirname as dirname10, join as join32, resolve as resolve11 } from "node:path";
|
|
35107
35472
|
function browserRestoreKey(session) {
|
|
35108
35473
|
if (!/^[A-Za-z0-9_-]{1,96}$/.test(session)) throw new Error("Invalid browser session.");
|
|
35109
|
-
return `omb-${
|
|
35474
|
+
return `omb-${createHash8("sha256").update(session).digest("hex")}`;
|
|
35110
35475
|
}
|
|
35111
35476
|
function browserSessionsDirectory(env) {
|
|
35112
35477
|
const namespace = env.AGENT_BROWSER_NAMESPACE;
|
|
35113
35478
|
if (namespace && !/^[a-z0-9]+(?:[-_][a-z0-9]+)*$/.test(namespace)) throw new Error("Invalid browser namespace.");
|
|
35114
|
-
const home = (process.platform === "win32" ? env.USERPROFILE : env.HOME) ||
|
|
35115
|
-
const stateRoot = namespace ?
|
|
35116
|
-
return
|
|
35479
|
+
const home = (process.platform === "win32" ? env.USERPROFILE : env.HOME) || homedir23();
|
|
35480
|
+
const stateRoot = namespace ? join32(home, ".agent-browser", "namespaces", namespace, "state") : join32(home, ".agent-browser");
|
|
35481
|
+
return join32(stateRoot, "sessions");
|
|
35117
35482
|
}
|
|
35118
35483
|
function managedBrowserConfigPath(env) {
|
|
35119
|
-
return
|
|
35484
|
+
return join32(browserSessionsDirectory(env), "..", "omb-managed-config.json");
|
|
35120
35485
|
}
|
|
35121
35486
|
function ensureManagedBrowserConfig(env) {
|
|
35122
35487
|
const path3 = managedBrowserConfigPath(env);
|
|
35123
|
-
|
|
35488
|
+
mkdirSync13(dirname10(path3), { recursive: true, mode: 448 });
|
|
35124
35489
|
try {
|
|
35125
|
-
|
|
35490
|
+
writeFileSync13(path3, "{}\n", { flag: "wx", mode: 384 });
|
|
35126
35491
|
} catch (error51) {
|
|
35127
35492
|
if (error51.code !== "EEXIST") throw error51;
|
|
35128
35493
|
if (readFileSync19(path3, "utf8").trim() !== "{}") throw new Error("The managed browser configuration was changed. Restore it to an empty JSON object before connecting.");
|
|
@@ -35189,7 +35554,7 @@ async function closeBrowserSession(binaryPath, env, timeoutMs = 15e3) {
|
|
|
35189
35554
|
} catch {
|
|
35190
35555
|
return false;
|
|
35191
35556
|
}
|
|
35192
|
-
await new Promise((
|
|
35557
|
+
await new Promise((resolve13) => setTimeout(resolve13, Math.min(25, Math.max(1, deadline - Date.now()))));
|
|
35193
35558
|
}
|
|
35194
35559
|
return false;
|
|
35195
35560
|
}
|
|
@@ -35203,11 +35568,11 @@ async function prepareBrowserSessionState(binaryPath, session, options = {}) {
|
|
|
35203
35568
|
ensureManagedBrowserConfig(env);
|
|
35204
35569
|
if (options.persistent === false) return;
|
|
35205
35570
|
const directory = browserSessionsDirectory(env);
|
|
35206
|
-
const key =
|
|
35571
|
+
const key = join32(directory, session);
|
|
35207
35572
|
let pending = preparedBrowserSessions.get(key);
|
|
35208
35573
|
if (!pending) {
|
|
35209
35574
|
pending = (async () => {
|
|
35210
|
-
const targetBase =
|
|
35575
|
+
const targetBase = join32(directory, `${restoreKey}-${session}`);
|
|
35211
35576
|
const hasTarget = () => existsSync15(`${targetBase}.json.enc`) || existsSync15(`${targetBase}.json`);
|
|
35212
35577
|
if (hasTarget()) return;
|
|
35213
35578
|
check2();
|
|
@@ -35217,7 +35582,7 @@ async function prepareBrowserSessionState(binaryPath, session, options = {}) {
|
|
|
35217
35582
|
check2();
|
|
35218
35583
|
if (hasTarget()) return;
|
|
35219
35584
|
const candidates = [".json.enc", ".json"].flatMap((suffix) => {
|
|
35220
|
-
const path3 =
|
|
35585
|
+
const path3 = join32(directory, `${session}-${session}${suffix}`);
|
|
35221
35586
|
try {
|
|
35222
35587
|
const stat4 = statSync3(path3);
|
|
35223
35588
|
if (!stat4.isFile()) throw new Error("Saved browser state is not a file.");
|
|
@@ -35252,14 +35617,14 @@ function isMusl(platform = process.platform, exists = existsSync15) {
|
|
|
35252
35617
|
}
|
|
35253
35618
|
function pinnedBinaryPath(dataDir = DATA_DIR, platform = process.platform, arch = process.arch) {
|
|
35254
35619
|
const version2 = agentBrowserReleaseVersion(resolveAgentBrowserReleaseAsset(platform, arch));
|
|
35255
|
-
return
|
|
35620
|
+
return join32(dataDir, ENGINE_DIR, version2, executableName(platform));
|
|
35256
35621
|
}
|
|
35257
35622
|
function onPath(env, platform, exists) {
|
|
35258
35623
|
const pathValue = platform === "win32" ? Object.entries(env).findLast(([key]) => key.toUpperCase() === "PATH")?.[1] : env.PATH;
|
|
35259
35624
|
for (const part of (pathValue ?? "").split(delimiter6)) {
|
|
35260
35625
|
const dir = part.trim().replace(/^"|"$/gu, "");
|
|
35261
35626
|
if (!dir) continue;
|
|
35262
|
-
const candidate =
|
|
35627
|
+
const candidate = resolve11(dir, executableName(platform));
|
|
35263
35628
|
if (exists(candidate)) return candidate;
|
|
35264
35629
|
}
|
|
35265
35630
|
return null;
|
|
@@ -35268,7 +35633,7 @@ function packagedBrowser(options) {
|
|
|
35268
35633
|
const resources = (options.env ?? process.env).OMB_RESOURCES_PATH;
|
|
35269
35634
|
if (!resources) return null;
|
|
35270
35635
|
try {
|
|
35271
|
-
return browserBundlePaths(
|
|
35636
|
+
return browserBundlePaths(join32(resolve11(resources), "browser-engine"), `${options.platform ?? process.platform}-${options.arch ?? process.arch}`);
|
|
35272
35637
|
} catch {
|
|
35273
35638
|
return null;
|
|
35274
35639
|
}
|
|
@@ -35281,7 +35646,7 @@ function resolveAgentBrowserBinary(options = {}) {
|
|
|
35281
35646
|
const platform = options.platform ?? process.platform;
|
|
35282
35647
|
const exists = options.exists ?? existsSync15;
|
|
35283
35648
|
const override = env.OMB_AGENT_BROWSER_PATH?.trim();
|
|
35284
|
-
if (override) return
|
|
35649
|
+
if (override) return resolve11(override) && exists(resolve11(override)) ? resolve11(override) : null;
|
|
35285
35650
|
const bundle = packagedBrowser(options);
|
|
35286
35651
|
if (bundle && exists(bundle.directory)) return completePackage(bundle, exists) ? bundle.engine : null;
|
|
35287
35652
|
const pinned = pinnedBinaryPath(options.dataDir, platform, options.arch);
|
|
@@ -35293,8 +35658,8 @@ async function installAgentBrowserBinary(options = {}) {
|
|
|
35293
35658
|
const asset = options.asset ?? resolveAgentBrowserReleaseAsset(platform, options.arch ?? process.arch, options.musl ?? isMusl(platform));
|
|
35294
35659
|
if (!asset) throw new Error(`agent-browser publishes no build for ${platform}-${options.arch ?? process.arch}.`);
|
|
35295
35660
|
const destination = pinnedBinaryPath(options.dataDir, platform, options.arch);
|
|
35296
|
-
const directory =
|
|
35297
|
-
|
|
35661
|
+
const directory = join32(destination, "..");
|
|
35662
|
+
mkdirSync13(directory, { recursive: true, mode: 448 });
|
|
35298
35663
|
const url2 = agentBrowserReleaseUrl(asset);
|
|
35299
35664
|
options.log?.(`downloading agent-browser ${agentBrowserReleaseVersion(asset)} (${Math.round(asset.bytes / 1024 / 1024)} MB, digest pinned)`);
|
|
35300
35665
|
const controller = new AbortController();
|
|
@@ -35309,17 +35674,17 @@ async function installAgentBrowserBinary(options = {}) {
|
|
|
35309
35674
|
clearTimeout(timer);
|
|
35310
35675
|
}
|
|
35311
35676
|
if (body.length !== asset.bytes) throw new Error("the agent-browser download did not match its pinned size; nothing was installed");
|
|
35312
|
-
const digest2 =
|
|
35677
|
+
const digest2 = createHash8("sha256").update(body).digest("hex");
|
|
35313
35678
|
if (digest2 !== asset.sha256) throw new Error("the agent-browser download failed its SHA-256 check; nothing was installed");
|
|
35314
35679
|
const staging = `${destination}.${randomBytes3(6).toString("hex")}.part`;
|
|
35315
|
-
|
|
35680
|
+
writeFileSync13(staging, body, { mode: 493 });
|
|
35316
35681
|
if (platform !== "win32") chmodSync6(staging, 493);
|
|
35317
35682
|
renameSync5(staging, destination);
|
|
35318
35683
|
return destination;
|
|
35319
35684
|
}
|
|
35320
35685
|
function ensureChrome(binaryPath, options = {}) {
|
|
35321
35686
|
const bundle = packagedBrowser(options);
|
|
35322
|
-
if (!options.withDeps && bundle &&
|
|
35687
|
+
if (!options.withDeps && bundle && resolve11(binaryPath) === bundle.engine && completePackage(bundle, existsSync15)) {
|
|
35323
35688
|
options.log?.("agent-browser: the bundled browser is ready; no download needed");
|
|
35324
35689
|
return Promise.resolve();
|
|
35325
35690
|
}
|
|
@@ -35345,14 +35710,14 @@ function ensureChrome(binaryPath, options = {}) {
|
|
|
35345
35710
|
});
|
|
35346
35711
|
}
|
|
35347
35712
|
function browserEngineEncryptionKey(dataDir = DATA_DIR) {
|
|
35348
|
-
const file2 =
|
|
35713
|
+
const file2 = join32(dataDir, KEY_FILE);
|
|
35349
35714
|
try {
|
|
35350
35715
|
const existing = readFileSync19(file2, "utf8").trim();
|
|
35351
35716
|
if (/^[0-9a-f]{64}$/u.test(existing)) return existing;
|
|
35352
35717
|
} catch {
|
|
35353
35718
|
}
|
|
35354
35719
|
const key = randomBytes3(32).toString("hex");
|
|
35355
|
-
|
|
35720
|
+
mkdirSync13(dataDir, { recursive: true });
|
|
35356
35721
|
writeFileAtomic(file2, `${key}
|
|
35357
35722
|
`, { mode: 384 });
|
|
35358
35723
|
return key;
|
|
@@ -35399,13 +35764,13 @@ function agentBrowserIntegration(input) {
|
|
|
35399
35764
|
if (sourceEnv[name]) env[name] = sourceEnv[name];
|
|
35400
35765
|
}
|
|
35401
35766
|
const bundle = packagedBrowser({ env: sourceEnv });
|
|
35402
|
-
if (!env.AGENT_BROWSER_EXECUTABLE_PATH && bundle &&
|
|
35767
|
+
if (!env.AGENT_BROWSER_EXECUTABLE_PATH && bundle && resolve11(input.binaryPath) === bundle.engine && completePackage(bundle, existsSync15)) {
|
|
35403
35768
|
env.AGENT_BROWSER_EXECUTABLE_PATH = bundle.chrome;
|
|
35404
35769
|
}
|
|
35405
35770
|
return { command: input.binaryPath, args: ["mcp", "--tools", "core", "--no-webmcp"], env };
|
|
35406
35771
|
}
|
|
35407
35772
|
function agentBrowserFrame(input) {
|
|
35408
|
-
const file2 =
|
|
35773
|
+
const file2 = join32(tmpdir5(), `openmausbot-browser-${randomUUID11()}.png`);
|
|
35409
35774
|
return new Promise((settle, fail) => {
|
|
35410
35775
|
const child = spawn7(input.binaryPath, ["screenshot", file2], {
|
|
35411
35776
|
env: browserRuntimeEnv(input.env),
|
|
@@ -35475,8 +35840,8 @@ async function clearBrowserSessionState(binaryPath, session, options = {}) {
|
|
|
35475
35840
|
}
|
|
35476
35841
|
};
|
|
35477
35842
|
try {
|
|
35478
|
-
for (const base2 of bases) for (const suffix of [".json", ".json.enc", ".json.previous", ".json.enc.previous"]) remove(
|
|
35479
|
-
const pendingDirectory =
|
|
35843
|
+
for (const base2 of bases) for (const suffix of [".json", ".json.enc", ".json.previous", ".json.enc.previous"]) remove(join32(directory, base2 + suffix));
|
|
35844
|
+
const pendingDirectory = join32(directory, ".tmp");
|
|
35480
35845
|
let pendingFiles = [];
|
|
35481
35846
|
try {
|
|
35482
35847
|
pendingFiles = readdirSync3(pendingDirectory);
|
|
@@ -35484,8 +35849,8 @@ async function clearBrowserSessionState(binaryPath, session, options = {}) {
|
|
|
35484
35849
|
if (error51.code !== "ENOENT") throw error51;
|
|
35485
35850
|
}
|
|
35486
35851
|
const candidates = bases.map((base2) => new RegExp(`^${base2}-candidate-[0-9]+\\.json(?:\\.enc)?$`));
|
|
35487
|
-
for (const name of pendingFiles) if (candidates.some((candidate) => candidate.test(name))) remove(
|
|
35488
|
-
preparedBrowserSessions.delete(
|
|
35852
|
+
for (const name of pendingFiles) if (candidates.some((candidate) => candidate.test(name))) remove(join32(pendingDirectory, name));
|
|
35853
|
+
preparedBrowserSessions.delete(join32(directory, session));
|
|
35489
35854
|
return true;
|
|
35490
35855
|
} catch {
|
|
35491
35856
|
return false;
|
|
@@ -35512,9 +35877,9 @@ var init_browser_engine = __esm({
|
|
|
35512
35877
|
// server/cli.ts
|
|
35513
35878
|
var import_qrcode_terminal = __toESM(require_main(), 1);
|
|
35514
35879
|
import { spawn as spawn8 } from "node:child_process";
|
|
35515
|
-
import { closeSync as closeSync3, existsSync as existsSync16, mkdirSync as
|
|
35516
|
-
import { homedir as
|
|
35517
|
-
import { dirname as
|
|
35880
|
+
import { closeSync as closeSync3, existsSync as existsSync16, mkdirSync as mkdirSync14, openSync as openSync3, readFileSync as readFileSync20 } from "node:fs";
|
|
35881
|
+
import { homedir as homedir24 } from "node:os";
|
|
35882
|
+
import { dirname as dirname11, join as join33, resolve as resolve12 } from "node:path";
|
|
35518
35883
|
import { createInterface as createInterface2 } from "node:readline/promises";
|
|
35519
35884
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
35520
35885
|
|
|
@@ -36112,13 +36477,13 @@ function writePrivateToken(runtimeRoot2, token, { fileSystem, processId, identif
|
|
|
36112
36477
|
}
|
|
36113
36478
|
async function waitForExit(child, milliseconds) {
|
|
36114
36479
|
if (child.exitCode !== null || child.signalCode !== null) return;
|
|
36115
|
-
await new Promise((
|
|
36480
|
+
await new Promise((resolve13) => {
|
|
36116
36481
|
let settled = false;
|
|
36117
36482
|
const finish = () => {
|
|
36118
36483
|
if (settled) return;
|
|
36119
36484
|
settled = true;
|
|
36120
36485
|
clearTimeout(timer);
|
|
36121
|
-
|
|
36486
|
+
resolve13();
|
|
36122
36487
|
};
|
|
36123
36488
|
child.once("exit", finish);
|
|
36124
36489
|
const timer = setTimeout(finish, milliseconds);
|
|
@@ -36282,8 +36647,8 @@ function createManagedCompanionTunnel({
|
|
|
36282
36647
|
child = spawned;
|
|
36283
36648
|
const cancellationController = new AbortController();
|
|
36284
36649
|
let resolveCancellation;
|
|
36285
|
-
const cancellation = new Promise((
|
|
36286
|
-
resolveCancellation =
|
|
36650
|
+
const cancellation = new Promise((resolve13) => {
|
|
36651
|
+
resolveCancellation = resolve13;
|
|
36287
36652
|
});
|
|
36288
36653
|
let cancelled = false;
|
|
36289
36654
|
attemptHandle = {
|
|
@@ -36299,8 +36664,8 @@ function createManagedCompanionTunnel({
|
|
|
36299
36664
|
let terminated = false;
|
|
36300
36665
|
let expectedStop = false;
|
|
36301
36666
|
let resolveExit;
|
|
36302
|
-
const exit = new Promise((
|
|
36303
|
-
resolveExit =
|
|
36667
|
+
const exit = new Promise((resolve13) => {
|
|
36668
|
+
resolveExit = resolve13;
|
|
36304
36669
|
});
|
|
36305
36670
|
const onTerminated = () => {
|
|
36306
36671
|
if (terminated) return;
|
|
@@ -36334,8 +36699,8 @@ function createManagedCompanionTunnel({
|
|
|
36334
36699
|
}
|
|
36335
36700
|
if (Date.now() >= deadline) break;
|
|
36336
36701
|
await Promise.race([
|
|
36337
|
-
new Promise((
|
|
36338
|
-
const timer = setTimeout(
|
|
36702
|
+
new Promise((resolve13) => {
|
|
36703
|
+
const timer = setTimeout(resolve13, verifyIntervalMs);
|
|
36339
36704
|
timer.unref?.();
|
|
36340
36705
|
}),
|
|
36341
36706
|
exit,
|
|
@@ -37111,16 +37476,190 @@ function normalizeDomainOption(raw) {
|
|
|
37111
37476
|
return value;
|
|
37112
37477
|
}
|
|
37113
37478
|
|
|
37479
|
+
// server/service-cli.ts
|
|
37480
|
+
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "node:fs";
|
|
37481
|
+
import { homedir as homedir2 } from "node:os";
|
|
37482
|
+
|
|
37483
|
+
// server/service-unit.ts
|
|
37484
|
+
import { homedir, userInfo } from "node:os";
|
|
37485
|
+
import { posix } from "node:path";
|
|
37486
|
+
var { basename, dirname, join: join2 } = posix;
|
|
37487
|
+
var SYSTEMD_UNIT_NAME = "openmausbot.service";
|
|
37488
|
+
var LAUNCHD_LABEL = "com.openmausbot.serve";
|
|
37489
|
+
function quoteSystemd(value) {
|
|
37490
|
+
return /[\s"\\]/.test(value) ? `"${value.replace(/[\\"]/g, "\\$&")}"` : value;
|
|
37491
|
+
}
|
|
37492
|
+
function needsStripTypes(script) {
|
|
37493
|
+
return script.endsWith(".ts");
|
|
37494
|
+
}
|
|
37495
|
+
function serviceCommand(spec) {
|
|
37496
|
+
return [spec.node, ...needsStripTypes(spec.script) ? ["--experimental-strip-types"] : [], spec.script, "serve", ...spec.serveArgs];
|
|
37497
|
+
}
|
|
37498
|
+
function systemdUnit(spec) {
|
|
37499
|
+
const lines = [
|
|
37500
|
+
"# Written by `openmausbot service install`. Re-run it to change the options.",
|
|
37501
|
+
"[Unit]",
|
|
37502
|
+
`Description=OpenMausBot${spec.label ? ` (${spec.label})` : ""}`,
|
|
37503
|
+
"After=network-online.target",
|
|
37504
|
+
"Wants=network-online.target",
|
|
37505
|
+
"",
|
|
37506
|
+
"[Service]",
|
|
37507
|
+
"Type=simple",
|
|
37508
|
+
`User=${spec.user}`,
|
|
37509
|
+
`WorkingDirectory=${spec.home}`,
|
|
37510
|
+
`Environment=HOME=${spec.home}`,
|
|
37511
|
+
`Environment=OMB_DATA_DIR=${spec.dataDir}`,
|
|
37512
|
+
`ExecStart=${serviceCommand(spec).map(quoteSystemd).join(" ")}`,
|
|
37513
|
+
"Restart=always",
|
|
37514
|
+
"RestartSec=3",
|
|
37515
|
+
"KillMode=mixed",
|
|
37516
|
+
"TimeoutStopSec=30"
|
|
37517
|
+
];
|
|
37518
|
+
if (spec.bindsLowPorts) {
|
|
37519
|
+
lines.push("# serve --domain: Caddy binds ports 80 and 443 without running as root.");
|
|
37520
|
+
lines.push("AmbientCapabilities=CAP_NET_BIND_SERVICE");
|
|
37521
|
+
lines.push("CapabilityBoundingSet=CAP_NET_BIND_SERVICE");
|
|
37522
|
+
}
|
|
37523
|
+
lines.push("", "[Install]", "WantedBy=multi-user.target", "");
|
|
37524
|
+
return lines.join("\n");
|
|
37525
|
+
}
|
|
37526
|
+
function xml(value) {
|
|
37527
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
37528
|
+
}
|
|
37529
|
+
function launchdPlist(spec) {
|
|
37530
|
+
const args = serviceCommand(spec).map((arg) => ` <string>${xml(arg)}</string>`).join("\n");
|
|
37531
|
+
return [
|
|
37532
|
+
'<?xml version="1.0" encoding="UTF-8"?>',
|
|
37533
|
+
'<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">',
|
|
37534
|
+
'<plist version="1.0">',
|
|
37535
|
+
"<dict>",
|
|
37536
|
+
" <key>Label</key>",
|
|
37537
|
+
` <string>${LAUNCHD_LABEL}</string>`,
|
|
37538
|
+
" <key>ProgramArguments</key>",
|
|
37539
|
+
" <array>",
|
|
37540
|
+
args,
|
|
37541
|
+
" </array>",
|
|
37542
|
+
" <key>EnvironmentVariables</key>",
|
|
37543
|
+
" <dict>",
|
|
37544
|
+
" <key>HOME</key>",
|
|
37545
|
+
` <string>${xml(spec.home)}</string>`,
|
|
37546
|
+
" <key>OMB_DATA_DIR</key>",
|
|
37547
|
+
` <string>${xml(spec.dataDir)}</string>`,
|
|
37548
|
+
" <key>PATH</key>",
|
|
37549
|
+
" <string>/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin</string>",
|
|
37550
|
+
" </dict>",
|
|
37551
|
+
" <key>WorkingDirectory</key>",
|
|
37552
|
+
` <string>${xml(spec.home)}</string>`,
|
|
37553
|
+
" <key>RunAtLoad</key>",
|
|
37554
|
+
" <true/>",
|
|
37555
|
+
" <key>KeepAlive</key>",
|
|
37556
|
+
" <true/>",
|
|
37557
|
+
" <key>StandardOutPath</key>",
|
|
37558
|
+
` <string>${xml(join2(spec.dataDir, "logs", "service.log"))}</string>`,
|
|
37559
|
+
" <key>StandardErrorPath</key>",
|
|
37560
|
+
` <string>${xml(join2(spec.dataDir, "logs", "service.log"))}</string>`,
|
|
37561
|
+
"</dict>",
|
|
37562
|
+
"</plist>",
|
|
37563
|
+
""
|
|
37564
|
+
].join("\n");
|
|
37565
|
+
}
|
|
37566
|
+
function unstableInstallWarning(script) {
|
|
37567
|
+
const normalized = script.replace(/\\/g, "/");
|
|
37568
|
+
if (/\/_npx\//.test(normalized) || /\/\.npm\/_npx\//.test(normalized)) {
|
|
37569
|
+
return `this command runs from an npx cache (${dirname(script)}), which npm may delete at any time. Install it permanently first (npm install -g openmausbot) and run \`openmausbot service install\` from that install.`;
|
|
37570
|
+
}
|
|
37571
|
+
return null;
|
|
37572
|
+
}
|
|
37573
|
+
function servicePlan(platform, dataDir, home = homedir()) {
|
|
37574
|
+
if (platform === "linux") {
|
|
37575
|
+
const installed = `/etc/systemd/system/${SYSTEMD_UNIT_NAME}`;
|
|
37576
|
+
return {
|
|
37577
|
+
file: join2(dataDir, SYSTEMD_UNIT_NAME),
|
|
37578
|
+
installed,
|
|
37579
|
+
activate: [`sudo install -m 644 ${join2(dataDir, SYSTEMD_UNIT_NAME)} ${installed}`, "sudo systemctl daemon-reload", `sudo systemctl enable --now ${basename(SYSTEMD_UNIT_NAME, ".service")}`],
|
|
37580
|
+
deactivate: [`sudo systemctl disable --now ${basename(SYSTEMD_UNIT_NAME, ".service")}`, `sudo rm ${installed}`, "sudo systemctl daemon-reload"]
|
|
37581
|
+
};
|
|
37582
|
+
}
|
|
37583
|
+
if (platform === "darwin") {
|
|
37584
|
+
const installed = join2(home, "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
|
|
37585
|
+
return {
|
|
37586
|
+
file: join2(dataDir, `${LAUNCHD_LABEL}.plist`),
|
|
37587
|
+
installed,
|
|
37588
|
+
activate: [`mkdir -p ${dirname(installed)} && cp ${join2(dataDir, `${LAUNCHD_LABEL}.plist`)} ${installed}`, `launchctl bootstrap gui/$(id -u) ${installed}`],
|
|
37589
|
+
deactivate: [`launchctl bootout gui/$(id -u)/${LAUNCHD_LABEL}`, `rm ${installed}`]
|
|
37590
|
+
};
|
|
37591
|
+
}
|
|
37592
|
+
return null;
|
|
37593
|
+
}
|
|
37594
|
+
function currentUser() {
|
|
37595
|
+
try {
|
|
37596
|
+
return userInfo().username;
|
|
37597
|
+
} catch {
|
|
37598
|
+
return process.env.USER || process.env.USERNAME || "openmausbot";
|
|
37599
|
+
}
|
|
37600
|
+
}
|
|
37601
|
+
|
|
37602
|
+
// server/service-cli.ts
|
|
37603
|
+
function serviceServeArgs(input) {
|
|
37604
|
+
const args = ["--port", String(input.port), "--data-dir", input.dataDir, "--no-pair"];
|
|
37605
|
+
if (input.domain) args.push("--domain", input.domain);
|
|
37606
|
+
else if (input.tunnel) args.push("--tunnel");
|
|
37607
|
+
else if (input.tailscale) args.push("--tailscale");
|
|
37608
|
+
if (input.label) args.push("--label", input.label);
|
|
37609
|
+
return args;
|
|
37610
|
+
}
|
|
37611
|
+
function runServiceCommand(input, io) {
|
|
37612
|
+
const platform = input.platform ?? process.platform;
|
|
37613
|
+
const home = input.home ?? homedir2();
|
|
37614
|
+
const plan = servicePlan(platform, input.dataDir, home);
|
|
37615
|
+
if (!plan) {
|
|
37616
|
+
io.error("services are written for Linux (systemd) and macOS (launchd); on Windows, use Task Scheduler to run `openmausbot serve` at startup");
|
|
37617
|
+
return 1;
|
|
37618
|
+
}
|
|
37619
|
+
if (input.action === "uninstall") {
|
|
37620
|
+
io.log(`to stop and remove the service:`);
|
|
37621
|
+
for (const line of plan.deactivate) io.log(` ${line}`);
|
|
37622
|
+
return 0;
|
|
37623
|
+
}
|
|
37624
|
+
const warning = unstableInstallWarning(input.script);
|
|
37625
|
+
if (warning) {
|
|
37626
|
+
io.error(warning);
|
|
37627
|
+
return 1;
|
|
37628
|
+
}
|
|
37629
|
+
const spec = {
|
|
37630
|
+
node: input.node,
|
|
37631
|
+
script: input.script,
|
|
37632
|
+
serveArgs: serviceServeArgs(input),
|
|
37633
|
+
dataDir: input.dataDir,
|
|
37634
|
+
user: input.user ?? currentUser(),
|
|
37635
|
+
home,
|
|
37636
|
+
bindsLowPorts: Boolean(input.domain),
|
|
37637
|
+
...input.label ? { label: input.label } : {}
|
|
37638
|
+
};
|
|
37639
|
+
const rendered = platform === "darwin" ? launchdPlist(spec) : systemdUnit(spec);
|
|
37640
|
+
mkdirSync2(input.dataDir, { recursive: true, mode: 448 });
|
|
37641
|
+
writeFileSync3(plan.file, rendered, { mode: 420 });
|
|
37642
|
+
io.log(`wrote ${plan.file}`);
|
|
37643
|
+
io.log("");
|
|
37644
|
+
io.log(platform === "darwin" ? "to install and start it (runs at login):" : "to install and start it (runs at boot, restarts if it stops):");
|
|
37645
|
+
for (const line of plan.activate) io.log(` ${line}`);
|
|
37646
|
+
io.log("");
|
|
37647
|
+
if (input.domain && platform === "linux") io.log("the unit grants Caddy the capability for ports 80 and 443, so no setcap is needed under the service");
|
|
37648
|
+
io.log(`logs: ${platform === "darwin" ? `${input.dataDir}/logs/service.log` : "journalctl -u openmausbot -f"}`);
|
|
37649
|
+
io.log(`change options later by running \`openmausbot service install\` again with the new ones, then: ${platform === "darwin" ? plan.activate[1] : "sudo systemctl daemon-reload && sudo systemctl restart openmausbot"}`);
|
|
37650
|
+
return 0;
|
|
37651
|
+
}
|
|
37652
|
+
|
|
37114
37653
|
// server/tailscale.ts
|
|
37115
37654
|
import { execFile } from "node:child_process";
|
|
37116
37655
|
|
|
37117
37656
|
// companion/src/listener.ts
|
|
37118
|
-
import { homedir, networkInterfaces } from "node:os";
|
|
37119
|
-
import { delimiter as delimiter2, join as
|
|
37120
|
-
function tailscaleCandidates(home =
|
|
37657
|
+
import { homedir as homedir3, networkInterfaces } from "node:os";
|
|
37658
|
+
import { delimiter as delimiter2, join as join3 } from "node:path";
|
|
37659
|
+
function tailscaleCandidates(home = homedir3()) {
|
|
37121
37660
|
return [
|
|
37122
37661
|
"/Applications/Tailscale.app/Contents/MacOS/Tailscale",
|
|
37123
|
-
|
|
37662
|
+
join3(home, "Applications", "Tailscale.app", "Contents", "MacOS", "Tailscale"),
|
|
37124
37663
|
"/opt/homebrew/bin/tailscale",
|
|
37125
37664
|
"/usr/local/bin/tailscale",
|
|
37126
37665
|
"/usr/bin/tailscale",
|
|
@@ -37161,14 +37700,14 @@ function explainTailscaleFailure(reason) {
|
|
|
37161
37700
|
}
|
|
37162
37701
|
}
|
|
37163
37702
|
function run(cli, args, timeoutMs) {
|
|
37164
|
-
return new Promise((
|
|
37703
|
+
return new Promise((resolve13) => {
|
|
37165
37704
|
execFile(
|
|
37166
37705
|
cli,
|
|
37167
37706
|
args,
|
|
37168
37707
|
{ timeout: timeoutMs, killSignal: "SIGKILL", maxBuffer: 16 * 1024 * 1024, env: { ...process.env, PATH: searchPath() } },
|
|
37169
37708
|
(error51, stdout2, stderr) => {
|
|
37170
37709
|
const code = error51 && "code" in error51 && typeof error51.code === "number" ? error51.code : error51 ? null : 0;
|
|
37171
|
-
|
|
37710
|
+
resolve13({ ok: !error51, stdout: String(stdout2 ?? ""), stderr: String(stderr ?? ""), code });
|
|
37172
37711
|
}
|
|
37173
37712
|
);
|
|
37174
37713
|
});
|
|
@@ -37333,9 +37872,9 @@ function phonePairingInstructions(phone, input) {
|
|
|
37333
37872
|
// server/tunnel.ts
|
|
37334
37873
|
import { spawn as spawn3 } from "node:child_process";
|
|
37335
37874
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
37336
|
-
import { chmodSync as chmodSync2, existsSync as existsSync2, mkdirSync as
|
|
37875
|
+
import { chmodSync as chmodSync2, existsSync as existsSync2, mkdirSync as mkdirSync3, readFileSync, statSync } from "node:fs";
|
|
37337
37876
|
import { hostname } from "node:os";
|
|
37338
|
-
import { dirname, join as
|
|
37877
|
+
import { dirname as dirname2, join as join4, resolve as resolve2 } from "node:path";
|
|
37339
37878
|
import { fileURLToPath } from "node:url";
|
|
37340
37879
|
|
|
37341
37880
|
// electron/secure-credential-state.mjs
|
|
@@ -37408,7 +37947,7 @@ function createSecureCredentialState(initialCredentials, persist, { writable = t
|
|
|
37408
37947
|
|
|
37409
37948
|
// server/tunnel.ts
|
|
37410
37949
|
init_atomic();
|
|
37411
|
-
var HERE =
|
|
37950
|
+
var HERE = dirname2(fileURLToPath(import.meta.url));
|
|
37412
37951
|
var TUNNEL_CREDENTIALS_FILE = "tunnel-account.json";
|
|
37413
37952
|
var TUNNEL_RUNTIME_DIR = "tunnel-runtime";
|
|
37414
37953
|
function plainDocument(value) {
|
|
@@ -37418,7 +37957,7 @@ function plainDocument(value) {
|
|
|
37418
37957
|
return document;
|
|
37419
37958
|
}
|
|
37420
37959
|
function openTunnelCredentials(dataDir) {
|
|
37421
|
-
const file2 =
|
|
37960
|
+
const file2 = join4(dataDir, TUNNEL_CREDENTIALS_FILE);
|
|
37422
37961
|
let initial = {};
|
|
37423
37962
|
let status = "empty";
|
|
37424
37963
|
if (existsSync2(file2)) {
|
|
@@ -37433,7 +37972,7 @@ function openTunnelCredentials(dataDir) {
|
|
|
37433
37972
|
}
|
|
37434
37973
|
}
|
|
37435
37974
|
const persist = (next) => {
|
|
37436
|
-
|
|
37975
|
+
mkdirSync3(dataDir, { recursive: true, mode: 448 });
|
|
37437
37976
|
writeFileAtomic(file2, `${JSON.stringify(next, null, 2)}
|
|
37438
37977
|
`, { mode: 384 });
|
|
37439
37978
|
};
|
|
@@ -37500,11 +38039,11 @@ function cloudflaredPath(dataDir, env = process.env) {
|
|
|
37500
38039
|
return resolveCloudflaredBinary({ isPackaged: false, appPath: dataDir, environment: env });
|
|
37501
38040
|
}
|
|
37502
38041
|
function prepareEntry(here = HERE) {
|
|
37503
|
-
const bundled =
|
|
38042
|
+
const bundled = join4(here, "prepare-cloudflared.js");
|
|
37504
38043
|
return existsSync2(bundled) ? bundled : resolve2(here, "..", "scripts", "prepare-cloudflared.mjs");
|
|
37505
38044
|
}
|
|
37506
38045
|
function guardianEntry(here = HERE) {
|
|
37507
|
-
const bundled =
|
|
38046
|
+
const bundled = join4(here, "tunnel-guardian.js");
|
|
37508
38047
|
if (existsSync2(bundled)) return bundled;
|
|
37509
38048
|
const source = resolve2(here, "..", "electron", "managed-companion-guardian-main.mjs");
|
|
37510
38049
|
return existsSync2(source) ? source : null;
|
|
@@ -37539,7 +38078,7 @@ function startTunnel(options) {
|
|
|
37539
38078
|
const tunnel = createManagedCompanionTunnel({
|
|
37540
38079
|
binaryPath: options.binaryPath,
|
|
37541
38080
|
guardianEntry: options.guardian,
|
|
37542
|
-
runtimeRoot:
|
|
38081
|
+
runtimeRoot: join4(options.dataDir, TUNNEL_RUNTIME_DIR),
|
|
37543
38082
|
originPort,
|
|
37544
38083
|
environment: env,
|
|
37545
38084
|
fetchImpl: options.fetchImpl,
|
|
@@ -37574,8 +38113,8 @@ function describeTunnelState(state, address) {
|
|
|
37574
38113
|
}
|
|
37575
38114
|
|
|
37576
38115
|
// server/cli.ts
|
|
37577
|
-
var HERE2 =
|
|
37578
|
-
var COMMANDS = ["setup", "start", "serve", "pair", "sessions", "status", "login", "logout", "access", "browser", "help", "--help", "-h"];
|
|
38116
|
+
var HERE2 = dirname11(fileURLToPath3(import.meta.url));
|
|
38117
|
+
var COMMANDS = ["setup", "start", "serve", "pair", "sessions", "status", "login", "logout", "access", "service", "browser", "help", "--help", "-h"];
|
|
37579
38118
|
function parseArgs(argv, env = process.env) {
|
|
37580
38119
|
const implicitStart = !argv.length || argv[0].startsWith("--") && argv[0] !== "--help";
|
|
37581
38120
|
const [command = "start", ...rest] = implicitStart ? ["start", ...argv] : argv;
|
|
@@ -37585,7 +38124,7 @@ function parseArgs(argv, env = process.env) {
|
|
|
37585
38124
|
const options = {
|
|
37586
38125
|
command: command === "--help" || command === "-h" ? "help" : command,
|
|
37587
38126
|
port: Number(env.OMB_PORT || 8799),
|
|
37588
|
-
dataDir: env.OMB_DATA_DIR ||
|
|
38127
|
+
dataDir: env.OMB_DATA_DIR || join33(homedir24(), ".openmausbot"),
|
|
37589
38128
|
tailscale: false,
|
|
37590
38129
|
tunnel: false,
|
|
37591
38130
|
client: false,
|
|
@@ -37604,7 +38143,7 @@ function parseArgs(argv, env = process.env) {
|
|
|
37604
38143
|
};
|
|
37605
38144
|
try {
|
|
37606
38145
|
if (arg === "--port") options.port = Number(value());
|
|
37607
|
-
else if (arg === "--data-dir") options.dataDir =
|
|
38146
|
+
else if (arg === "--data-dir") options.dataDir = resolve12(value());
|
|
37608
38147
|
else if (arg === "--label") options.label = value();
|
|
37609
38148
|
else if (arg === "--public-url") options.publicUrl = value().replace(/\/+$/, "");
|
|
37610
38149
|
else if (arg === "--tailscale") options.tailscale = true;
|
|
@@ -37624,6 +38163,7 @@ function parseArgs(argv, env = process.env) {
|
|
|
37624
38163
|
options.accessAction = arg;
|
|
37625
38164
|
if (arg !== "list") options.email = value();
|
|
37626
38165
|
} else if (options.command === "access" && arg === "--chat-only") options.chatOnly = true;
|
|
38166
|
+
else if (options.command === "service" && !options.serviceAction && (arg === "install" || arg === "uninstall")) options.serviceAction = arg;
|
|
37627
38167
|
else if (options.command === "browser" && (arg === "install" || arg === "status")) options.browserAction = arg;
|
|
37628
38168
|
else if (options.command === "browser" && arg === "--with-deps") options.withDeps = true;
|
|
37629
38169
|
else return { error: `unknown argument "${arg}"` };
|
|
@@ -37635,6 +38175,7 @@ function parseArgs(argv, env = process.env) {
|
|
|
37635
38175
|
if (options.publicUrl && !/^https?:\/\//.test(options.publicUrl)) return { error: "--public-url must start with http:// or https://" };
|
|
37636
38176
|
if (options.tailscale && options.tunnel) return { error: "choose one of --tailscale (your tailnet) and --tunnel (a public address)" };
|
|
37637
38177
|
if (options.command === "access" && !options.accessAction) return { error: "access needs one of: list, add EMAIL [--chat-only], remove EMAIL" };
|
|
38178
|
+
if (options.command === "service" && !options.serviceAction) return { error: "service needs one of: install [the same options as serve], uninstall" };
|
|
37638
38179
|
if (options.domain && (options.tailscale || options.tunnel || options.publicUrl)) return { error: "--domain already gives the server its address; drop --tailscale, --tunnel and --public-url" };
|
|
37639
38180
|
if (options.local && (options.tailscale || options.tunnel || options.publicUrl)) return { error: "--local cannot be combined with a remote-access option" };
|
|
37640
38181
|
if (options.command === "browser" && !options.browserAction) return { error: "browser needs an action: install or status" };
|
|
@@ -37653,6 +38194,7 @@ var USAGE = `openmausbot \u2014 your team of AI bots, ready in a few steps
|
|
|
37653
38194
|
openmausbot login [--email you@example.com]
|
|
37654
38195
|
openmausbot logout
|
|
37655
38196
|
openmausbot access list | add EMAIL [--chat-only] | remove EMAIL
|
|
38197
|
+
openmausbot service install [--domain HOST | --tunnel | --tailscale] [--port N] [--data-dir DIR] | uninstall
|
|
37656
38198
|
openmausbot browser install [--with-deps] | status
|
|
37657
38199
|
|
|
37658
38200
|
setup choose AI access and optional phone access; keep existing bots and chats
|
|
@@ -37667,6 +38209,10 @@ logout releases that address and signs out
|
|
|
37667
38209
|
access who may sign in with an emailed code at /pair: an address or
|
|
37668
38210
|
@domain; --chat-only gives chat and approvals without settings.
|
|
37669
38211
|
Takes effect at once, no restart.
|
|
38212
|
+
service keep the server running across reboots: writes a systemd unit
|
|
38213
|
+
(Linux) or a launchd agent (macOS) for the same serve options and
|
|
38214
|
+
prints the commands that install it. Install the package
|
|
38215
|
+
permanently first (npm install -g openmausbot).
|
|
37670
38216
|
browser install: the bots' browser engine (agent-browser, pinned) into the
|
|
37671
38217
|
data dir, and Chrome for Testing into the user's browser cache.
|
|
37672
38218
|
--with-deps also installs
|
|
@@ -37708,7 +38254,7 @@ function defaultIo() {
|
|
|
37708
38254
|
}
|
|
37709
38255
|
function serverVersion(here = HERE2) {
|
|
37710
38256
|
try {
|
|
37711
|
-
const parsed = JSON.parse(readFileSync20(
|
|
38257
|
+
const parsed = JSON.parse(readFileSync20(resolve12(here, "..", "package.json"), "utf8"));
|
|
37712
38258
|
const version2 = typeof parsed === "object" && parsed !== null ? Reflect.get(parsed, "version") : void 0;
|
|
37713
38259
|
return typeof version2 === "string" && version2 ? version2 : "0.0.0";
|
|
37714
38260
|
} catch {
|
|
@@ -37733,7 +38279,7 @@ async function isWorkspaceRunning(options) {
|
|
|
37733
38279
|
try {
|
|
37734
38280
|
const { status, body } = await api(options.port, "/api/health");
|
|
37735
38281
|
if (status !== 200 || body?.app !== "openmausbot") return false;
|
|
37736
|
-
const expected = readFileSync20(
|
|
38282
|
+
const expected = readFileSync20(join33(options.dataDir, "environment-id"), "utf8").trim();
|
|
37737
38283
|
const descriptor = await api(options.port, "/.well-known/openmausbot/environment");
|
|
37738
38284
|
return /^[0-9a-f-]{36}$/i.test(expected) && descriptor.status === 200 && descriptor.body?.environmentId === expected;
|
|
37739
38285
|
} catch {
|
|
@@ -37933,7 +38479,7 @@ async function runStatus(options, io = defaultIo()) {
|
|
|
37933
38479
|
return code;
|
|
37934
38480
|
}
|
|
37935
38481
|
async function runAccess(options, io = defaultIo()) {
|
|
37936
|
-
const file2 =
|
|
38482
|
+
const file2 = join33(options.dataDir, "config.json");
|
|
37937
38483
|
let raw = {};
|
|
37938
38484
|
if (existsSync16(file2)) {
|
|
37939
38485
|
try {
|
|
@@ -37951,7 +38497,7 @@ async function runAccess(options, io = defaultIo()) {
|
|
|
37951
38497
|
const members = list(Reflect.get(current, "members"));
|
|
37952
38498
|
const overridden = process.env.OMB_SIGNIN_EMAILS !== void 0 || process.env.OMB_SIGNIN_MEMBER_EMAILS !== void 0;
|
|
37953
38499
|
const write = (next) => {
|
|
37954
|
-
|
|
38500
|
+
mkdirSync14(options.dataDir, { recursive: true, mode: 448 });
|
|
37955
38501
|
writeFileAtomic(file2, `${JSON.stringify({ ...raw, signIn: next }, null, 2)}
|
|
37956
38502
|
`, { mode: 384 });
|
|
37957
38503
|
};
|
|
@@ -38085,16 +38631,16 @@ async function runBrowser(options, io = defaultIo()) {
|
|
|
38085
38631
|
return 0;
|
|
38086
38632
|
}
|
|
38087
38633
|
function serverEntry(here = HERE2) {
|
|
38088
|
-
const bundled =
|
|
38089
|
-
const root =
|
|
38634
|
+
const bundled = join33(here, "index.js");
|
|
38635
|
+
const root = resolve12(here, "..");
|
|
38090
38636
|
if (existsSync16(bundled)) {
|
|
38091
|
-
const staticDir2 = [
|
|
38092
|
-
const skillsDir = existsSync16(
|
|
38637
|
+
const staticDir2 = [join33(root, "dist"), join33(here, "..", "ui")].find((d) => existsSync16(join33(d, "index.html"))) ?? null;
|
|
38638
|
+
const skillsDir = existsSync16(join33(root, "skills")) ? join33(root, "skills") : null;
|
|
38093
38639
|
return { command: process.execPath, args: [bundled], staticDir: staticDir2, skillsDir };
|
|
38094
38640
|
}
|
|
38095
|
-
const source =
|
|
38096
|
-
const staticDir = existsSync16(
|
|
38097
|
-
return { command: process.execPath, args: ["--experimental-strip-types", source], staticDir, skillsDir: existsSync16(
|
|
38641
|
+
const source = join33(here, "index.ts");
|
|
38642
|
+
const staticDir = existsSync16(join33(root, "dist", "index.html")) ? join33(root, "dist") : null;
|
|
38643
|
+
return { command: process.execPath, args: ["--experimental-strip-types", source], staticDir, skillsDir: existsSync16(join33(root, "skills")) ? join33(root, "skills") : null };
|
|
38098
38644
|
}
|
|
38099
38645
|
async function planTunnel(options, log) {
|
|
38100
38646
|
let access2 = null;
|
|
@@ -38194,9 +38740,9 @@ async function runServe(options, log = console.log) {
|
|
|
38194
38740
|
let child;
|
|
38195
38741
|
try {
|
|
38196
38742
|
if (options.guided) {
|
|
38197
|
-
const logsDir =
|
|
38198
|
-
|
|
38199
|
-
logPath =
|
|
38743
|
+
const logsDir = join33(options.dataDir, "logs");
|
|
38744
|
+
mkdirSync14(logsDir, { recursive: true, mode: 448 });
|
|
38745
|
+
logPath = join33(logsDir, `server-${Date.now()}-${process.pid}.log`);
|
|
38200
38746
|
logFd = openSync3(logPath, "wx", 384);
|
|
38201
38747
|
log("\nStarting your workspace\u2026");
|
|
38202
38748
|
}
|
|
@@ -38388,7 +38934,7 @@ async function runOnboardingCommand(options, io = defaultIo(), startServer = run
|
|
|
38388
38934
|
}
|
|
38389
38935
|
if (options.command === "setup") {
|
|
38390
38936
|
io.log("\nAll set. Start with: openmausbot (or npx openmausbot without a global install).");
|
|
38391
|
-
if (options.dataDir !==
|
|
38937
|
+
if (options.dataDir !== join33(homedir24(), ".openmausbot") || options.port !== 8799) {
|
|
38392
38938
|
io.log(`Use the same --data-dir (${options.dataDir}) and --port (${options.port}) options when starting.`);
|
|
38393
38939
|
}
|
|
38394
38940
|
return 0;
|
|
@@ -38426,6 +38972,18 @@ ${USAGE}`);
|
|
|
38426
38972
|
return runLogin(options);
|
|
38427
38973
|
case "access":
|
|
38428
38974
|
return runAccess(options);
|
|
38975
|
+
case "service":
|
|
38976
|
+
return runServiceCommand({
|
|
38977
|
+
action: options.serviceAction ?? "install",
|
|
38978
|
+
dataDir: options.dataDir,
|
|
38979
|
+
port: options.port,
|
|
38980
|
+
domain: options.domain,
|
|
38981
|
+
tunnel: options.tunnel,
|
|
38982
|
+
tailscale: options.tailscale,
|
|
38983
|
+
label: options.label,
|
|
38984
|
+
script: process.argv[1] ?? "",
|
|
38985
|
+
node: process.execPath
|
|
38986
|
+
}, { log: (line) => console.log(line), error: (line) => console.error(line) });
|
|
38429
38987
|
case "logout":
|
|
38430
38988
|
return runLogout(options);
|
|
38431
38989
|
case "browser":
|