agent-phonon 0.2.9 → 0.2.11
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 +298 -61
- package/dist/cli.js.map +1 -1
- package/dist/daemon.js +222 -59
- package/dist/daemon.js.map +1 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -1725,12 +1725,12 @@ var init_rpc = __esm({
|
|
|
1725
1725
|
requestRaw(method, params, timeoutMs = 12e4) {
|
|
1726
1726
|
const id = this.nextId++;
|
|
1727
1727
|
const msg = { jsonrpc: "2.0", id, method, params };
|
|
1728
|
-
return new Promise((
|
|
1728
|
+
return new Promise((resolve6, reject) => {
|
|
1729
1729
|
const timer = timeoutMs > 0 ? setTimeout(() => {
|
|
1730
1730
|
this.pending.delete(id);
|
|
1731
1731
|
reject(new PhononError("errInternal", `RPC timeout: ${method}`));
|
|
1732
1732
|
}, timeoutMs) : void 0;
|
|
1733
|
-
this.pending.set(id, { resolve:
|
|
1733
|
+
this.pending.set(id, { resolve: resolve6, reject, timer });
|
|
1734
1734
|
this.transport.send(JSON.stringify(msg));
|
|
1735
1735
|
});
|
|
1736
1736
|
}
|
|
@@ -2186,8 +2186,8 @@ var SessionEngine = class {
|
|
|
2186
2186
|
this.interactionWaiters.delete(requestId);
|
|
2187
2187
|
}
|
|
2188
2188
|
}
|
|
2189
|
-
registerInteractionWaiter(requestId,
|
|
2190
|
-
this.interactionWaiters.set(requestId,
|
|
2189
|
+
registerInteractionWaiter(requestId, resolve6) {
|
|
2190
|
+
this.interactionWaiters.set(requestId, resolve6);
|
|
2191
2191
|
}
|
|
2192
2192
|
list(tenantId, filter) {
|
|
2193
2193
|
const all = [];
|
|
@@ -3762,7 +3762,7 @@ ${message}`;
|
|
|
3762
3762
|
return void 0;
|
|
3763
3763
|
}
|
|
3764
3764
|
run(args2, signal, environment) {
|
|
3765
|
-
return new Promise((
|
|
3765
|
+
return new Promise((resolve6, reject) => {
|
|
3766
3766
|
const child = spawn2("openclaw", args2, { cwd: this.cwd, env: { ...process.env, ...environment ?? {} } });
|
|
3767
3767
|
this.current = child;
|
|
3768
3768
|
let out = "";
|
|
@@ -3780,9 +3780,9 @@ ${message}`;
|
|
|
3780
3780
|
signal?.removeEventListener("abort", onAbort);
|
|
3781
3781
|
this.current = void 0;
|
|
3782
3782
|
if (killed)
|
|
3783
|
-
return
|
|
3783
|
+
return resolve6(null);
|
|
3784
3784
|
if (code === 0)
|
|
3785
|
-
|
|
3785
|
+
resolve6(out);
|
|
3786
3786
|
else
|
|
3787
3787
|
reject(new Error(`openclaw exited ${code}: ${err.slice(0, 500)}`));
|
|
3788
3788
|
});
|
|
@@ -3834,12 +3834,12 @@ var OpenClawAdapter = class {
|
|
|
3834
3834
|
return new OpenClawSession(params.sessionId, params.model, params.cwd, openclawAgent);
|
|
3835
3835
|
}
|
|
3836
3836
|
probeVersion() {
|
|
3837
|
-
return new Promise((
|
|
3837
|
+
return new Promise((resolve6) => {
|
|
3838
3838
|
const child = spawn2("openclaw", ["--version"]);
|
|
3839
3839
|
let out = "";
|
|
3840
3840
|
child.stdout.on("data", (d) => out += d.toString());
|
|
3841
|
-
child.on("error", () =>
|
|
3842
|
-
child.on("close", (code) =>
|
|
3841
|
+
child.on("error", () => resolve6(null));
|
|
3842
|
+
child.on("close", (code) => resolve6(code === 0 ? out.trim() : null));
|
|
3843
3843
|
});
|
|
3844
3844
|
}
|
|
3845
3845
|
};
|
|
@@ -3872,7 +3872,7 @@ var GatewayClient = class {
|
|
|
3872
3872
|
return this.connectPromise;
|
|
3873
3873
|
}
|
|
3874
3874
|
doConnect() {
|
|
3875
|
-
return new Promise((
|
|
3875
|
+
return new Promise((resolve6, reject) => {
|
|
3876
3876
|
const wsUrl = this.config.baseUrl.replace(/^http/, "ws");
|
|
3877
3877
|
const ws = new WebSocket(wsUrl);
|
|
3878
3878
|
this.ws = ws;
|
|
@@ -3903,7 +3903,7 @@ var GatewayClient = class {
|
|
|
3903
3903
|
} else if (frame.type === "res" && frame.ok && frame.payload?.type === "hello-ok") {
|
|
3904
3904
|
handshakeDone = true;
|
|
3905
3905
|
this.connected = true;
|
|
3906
|
-
|
|
3906
|
+
resolve6();
|
|
3907
3907
|
} else if (frame.type === "res" && !frame.ok) {
|
|
3908
3908
|
reject(new Error(`handshake failed: ${JSON.stringify(frame.error)}`));
|
|
3909
3909
|
}
|
|
@@ -3949,13 +3949,13 @@ var GatewayClient = class {
|
|
|
3949
3949
|
async rpc(method, params, timeoutMs = 12e4) {
|
|
3950
3950
|
if (!this.connected)
|
|
3951
3951
|
await this.connect();
|
|
3952
|
-
return new Promise((
|
|
3952
|
+
return new Promise((resolve6, reject) => {
|
|
3953
3953
|
const id = randomUUID();
|
|
3954
3954
|
const timer = setTimeout(() => {
|
|
3955
3955
|
this.pending.delete(id);
|
|
3956
3956
|
reject(new Error(`RPC timeout: ${method}`));
|
|
3957
3957
|
}, timeoutMs);
|
|
3958
|
-
this.pending.set(id, { resolve:
|
|
3958
|
+
this.pending.set(id, { resolve: resolve6, reject, timer });
|
|
3959
3959
|
this.ws.send(JSON.stringify({ type: "req", id, method, params }));
|
|
3960
3960
|
});
|
|
3961
3961
|
}
|
|
@@ -4082,14 +4082,14 @@ var GatewaySession = class {
|
|
|
4082
4082
|
|
|
4083
4083
|
${input}`;
|
|
4084
4084
|
}
|
|
4085
|
-
await new Promise((
|
|
4085
|
+
await new Promise((resolve6) => {
|
|
4086
4086
|
let settled = false;
|
|
4087
4087
|
const finish = () => {
|
|
4088
4088
|
if (settled)
|
|
4089
4089
|
return;
|
|
4090
4090
|
settled = true;
|
|
4091
4091
|
clearTimeout(guard);
|
|
4092
|
-
|
|
4092
|
+
resolve6();
|
|
4093
4093
|
};
|
|
4094
4094
|
this.activeTurn = { turnId, emit, verbosity: opts.verbosity, done: finish, acc: "" };
|
|
4095
4095
|
this.gw.rpc("chat.send", {
|
|
@@ -4350,7 +4350,7 @@ var PhononClient = class {
|
|
|
4350
4350
|
}
|
|
4351
4351
|
/** 连接并完成握手,resolve 后即可接收 server 的 session.* 下发。 */
|
|
4352
4352
|
connect() {
|
|
4353
|
-
return new Promise((
|
|
4353
|
+
return new Promise((resolve6, reject) => {
|
|
4354
4354
|
const ws = new WebSocket2(this.serverUrl);
|
|
4355
4355
|
this.ws = ws;
|
|
4356
4356
|
const transport = {
|
|
@@ -4392,7 +4392,7 @@ var PhononClient = class {
|
|
|
4392
4392
|
if (wAck && wAck.length > 0) {
|
|
4393
4393
|
conn.replayPending(wAck.map((a) => ({ sessionId: a.sessionId, fromSeq: a.lastSeq })));
|
|
4394
4394
|
}
|
|
4395
|
-
|
|
4395
|
+
resolve6({ tenantId: welcome.tenantId });
|
|
4396
4396
|
} catch (err) {
|
|
4397
4397
|
reject(err);
|
|
4398
4398
|
}
|
|
@@ -4462,12 +4462,12 @@ var HookBridge = class {
|
|
|
4462
4462
|
this.token = opts?.token;
|
|
4463
4463
|
}
|
|
4464
4464
|
listen(port = 4318, host = "127.0.0.1") {
|
|
4465
|
-
return new Promise((
|
|
4465
|
+
return new Promise((resolve6) => {
|
|
4466
4466
|
const server = createServer((req, res) => this.onRequest(req, res));
|
|
4467
4467
|
this.server = server;
|
|
4468
4468
|
server.listen(port, host, () => {
|
|
4469
4469
|
const addr = server.address();
|
|
4470
|
-
|
|
4470
|
+
resolve6(typeof addr === "object" && addr ? addr.port : port);
|
|
4471
4471
|
});
|
|
4472
4472
|
});
|
|
4473
4473
|
}
|
|
@@ -4520,10 +4520,10 @@ var HookBridge = class {
|
|
|
4520
4520
|
});
|
|
4521
4521
|
}
|
|
4522
4522
|
close() {
|
|
4523
|
-
return new Promise((
|
|
4523
|
+
return new Promise((resolve6) => {
|
|
4524
4524
|
if (!this.server)
|
|
4525
|
-
return
|
|
4526
|
-
this.server.close(() =>
|
|
4525
|
+
return resolve6();
|
|
4526
|
+
this.server.close(() => resolve6());
|
|
4527
4527
|
});
|
|
4528
4528
|
}
|
|
4529
4529
|
};
|
|
@@ -4624,7 +4624,12 @@ function fileSize(p) {
|
|
|
4624
4624
|
import { spawn as spawn3 } from "node:child_process";
|
|
4625
4625
|
import { homedir as homedir5 } from "node:os";
|
|
4626
4626
|
import { join as join7 } from "node:path";
|
|
4627
|
-
import { existsSync as existsSync7, readdirSync, statSync as statSync2 } from "node:fs";
|
|
4627
|
+
import { existsSync as existsSync7, readdirSync, statSync as statSync2, readFileSync as readFileSync4 } from "node:fs";
|
|
4628
|
+
var CODEX_FALLBACK_MODELS = [
|
|
4629
|
+
{ id: "gpt-5.5", available: true },
|
|
4630
|
+
{ id: "gpt-5.4", available: true },
|
|
4631
|
+
{ id: "gpt-5.3-codex", available: true }
|
|
4632
|
+
];
|
|
4628
4633
|
var CAPABILITIES2 = {
|
|
4629
4634
|
nativeSession: true,
|
|
4630
4635
|
// exec resume <thread_id>
|
|
@@ -4674,6 +4679,60 @@ function resolveCodexSessionFile(threadId, codexHome = join7(homedir5(), ".codex
|
|
|
4674
4679
|
hits.sort((a, b) => b.mtime - a.mtime);
|
|
4675
4680
|
return hits[0].path;
|
|
4676
4681
|
}
|
|
4682
|
+
function parseCodexConfig(configPath = join7(homedir5(), ".codex", "config.toml")) {
|
|
4683
|
+
if (!existsSync7(configPath))
|
|
4684
|
+
return {};
|
|
4685
|
+
const text = readFileSync4(configPath, "utf8");
|
|
4686
|
+
const model = text.match(/^model\s*=\s*"([^"]+)"/m)?.[1];
|
|
4687
|
+
const providerId = text.match(/^model_provider\s*=\s*"([^"]+)"/m)?.[1];
|
|
4688
|
+
let baseUrl;
|
|
4689
|
+
if (providerId) {
|
|
4690
|
+
const escaped = providerId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
4691
|
+
const section = text.match(new RegExp(`\\[model_providers\\.${escaped}\\]([\\s\\S]*?)(?:\\n\\[|$)`))?.[1];
|
|
4692
|
+
baseUrl = section?.match(/^base_url\s*=\s*"([^"]+)"/m)?.[1];
|
|
4693
|
+
}
|
|
4694
|
+
return { model, providerId, baseUrl };
|
|
4695
|
+
}
|
|
4696
|
+
function normalizeOpenAiModels(data) {
|
|
4697
|
+
const rows = Array.isArray(data.data) ? data.data : Array.isArray(data) ? data : [];
|
|
4698
|
+
const out = [];
|
|
4699
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4700
|
+
for (const row of rows) {
|
|
4701
|
+
const obj = row;
|
|
4702
|
+
const id = typeof obj.id === "string" ? obj.id : void 0;
|
|
4703
|
+
if (!id || seen.has(id))
|
|
4704
|
+
continue;
|
|
4705
|
+
seen.add(id);
|
|
4706
|
+
out.push({ id, ...typeof obj.name === "string" ? { displayName: obj.name } : {}, available: true });
|
|
4707
|
+
}
|
|
4708
|
+
return out;
|
|
4709
|
+
}
|
|
4710
|
+
function fetchJson(url, headers) {
|
|
4711
|
+
return new Promise((resolve6, reject) => {
|
|
4712
|
+
const u = new URL(url);
|
|
4713
|
+
const req = (u.protocol === "http:" ? import("node:http") : import("node:https")).then((mod) => mod.request(url, { method: "GET", headers, timeout: 5e3 }, (res) => {
|
|
4714
|
+
let body = "";
|
|
4715
|
+
res.setEncoding("utf8");
|
|
4716
|
+
res.on("data", (d) => body += d);
|
|
4717
|
+
res.on("end", () => {
|
|
4718
|
+
if ((res.statusCode ?? 500) < 200 || (res.statusCode ?? 500) >= 300) {
|
|
4719
|
+
reject(new Error(`GET ${url} failed: ${res.statusCode}`));
|
|
4720
|
+
return;
|
|
4721
|
+
}
|
|
4722
|
+
try {
|
|
4723
|
+
resolve6(JSON.parse(body));
|
|
4724
|
+
} catch (e) {
|
|
4725
|
+
reject(e);
|
|
4726
|
+
}
|
|
4727
|
+
});
|
|
4728
|
+
}));
|
|
4729
|
+
req.then((r) => {
|
|
4730
|
+
r.on("timeout", () => r.destroy(new Error(`GET ${url} timeout`)));
|
|
4731
|
+
r.on("error", reject);
|
|
4732
|
+
r.end();
|
|
4733
|
+
}, reject);
|
|
4734
|
+
});
|
|
4735
|
+
}
|
|
4677
4736
|
var CodexSession = class {
|
|
4678
4737
|
sessionId;
|
|
4679
4738
|
model;
|
|
@@ -4723,7 +4782,7 @@ ${prompt}`;
|
|
|
4723
4782
|
await this.run(args2, prompt, turnId, emit, opts);
|
|
4724
4783
|
}
|
|
4725
4784
|
run(args2, stdin, turnId, emit, opts) {
|
|
4726
|
-
return new Promise((
|
|
4785
|
+
return new Promise((resolve6) => {
|
|
4727
4786
|
const child = spawn3(this.env.binPath ?? "codex", args2, {
|
|
4728
4787
|
cwd: this.cwd,
|
|
4729
4788
|
shell: process.platform === "win32",
|
|
@@ -4744,7 +4803,7 @@ ${prompt}`;
|
|
|
4744
4803
|
} else {
|
|
4745
4804
|
emit({ type: "result", sessionId: this.sessionId, turnId, seq: 0, at: (/* @__PURE__ */ new Date()).toISOString(), text, status, final: true });
|
|
4746
4805
|
}
|
|
4747
|
-
|
|
4806
|
+
resolve6();
|
|
4748
4807
|
};
|
|
4749
4808
|
const guard = setTimeout(() => finish("timeout", acc), 18e5);
|
|
4750
4809
|
opts.signal?.addEventListener("abort", () => {
|
|
@@ -4837,6 +4896,7 @@ var CodexAdapter = class {
|
|
|
4837
4896
|
async discoverAgents() {
|
|
4838
4897
|
const version = await this.probeVersion();
|
|
4839
4898
|
const available = version !== null;
|
|
4899
|
+
const models = await this.discoverModels();
|
|
4840
4900
|
return [{
|
|
4841
4901
|
agentId: "codex",
|
|
4842
4902
|
displayName: "Codex",
|
|
@@ -4844,7 +4904,7 @@ var CodexAdapter = class {
|
|
|
4844
4904
|
available,
|
|
4845
4905
|
...available ? {} : { unavailableReason: "codex CLI not found" },
|
|
4846
4906
|
...version ? { version } : {},
|
|
4847
|
-
models
|
|
4907
|
+
models,
|
|
4848
4908
|
capabilities: CAPABILITIES2,
|
|
4849
4909
|
scannedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4850
4910
|
}];
|
|
@@ -4852,13 +4912,35 @@ var CodexAdapter = class {
|
|
|
4852
4912
|
async createSession(params) {
|
|
4853
4913
|
return new CodexSession(params.sessionId, params.model, params.cwd, this.env);
|
|
4854
4914
|
}
|
|
4915
|
+
async discoverModels() {
|
|
4916
|
+
if (this.env.models?.length)
|
|
4917
|
+
return this.env.models;
|
|
4918
|
+
const cfg = parseCodexConfig();
|
|
4919
|
+
const baseUrl = this.env.baseUrl ?? cfg.baseUrl;
|
|
4920
|
+
if (baseUrl) {
|
|
4921
|
+
try {
|
|
4922
|
+
const data = await fetchJson(`${baseUrl.replace(/\/$/, "")}/models`, this.env.apiKey ? { Authorization: `Bearer ${this.env.apiKey}` } : void 0);
|
|
4923
|
+
const models = normalizeOpenAiModels(data);
|
|
4924
|
+
if (models.length > 0)
|
|
4925
|
+
return models;
|
|
4926
|
+
} catch {
|
|
4927
|
+
}
|
|
4928
|
+
}
|
|
4929
|
+
const configured = this.env.defaultModel !== "default" ? this.env.defaultModel : cfg.model;
|
|
4930
|
+
const base = configured ? [{ id: configured, available: true }] : [];
|
|
4931
|
+
const seen = new Set(base.map((m) => m.id));
|
|
4932
|
+
for (const m of CODEX_FALLBACK_MODELS)
|
|
4933
|
+
if (!seen.has(m.id))
|
|
4934
|
+
base.push(m);
|
|
4935
|
+
return base.length > 0 ? base : CODEX_FALLBACK_MODELS;
|
|
4936
|
+
}
|
|
4855
4937
|
probeVersion() {
|
|
4856
|
-
return new Promise((
|
|
4938
|
+
return new Promise((resolve6) => {
|
|
4857
4939
|
const child = spawn3(this.env.binPath ?? "codex", ["--version"], { shell: process.platform === "win32" });
|
|
4858
4940
|
let out = "";
|
|
4859
4941
|
child.stdout.on("data", (d) => out += d.toString());
|
|
4860
|
-
child.on("error", () =>
|
|
4861
|
-
child.on("close", (code) =>
|
|
4942
|
+
child.on("error", () => resolve6(null));
|
|
4943
|
+
child.on("close", (code) => resolve6(code === 0 ? out.trim() : null));
|
|
4862
4944
|
});
|
|
4863
4945
|
}
|
|
4864
4946
|
};
|
|
@@ -4934,7 +5016,7 @@ ${message}`;
|
|
|
4934
5016
|
await this.run(args2, turnId, emit, opts);
|
|
4935
5017
|
}
|
|
4936
5018
|
run(args2, turnId, emit, opts) {
|
|
4937
|
-
return new Promise((
|
|
5019
|
+
return new Promise((resolve6) => {
|
|
4938
5020
|
const child = spawn4(this.bin, args2, { cwd: this.cwd, stdio: ["ignore", "pipe", "pipe"], env: { ...process.env, ...opts.environment ?? {} } });
|
|
4939
5021
|
this.current = child;
|
|
4940
5022
|
let buf = "";
|
|
@@ -4951,7 +5033,7 @@ ${message}`;
|
|
|
4951
5033
|
} else {
|
|
4952
5034
|
emit({ type: "result", sessionId: this.sessionId, turnId, seq: 0, at: (/* @__PURE__ */ new Date()).toISOString(), text, status, final: true });
|
|
4953
5035
|
}
|
|
4954
|
-
|
|
5036
|
+
resolve6();
|
|
4955
5037
|
};
|
|
4956
5038
|
const guard = setTimeout(() => finish("timeout", acc), 18e5);
|
|
4957
5039
|
opts.signal?.addEventListener("abort", () => {
|
|
@@ -5082,12 +5164,12 @@ var OpenCodeAdapter = class {
|
|
|
5082
5164
|
return new OpenCodeSession(params.sessionId, model, params.cwd, this.bin);
|
|
5083
5165
|
}
|
|
5084
5166
|
probeVersion() {
|
|
5085
|
-
return new Promise((
|
|
5167
|
+
return new Promise((resolve6) => {
|
|
5086
5168
|
const child = spawn4(this.bin, ["--version"]);
|
|
5087
5169
|
let out = "";
|
|
5088
5170
|
child.stdout.on("data", (d) => out += d.toString());
|
|
5089
|
-
child.on("error", () =>
|
|
5090
|
-
child.on("close", (code) =>
|
|
5171
|
+
child.on("error", () => resolve6(null));
|
|
5172
|
+
child.on("close", (code) => resolve6(code === 0 ? out.trim() : null));
|
|
5091
5173
|
});
|
|
5092
5174
|
}
|
|
5093
5175
|
};
|
|
@@ -5098,7 +5180,29 @@ import { randomUUID as randomUUID3 } from "node:crypto";
|
|
|
5098
5180
|
import { DatabaseSync as DatabaseSync4 } from "node:sqlite";
|
|
5099
5181
|
import { homedir as homedir7 } from "node:os";
|
|
5100
5182
|
import { join as join9 } from "node:path";
|
|
5101
|
-
import { existsSync as existsSync9 } from "node:fs";
|
|
5183
|
+
import { existsSync as existsSync9, readFileSync as readFileSync5 } from "node:fs";
|
|
5184
|
+
var HERMES_PROVIDER_FALLBACK_MODELS = {
|
|
5185
|
+
// Hermes' built-in Copilot picker exposes these account/integrator-safe model ids.
|
|
5186
|
+
copilot: [
|
|
5187
|
+
"gpt-5.4",
|
|
5188
|
+
"gpt-5.4-mini",
|
|
5189
|
+
"gpt-5-mini",
|
|
5190
|
+
"gpt-5.3-codex",
|
|
5191
|
+
"gpt-5.2-codex",
|
|
5192
|
+
"gpt-4.1",
|
|
5193
|
+
"gpt-4o",
|
|
5194
|
+
"gpt-4o-mini",
|
|
5195
|
+
"claude-sonnet-4.6",
|
|
5196
|
+
"claude-sonnet-4",
|
|
5197
|
+
"claude-sonnet-4.5",
|
|
5198
|
+
"claude-haiku-4.5",
|
|
5199
|
+
"gemini-3.1-pro-preview",
|
|
5200
|
+
"gemini-3-pro-preview",
|
|
5201
|
+
"gemini-3-flash-preview",
|
|
5202
|
+
"gemini-2.5-pro"
|
|
5203
|
+
],
|
|
5204
|
+
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"]
|
|
5205
|
+
};
|
|
5102
5206
|
var CAPABILITIES4 = {
|
|
5103
5207
|
nativeSession: true,
|
|
5104
5208
|
// --resume / --pass-session-id
|
|
@@ -5118,6 +5222,49 @@ var CAPABILITIES4 = {
|
|
|
5118
5222
|
// -z 是纯文本一次性输出,非流式 → 用 final 事件
|
|
5119
5223
|
limits: { maxConcurrentSessions: 4 }
|
|
5120
5224
|
};
|
|
5225
|
+
function parseHermesConfig(configPath = join9(homedir7(), ".hermes", "config.yaml")) {
|
|
5226
|
+
if (!existsSync9(configPath))
|
|
5227
|
+
return {};
|
|
5228
|
+
const text = readFileSync5(configPath, "utf8");
|
|
5229
|
+
const modelBlock = text.match(/(?:^|\n)model:\n([\s\S]*?)(?:\n[A-Za-z_][A-Za-z0-9_-]*:|$)/)?.[1] ?? "";
|
|
5230
|
+
const defaultModel = modelBlock.match(/^\s+default:\s*['"]?([^'"\n]+)['"]?/m)?.[1]?.trim();
|
|
5231
|
+
const provider = modelBlock.match(/^\s+provider:\s*['"]?([^'"\n]+)['"]?/m)?.[1]?.trim();
|
|
5232
|
+
const catalogBlock = text.match(/(?:^|\n)model_catalog:\n([\s\S]*?)(?:\n[A-Za-z_][A-Za-z0-9_-]*:|$)/)?.[1] ?? "";
|
|
5233
|
+
const catalogUrl = catalogBlock.match(/^\s+url:\s*['"]?([^'"\n]+)['"]?/m)?.[1]?.trim();
|
|
5234
|
+
return { defaultModel, provider, catalogUrl };
|
|
5235
|
+
}
|
|
5236
|
+
function fetchHermesCatalogModels(url, provider) {
|
|
5237
|
+
return new Promise((resolve6) => {
|
|
5238
|
+
const u = new URL(url);
|
|
5239
|
+
const reqMod = u.protocol === "http:" ? import("node:http") : import("node:https");
|
|
5240
|
+
reqMod.then((mod) => {
|
|
5241
|
+
const req = mod.request(url, { method: "GET", timeout: 5e3 }, (res) => {
|
|
5242
|
+
let body = "";
|
|
5243
|
+
res.setEncoding("utf8");
|
|
5244
|
+
res.on("data", (d) => body += d);
|
|
5245
|
+
res.on("end", () => {
|
|
5246
|
+
try {
|
|
5247
|
+
const data = JSON.parse(body);
|
|
5248
|
+
const providers = data.providers ?? {};
|
|
5249
|
+
const rows = provider ? providers[provider]?.models ?? [] : Object.values(providers).flatMap((p) => p.models ?? []);
|
|
5250
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5251
|
+
resolve6(rows.flatMap((m) => {
|
|
5252
|
+
if (!m.id || seen.has(m.id))
|
|
5253
|
+
return [];
|
|
5254
|
+
seen.add(m.id);
|
|
5255
|
+
return [{ id: m.id, ...m.description ? { displayName: m.description } : {}, available: true }];
|
|
5256
|
+
}));
|
|
5257
|
+
} catch {
|
|
5258
|
+
resolve6([]);
|
|
5259
|
+
}
|
|
5260
|
+
});
|
|
5261
|
+
});
|
|
5262
|
+
req.on("timeout", () => req.destroy());
|
|
5263
|
+
req.on("error", () => resolve6([]));
|
|
5264
|
+
req.end();
|
|
5265
|
+
}, () => resolve6([]));
|
|
5266
|
+
});
|
|
5267
|
+
}
|
|
5121
5268
|
var HermesSession = class {
|
|
5122
5269
|
sessionId;
|
|
5123
5270
|
model;
|
|
@@ -5163,7 +5310,7 @@ ${prompt}`;
|
|
|
5163
5310
|
await this.run(args2, turnId, emit, opts);
|
|
5164
5311
|
}
|
|
5165
5312
|
run(args2, turnId, emit, opts) {
|
|
5166
|
-
return new Promise((
|
|
5313
|
+
return new Promise((resolve6) => {
|
|
5167
5314
|
const child = spawn5(this.env.binPath ?? "hermes", args2, {
|
|
5168
5315
|
cwd: this.cwd,
|
|
5169
5316
|
shell: process.platform === "win32",
|
|
@@ -5186,7 +5333,7 @@ ${prompt}`;
|
|
|
5186
5333
|
emit({ type: "message", sessionId: this.sessionId, turnId, seq: 0, at: (/* @__PURE__ */ new Date()).toISOString(), role: "assistant", text, delta: false });
|
|
5187
5334
|
emit({ type: "result", sessionId: this.sessionId, turnId, seq: 0, at: (/* @__PURE__ */ new Date()).toISOString(), text, status, final: true });
|
|
5188
5335
|
}
|
|
5189
|
-
|
|
5336
|
+
resolve6();
|
|
5190
5337
|
};
|
|
5191
5338
|
const guard = setTimeout(() => finish("timeout", out), 18e5);
|
|
5192
5339
|
opts.signal?.addEventListener("abort", () => {
|
|
@@ -5311,6 +5458,10 @@ var HermesAdapter = class {
|
|
|
5311
5458
|
}];
|
|
5312
5459
|
}
|
|
5313
5460
|
const profiles = await this.listProfiles();
|
|
5461
|
+
const cfg = parseHermesConfig();
|
|
5462
|
+
const provider = this.env.provider ?? cfg.provider;
|
|
5463
|
+
const catalogModels = cfg.catalogUrl ? await fetchHermesCatalogModels(cfg.catalogUrl, provider) : [];
|
|
5464
|
+
const providerFallbackModels = provider ? (HERMES_PROVIDER_FALLBACK_MODELS[provider] ?? []).map((id) => ({ id, available: true })) : [];
|
|
5314
5465
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
5315
5466
|
return profiles.map((p) => ({
|
|
5316
5467
|
agentId: `hermes:${p.name}`,
|
|
@@ -5318,11 +5469,23 @@ var HermesAdapter = class {
|
|
|
5318
5469
|
adapter: "hermes",
|
|
5319
5470
|
available: true,
|
|
5320
5471
|
...version ? { version } : {},
|
|
5321
|
-
models:
|
|
5472
|
+
models: this.modelsForProfile(p.model, [...catalogModels, ...providerFallbackModels], cfg.defaultModel),
|
|
5322
5473
|
capabilities: CAPABILITIES4,
|
|
5323
5474
|
scannedAt: now
|
|
5324
5475
|
}));
|
|
5325
5476
|
}
|
|
5477
|
+
modelsForProfile(profileModel, catalogModels, configDefault) {
|
|
5478
|
+
const preferred = profileModel ?? this.env.defaultModel ?? configDefault;
|
|
5479
|
+
const models = preferred ? [{ id: preferred, available: true }] : [];
|
|
5480
|
+
const seen = new Set(models.map((m) => m.id));
|
|
5481
|
+
for (const m of catalogModels) {
|
|
5482
|
+
if (!seen.has(m.id)) {
|
|
5483
|
+
models.push(m);
|
|
5484
|
+
seen.add(m.id);
|
|
5485
|
+
}
|
|
5486
|
+
}
|
|
5487
|
+
return models.length > 0 ? models : [{ id: "default", displayName: "Hermes default", available: true }];
|
|
5488
|
+
}
|
|
5326
5489
|
async createSession(params) {
|
|
5327
5490
|
const profile = params.agentId.includes(":") ? params.agentId.split(":")[1] : this.defaultProfile;
|
|
5328
5491
|
const model = params.model && params.model !== "default" ? params.model : this.env.defaultModel ?? "";
|
|
@@ -5330,11 +5493,11 @@ var HermesAdapter = class {
|
|
|
5330
5493
|
}
|
|
5331
5494
|
/** 枚举 Hermes profile(去 ANSI 色解析 profile list)。 */
|
|
5332
5495
|
listProfiles() {
|
|
5333
|
-
return new Promise((
|
|
5496
|
+
return new Promise((resolve6) => {
|
|
5334
5497
|
const child = spawn5(this.env.binPath ?? "hermes", ["profile", "list"], { shell: process.platform === "win32" });
|
|
5335
5498
|
let out = "";
|
|
5336
5499
|
child.stdout.on("data", (d) => out += d.toString());
|
|
5337
|
-
child.on("error", () =>
|
|
5500
|
+
child.on("error", () => resolve6([{ name: this.defaultProfile }]));
|
|
5338
5501
|
child.on("close", () => {
|
|
5339
5502
|
const clean = out.replace(/\u001b\[[0-9;]*m/g, "");
|
|
5340
5503
|
const names = [];
|
|
@@ -5345,17 +5508,17 @@ var HermesAdapter = class {
|
|
|
5345
5508
|
names.push({ name: m[1], model: rest[0] || void 0 });
|
|
5346
5509
|
}
|
|
5347
5510
|
}
|
|
5348
|
-
|
|
5511
|
+
resolve6(names.length > 0 ? names : [{ name: this.defaultProfile }]);
|
|
5349
5512
|
});
|
|
5350
5513
|
});
|
|
5351
5514
|
}
|
|
5352
5515
|
probeVersion() {
|
|
5353
|
-
return new Promise((
|
|
5516
|
+
return new Promise((resolve6) => {
|
|
5354
5517
|
const child = spawn5(this.env.binPath ?? "hermes", ["--version"], { shell: process.platform === "win32" });
|
|
5355
5518
|
let out = "";
|
|
5356
5519
|
child.stdout.on("data", (d) => out += d.toString());
|
|
5357
|
-
child.on("error", () =>
|
|
5358
|
-
child.on("close", (code) =>
|
|
5520
|
+
child.on("error", () => resolve6(null));
|
|
5521
|
+
child.on("close", (code) => resolve6(code === 0 ? out.trim().split("\n")[0] ?? "hermes" : null));
|
|
5359
5522
|
});
|
|
5360
5523
|
}
|
|
5361
5524
|
};
|
|
@@ -5578,7 +5741,7 @@ ${prompt}`;
|
|
|
5578
5741
|
await this.run(args2, envelope, turnId, emit, opts);
|
|
5579
5742
|
}
|
|
5580
5743
|
run(args2, stdin, turnId, emit, opts) {
|
|
5581
|
-
return new Promise((
|
|
5744
|
+
return new Promise((resolve6) => {
|
|
5582
5745
|
const childEnv = {};
|
|
5583
5746
|
for (const [k, v] of Object.entries(process.env)) {
|
|
5584
5747
|
if (k === "CLAUDECODE" || k.startsWith("CLAUDECODE_") || k.startsWith("CLAUDE_CODE_"))
|
|
@@ -5610,7 +5773,7 @@ ${prompt}`;
|
|
|
5610
5773
|
} else {
|
|
5611
5774
|
emit({ type: "result", sessionId: this.sessionId, turnId, seq: 0, at: (/* @__PURE__ */ new Date()).toISOString(), text, status, final: true });
|
|
5612
5775
|
}
|
|
5613
|
-
|
|
5776
|
+
resolve6();
|
|
5614
5777
|
};
|
|
5615
5778
|
const guard = setTimeout(() => finish("timeout", acc), 18e5);
|
|
5616
5779
|
opts.signal?.addEventListener("abort", () => {
|
|
@@ -5727,12 +5890,12 @@ var ClaudeCodeAdapter = class {
|
|
|
5727
5890
|
return new ClaudeCodeSession(params.sessionId, params.model, params.cwd, this.env);
|
|
5728
5891
|
}
|
|
5729
5892
|
probeVersion() {
|
|
5730
|
-
return new Promise((
|
|
5893
|
+
return new Promise((resolve6) => {
|
|
5731
5894
|
const child = spawn6(this.env.binPath ?? "claude", ["--version"], { shell: process.platform === "win32" });
|
|
5732
5895
|
let out = "";
|
|
5733
5896
|
child.stdout.on("data", (d) => out += d.toString());
|
|
5734
|
-
child.on("error", () =>
|
|
5735
|
-
child.on("close", (code) =>
|
|
5897
|
+
child.on("error", () => resolve6(null));
|
|
5898
|
+
child.on("close", (code) => resolve6(code === 0 ? out.trim() : null));
|
|
5736
5899
|
});
|
|
5737
5900
|
}
|
|
5738
5901
|
};
|
|
@@ -6070,7 +6233,7 @@ var PhononConnection = class {
|
|
|
6070
6233
|
};
|
|
6071
6234
|
|
|
6072
6235
|
// src/config.ts
|
|
6073
|
-
import { readFileSync as
|
|
6236
|
+
import { readFileSync as readFileSync6, existsSync as existsSync11, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3, chmodSync as chmodSync2 } from "node:fs";
|
|
6074
6237
|
import { homedir as homedir9, hostname as hostname2 } from "node:os";
|
|
6075
6238
|
import { join as join11, dirname as dirname4 } from "node:path";
|
|
6076
6239
|
var DEFAULT_DIR = join11(homedir9(), ".agent-phonon");
|
|
@@ -6090,7 +6253,7 @@ function loadConfig(path = DEFAULT_CONFIG_PATH) {
|
|
|
6090
6253
|
if (!existsSync11(path)) {
|
|
6091
6254
|
throw new Error(`config not found at ${path} \u2014 run 'agent-phonon init' first`);
|
|
6092
6255
|
}
|
|
6093
|
-
const raw = JSON.parse(
|
|
6256
|
+
const raw = JSON.parse(readFileSync6(path, "utf8"));
|
|
6094
6257
|
const d = defaultConfig();
|
|
6095
6258
|
return {
|
|
6096
6259
|
deviceId: raw.deviceId ?? d.deviceId,
|
|
@@ -6129,7 +6292,7 @@ function redactConfig(cfg) {
|
|
|
6129
6292
|
function readOpenClawGatewayToken() {
|
|
6130
6293
|
try {
|
|
6131
6294
|
const p = join11(homedir9(), ".openclaw", "openclaw.json");
|
|
6132
|
-
const cfg = JSON.parse(
|
|
6295
|
+
const cfg = JSON.parse(readFileSync6(p, "utf8"));
|
|
6133
6296
|
return cfg?.gateway?.auth?.token;
|
|
6134
6297
|
} catch {
|
|
6135
6298
|
return void 0;
|
|
@@ -6138,9 +6301,9 @@ function readOpenClawGatewayToken() {
|
|
|
6138
6301
|
|
|
6139
6302
|
// src/commands.ts
|
|
6140
6303
|
import { spawnSync } from "node:child_process";
|
|
6141
|
-
import { existsSync as existsSync12, cpSync, mkdirSync as mkdirSync4, rmSync as rmSync3, writeFileSync as writeFileSync4, readFileSync as
|
|
6304
|
+
import { existsSync as existsSync12, cpSync, mkdirSync as mkdirSync4, rmSync as rmSync3, writeFileSync as writeFileSync4, readFileSync as readFileSync7, chmodSync as chmodSync3 } from "node:fs";
|
|
6142
6305
|
import { homedir as homedir10, platform as platform2 } from "node:os";
|
|
6143
|
-
import { join as join12, dirname as dirname5, delimiter } from "node:path";
|
|
6306
|
+
import { join as join12, dirname as dirname5, delimiter, resolve as resolve5 } from "node:path";
|
|
6144
6307
|
import { fileURLToPath } from "node:url";
|
|
6145
6308
|
function probe(bin, args2 = ["--version"]) {
|
|
6146
6309
|
const r = spawnSync(bin, args2, { timeout: 8e3, shell: platform2() === "win32" });
|
|
@@ -6320,6 +6483,75 @@ function cmdAdapterList() {
|
|
|
6320
6483
|
console.log(`- ${a.type}${a.defaultAgent ? ` (agent: ${a.defaultAgent})` : ""}${auto}`);
|
|
6321
6484
|
}
|
|
6322
6485
|
}
|
|
6486
|
+
function systemctlUser(args2) {
|
|
6487
|
+
const r = spawnSync("systemctl", ["--user", ...args2], { stdio: "inherit" });
|
|
6488
|
+
if (r.status !== 0) fail(`systemctl --user ${args2.join(" ")} failed`);
|
|
6489
|
+
}
|
|
6490
|
+
function serviceUnitPath() {
|
|
6491
|
+
return join12(homedir10(), ".config", "systemd", "user", "agent-phonon.service");
|
|
6492
|
+
}
|
|
6493
|
+
function serviceUnitContent() {
|
|
6494
|
+
const node = process.execPath;
|
|
6495
|
+
const cli = resolve5(process.argv[1] ?? fileURLToPath(import.meta.url));
|
|
6496
|
+
return `[Unit]
|
|
6497
|
+
Description=agent-phonon device daemon
|
|
6498
|
+
After=network-online.target
|
|
6499
|
+
Wants=network-online.target
|
|
6500
|
+
|
|
6501
|
+
[Service]
|
|
6502
|
+
Type=simple
|
|
6503
|
+
ExecStart=${node} ${cli} start
|
|
6504
|
+
Restart=always
|
|
6505
|
+
RestartSec=5
|
|
6506
|
+
MemoryMax=256M
|
|
6507
|
+
|
|
6508
|
+
[Install]
|
|
6509
|
+
WantedBy=default.target
|
|
6510
|
+
`;
|
|
6511
|
+
}
|
|
6512
|
+
function cmdService(sub, opts = {}) {
|
|
6513
|
+
if (platform2() !== "linux") {
|
|
6514
|
+
fail(`service ${sub ?? ""} is currently implemented for Linux systemd --user only (platform=${platform2()})`);
|
|
6515
|
+
}
|
|
6516
|
+
const unit = serviceUnitPath();
|
|
6517
|
+
switch (sub) {
|
|
6518
|
+
case "install": {
|
|
6519
|
+
if (existsSync12(unit) && !opts.force) fail(`${unit} already exists (use --force to overwrite)`);
|
|
6520
|
+
mkdirSync4(dirname5(unit), { recursive: true });
|
|
6521
|
+
writeFileSync4(unit, serviceUnitContent(), { mode: 420 });
|
|
6522
|
+
chmodSync3(unit, 420);
|
|
6523
|
+
systemctlUser(["daemon-reload"]);
|
|
6524
|
+
systemctlUser(["enable", "agent-phonon.service"]);
|
|
6525
|
+
console.log(`installed systemd user service \u2192 ${unit}`);
|
|
6526
|
+
console.log("start it with: agent-phonon service start");
|
|
6527
|
+
if (!existsSync12(join12(homedir10(), ".agent-phonon", "config.json"))) console.log("config not found yet; run: agent-phonon init");
|
|
6528
|
+
break;
|
|
6529
|
+
}
|
|
6530
|
+
case "start":
|
|
6531
|
+
systemctlUser(["start", "agent-phonon.service"]);
|
|
6532
|
+
console.log("started agent-phonon.service");
|
|
6533
|
+
break;
|
|
6534
|
+
case "stop":
|
|
6535
|
+
systemctlUser(["stop", "agent-phonon.service"]);
|
|
6536
|
+
console.log("stopped agent-phonon.service");
|
|
6537
|
+
break;
|
|
6538
|
+
case "restart":
|
|
6539
|
+
systemctlUser(["restart", "agent-phonon.service"]);
|
|
6540
|
+
console.log("restarted agent-phonon.service");
|
|
6541
|
+
break;
|
|
6542
|
+
case "status":
|
|
6543
|
+
systemctlUser(["status", "agent-phonon.service", "--no-pager"]);
|
|
6544
|
+
break;
|
|
6545
|
+
case "uninstall":
|
|
6546
|
+
systemctlUser(["disable", "--now", "agent-phonon.service"]);
|
|
6547
|
+
rmSync3(unit, { force: true });
|
|
6548
|
+
systemctlUser(["daemon-reload"]);
|
|
6549
|
+
console.log(`removed ${unit}`);
|
|
6550
|
+
break;
|
|
6551
|
+
default:
|
|
6552
|
+
fail("usage: agent-phonon service install|start|stop|restart|status|uninstall [--force]");
|
|
6553
|
+
}
|
|
6554
|
+
}
|
|
6323
6555
|
function cmdPluginInstall(which) {
|
|
6324
6556
|
if (which !== "openclaw") return fail(`plugin install supports: openclaw (got: ${which})`);
|
|
6325
6557
|
const here = dirname5(fileURLToPath(import.meta.url));
|
|
@@ -6332,7 +6564,7 @@ function cmdPluginInstall(which) {
|
|
|
6332
6564
|
mkdirSync4(dist, { recursive: true });
|
|
6333
6565
|
cpSync(join12(pluginSrc, "dist"), join12(dist, "dist"), { recursive: true });
|
|
6334
6566
|
cpSync(join12(pluginSrc, "openclaw.plugin.json"), join12(dist, "openclaw.plugin.json"));
|
|
6335
|
-
const pkg = JSON.parse(
|
|
6567
|
+
const pkg = JSON.parse(readFileSync7(join12(pluginSrc, "package.json"), "utf8"));
|
|
6336
6568
|
delete pkg.devDependencies;
|
|
6337
6569
|
writeFileSync4(join12(dist, "package.json"), JSON.stringify(pkg, null, 2));
|
|
6338
6570
|
console.log(`exported clean plugin \u2192 ${dist}`);
|
|
@@ -6358,13 +6590,13 @@ var ObsServer = class {
|
|
|
6358
6590
|
deps.bus.onEvent((e) => this.broadcast(e));
|
|
6359
6591
|
}
|
|
6360
6592
|
listen(port = 4319, host = "127.0.0.1") {
|
|
6361
|
-
return new Promise((
|
|
6593
|
+
return new Promise((resolve6) => {
|
|
6362
6594
|
const server = createServer2((req, res) => this.handle(req, res));
|
|
6363
6595
|
this.server = server;
|
|
6364
6596
|
server.listen(port, host, () => {
|
|
6365
6597
|
const addr = server.address();
|
|
6366
6598
|
this.actualPort = typeof addr === "object" && addr ? addr.port : port;
|
|
6367
|
-
|
|
6599
|
+
resolve6(this.actualPort);
|
|
6368
6600
|
});
|
|
6369
6601
|
});
|
|
6370
6602
|
}
|
|
@@ -6442,11 +6674,11 @@ var ObsServer = class {
|
|
|
6442
6674
|
return this.actualPort;
|
|
6443
6675
|
}
|
|
6444
6676
|
close() {
|
|
6445
|
-
return new Promise((
|
|
6677
|
+
return new Promise((resolve6) => {
|
|
6446
6678
|
for (const c of this.sseClients) c.end();
|
|
6447
6679
|
this.sseClients.clear();
|
|
6448
|
-
if (!this.server) return
|
|
6449
|
-
this.server.close(() =>
|
|
6680
|
+
if (!this.server) return resolve6();
|
|
6681
|
+
this.server.close(() => resolve6());
|
|
6450
6682
|
});
|
|
6451
6683
|
}
|
|
6452
6684
|
};
|
|
@@ -6672,6 +6904,10 @@ async function main() {
|
|
|
6672
6904
|
}
|
|
6673
6905
|
break;
|
|
6674
6906
|
}
|
|
6907
|
+
case "service": {
|
|
6908
|
+
cmdService(args[0], { force: flag("force") });
|
|
6909
|
+
break;
|
|
6910
|
+
}
|
|
6675
6911
|
case "plugin": {
|
|
6676
6912
|
const sub = args[0];
|
|
6677
6913
|
if (sub === "install") cmdPluginInstall(args[1] ?? "");
|
|
@@ -6689,6 +6925,7 @@ async function main() {
|
|
|
6689
6925
|
console.log(" adapter add <type> [opts] configure an adapter override (auto-detect covers common local agents)");
|
|
6690
6926
|
console.log(" adapter list list configured + auto-detected adapters");
|
|
6691
6927
|
console.log(" plugin install openclaw install OpenClaw HITL plugin");
|
|
6928
|
+
console.log(" service install|start|status manage Linux systemd --user service");
|
|
6692
6929
|
console.log(" server add <url> [--trust-local] [--device-key <k>]");
|
|
6693
6930
|
console.log(" server list");
|
|
6694
6931
|
console.log(" config [--show-secrets] show config (redacted by default)");
|