agent-phonon 0.2.8 → 0.2.10
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/cli.js +215 -30
- package/dist/cli.js.map +1 -1
- package/dist/daemon.js +213 -28
- package/dist/daemon.js.map +1 -1
- package/package.json +2 -2
package/dist/daemon.js
CHANGED
|
@@ -4623,7 +4623,12 @@ function fileSize(p) {
|
|
|
4623
4623
|
import { spawn as spawn3 } from "node:child_process";
|
|
4624
4624
|
import { homedir as homedir5 } from "node:os";
|
|
4625
4625
|
import { join as join7 } from "node:path";
|
|
4626
|
-
import { existsSync as existsSync7, readdirSync, statSync as statSync2 } from "node:fs";
|
|
4626
|
+
import { existsSync as existsSync7, readdirSync, statSync as statSync2, readFileSync as readFileSync4 } from "node:fs";
|
|
4627
|
+
var CODEX_FALLBACK_MODELS = [
|
|
4628
|
+
{ id: "gpt-5.5", available: true },
|
|
4629
|
+
{ id: "gpt-5.4", available: true },
|
|
4630
|
+
{ id: "gpt-5.3-codex", available: true }
|
|
4631
|
+
];
|
|
4627
4632
|
var CAPABILITIES2 = {
|
|
4628
4633
|
nativeSession: true,
|
|
4629
4634
|
// exec resume <thread_id>
|
|
@@ -4673,6 +4678,60 @@ function resolveCodexSessionFile(threadId, codexHome = join7(homedir5(), ".codex
|
|
|
4673
4678
|
hits.sort((a, b) => b.mtime - a.mtime);
|
|
4674
4679
|
return hits[0].path;
|
|
4675
4680
|
}
|
|
4681
|
+
function parseCodexConfig(configPath = join7(homedir5(), ".codex", "config.toml")) {
|
|
4682
|
+
if (!existsSync7(configPath))
|
|
4683
|
+
return {};
|
|
4684
|
+
const text = readFileSync4(configPath, "utf8");
|
|
4685
|
+
const model = text.match(/^model\s*=\s*"([^"]+)"/m)?.[1];
|
|
4686
|
+
const providerId = text.match(/^model_provider\s*=\s*"([^"]+)"/m)?.[1];
|
|
4687
|
+
let baseUrl;
|
|
4688
|
+
if (providerId) {
|
|
4689
|
+
const escaped = providerId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
4690
|
+
const section = text.match(new RegExp(`\\[model_providers\\.${escaped}\\]([\\s\\S]*?)(?:\\n\\[|$)`))?.[1];
|
|
4691
|
+
baseUrl = section?.match(/^base_url\s*=\s*"([^"]+)"/m)?.[1];
|
|
4692
|
+
}
|
|
4693
|
+
return { model, providerId, baseUrl };
|
|
4694
|
+
}
|
|
4695
|
+
function normalizeOpenAiModels(data) {
|
|
4696
|
+
const rows = Array.isArray(data.data) ? data.data : Array.isArray(data) ? data : [];
|
|
4697
|
+
const out = [];
|
|
4698
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4699
|
+
for (const row of rows) {
|
|
4700
|
+
const obj = row;
|
|
4701
|
+
const id = typeof obj.id === "string" ? obj.id : void 0;
|
|
4702
|
+
if (!id || seen.has(id))
|
|
4703
|
+
continue;
|
|
4704
|
+
seen.add(id);
|
|
4705
|
+
out.push({ id, ...typeof obj.name === "string" ? { displayName: obj.name } : {}, available: true });
|
|
4706
|
+
}
|
|
4707
|
+
return out;
|
|
4708
|
+
}
|
|
4709
|
+
function fetchJson(url, headers) {
|
|
4710
|
+
return new Promise((resolve5, reject) => {
|
|
4711
|
+
const u = new URL(url);
|
|
4712
|
+
const req = (u.protocol === "http:" ? import("node:http") : import("node:https")).then((mod) => mod.request(url, { method: "GET", headers, timeout: 5e3 }, (res) => {
|
|
4713
|
+
let body = "";
|
|
4714
|
+
res.setEncoding("utf8");
|
|
4715
|
+
res.on("data", (d) => body += d);
|
|
4716
|
+
res.on("end", () => {
|
|
4717
|
+
if ((res.statusCode ?? 500) < 200 || (res.statusCode ?? 500) >= 300) {
|
|
4718
|
+
reject(new Error(`GET ${url} failed: ${res.statusCode}`));
|
|
4719
|
+
return;
|
|
4720
|
+
}
|
|
4721
|
+
try {
|
|
4722
|
+
resolve5(JSON.parse(body));
|
|
4723
|
+
} catch (e) {
|
|
4724
|
+
reject(e);
|
|
4725
|
+
}
|
|
4726
|
+
});
|
|
4727
|
+
}));
|
|
4728
|
+
req.then((r) => {
|
|
4729
|
+
r.on("timeout", () => r.destroy(new Error(`GET ${url} timeout`)));
|
|
4730
|
+
r.on("error", reject);
|
|
4731
|
+
r.end();
|
|
4732
|
+
}, reject);
|
|
4733
|
+
});
|
|
4734
|
+
}
|
|
4676
4735
|
var CodexSession = class {
|
|
4677
4736
|
sessionId;
|
|
4678
4737
|
model;
|
|
@@ -4725,6 +4784,7 @@ ${prompt}`;
|
|
|
4725
4784
|
return new Promise((resolve5) => {
|
|
4726
4785
|
const child = spawn3(this.env.binPath ?? "codex", args, {
|
|
4727
4786
|
cwd: this.cwd,
|
|
4787
|
+
shell: process.platform === "win32",
|
|
4728
4788
|
env: { ...process.env, ...opts.environment ?? {}, ...this.env.apiKey ? { OPENAI_API_KEY: this.env.apiKey } : {} }
|
|
4729
4789
|
});
|
|
4730
4790
|
this.current = child;
|
|
@@ -4835,6 +4895,7 @@ var CodexAdapter = class {
|
|
|
4835
4895
|
async discoverAgents() {
|
|
4836
4896
|
const version = await this.probeVersion();
|
|
4837
4897
|
const available = version !== null;
|
|
4898
|
+
const models = await this.discoverModels();
|
|
4838
4899
|
return [{
|
|
4839
4900
|
agentId: "codex",
|
|
4840
4901
|
displayName: "Codex",
|
|
@@ -4842,7 +4903,7 @@ var CodexAdapter = class {
|
|
|
4842
4903
|
available,
|
|
4843
4904
|
...available ? {} : { unavailableReason: "codex CLI not found" },
|
|
4844
4905
|
...version ? { version } : {},
|
|
4845
|
-
models
|
|
4906
|
+
models,
|
|
4846
4907
|
capabilities: CAPABILITIES2,
|
|
4847
4908
|
scannedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4848
4909
|
}];
|
|
@@ -4850,9 +4911,31 @@ var CodexAdapter = class {
|
|
|
4850
4911
|
async createSession(params) {
|
|
4851
4912
|
return new CodexSession(params.sessionId, params.model, params.cwd, this.env);
|
|
4852
4913
|
}
|
|
4914
|
+
async discoverModels() {
|
|
4915
|
+
if (this.env.models?.length)
|
|
4916
|
+
return this.env.models;
|
|
4917
|
+
const cfg = parseCodexConfig();
|
|
4918
|
+
const baseUrl = this.env.baseUrl ?? cfg.baseUrl;
|
|
4919
|
+
if (baseUrl) {
|
|
4920
|
+
try {
|
|
4921
|
+
const data = await fetchJson(`${baseUrl.replace(/\/$/, "")}/models`, this.env.apiKey ? { Authorization: `Bearer ${this.env.apiKey}` } : void 0);
|
|
4922
|
+
const models = normalizeOpenAiModels(data);
|
|
4923
|
+
if (models.length > 0)
|
|
4924
|
+
return models;
|
|
4925
|
+
} catch {
|
|
4926
|
+
}
|
|
4927
|
+
}
|
|
4928
|
+
const configured = this.env.defaultModel !== "default" ? this.env.defaultModel : cfg.model;
|
|
4929
|
+
const base = configured ? [{ id: configured, available: true }] : [];
|
|
4930
|
+
const seen = new Set(base.map((m) => m.id));
|
|
4931
|
+
for (const m of CODEX_FALLBACK_MODELS)
|
|
4932
|
+
if (!seen.has(m.id))
|
|
4933
|
+
base.push(m);
|
|
4934
|
+
return base.length > 0 ? base : CODEX_FALLBACK_MODELS;
|
|
4935
|
+
}
|
|
4853
4936
|
probeVersion() {
|
|
4854
4937
|
return new Promise((resolve5) => {
|
|
4855
|
-
const child = spawn3(this.env.binPath ?? "codex", ["--version"]);
|
|
4938
|
+
const child = spawn3(this.env.binPath ?? "codex", ["--version"], { shell: process.platform === "win32" });
|
|
4856
4939
|
let out = "";
|
|
4857
4940
|
child.stdout.on("data", (d) => out += d.toString());
|
|
4858
4941
|
child.on("error", () => resolve5(null));
|
|
@@ -5096,7 +5179,29 @@ import { randomUUID as randomUUID3 } from "node:crypto";
|
|
|
5096
5179
|
import { DatabaseSync as DatabaseSync4 } from "node:sqlite";
|
|
5097
5180
|
import { homedir as homedir7 } from "node:os";
|
|
5098
5181
|
import { join as join9 } from "node:path";
|
|
5099
|
-
import { existsSync as existsSync9 } from "node:fs";
|
|
5182
|
+
import { existsSync as existsSync9, readFileSync as readFileSync5 } from "node:fs";
|
|
5183
|
+
var HERMES_PROVIDER_FALLBACK_MODELS = {
|
|
5184
|
+
// Hermes' built-in Copilot picker exposes these account/integrator-safe model ids.
|
|
5185
|
+
copilot: [
|
|
5186
|
+
"gpt-5.4",
|
|
5187
|
+
"gpt-5.4-mini",
|
|
5188
|
+
"gpt-5-mini",
|
|
5189
|
+
"gpt-5.3-codex",
|
|
5190
|
+
"gpt-5.2-codex",
|
|
5191
|
+
"gpt-4.1",
|
|
5192
|
+
"gpt-4o",
|
|
5193
|
+
"gpt-4o-mini",
|
|
5194
|
+
"claude-sonnet-4.6",
|
|
5195
|
+
"claude-sonnet-4",
|
|
5196
|
+
"claude-sonnet-4.5",
|
|
5197
|
+
"claude-haiku-4.5",
|
|
5198
|
+
"gemini-3.1-pro-preview",
|
|
5199
|
+
"gemini-3-pro-preview",
|
|
5200
|
+
"gemini-3-flash-preview",
|
|
5201
|
+
"gemini-2.5-pro"
|
|
5202
|
+
],
|
|
5203
|
+
zai: ["glm-4.5", "glm-4.5-air", "glm-4.6", "glm-4.7", "glm-5", "glm-5-turbo", "glm-5.1", "glm-5.2"]
|
|
5204
|
+
};
|
|
5100
5205
|
var CAPABILITIES4 = {
|
|
5101
5206
|
nativeSession: true,
|
|
5102
5207
|
// --resume / --pass-session-id
|
|
@@ -5116,6 +5221,49 @@ var CAPABILITIES4 = {
|
|
|
5116
5221
|
// -z 是纯文本一次性输出,非流式 → 用 final 事件
|
|
5117
5222
|
limits: { maxConcurrentSessions: 4 }
|
|
5118
5223
|
};
|
|
5224
|
+
function parseHermesConfig(configPath = join9(homedir7(), ".hermes", "config.yaml")) {
|
|
5225
|
+
if (!existsSync9(configPath))
|
|
5226
|
+
return {};
|
|
5227
|
+
const text = readFileSync5(configPath, "utf8");
|
|
5228
|
+
const modelBlock = text.match(/(?:^|\n)model:\n([\s\S]*?)(?:\n[A-Za-z_][A-Za-z0-9_-]*:|$)/)?.[1] ?? "";
|
|
5229
|
+
const defaultModel = modelBlock.match(/^\s+default:\s*['"]?([^'"\n]+)['"]?/m)?.[1]?.trim();
|
|
5230
|
+
const provider = modelBlock.match(/^\s+provider:\s*['"]?([^'"\n]+)['"]?/m)?.[1]?.trim();
|
|
5231
|
+
const catalogBlock = text.match(/(?:^|\n)model_catalog:\n([\s\S]*?)(?:\n[A-Za-z_][A-Za-z0-9_-]*:|$)/)?.[1] ?? "";
|
|
5232
|
+
const catalogUrl = catalogBlock.match(/^\s+url:\s*['"]?([^'"\n]+)['"]?/m)?.[1]?.trim();
|
|
5233
|
+
return { defaultModel, provider, catalogUrl };
|
|
5234
|
+
}
|
|
5235
|
+
function fetchHermesCatalogModels(url, provider) {
|
|
5236
|
+
return new Promise((resolve5) => {
|
|
5237
|
+
const u = new URL(url);
|
|
5238
|
+
const reqMod = u.protocol === "http:" ? import("node:http") : import("node:https");
|
|
5239
|
+
reqMod.then((mod) => {
|
|
5240
|
+
const req = mod.request(url, { method: "GET", timeout: 5e3 }, (res) => {
|
|
5241
|
+
let body = "";
|
|
5242
|
+
res.setEncoding("utf8");
|
|
5243
|
+
res.on("data", (d) => body += d);
|
|
5244
|
+
res.on("end", () => {
|
|
5245
|
+
try {
|
|
5246
|
+
const data = JSON.parse(body);
|
|
5247
|
+
const providers = data.providers ?? {};
|
|
5248
|
+
const rows = provider ? providers[provider]?.models ?? [] : Object.values(providers).flatMap((p) => p.models ?? []);
|
|
5249
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5250
|
+
resolve5(rows.flatMap((m) => {
|
|
5251
|
+
if (!m.id || seen.has(m.id))
|
|
5252
|
+
return [];
|
|
5253
|
+
seen.add(m.id);
|
|
5254
|
+
return [{ id: m.id, ...m.description ? { displayName: m.description } : {}, available: true }];
|
|
5255
|
+
}));
|
|
5256
|
+
} catch {
|
|
5257
|
+
resolve5([]);
|
|
5258
|
+
}
|
|
5259
|
+
});
|
|
5260
|
+
});
|
|
5261
|
+
req.on("timeout", () => req.destroy());
|
|
5262
|
+
req.on("error", () => resolve5([]));
|
|
5263
|
+
req.end();
|
|
5264
|
+
}, () => resolve5([]));
|
|
5265
|
+
});
|
|
5266
|
+
}
|
|
5119
5267
|
var HermesSession = class {
|
|
5120
5268
|
sessionId;
|
|
5121
5269
|
model;
|
|
@@ -5164,6 +5312,7 @@ ${prompt}`;
|
|
|
5164
5312
|
return new Promise((resolve5) => {
|
|
5165
5313
|
const child = spawn5(this.env.binPath ?? "hermes", args, {
|
|
5166
5314
|
cwd: this.cwd,
|
|
5315
|
+
shell: process.platform === "win32",
|
|
5167
5316
|
env: { ...process.env, ...opts.environment ?? {}, HERMES_PROFILE: this.profile }
|
|
5168
5317
|
});
|
|
5169
5318
|
this.current = child;
|
|
@@ -5308,6 +5457,10 @@ var HermesAdapter = class {
|
|
|
5308
5457
|
}];
|
|
5309
5458
|
}
|
|
5310
5459
|
const profiles = await this.listProfiles();
|
|
5460
|
+
const cfg = parseHermesConfig();
|
|
5461
|
+
const provider = this.env.provider ?? cfg.provider;
|
|
5462
|
+
const catalogModels = cfg.catalogUrl ? await fetchHermesCatalogModels(cfg.catalogUrl, provider) : [];
|
|
5463
|
+
const providerFallbackModels = provider ? (HERMES_PROVIDER_FALLBACK_MODELS[provider] ?? []).map((id) => ({ id, available: true })) : [];
|
|
5311
5464
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
5312
5465
|
return profiles.map((p) => ({
|
|
5313
5466
|
agentId: `hermes:${p.name}`,
|
|
@@ -5315,11 +5468,23 @@ var HermesAdapter = class {
|
|
|
5315
5468
|
adapter: "hermes",
|
|
5316
5469
|
available: true,
|
|
5317
5470
|
...version ? { version } : {},
|
|
5318
|
-
models:
|
|
5471
|
+
models: this.modelsForProfile(p.model, [...catalogModels, ...providerFallbackModels], cfg.defaultModel),
|
|
5319
5472
|
capabilities: CAPABILITIES4,
|
|
5320
5473
|
scannedAt: now
|
|
5321
5474
|
}));
|
|
5322
5475
|
}
|
|
5476
|
+
modelsForProfile(profileModel, catalogModels, configDefault) {
|
|
5477
|
+
const preferred = profileModel ?? this.env.defaultModel ?? configDefault;
|
|
5478
|
+
const models = preferred ? [{ id: preferred, available: true }] : [];
|
|
5479
|
+
const seen = new Set(models.map((m) => m.id));
|
|
5480
|
+
for (const m of catalogModels) {
|
|
5481
|
+
if (!seen.has(m.id)) {
|
|
5482
|
+
models.push(m);
|
|
5483
|
+
seen.add(m.id);
|
|
5484
|
+
}
|
|
5485
|
+
}
|
|
5486
|
+
return models.length > 0 ? models : [{ id: "default", displayName: "Hermes default", available: true }];
|
|
5487
|
+
}
|
|
5323
5488
|
async createSession(params) {
|
|
5324
5489
|
const profile = params.agentId.includes(":") ? params.agentId.split(":")[1] : this.defaultProfile;
|
|
5325
5490
|
const model = params.model && params.model !== "default" ? params.model : this.env.defaultModel ?? "";
|
|
@@ -5328,7 +5493,7 @@ var HermesAdapter = class {
|
|
|
5328
5493
|
/** 枚举 Hermes profile(去 ANSI 色解析 profile list)。 */
|
|
5329
5494
|
listProfiles() {
|
|
5330
5495
|
return new Promise((resolve5) => {
|
|
5331
|
-
const child = spawn5(this.env.binPath ?? "hermes", ["profile", "list"]);
|
|
5496
|
+
const child = spawn5(this.env.binPath ?? "hermes", ["profile", "list"], { shell: process.platform === "win32" });
|
|
5332
5497
|
let out = "";
|
|
5333
5498
|
child.stdout.on("data", (d) => out += d.toString());
|
|
5334
5499
|
child.on("error", () => resolve5([{ name: this.defaultProfile }]));
|
|
@@ -5348,7 +5513,7 @@ var HermesAdapter = class {
|
|
|
5348
5513
|
}
|
|
5349
5514
|
probeVersion() {
|
|
5350
5515
|
return new Promise((resolve5) => {
|
|
5351
|
-
const child = spawn5(this.env.binPath ?? "hermes", ["--version"]);
|
|
5516
|
+
const child = spawn5(this.env.binPath ?? "hermes", ["--version"], { shell: process.platform === "win32" });
|
|
5352
5517
|
let out = "";
|
|
5353
5518
|
child.stdout.on("data", (d) => out += d.toString());
|
|
5354
5519
|
child.on("error", () => resolve5(null));
|
|
@@ -5583,7 +5748,7 @@ ${prompt}`;
|
|
|
5583
5748
|
if (v !== void 0)
|
|
5584
5749
|
childEnv[k] = v;
|
|
5585
5750
|
}
|
|
5586
|
-
const child = spawn6(this.env.binPath ?? "claude", args, { cwd: this.cwd, env: { ...childEnv, ...opts.environment ?? {} } });
|
|
5751
|
+
const child = spawn6(this.env.binPath ?? "claude", args, { cwd: this.cwd, shell: process.platform === "win32", env: { ...childEnv, ...opts.environment ?? {} } });
|
|
5587
5752
|
this.current = child;
|
|
5588
5753
|
let buf = "";
|
|
5589
5754
|
let acc = "";
|
|
@@ -5725,7 +5890,7 @@ var ClaudeCodeAdapter = class {
|
|
|
5725
5890
|
}
|
|
5726
5891
|
probeVersion() {
|
|
5727
5892
|
return new Promise((resolve5) => {
|
|
5728
|
-
const child = spawn6(this.env.binPath ?? "claude", ["--version"]);
|
|
5893
|
+
const child = spawn6(this.env.binPath ?? "claude", ["--version"], { shell: process.platform === "win32" });
|
|
5729
5894
|
let out = "";
|
|
5730
5895
|
child.stdout.on("data", (d) => out += d.toString());
|
|
5731
5896
|
child.on("error", () => resolve5(null));
|
|
@@ -6067,7 +6232,7 @@ var PhononConnection = class {
|
|
|
6067
6232
|
};
|
|
6068
6233
|
|
|
6069
6234
|
// src/config.ts
|
|
6070
|
-
import { readFileSync as
|
|
6235
|
+
import { readFileSync as readFileSync6, existsSync as existsSync11, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3, chmodSync as chmodSync2 } from "node:fs";
|
|
6071
6236
|
import { homedir as homedir9, hostname as hostname2 } from "node:os";
|
|
6072
6237
|
import { join as join11, dirname as dirname4 } from "node:path";
|
|
6073
6238
|
var DEFAULT_DIR = join11(homedir9(), ".agent-phonon");
|
|
@@ -6075,7 +6240,7 @@ var DEFAULT_CONFIG_PATH = process.env.PHONON_CONFIG ?? join11(DEFAULT_DIR, "conf
|
|
|
6075
6240
|
function readOpenClawGatewayToken() {
|
|
6076
6241
|
try {
|
|
6077
6242
|
const p = join11(homedir9(), ".openclaw", "openclaw.json");
|
|
6078
|
-
const cfg = JSON.parse(
|
|
6243
|
+
const cfg = JSON.parse(readFileSync6(p, "utf8"));
|
|
6079
6244
|
return cfg?.gateway?.auth?.token;
|
|
6080
6245
|
} catch {
|
|
6081
6246
|
return void 0;
|
|
@@ -6084,32 +6249,52 @@ function readOpenClawGatewayToken() {
|
|
|
6084
6249
|
|
|
6085
6250
|
// src/commands.ts
|
|
6086
6251
|
import { spawnSync } from "node:child_process";
|
|
6087
|
-
import { existsSync as existsSync12, cpSync, mkdirSync as mkdirSync4, rmSync as rmSync3, writeFileSync as writeFileSync4, readFileSync as
|
|
6088
|
-
import { homedir as homedir10 } from "node:os";
|
|
6089
|
-
import { join as join12, dirname as dirname5 } from "node:path";
|
|
6252
|
+
import { existsSync as existsSync12, cpSync, mkdirSync as mkdirSync4, rmSync as rmSync3, writeFileSync as writeFileSync4, readFileSync as readFileSync7 } from "node:fs";
|
|
6253
|
+
import { homedir as homedir10, platform as platform2 } from "node:os";
|
|
6254
|
+
import { join as join12, dirname as dirname5, delimiter } from "node:path";
|
|
6090
6255
|
import { fileURLToPath } from "node:url";
|
|
6091
6256
|
function probe(bin, args = ["--version"]) {
|
|
6092
|
-
const r = spawnSync(bin, args, { timeout: 8e3 });
|
|
6257
|
+
const r = spawnSync(bin, args, { timeout: 8e3, shell: platform2() === "win32" });
|
|
6093
6258
|
return { ok: r.status === 0, out: (r.stdout?.toString() ?? "").trim().split("\n")[0] ?? "" };
|
|
6094
6259
|
}
|
|
6260
|
+
function executableNames(bin) {
|
|
6261
|
+
if (platform2() !== "win32") return [bin];
|
|
6262
|
+
const exts = (process.env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").map((e) => e.toLowerCase());
|
|
6263
|
+
return [bin, ...exts.map((e) => `${bin}${e}`), ...exts.map((e) => `${bin}${e.toUpperCase()}`)];
|
|
6264
|
+
}
|
|
6095
6265
|
function commandPath(bin) {
|
|
6096
|
-
const
|
|
6097
|
-
|
|
6098
|
-
|
|
6099
|
-
|
|
6100
|
-
join12(
|
|
6101
|
-
|
|
6102
|
-
|
|
6103
|
-
|
|
6266
|
+
const home = homedir10();
|
|
6267
|
+
const appData = process.env.APPDATA;
|
|
6268
|
+
const localAppData = process.env.LOCALAPPDATA;
|
|
6269
|
+
const dirs = [
|
|
6270
|
+
join12(home, ".npm-global", "bin"),
|
|
6271
|
+
join12(home, ".local", "bin"),
|
|
6272
|
+
join12(home, ".bun", "bin"),
|
|
6273
|
+
join12(home, ".cargo", "bin"),
|
|
6274
|
+
...appData ? [join12(appData, "npm")] : [],
|
|
6275
|
+
...localAppData ? [join12(localAppData, "Programs"), join12(localAppData, "Microsoft", "WindowsApps")] : [],
|
|
6276
|
+
"/opt/homebrew/bin",
|
|
6277
|
+
"/usr/local/bin",
|
|
6278
|
+
"/usr/bin",
|
|
6279
|
+
...(process.env.PATH ?? "").split(delimiter).filter(Boolean)
|
|
6104
6280
|
];
|
|
6105
|
-
for (const
|
|
6106
|
-
|
|
6107
|
-
|
|
6281
|
+
for (const dir of dirs) {
|
|
6282
|
+
for (const name of executableNames(bin)) {
|
|
6283
|
+
const p = join12(dir, name);
|
|
6284
|
+
if (existsSync12(p)) return p;
|
|
6285
|
+
}
|
|
6286
|
+
}
|
|
6287
|
+
const r = platform2() === "win32" ? spawnSync("where.exe", [bin], { timeout: 3e3 }) : spawnSync("sh", ["-lc", `command -v ${bin}`], { timeout: 3e3 });
|
|
6288
|
+
const out = (r.stdout?.toString() ?? "").trim().split(/\r?\n/)[0];
|
|
6108
6289
|
return r.status === 0 && out ? out : void 0;
|
|
6109
6290
|
}
|
|
6110
6291
|
function openCodeBin() {
|
|
6111
|
-
const
|
|
6112
|
-
|
|
6292
|
+
const bundledDir = join12(homedir10(), ".opencode", "bin");
|
|
6293
|
+
for (const name of executableNames("opencode")) {
|
|
6294
|
+
const p = join12(bundledDir, name);
|
|
6295
|
+
if (existsSync12(p)) return p;
|
|
6296
|
+
}
|
|
6297
|
+
return commandPath("opencode") ?? "opencode";
|
|
6113
6298
|
}
|
|
6114
6299
|
function autoDetectAdapters(adapters) {
|
|
6115
6300
|
const out = [...adapters];
|