agent-phonon 0.2.3 → 0.2.5

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 CHANGED
@@ -4245,11 +4245,12 @@ var OpenClawGatewayAdapter = class {
4245
4245
  if (subAgents.length === 0)
4246
4246
  subAgents = [{ id: this.defaultAgent }];
4247
4247
  const now = (/* @__PURE__ */ new Date()).toISOString();
4248
+ const gatewayModels = await this.listGatewayModels();
4248
4249
  return subAgents.map((a) => {
4249
4250
  if (a.workspace)
4250
4251
  this.workspaceCache.set(`openclaw:${a.id}`, a.workspace);
4251
4252
  const primaryModel = typeof a.model === "string" ? a.model : a.model?.primary;
4252
- const models = primaryModel ? [{ id: primaryModel, available: true }] : [];
4253
+ const models = gatewayModels.length > 0 ? gatewayModels : primaryModel ? [{ id: primaryModel, available: true }] : [];
4253
4254
  return {
4254
4255
  // 复合 agentId:openclaw:<subAgentId>(design D32)
4255
4256
  agentId: `openclaw:${a.id}`,
@@ -4262,6 +4263,32 @@ var OpenClawGatewayAdapter = class {
4262
4263
  };
4263
4264
  });
4264
4265
  }
4266
+ async listGatewayModels() {
4267
+ try {
4268
+ const r = await this.gw.rpc("models.list", { view: "all" }, 8e3);
4269
+ const rows = Array.isArray(r.models) ? r.models : [];
4270
+ const models = [];
4271
+ const seen = /* @__PURE__ */ new Set();
4272
+ for (const row of rows) {
4273
+ const id = typeof row.key === "string" ? row.key : typeof row.id === "string" ? row.id : void 0;
4274
+ if (!id || seen.has(id))
4275
+ continue;
4276
+ if (row.available === false || row.missing === true)
4277
+ continue;
4278
+ seen.add(id);
4279
+ const contextWindow = typeof row.contextWindow === "number" ? row.contextWindow : typeof row.contextTokens === "number" ? row.contextTokens : void 0;
4280
+ models.push({
4281
+ id,
4282
+ ...typeof row.name === "string" ? { displayName: row.name } : {},
4283
+ ...contextWindow && contextWindow > 0 ? { contextWindow } : {},
4284
+ available: true
4285
+ });
4286
+ }
4287
+ return models;
4288
+ } catch {
4289
+ return [];
4290
+ }
4291
+ }
4265
4292
  async createSession(params) {
4266
4293
  await this.gw.connect();
4267
4294
  const subAgent = params.agentConfig?.openclawAgent ?? (params.agentId.includes(":") ? params.agentId.split(":")[1] : this.defaultAgent);
@@ -4663,6 +4690,8 @@ var CodexSession = class {
4663
4690
  this.env = env;
4664
4691
  }
4665
4692
  providerArgs() {
4693
+ if (!this.env.baseUrl || !this.env.apiKey)
4694
+ return [];
4666
4695
  const id = this.env.providerId ?? "phonon_gateway";
4667
4696
  const name = this.env.providerName ?? "phonon-gateway";
4668
4697
  return [
@@ -4690,14 +4719,14 @@ var CodexSession = class {
4690
4719
 
4691
4720
  ${prompt}`;
4692
4721
  }
4693
- const args2 = this.threadId ? ["exec", "resume", this.threadId, "-", "--json", ...this.providerArgs(), "--model", this.model, "--dangerously-bypass-approvals-and-sandbox"] : ["exec", "-", "--json", ...this.providerArgs(), "--model", this.model, "--dangerously-bypass-approvals-and-sandbox"];
4722
+ const args2 = this.threadId ? ["exec", "resume", this.threadId, "-", "--json", ...this.providerArgs(), ...this.model !== "default" ? ["--model", this.model] : [], "--dangerously-bypass-approvals-and-sandbox"] : ["exec", "-", "--json", ...this.providerArgs(), ...this.model !== "default" ? ["--model", this.model] : [], "--dangerously-bypass-approvals-and-sandbox"];
4694
4723
  await this.run(args2, prompt, turnId, emit, opts);
4695
4724
  }
4696
4725
  run(args2, stdin, turnId, emit, opts) {
4697
4726
  return new Promise((resolve5) => {
4698
4727
  const child = spawn3("codex", args2, {
4699
4728
  cwd: this.cwd,
4700
- env: { ...process.env, ...opts.environment ?? {}, OPENAI_API_KEY: this.env.apiKey }
4729
+ env: { ...process.env, ...opts.environment ?? {}, ...this.env.apiKey ? { OPENAI_API_KEY: this.env.apiKey } : {} }
4701
4730
  });
4702
4731
  this.current = child;
4703
4732
  let buf = "";
@@ -4814,10 +4843,7 @@ var CodexAdapter = class {
4814
4843
  available,
4815
4844
  ...available ? {} : { unavailableReason: "codex CLI not found" },
4816
4845
  ...version ? { version } : {},
4817
- models: [
4818
- { id: "gpt-5.5", displayName: "GPT-5.5", available: true },
4819
- { id: "gpt-5.3-codex", displayName: "GPT-5.3 Codex", available: true }
4820
- ],
4846
+ models: this.env.models?.length ? this.env.models : [{ id: this.env.defaultModel, available: true }],
4821
4847
  capabilities: CAPABILITIES2,
4822
4848
  scannedAt: (/* @__PURE__ */ new Date()).toISOString()
4823
4849
  }];
@@ -5465,16 +5491,20 @@ var CAPABILITIES5 = {
5465
5491
  limits: { maxConcurrentSessions: 4 }
5466
5492
  };
5467
5493
  function writeSettingsFile(env, model) {
5494
+ if (!env.baseUrl || !env.authToken)
5495
+ return void 0;
5468
5496
  const dir = mkdtempSync(join10(tmpdir2(), "phonon-cc-"));
5469
5497
  const file = join10(dir, "settings.json");
5470
5498
  const content = JSON.stringify({
5471
5499
  env: {
5472
5500
  ANTHROPIC_BASE_URL: env.baseUrl,
5473
5501
  ANTHROPIC_AUTH_TOKEN: env.authToken,
5474
- ANTHROPIC_MODEL: model,
5475
- ANTHROPIC_DEFAULT_OPUS_MODEL: model,
5476
- ANTHROPIC_DEFAULT_SONNET_MODEL: model,
5477
- ANTHROPIC_DEFAULT_HAIKU_MODEL: model,
5502
+ ...model !== "default" ? {
5503
+ ANTHROPIC_MODEL: model,
5504
+ ANTHROPIC_DEFAULT_OPUS_MODEL: model,
5505
+ ANTHROPIC_DEFAULT_SONNET_MODEL: model,
5506
+ ANTHROPIC_DEFAULT_HAIKU_MODEL: model
5507
+ } : {},
5478
5508
  CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: "1"
5479
5509
  }
5480
5510
  });
@@ -5527,12 +5557,13 @@ ${prompt}`;
5527
5557
  // 最高权限:bypassPermissions 跳过所有权限确认;不限定 allowedTools = 所有工具可用
5528
5558
  // (phonon 定位:全自动执行,牺牲安全换自动化)
5529
5559
  "--permission-mode",
5530
- "bypassPermissions",
5531
- "--settings",
5532
- this.settingsFile(),
5533
- "--model",
5534
- this.model
5560
+ "bypassPermissions"
5535
5561
  ];
5562
+ const settings = this.settingsFile();
5563
+ if (settings)
5564
+ args2.push("--settings", settings);
5565
+ if (this.model !== "default")
5566
+ args2.push("--model", this.model);
5536
5567
  if (this.started)
5537
5568
  args2.push("--resume", this.uuid);
5538
5569
  else
@@ -5685,11 +5716,7 @@ var ClaudeCodeAdapter = class {
5685
5716
  available,
5686
5717
  ...available ? {} : { unavailableReason: "claude CLI not found" },
5687
5718
  ...version ? { version } : {},
5688
- models: [
5689
- { id: "claude-opus-4.6", displayName: "Claude Opus 4.6", available: true },
5690
- { id: "claude-opus-4.7", displayName: "Claude Opus 4.7", available: true },
5691
- { id: "claude-sonnet-4.6", displayName: "Claude Sonnet 4.6", available: true }
5692
- ],
5719
+ models: this.env.models?.length ? this.env.models : [{ id: this.env.defaultModel, available: true }],
5693
5720
  capabilities: CAPABILITIES5,
5694
5721
  scannedAt: (/* @__PURE__ */ new Date()).toISOString()
5695
5722
  }];
@@ -6107,6 +6134,166 @@ function readOpenClawGatewayToken() {
6107
6134
  }
6108
6135
  }
6109
6136
 
6137
+ // src/commands.ts
6138
+ import { spawnSync } from "node:child_process";
6139
+ import { existsSync as existsSync12, cpSync, mkdirSync as mkdirSync4, rmSync as rmSync3, writeFileSync as writeFileSync4, readFileSync as readFileSync5 } from "node:fs";
6140
+ import { homedir as homedir10 } from "node:os";
6141
+ import { join as join12, dirname as dirname5 } from "node:path";
6142
+ import { fileURLToPath } from "node:url";
6143
+ function probe(bin, args2 = ["--version"]) {
6144
+ const r = spawnSync(bin, args2, { timeout: 8e3 });
6145
+ return { ok: r.status === 0, out: (r.stdout?.toString() ?? "").trim().split("\n")[0] ?? "" };
6146
+ }
6147
+ function gatewayReachable(url) {
6148
+ try {
6149
+ const u = new URL(url.replace(/^ws/, "http"));
6150
+ const r = spawnSync("bash", ["-c", `exec 3<>/dev/tcp/${u.hostname}/${u.port || 80} && echo ok`], { timeout: 3e3 });
6151
+ return r.status === 0;
6152
+ } catch {
6153
+ return false;
6154
+ }
6155
+ }
6156
+ function openCodeBin() {
6157
+ const bundled = join12(homedir10(), ".opencode", "bin", "opencode");
6158
+ return existsSync12(bundled) ? bundled : "opencode";
6159
+ }
6160
+ function autoDetectAdapters(adapters) {
6161
+ const out = [...adapters];
6162
+ const has = (type2) => out.some((a) => a.type === type2);
6163
+ if (!has("hermes") && probe("hermes").ok) out.push({ type: "hermes" });
6164
+ const ocBin = openCodeBin();
6165
+ if (!has("opencode") && probe(ocBin).ok) out.push({ type: "opencode", opencodeBinPath: ocBin === "opencode" ? void 0 : ocBin });
6166
+ if (!has("claude-code") && probe("claude").ok) out.push({ type: "claude-code", claudeDefaultModel: "default" });
6167
+ if (!has("codex") && probe("codex").ok) out.push({ type: "codex", codexDefaultModel: "default" });
6168
+ return out;
6169
+ }
6170
+ function cmdDoctor() {
6171
+ console.log("agent-phonon doctor\n");
6172
+ const gwToken = readOpenClawGatewayToken();
6173
+ const gwUrl = "ws://127.0.0.1:18789";
6174
+ const gwOk = gatewayReachable(gwUrl);
6175
+ console.log(`OpenClaw Gateway (${gwUrl}): ${gwOk ? "\u2713 reachable" : "\u2717 unreachable"}${gwToken ? " (token found)" : " (no token in ~/.openclaw/openclaw.json)"}`);
6176
+ const pluginDir = join12(homedir10(), ".openclaw", "extensions", "agent-phonon-hitl");
6177
+ console.log(`OpenClaw HITL plugin: ${existsSync12(pluginDir) ? "\u2713 installed" : "\u2717 not installed (run: agent-phonon plugin install openclaw)"}`);
6178
+ console.log("\nCLI agents:");
6179
+ for (const [name, bin] of [["Claude Code", "claude"], ["Codex", "codex"], ["Hermes", "hermes"]]) {
6180
+ const p = probe(bin);
6181
+ console.log(` ${name} (${bin}): ${p.ok ? "\u2713 " + p.out : "\u2717 not found"}`);
6182
+ }
6183
+ const ocBin = openCodeBin();
6184
+ const oc = probe(ocBin);
6185
+ console.log(` OpenCode (${ocBin}): ${oc.ok ? "\u2713 " + oc.out : "\u2717 not found"}`);
6186
+ console.log("");
6187
+ try {
6188
+ const cfg = loadConfig();
6189
+ const effective = autoDetectAdapters(cfg.adapters);
6190
+ console.log(`config: ${cfg.adapters.length} configured adapter(s), ${effective.length} effective adapter(s), ${cfg.servers.length} server(s)`);
6191
+ } catch {
6192
+ console.log("config: not initialized (run: agent-phonon init)");
6193
+ }
6194
+ }
6195
+ async function cmdDiscover() {
6196
+ let cfg;
6197
+ try {
6198
+ cfg = loadConfig();
6199
+ } catch {
6200
+ console.error("config not initialized \u2014 run 'agent-phonon init' first");
6201
+ process.exit(1);
6202
+ return;
6203
+ }
6204
+ const reg = buildRegistry(cfg.adapters);
6205
+ const nested = await Promise.all(reg.all().map((a) => a.discoverAgents()));
6206
+ const agents = nested.flat();
6207
+ console.log(`discovered ${agents.length} agent(s):
6208
+ `);
6209
+ for (const a of agents) {
6210
+ console.log(` ${a.available ? "\u2713" : "\u2717"} ${a.agentId} (${a.displayName})${a.available ? "" : " \u2014 " + (a.unavailableReason ?? "unavailable")}`);
6211
+ if (a.models.length) console.log(` models: ${a.models.map((m) => m.id).join(", ")}`);
6212
+ }
6213
+ }
6214
+ function buildRegistry(adapters) {
6215
+ const reg = new AdapterRegistry();
6216
+ for (const a of autoDetectAdapters(adapters)) {
6217
+ if (a.type === "openclaw-gateway") {
6218
+ const token = a.gatewayToken ?? readOpenClawGatewayToken();
6219
+ if (token) reg.register(new OpenClawGatewayAdapter({ gateway: { baseUrl: a.gatewayUrl ?? "ws://127.0.0.1:18789", token }, defaultAgent: a.defaultAgent ?? "main" }));
6220
+ } else if (a.type === "claude-code") {
6221
+ reg.register(new ClaudeCodeAdapter({ env: { baseUrl: a.claudeBaseUrl, authToken: a.claudeAuthToken, defaultModel: a.claudeDefaultModel ?? "default", models: a.claudeModels } }));
6222
+ } else if (a.type === "codex") {
6223
+ reg.register(new CodexAdapter({ env: { baseUrl: a.codexBaseUrl, apiKey: a.codexApiKey, defaultModel: a.codexDefaultModel ?? "default", models: a.codexModels, wireApi: a.codexWireApi ?? "responses" } }));
6224
+ } else if (a.type === "hermes") {
6225
+ reg.register(new HermesAdapter({ env: { defaultModel: a.hermesModel, provider: a.hermesProvider } }));
6226
+ } else if (a.type === "opencode") {
6227
+ reg.register(new OpenCodeAdapter({ env: { binPath: a.opencodeBinPath, defaultModel: a.opencodeModel } }));
6228
+ }
6229
+ }
6230
+ return reg;
6231
+ }
6232
+ function cmdAdapterAdd(type2, opts) {
6233
+ const cfg = loadConfig();
6234
+ let a;
6235
+ switch (type2) {
6236
+ case "openclaw":
6237
+ case "openclaw-gateway":
6238
+ a = { type: "openclaw-gateway", gatewayUrl: opts.gatewayUrl ?? "ws://127.0.0.1:18789", gatewayToken: opts.token, defaultAgent: opts.defaultAgent ?? "main" };
6239
+ break;
6240
+ case "claude-code":
6241
+ a = { type: "claude-code", claudeBaseUrl: opts.baseUrl, claudeAuthToken: opts.token, claudeDefaultModel: opts.model ?? "default" };
6242
+ break;
6243
+ case "codex":
6244
+ a = { type: "codex", codexBaseUrl: opts.baseUrl, codexApiKey: opts.apiKey, codexDefaultModel: opts.model ?? "default", codexWireApi: opts.wireApi ?? "responses" };
6245
+ break;
6246
+ case "hermes":
6247
+ a = { type: "hermes", hermesModel: opts.model, hermesProvider: opts.provider };
6248
+ break;
6249
+ case "opencode":
6250
+ a = { type: "opencode", opencodeBinPath: opts.bin, opencodeModel: opts.model };
6251
+ break;
6252
+ default:
6253
+ return fail(`unknown adapter type: ${type2} (openclaw|claude-code|codex|hermes|opencode)`);
6254
+ }
6255
+ cfg.adapters = cfg.adapters.filter((x) => x.type !== a.type);
6256
+ cfg.adapters.push(a);
6257
+ writeConfig(cfg);
6258
+ console.log(`added ${a.type} adapter (${cfg.adapters.length} total)`);
6259
+ }
6260
+ function cmdAdapterList() {
6261
+ const cfg = loadConfig();
6262
+ const effective = autoDetectAdapters(cfg.adapters);
6263
+ if (effective.length === 0) {
6264
+ console.log("(no adapters available)");
6265
+ return;
6266
+ }
6267
+ for (const a of effective) {
6268
+ const auto = cfg.adapters.some((x) => x.type === a.type) ? "" : " [auto]";
6269
+ console.log(`- ${a.type}${a.defaultAgent ? ` (agent: ${a.defaultAgent})` : ""}${auto}`);
6270
+ }
6271
+ }
6272
+ function cmdPluginInstall(which) {
6273
+ if (which !== "openclaw") return fail(`plugin install supports: openclaw (got: ${which})`);
6274
+ const here = dirname5(fileURLToPath(import.meta.url));
6275
+ const pluginSrc = join12(here, "..", "..", "openclaw-plugin");
6276
+ if (!existsSync12(join12(pluginSrc, "dist", "index.js"))) {
6277
+ return fail(`plugin not built. Run: cd ${pluginSrc} && pnpm build`);
6278
+ }
6279
+ const dist = join12(homedir10(), ".agent-phonon", "openclaw-plugin-dist");
6280
+ rmSync3(dist, { recursive: true, force: true });
6281
+ mkdirSync4(dist, { recursive: true });
6282
+ cpSync(join12(pluginSrc, "dist"), join12(dist, "dist"), { recursive: true });
6283
+ cpSync(join12(pluginSrc, "openclaw.plugin.json"), join12(dist, "openclaw.plugin.json"));
6284
+ const pkg = JSON.parse(readFileSync5(join12(pluginSrc, "package.json"), "utf8"));
6285
+ delete pkg.devDependencies;
6286
+ writeFileSync4(join12(dist, "package.json"), JSON.stringify(pkg, null, 2));
6287
+ console.log(`exported clean plugin \u2192 ${dist}`);
6288
+ const r = spawnSync("openclaw", ["plugins", "install", "--force", dist], { stdio: "inherit" });
6289
+ if (r.status === 0) console.log("\n\u2713 installed. Restart OpenClaw Gateway to load: systemctl --user restart openclaw-gateway.service");
6290
+ else fail("openclaw plugins install failed");
6291
+ }
6292
+ function fail(msg) {
6293
+ console.error("error:", msg);
6294
+ process.exit(1);
6295
+ }
6296
+
6110
6297
  // src/obs-server.ts
6111
6298
  import { createServer as createServer2 } from "node:http";
6112
6299
  var ObsServer = class {
@@ -6234,7 +6421,7 @@ var PhononDaemon = class {
6234
6421
  this.registerAdapters();
6235
6422
  }
6236
6423
  registerAdapters() {
6237
- for (const a of this.cfg.adapters) {
6424
+ for (const a of autoDetectAdapters(this.cfg.adapters)) {
6238
6425
  if (a.type === "openclaw-gateway") {
6239
6426
  const token = a.gatewayToken ?? readOpenClawGatewayToken();
6240
6427
  if (!token) {
@@ -6248,17 +6435,9 @@ var PhononDaemon = class {
6248
6435
  this.gatewayAdapters.push(ad);
6249
6436
  this.registry.register(ad);
6250
6437
  } else if (a.type === "claude-code") {
6251
- if (a.claudeBaseUrl && a.claudeAuthToken) {
6252
- this.registry.register(new ClaudeCodeAdapter({ env: { baseUrl: a.claudeBaseUrl, authToken: a.claudeAuthToken, defaultModel: a.claudeDefaultModel ?? "claude-opus-4.6" } }));
6253
- } else {
6254
- console.warn("[daemon] claude-code adapter skipped: need claudeBaseUrl + claudeAuthToken");
6255
- }
6438
+ this.registry.register(new ClaudeCodeAdapter({ env: { baseUrl: a.claudeBaseUrl, authToken: a.claudeAuthToken, defaultModel: a.claudeDefaultModel ?? "default", models: a.claudeModels } }));
6256
6439
  } else if (a.type === "codex") {
6257
- if (a.codexBaseUrl && a.codexApiKey) {
6258
- this.registry.register(new CodexAdapter({ env: { baseUrl: a.codexBaseUrl, apiKey: a.codexApiKey, defaultModel: a.codexDefaultModel ?? "gpt-5.5", wireApi: a.codexWireApi ?? "responses" } }));
6259
- } else {
6260
- console.warn("[daemon] codex adapter skipped: need codexBaseUrl + codexApiKey");
6261
- }
6440
+ this.registry.register(new CodexAdapter({ env: { baseUrl: a.codexBaseUrl, apiKey: a.codexApiKey, defaultModel: a.codexDefaultModel ?? "default", models: a.codexModels, wireApi: a.codexWireApi ?? "responses" } }));
6262
6441
  } else if (a.type === "hermes") {
6263
6442
  this.registry.register(new HermesAdapter({ env: { defaultModel: a.hermesModel, provider: a.hermesProvider } }));
6264
6443
  } else if (a.type === "opencode") {
@@ -6363,189 +6542,6 @@ var PhononDaemon = class {
6363
6542
 
6364
6543
  // src/cli.ts
6365
6544
  import { existsSync as existsSync13 } from "node:fs";
6366
-
6367
- // src/commands.ts
6368
- import { spawnSync } from "node:child_process";
6369
- import { existsSync as existsSync12, cpSync, mkdirSync as mkdirSync4, rmSync as rmSync3, writeFileSync as writeFileSync4, readFileSync as readFileSync5 } from "node:fs";
6370
- import { homedir as homedir10 } from "node:os";
6371
- import { join as join12, dirname as dirname5 } from "node:path";
6372
- import { fileURLToPath } from "node:url";
6373
- function probe(bin, args2 = ["--version"]) {
6374
- const r = spawnSync(bin, args2, { timeout: 8e3 });
6375
- return { ok: r.status === 0, out: (r.stdout?.toString() ?? "").trim().split("\n")[0] ?? "" };
6376
- }
6377
- function gatewayReachable(url) {
6378
- try {
6379
- const u = new URL(url.replace(/^ws/, "http"));
6380
- const r = spawnSync("bash", ["-c", `exec 3<>/dev/tcp/${u.hostname}/${u.port || 80} && echo ok`], { timeout: 3e3 });
6381
- return r.status === 0;
6382
- } catch {
6383
- return false;
6384
- }
6385
- }
6386
- function openCodeBin() {
6387
- const bundled = join12(homedir10(), ".opencode", "bin", "opencode");
6388
- return existsSync12(bundled) ? bundled : "opencode";
6389
- }
6390
- function readDefaultLlmGateway() {
6391
- try {
6392
- const p = join12(homedir10(), ".openclaw", "openclaw.json");
6393
- const j = JSON.parse(readFileSync5(p, "utf8"));
6394
- const provider = j.models?.providers?.["phgeek-gw"];
6395
- if (provider?.baseUrl && provider?.apiKey) return { baseUrl: provider.baseUrl.replace(/\/$/, ""), apiKey: provider.apiKey };
6396
- } catch {
6397
- }
6398
- const baseUrl = process.env.PHONON_LLM_BASE_URL;
6399
- const apiKey = process.env.PHONON_LLM_API_KEY;
6400
- return baseUrl && apiKey ? { baseUrl: baseUrl.replace(/\/$/, ""), apiKey } : void 0;
6401
- }
6402
- function autoDetectAdapters(adapters) {
6403
- const out = [...adapters];
6404
- const has = (type2) => out.some((a) => a.type === type2);
6405
- if (!has("hermes") && probe("hermes").ok) out.push({ type: "hermes" });
6406
- const ocBin = openCodeBin();
6407
- if (!has("opencode") && probe(ocBin).ok) out.push({ type: "opencode", opencodeBinPath: ocBin === "opencode" ? void 0 : ocBin });
6408
- const gw = readDefaultLlmGateway();
6409
- if (gw) {
6410
- if (!has("claude-code") && probe("claude").ok) {
6411
- out.push({ type: "claude-code", claudeBaseUrl: gw.baseUrl, claudeAuthToken: gw.apiKey, claudeDefaultModel: "claude-opus-4.8" });
6412
- }
6413
- if (!has("codex") && probe("codex").ok) {
6414
- out.push({ type: "codex", codexBaseUrl: `${gw.baseUrl}/v1`, codexApiKey: gw.apiKey, codexDefaultModel: "gpt-5.5", codexWireApi: "responses" });
6415
- }
6416
- }
6417
- return out;
6418
- }
6419
- function cmdDoctor() {
6420
- console.log("agent-phonon doctor\n");
6421
- const gwToken = readOpenClawGatewayToken();
6422
- const gwUrl = "ws://127.0.0.1:18789";
6423
- const gwOk = gatewayReachable(gwUrl);
6424
- console.log(`OpenClaw Gateway (${gwUrl}): ${gwOk ? "\u2713 reachable" : "\u2717 unreachable"}${gwToken ? " (token found)" : " (no token in ~/.openclaw/openclaw.json)"}`);
6425
- const pluginDir = join12(homedir10(), ".openclaw", "extensions", "agent-phonon-hitl");
6426
- console.log(`OpenClaw HITL plugin: ${existsSync12(pluginDir) ? "\u2713 installed" : "\u2717 not installed (run: agent-phonon plugin install openclaw)"}`);
6427
- console.log("\nCLI agents:");
6428
- for (const [name, bin] of [["Claude Code", "claude"], ["Codex", "codex"], ["Hermes", "hermes"]]) {
6429
- const p = probe(bin);
6430
- console.log(` ${name} (${bin}): ${p.ok ? "\u2713 " + p.out : "\u2717 not found"}`);
6431
- }
6432
- const ocBin = openCodeBin();
6433
- const oc = probe(ocBin);
6434
- console.log(` OpenCode (${ocBin}): ${oc.ok ? "\u2713 " + oc.out : "\u2717 not found"}`);
6435
- console.log("");
6436
- try {
6437
- const cfg = loadConfig();
6438
- const effective = autoDetectAdapters(cfg.adapters);
6439
- console.log(`config: ${cfg.adapters.length} configured adapter(s), ${effective.length} effective adapter(s), ${cfg.servers.length} server(s)`);
6440
- } catch {
6441
- console.log("config: not initialized (run: agent-phonon init)");
6442
- }
6443
- }
6444
- async function cmdDiscover() {
6445
- let cfg;
6446
- try {
6447
- cfg = loadConfig();
6448
- } catch {
6449
- console.error("config not initialized \u2014 run 'agent-phonon init' first");
6450
- process.exit(1);
6451
- return;
6452
- }
6453
- const reg = buildRegistry(cfg.adapters);
6454
- const nested = await Promise.all(reg.all().map((a) => a.discoverAgents()));
6455
- const agents = nested.flat();
6456
- console.log(`discovered ${agents.length} agent(s):
6457
- `);
6458
- for (const a of agents) {
6459
- console.log(` ${a.available ? "\u2713" : "\u2717"} ${a.agentId} (${a.displayName})${a.available ? "" : " \u2014 " + (a.unavailableReason ?? "unavailable")}`);
6460
- if (a.models.length) console.log(` models: ${a.models.map((m) => m.id).join(", ")}`);
6461
- }
6462
- }
6463
- function buildRegistry(adapters) {
6464
- const reg = new AdapterRegistry();
6465
- for (const a of autoDetectAdapters(adapters)) {
6466
- if (a.type === "openclaw-gateway") {
6467
- const token = a.gatewayToken ?? readOpenClawGatewayToken();
6468
- if (token) reg.register(new OpenClawGatewayAdapter({ gateway: { baseUrl: a.gatewayUrl ?? "ws://127.0.0.1:18789", token }, defaultAgent: a.defaultAgent ?? "main" }));
6469
- } else if (a.type === "claude-code" && a.claudeBaseUrl && a.claudeAuthToken) {
6470
- reg.register(new ClaudeCodeAdapter({ env: { baseUrl: a.claudeBaseUrl, authToken: a.claudeAuthToken, defaultModel: a.claudeDefaultModel ?? "claude-opus-4.6" } }));
6471
- } else if (a.type === "codex" && a.codexBaseUrl && a.codexApiKey) {
6472
- reg.register(new CodexAdapter({ env: { baseUrl: a.codexBaseUrl, apiKey: a.codexApiKey, defaultModel: a.codexDefaultModel ?? "gpt-5.5", wireApi: a.codexWireApi ?? "responses" } }));
6473
- } else if (a.type === "hermes") {
6474
- reg.register(new HermesAdapter({ env: { defaultModel: a.hermesModel, provider: a.hermesProvider } }));
6475
- } else if (a.type === "opencode") {
6476
- reg.register(new OpenCodeAdapter({ env: { binPath: a.opencodeBinPath, defaultModel: a.opencodeModel } }));
6477
- }
6478
- }
6479
- return reg;
6480
- }
6481
- function cmdAdapterAdd(type2, opts) {
6482
- const cfg = loadConfig();
6483
- let a;
6484
- switch (type2) {
6485
- case "openclaw":
6486
- case "openclaw-gateway":
6487
- a = { type: "openclaw-gateway", gatewayUrl: opts.gatewayUrl ?? "ws://127.0.0.1:18789", gatewayToken: opts.token, defaultAgent: opts.defaultAgent ?? "main" };
6488
- break;
6489
- case "claude-code":
6490
- if (!opts.baseUrl || !opts.token) return fail("claude-code needs --base-url and --token");
6491
- a = { type: "claude-code", claudeBaseUrl: opts.baseUrl, claudeAuthToken: opts.token, claudeDefaultModel: opts.model ?? "claude-opus-4.6" };
6492
- break;
6493
- case "codex":
6494
- if (!opts.baseUrl || !opts.apiKey) return fail("codex needs --base-url and --api-key");
6495
- a = { type: "codex", codexBaseUrl: opts.baseUrl, codexApiKey: opts.apiKey, codexDefaultModel: opts.model ?? "gpt-5.5", codexWireApi: opts.wireApi ?? "responses" };
6496
- break;
6497
- case "hermes":
6498
- a = { type: "hermes", hermesModel: opts.model, hermesProvider: opts.provider };
6499
- break;
6500
- case "opencode":
6501
- a = { type: "opencode", opencodeBinPath: opts.bin, opencodeModel: opts.model };
6502
- break;
6503
- default:
6504
- return fail(`unknown adapter type: ${type2} (openclaw|claude-code|codex|hermes|opencode)`);
6505
- }
6506
- cfg.adapters = cfg.adapters.filter((x) => x.type !== a.type);
6507
- cfg.adapters.push(a);
6508
- writeConfig(cfg);
6509
- console.log(`added ${a.type} adapter (${cfg.adapters.length} total)`);
6510
- }
6511
- function cmdAdapterList() {
6512
- const cfg = loadConfig();
6513
- const effective = autoDetectAdapters(cfg.adapters);
6514
- if (effective.length === 0) {
6515
- console.log("(no adapters available)");
6516
- return;
6517
- }
6518
- for (const a of effective) {
6519
- const auto = cfg.adapters.some((x) => x.type === a.type) ? "" : " [auto]";
6520
- console.log(`- ${a.type}${a.defaultAgent ? ` (agent: ${a.defaultAgent})` : ""}${auto}`);
6521
- }
6522
- }
6523
- function cmdPluginInstall(which) {
6524
- if (which !== "openclaw") return fail(`plugin install supports: openclaw (got: ${which})`);
6525
- const here = dirname5(fileURLToPath(import.meta.url));
6526
- const pluginSrc = join12(here, "..", "..", "openclaw-plugin");
6527
- if (!existsSync12(join12(pluginSrc, "dist", "index.js"))) {
6528
- return fail(`plugin not built. Run: cd ${pluginSrc} && pnpm build`);
6529
- }
6530
- const dist = join12(homedir10(), ".agent-phonon", "openclaw-plugin-dist");
6531
- rmSync3(dist, { recursive: true, force: true });
6532
- mkdirSync4(dist, { recursive: true });
6533
- cpSync(join12(pluginSrc, "dist"), join12(dist, "dist"), { recursive: true });
6534
- cpSync(join12(pluginSrc, "openclaw.plugin.json"), join12(dist, "openclaw.plugin.json"));
6535
- const pkg = JSON.parse(readFileSync5(join12(pluginSrc, "package.json"), "utf8"));
6536
- delete pkg.devDependencies;
6537
- writeFileSync4(join12(dist, "package.json"), JSON.stringify(pkg, null, 2));
6538
- console.log(`exported clean plugin \u2192 ${dist}`);
6539
- const r = spawnSync("openclaw", ["plugins", "install", "--force", dist], { stdio: "inherit" });
6540
- if (r.status === 0) console.log("\n\u2713 installed. Restart OpenClaw Gateway to load: systemctl --user restart openclaw-gateway.service");
6541
- else fail("openclaw plugins install failed");
6542
- }
6543
- function fail(msg) {
6544
- console.error("error:", msg);
6545
- process.exit(1);
6546
- }
6547
-
6548
- // src/cli.ts
6549
6545
  var [cmd, ...args] = process.argv.slice(2);
6550
6546
  function flag(name) {
6551
6547
  return args.includes(`--${name}`);