agenticros 0.3.1 → 0.3.4

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.
Files changed (55) hide show
  1. package/README.md +13 -5
  2. package/dist/__tests__/claude-config.test.d.ts +2 -0
  3. package/dist/__tests__/claude-config.test.d.ts.map +1 -0
  4. package/dist/__tests__/claude-config.test.js +77 -0
  5. package/dist/__tests__/claude-config.test.js.map +1 -0
  6. package/dist/__tests__/hermes-config.test.d.ts +2 -0
  7. package/dist/__tests__/hermes-config.test.d.ts.map +1 -0
  8. package/dist/__tests__/hermes-config.test.js +88 -0
  9. package/dist/__tests__/hermes-config.test.js.map +1 -0
  10. package/dist/__tests__/mcp-setup.test.d.ts +2 -0
  11. package/dist/__tests__/mcp-setup.test.d.ts.map +1 -0
  12. package/dist/__tests__/mcp-setup.test.js +23 -0
  13. package/dist/__tests__/mcp-setup.test.js.map +1 -0
  14. package/dist/commands/claude.d.ts +16 -0
  15. package/dist/commands/claude.d.ts.map +1 -0
  16. package/dist/commands/claude.js +30 -0
  17. package/dist/commands/claude.js.map +1 -0
  18. package/dist/commands/codex.d.ts +4 -4
  19. package/dist/commands/codex.d.ts.map +1 -1
  20. package/dist/commands/codex.js +21 -90
  21. package/dist/commands/codex.js.map +1 -1
  22. package/dist/commands/doctor.d.ts.map +1 -1
  23. package/dist/commands/doctor.js +30 -22
  24. package/dist/commands/doctor.js.map +1 -1
  25. package/dist/commands/hermes.d.ts +14 -0
  26. package/dist/commands/hermes.d.ts.map +1 -0
  27. package/dist/commands/hermes.js +21 -0
  28. package/dist/commands/hermes.js.map +1 -0
  29. package/dist/commands/init.d.ts +1 -1
  30. package/dist/commands/init.d.ts.map +1 -1
  31. package/dist/commands/init.js +16 -18
  32. package/dist/commands/init.js.map +1 -1
  33. package/dist/commands/mcp.d.ts +20 -0
  34. package/dist/commands/mcp.d.ts.map +1 -0
  35. package/dist/commands/mcp.js +31 -0
  36. package/dist/commands/mcp.js.map +1 -0
  37. package/dist/index.js +76 -0
  38. package/dist/index.js.map +1 -1
  39. package/dist/util/claude-config.d.ts +47 -0
  40. package/dist/util/claude-config.d.ts.map +1 -0
  41. package/dist/util/claude-config.js +227 -0
  42. package/dist/util/claude-config.js.map +1 -0
  43. package/dist/util/hermes-config.d.ts +51 -0
  44. package/dist/util/hermes-config.d.ts.map +1 -0
  45. package/dist/util/hermes-config.js +277 -0
  46. package/dist/util/hermes-config.js.map +1 -0
  47. package/dist/util/mcp-setup.d.ts +55 -0
  48. package/dist/util/mcp-setup.d.ts.map +1 -0
  49. package/dist/util/mcp-setup.js +235 -0
  50. package/dist/util/mcp-setup.js.map +1 -0
  51. package/package.json +2 -1
  52. package/runtime/BUNDLE.json +1 -1
  53. package/runtime/README.md +87 -10
  54. package/runtime/docs/cli.md +89 -2
  55. package/runtime/packages/agenticros-claude-code/README.md +35 -0
package/README.md CHANGED
@@ -3,14 +3,14 @@
3
3
  > agentic AI for ROS-powered robots
4
4
 
5
5
  `agenticros` is the unified command-line tool for AgenticROS — bring up a real
6
- robot or a simulated one, drive it from Claude Code, OpenAI Codex, or OpenClaw,
6
+ robot or a simulated one, drive it from Claude Code, OpenAI Codex, Hermes Agent, or OpenClaw,
7
7
  and keep your workspace healthy from a single binary.
8
8
 
9
9
  ```bash
10
10
  # Brand new machine: one command end-to-end
11
- npx agenticros init # workspace + plugin + Codex MCP + API key + doctor
11
+ npx agenticros init # workspace + plugin + MCP clients + API key + doctor
12
12
  agenticros # interactive menu
13
- agenticros codex setup # register AgenticROS MCP for OpenAI Codex CLI
13
+ agenticros mcp setup # register AgenticROS MCP for Codex, Hermes, and Claude
14
14
  agenticros up real # bring up the real-robot stack
15
15
  agenticros up sim-amr # bring up a simulated 2-wheel AMR
16
16
  agenticros up sim-arm # bring up a simulated 6-DOF arm
@@ -54,8 +54,14 @@ Three ways, listed easiest first:
54
54
  | `agenticros up sim-arm` | Bring up the simulated 6-DOF arm (UR5e-shaped, per-joint position control). |
55
55
  | `agenticros down` | Stop everything we started. |
56
56
  | `agenticros doctor` | Coloured health-check table; `--json` for CI. |
57
- | `agenticros codex setup` | Register AgenticROS MCP in `~/.codex/config.toml` (or `--project`). |
57
+ | `agenticros mcp setup` | Register AgenticROS MCP for Codex, Hermes, and Claude (primary). |
58
+ | `agenticros mcp doctor` | Validate all MCP client configs. |
59
+ | `agenticros codex setup` | Codex only — `~/.codex/config.toml` (or `--project`). |
58
60
  | `agenticros codex doctor` | Validate Codex MCP config paths and namespace policy. |
61
+ | `agenticros hermes setup` | Hermes only — `~/.hermes/config.yaml`. |
62
+ | `agenticros hermes doctor` | Validate Hermes MCP config paths and namespace policy. |
63
+ | `agenticros claude setup` | Claude only — Desktop + project `.mcp.json`. |
64
+ | `agenticros claude doctor` | Validate Claude MCP config paths and namespace policy. |
59
65
  | `agenticros status` | Snapshot of running components + last mode. |
60
66
  | `agenticros logs [target]` | Tail `camera` / `mcp` / `sim` / `rosbridge` / `gateway`. |
61
67
  | `agenticros config [show\|set\|edit\|reset]` | Read or edit `~/.agenticros/config.json`. |
@@ -77,7 +83,8 @@ walks through:
77
83
  5. Robot config (namespace, transport mode, sample `~/.agenticros/config.json`)
78
84
  6. OpenAI API key (paste once → `scripts/configure_agenticros.sh`)
79
85
  7. Codex MCP config (optional — `~/.codex/config.toml` and project `.codex/config.toml`)
80
- 8. Final `agenticros doctor` summary
86
+ 8. Hermes MCP config (optional — `~/.hermes/config.yaml`)
87
+ 9. Final `agenticros doctor` summary
81
88
 
82
89
  Every step is **idempotent**: it checks doctor first and skips the work if
83
90
  nothing is missing. Use `agenticros init --force` to redo everything.
@@ -87,6 +94,7 @@ nothing is missing. Use `agenticros init --force` to redo everything.
87
94
  - `~/.agenticros/config.json` — AgenticROS runtime config (transport mode,
88
95
  robot namespace, safety limits, teleop defaults). Edited via `agenticros config`.
89
96
  - `~/.codex/config.toml` — OpenAI Codex CLI MCP servers (written by `agenticros codex setup`).
97
+ - `~/.hermes/config.yaml` — Hermes Agent MCP servers (written by `agenticros hermes setup`).
90
98
  - `~/.agenticros/cli-state.json` — CLI's own state (last mode, last namespace,
91
99
  for the menu's "(yesterday)" hint).
92
100
  - `~/agenticros/` — the install dir when invoked via `npx`. Contains a copy of
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=claude-config.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-config.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/claude-config.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,77 @@
1
+ import { mkdtempSync, writeFileSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { describe, it } from "node:test";
5
+ import assert from "node:assert/strict";
6
+ import { buildAgenticrosMcpServerEntry, readClaudeAgenticrosConfig, upsertAgenticrosMcpJson, validateClaudeAgenticrosConfig, } from "../util/claude-config.js";
7
+ describe("claude-config", () => {
8
+ it("buildAgenticrosMcpServerEntry uses sh -c wrapper and empty namespace", () => {
9
+ const entry = buildAgenticrosMcpServerEntry("/opt/agenticros/dist/index.js");
10
+ assert.equal(entry["type"], "stdio");
11
+ assert.equal(entry["command"], "sh");
12
+ assert.deepEqual(entry["args"], [
13
+ "-c",
14
+ "node /opt/agenticros/dist/index.js 2>>/tmp/agenticros-mcp.log",
15
+ ]);
16
+ assert.deepEqual(entry["env"], { AGENTICROS_ROBOT_NAMESPACE: "" });
17
+ });
18
+ it("upsertAgenticrosMcpJson preserves other servers", () => {
19
+ const existing = JSON.stringify({
20
+ mcpServers: {
21
+ other: { type: "stdio", command: "echo" },
22
+ agenticros: { type: "stdio", command: "node", args: ["old.js"] },
23
+ },
24
+ });
25
+ const entry = buildAgenticrosMcpServerEntry("/abs/index.js");
26
+ const merged = upsertAgenticrosMcpJson(existing, entry);
27
+ const parsed = JSON.parse(merged);
28
+ assert.ok(parsed.mcpServers.other);
29
+ assert.match(JSON.stringify(parsed.mcpServers.agenticros), /\/abs\/index.js/);
30
+ });
31
+ it("readClaudeAgenticrosConfig parses sh -c args", () => {
32
+ const dir = mkdtempSync(join(tmpdir(), "agenticros-claude-"));
33
+ const path = join(dir, ".mcp.json");
34
+ writeFileSync(path, JSON.stringify({
35
+ mcpServers: {
36
+ agenticros: {
37
+ type: "stdio",
38
+ command: "sh",
39
+ args: ["-c", "node /tmp/index.js 2>>/tmp/agenticros-mcp.log"],
40
+ env: { AGENTICROS_ROBOT_NAMESPACE: "" },
41
+ },
42
+ },
43
+ }));
44
+ const cfg = readClaudeAgenticrosConfig(path, "project");
45
+ assert.equal(cfg.command, "sh");
46
+ assert.deepEqual(cfg.args, ["-c", "node /tmp/index.js 2>>/tmp/agenticros-mcp.log"]);
47
+ assert.equal(cfg.env?.["AGENTICROS_ROBOT_NAMESPACE"], "");
48
+ });
49
+ it("validateClaudeAgenticrosConfig flags relative paths and hardcoded namespace", () => {
50
+ const cfg = {
51
+ configPath: "/tmp/.mcp.json",
52
+ exists: true,
53
+ target: "project",
54
+ command: "sh",
55
+ args: ["-c", "node packages/agenticros-claude-code/dist/index.js"],
56
+ env: { AGENTICROS_ROBOT_NAMESPACE: "robotabc" },
57
+ };
58
+ const v = validateClaudeAgenticrosConfig(cfg, "/abs/index.js");
59
+ assert.equal(v.ok, false);
60
+ assert.ok(v.issues.some((i) => i.message.includes("relative")));
61
+ assert.ok(v.issues.some((i) => i.message.includes("hardcoded")));
62
+ });
63
+ it("validateClaudeAgenticrosConfig passes for correct absolute config", () => {
64
+ const cfg = {
65
+ configPath: "/tmp/.mcp.json",
66
+ exists: true,
67
+ target: "project",
68
+ command: "sh",
69
+ args: ["-c", "node /abs/index.js 2>>/tmp/agenticros-mcp.log"],
70
+ env: { AGENTICROS_ROBOT_NAMESPACE: "" },
71
+ };
72
+ const v = validateClaudeAgenticrosConfig(cfg, "/abs/index.js");
73
+ assert.equal(v.ok, true);
74
+ assert.equal(v.issues.length, 0);
75
+ });
76
+ });
77
+ //# sourceMappingURL=claude-config.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-config.test.js","sourceRoot":"","sources":["../../src/__tests__/claude-config.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=hermes-config.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hermes-config.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/hermes-config.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,88 @@
1
+ import { mkdtempSync, writeFileSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { describe, it } from "node:test";
5
+ import assert from "node:assert/strict";
6
+ import { buildAgenticrosMcpYamlBlock, readHermesAgenticrosConfig, upsertAgenticrosBlock, validateHermesAgenticrosConfig, } from "../util/hermes-config.js";
7
+ describe("hermes-config", () => {
8
+ it("buildAgenticrosMcpYamlBlock uses absolute path and empty namespace", () => {
9
+ const block = buildAgenticrosMcpYamlBlock("/opt/agenticros/dist/index.js");
10
+ assert.match(block, /args: \["\/opt\/agenticros\/dist\/index.js"\]/);
11
+ assert.match(block, /AGENTICROS_ROBOT_NAMESPACE: ""/);
12
+ assert.match(block, /connect_timeout: 60/);
13
+ assert.match(block, /timeout: 120/);
14
+ });
15
+ it("upsertAgenticrosBlock replaces existing agenticros section", () => {
16
+ const existing = `llm:
17
+ provider: openrouter
18
+
19
+ mcp_servers:
20
+ other:
21
+ command: "echo"
22
+ agenticros:
23
+ command: "node"
24
+ args: ["relative/path.js"]
25
+ env:
26
+ AGENTICROS_ROBOT_NAMESPACE: "robot123"
27
+ `;
28
+ const block = buildAgenticrosMcpYamlBlock("/abs/index.js");
29
+ const merged = upsertAgenticrosBlock(existing, block);
30
+ assert.match(merged, /llm:/);
31
+ assert.match(merged, /other:/);
32
+ assert.match(merged, /\/abs\/index.js/);
33
+ assert.doesNotMatch(merged, /relative\/path\.js/);
34
+ assert.match(merged, /AGENTICROS_ROBOT_NAMESPACE: ""/);
35
+ });
36
+ it("upsertAgenticrosBlock appends mcp_servers when missing", () => {
37
+ const existing = "llm:\n provider: ollama\n";
38
+ const block = buildAgenticrosMcpYamlBlock("/abs/index.js");
39
+ const merged = upsertAgenticrosBlock(existing, block);
40
+ assert.match(merged, /mcp_servers:/);
41
+ assert.match(merged, /\/abs\/index.js/);
42
+ });
43
+ it("readHermesAgenticrosConfig parses stdio args and env", () => {
44
+ const dir = mkdtempSync(join(tmpdir(), "agenticros-hermes-"));
45
+ const path = join(dir, "config.yaml");
46
+ writeFileSync(path, `mcp_servers:
47
+ agenticros:
48
+ command: "node"
49
+ args: ["/tmp/index.js"]
50
+ env:
51
+ AGENTICROS_ROBOT_NAMESPACE: ""
52
+ connect_timeout: 60
53
+ timeout: 120
54
+ `);
55
+ const cfg = readHermesAgenticrosConfig(path);
56
+ assert.equal(cfg.command, "node");
57
+ assert.deepEqual(cfg.args, ["/tmp/index.js"]);
58
+ assert.equal(cfg.env?.["AGENTICROS_ROBOT_NAMESPACE"], "");
59
+ assert.equal(cfg.connectTimeout, 60);
60
+ assert.equal(cfg.timeout, 120);
61
+ });
62
+ it("validateHermesAgenticrosConfig flags relative paths and hardcoded namespace", () => {
63
+ const cfg = {
64
+ configPath: "/tmp/config.yaml",
65
+ exists: true,
66
+ command: "node",
67
+ args: ["packages/agenticros-claude-code/dist/index.js"],
68
+ env: { AGENTICROS_ROBOT_NAMESPACE: "robotabc" },
69
+ };
70
+ const v = validateHermesAgenticrosConfig(cfg, "/abs/index.js");
71
+ assert.equal(v.ok, false);
72
+ assert.ok(v.issues.some((i) => i.message.includes("relative")));
73
+ assert.ok(v.issues.some((i) => i.message.includes("hardcoded")));
74
+ });
75
+ it("validateHermesAgenticrosConfig passes for correct absolute config", () => {
76
+ const cfg = {
77
+ configPath: "/tmp/config.yaml",
78
+ exists: true,
79
+ command: "node",
80
+ args: ["/abs/index.js"],
81
+ env: { AGENTICROS_ROBOT_NAMESPACE: "" },
82
+ };
83
+ const v = validateHermesAgenticrosConfig(cfg, "/abs/index.js");
84
+ assert.equal(v.ok, true);
85
+ assert.equal(v.issues.length, 0);
86
+ });
87
+ });
88
+ //# sourceMappingURL=hermes-config.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hermes-config.test.js","sourceRoot":"","sources":["../../src/__tests__/hermes-config.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=mcp-setup.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-setup.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/mcp-setup.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,23 @@
1
+ import { describe, it } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { buildMcpDoctorChecks, resolveMcpHosts } from "../util/mcp-setup.js";
4
+ describe("mcp-setup", () => {
5
+ it("resolveMcpHosts defaults to all three hosts", () => {
6
+ assert.deepEqual(resolveMcpHosts({}), ["codex", "hermes", "claude"]);
7
+ });
8
+ it("resolveMcpHosts honors explicit host flags", () => {
9
+ assert.deepEqual(resolveMcpHosts({ codex: true, hermes: false, claude: false }), ["codex"]);
10
+ assert.deepEqual(resolveMcpHosts({ hermes: true }), ["hermes"]);
11
+ assert.deepEqual(resolveMcpHosts({ claude: true }), ["claude"]);
12
+ });
13
+ it("resolveMcpHosts uses project scope for legacy codex setup", () => {
14
+ assert.deepEqual(resolveMcpHosts({ codexScope: "project" }), ["codex"]);
15
+ });
16
+ it("buildMcpDoctorChecks filters by host", () => {
17
+ const all = buildMcpDoctorChecks("/abs/index.js", "/repo");
18
+ const codexOnly = buildMcpDoctorChecks("/abs/index.js", "/repo", ["codex"]);
19
+ assert.ok(all.length > codexOnly.length);
20
+ assert.ok(codexOnly.every((c) => c.id.startsWith("codex")));
21
+ });
22
+ });
23
+ //# sourceMappingURL=mcp-setup.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-setup.test.js","sourceRoot":"","sources":["../../src/__tests__/mcp-setup.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AAExC,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE7E,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,CAAC,SAAS,CAAC,eAAe,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,CAAC,SAAS,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;QAC5F,MAAM,CAAC,SAAS,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;QAChE,MAAM,CAAC,SAAS,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,MAAM,CAAC,SAAS,CAAC,eAAe,CAAC,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,GAAG,GAAG,oBAAoB,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;QAC3D,MAAM,SAAS,GAAG,oBAAoB,CAAC,eAAe,EAAE,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;QAC5E,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;QACzC,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * `agenticros claude` — thin wrapper around unified MCP setup (Claude hosts).
3
+ */
4
+ import { claudeOnPath } from "../util/mcp-setup.js";
5
+ export interface ClaudeSetupOptions {
6
+ project?: boolean;
7
+ desktop?: boolean;
8
+ quiet?: boolean;
9
+ }
10
+ export interface ClaudeDoctorOptions {
11
+ json?: boolean;
12
+ }
13
+ export { claudeOnPath };
14
+ export declare function claudeSetupCommand(opts?: ClaudeSetupOptions): Promise<void>;
15
+ export declare function claudeDoctorCommand(opts?: ClaudeDoctorOptions): Promise<number>;
16
+ //# sourceMappingURL=claude.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../../src/commands/claude.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,YAAY,EAAqC,MAAM,sBAAsB,CAAC;AAGvF,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,OAAO,EAAE,YAAY,EAAE,CAAC;AAExB,wBAAsB,kBAAkB,CAAC,IAAI,GAAE,kBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAerF;AAED,wBAAsB,mBAAmB,CAAC,IAAI,GAAE,mBAAwB,GAAG,OAAO,CAAC,MAAM,CAAC,CAMzF"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * `agenticros claude` — thin wrapper around unified MCP setup (Claude hosts).
3
+ */
4
+ import { header } from "../util/logger.js";
5
+ import { claudeOnPath, mcpDoctorCommand, mcpSetupCommand } from "../util/mcp-setup.js";
6
+ import { getCliPaths } from "../util/paths.js";
7
+ export { claudeOnPath };
8
+ export async function claudeSetupCommand(opts = {}) {
9
+ const paths = getCliPaths();
10
+ const desktopOnly = opts.desktop && !opts.project;
11
+ const projectOnly = opts.project && !opts.desktop;
12
+ await mcpSetupCommand({
13
+ codex: false,
14
+ hermes: false,
15
+ claude: true,
16
+ all: false,
17
+ project: projectOnly || (!desktopOnly && !!paths.repoRoot),
18
+ desktop: desktopOnly || !projectOnly,
19
+ repoRoot: paths.repoRoot,
20
+ quiet: opts.quiet,
21
+ });
22
+ }
23
+ export async function claudeDoctorCommand(opts = {}) {
24
+ if (!opts.json) {
25
+ header("Claude MCP doctor");
26
+ }
27
+ const paths = getCliPaths();
28
+ return mcpDoctorCommand({ json: opts.json, hosts: ["claude"], repoRoot: paths.repoRoot });
29
+ }
30
+ //# sourceMappingURL=claude.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude.js","sourceRoot":"","sources":["../../src/commands/claude.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvF,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAY/C,OAAO,EAAE,YAAY,EAAE,CAAC;AAExB,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,OAA2B,EAAE;IACpE,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;IAC5B,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;IAClD,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;IAElD,MAAM,eAAe,CAAC;QACpB,KAAK,EAAE,KAAK;QACZ,MAAM,EAAE,KAAK;QACb,MAAM,EAAE,IAAI;QACZ,GAAG,EAAE,KAAK;QACV,OAAO,EAAE,WAAW,IAAI,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC;QAC1D,OAAO,EAAE,WAAW,IAAI,CAAC,WAAW;QACpC,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,KAAK,EAAE,IAAI,CAAC,KAAK;KAClB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,OAA4B,EAAE;IACtE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACf,MAAM,CAAC,mBAAmB,CAAC,CAAC;IAC9B,CAAC;IACD,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;IAC5B,OAAO,gBAAgB,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC5F,CAAC"}
@@ -1,18 +1,18 @@
1
1
  /**
2
- * `agenticros codex` — configure OpenAI Codex CLI to use the AgenticROS MCP server.
2
+ * `agenticros codex` — thin wrapper around unified MCP setup (Codex host).
3
3
  */
4
4
  import { type CodexConfigScope } from "../util/codex-config.js";
5
+ import { codexOnPath } from "../util/mcp-setup.js";
6
+ export type { CodexConfigScope };
5
7
  export interface CodexSetupOptions {
6
8
  scope?: CodexConfigScope;
7
- /** Skip interactive confirmation when codex CLI is missing. */
8
9
  yes?: boolean;
9
- /** Suppress the section header (e.g. when called from `agenticros init`). */
10
10
  quiet?: boolean;
11
11
  }
12
12
  export interface CodexDoctorOptions {
13
13
  json?: boolean;
14
14
  }
15
- export declare function codexOnPath(): Promise<boolean>;
15
+ export { codexOnPath };
16
16
  export declare function codexSetupCommand(opts?: CodexSetupOptions): Promise<void>;
17
17
  export declare function codexDoctorCommand(opts?: CodexDoctorOptions): Promise<number>;
18
18
  //# sourceMappingURL=codex.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../../src/commands/codex.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EACL,KAAK,gBAAgB,EAOtB,MAAM,yBAAyB,CAAC;AAKjC,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,+DAA+D;IAC/D,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,6EAA6E;IAC7E,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAsB,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAOpD;AAED,wBAAsB,iBAAiB,CAAC,IAAI,GAAE,iBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgCnF;AAED,wBAAsB,kBAAkB,CAAC,IAAI,GAAE,kBAAuB,GAAG,OAAO,CAAC,MAAM,CAAC,CAuDvF"}
1
+ {"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../../src/commands/codex.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,OAAO,EAAE,WAAW,EAAqC,MAAM,sBAAsB,CAAC;AAEtF,YAAY,EAAE,gBAAgB,EAAE,CAAC;AAEjC,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,OAAO,EAAE,WAAW,EAAE,CAAC;AAEvB,wBAAsB,iBAAiB,CAAC,IAAI,GAAE,iBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBnF;AAED,wBAAsB,kBAAkB,CAAC,IAAI,GAAE,kBAAuB,GAAG,OAAO,CAAC,MAAM,CAAC,CAKvF"}
@@ -1,99 +1,30 @@
1
1
  /**
2
- * `agenticros codex` — configure OpenAI Codex CLI to use the AgenticROS MCP server.
2
+ * `agenticros codex` — thin wrapper around unified MCP setup (Codex host).
3
3
  */
4
- import { execa } from "execa";
5
- import { globalCodexConfigPath, projectCodexConfigPath, readCodexAgenticrosConfig, resolveCodexConfigPath, validateCodexAgenticrosConfig, writeCodexAgenticrosConfig, } from "../util/codex-config.js";
6
- import { findMcpEntry } from "../util/mcp-discovery.js";
7
- import { getCliPaths } from "../util/paths.js";
8
- import { colors, header, info, ok, warn, err } from "../util/logger.js";
9
- export async function codexOnPath() {
10
- try {
11
- const { exitCode } = await execa("codex", ["--version"], { reject: false });
12
- return exitCode === 0;
13
- }
14
- catch {
15
- return false;
16
- }
17
- }
4
+ import { header } from "../util/logger.js";
5
+ import { codexOnPath, mcpDoctorCommand, mcpSetupCommand } from "../util/mcp-setup.js";
6
+ export { codexOnPath };
18
7
  export async function codexSetupCommand(opts = {}) {
19
- if (!opts.quiet) {
20
- header("Configure Codex MCP");
21
- }
22
- const mcpEntry = findMcpEntry();
23
- if (!mcpEntry) {
24
- err("AgenticROS MCP server is not built.");
25
- info("Run `pnpm --filter @agenticros/claude-code build` or `agenticros init` first.");
26
- process.exit(1);
27
- }
28
8
  const scope = opts.scope ?? "global";
29
- const configPath = resolveCodexConfigPath(scope);
30
- writeCodexAgenticrosConfig(configPath, mcpEntry, { namespace: "" });
31
- ok(`Wrote Codex MCP config (${scope}): ${configPath}`);
32
- info(`MCP server: ${mcpEntry}`);
33
- const hasCodex = await codexOnPath();
34
- if (hasCodex) {
35
- info("Codex CLI detected. Verify in a Codex session with `/mcp` — you should see `agenticros` connected.");
36
- }
37
- else {
38
- warn("Codex CLI not found on PATH.");
39
- info("Install from https://developers.openai.com/codex/ then run `/mcp` in a Codex session.");
40
- }
41
- if (scope === "global") {
42
- dimHint("Tip: for a repo-scoped config instead, run `agenticros codex setup --project` from the project root.");
43
- }
9
+ if (scope === "project") {
10
+ await mcpSetupCommand({
11
+ codex: true,
12
+ codexScope: "project",
13
+ quiet: opts.quiet,
14
+ });
15
+ return;
16
+ }
17
+ await mcpSetupCommand({
18
+ codex: true,
19
+ hermes: false,
20
+ claude: false,
21
+ quiet: opts.quiet,
22
+ });
44
23
  }
45
24
  export async function codexDoctorCommand(opts = {}) {
46
- const paths = getCliPaths();
47
- const mcpEntry = findMcpEntry();
48
- const candidates = [
49
- { label: "global", path: globalCodexConfigPath() },
50
- ];
51
- if (paths.repoRoot) {
52
- candidates.push({ label: "project", path: projectCodexConfigPath(paths.repoRoot) });
53
- }
54
- const results = candidates.map((c) => {
55
- const cfg = readCodexAgenticrosConfig(c.path);
56
- const validation = validateCodexAgenticrosConfig(cfg, mcpEntry);
57
- return { ...c, cfg, validation };
58
- });
59
- if (opts.json) {
60
- process.stdout.write(`${JSON.stringify({ results, mcpEntry }, null, 2)}\n`);
61
- const anyRed = results.some((r) => r.validation.issues.some((i) => i.severity === "red"));
62
- return anyRed ? 1 : 0;
25
+ if (!opts.json) {
26
+ header("Codex MCP doctor");
63
27
  }
64
- header("Codex MCP doctor");
65
- if (!mcpEntry) {
66
- err("MCP server not built.");
67
- return 1;
68
- }
69
- info(`Expected MCP entry: ${mcpEntry}\n`);
70
- let exitCode = 0;
71
- for (const r of results) {
72
- process.stdout.write(`${colors.bold(r.label)} (${r.path})\n`);
73
- if (!r.cfg.exists) {
74
- process.stdout.write(` ${colors.yellow("○")} Config file not present\n`);
75
- process.stdout.write(` ${colors.dim("→ Run `agenticros codex setup" + (r.label === "project" ? " --project" : "") + "`")}\n`);
76
- if (r.label === "global")
77
- exitCode = 1;
78
- continue;
79
- }
80
- if (r.validation.ok) {
81
- process.stdout.write(` ${colors.green("✓")} agenticros MCP configured correctly\n`);
82
- continue;
83
- }
84
- for (const issue of r.validation.issues) {
85
- const icon = issue.severity === "red" ? colors.red("✗") : colors.yellow("○");
86
- process.stdout.write(` ${icon} ${issue.message}\n`);
87
- if (issue.hint) {
88
- process.stdout.write(` ${colors.dim("→ " + issue.hint)}\n`);
89
- }
90
- if (issue.severity === "red")
91
- exitCode = 1;
92
- }
93
- }
94
- return exitCode;
95
- }
96
- function dimHint(message) {
97
- process.stdout.write(`${colors.dim(message)}\n`);
28
+ return mcpDoctorCommand({ json: opts.json, hosts: ["codex"] });
98
29
  }
99
30
  //# sourceMappingURL=codex.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"codex.js","sourceRoot":"","sources":["../../src/commands/codex.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"codex.js","sourceRoot":"","sources":["../../src/commands/codex.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AActF,OAAO,EAAE,WAAW,EAAE,CAAC;AAEvB,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,OAA0B,EAAE;IAClE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,QAAQ,CAAC;IAErC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,eAAe,CAAC;YACpB,KAAK,EAAE,IAAI;YACX,UAAU,EAAE,SAAS;YACrB,KAAK,EAAE,IAAI,CAAC,KAAK;SAClB,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IAED,MAAM,eAAe,CAAC;QACpB,KAAK,EAAE,IAAI;QACX,MAAM,EAAE,KAAK;QACb,MAAM,EAAE,KAAK;QACb,KAAK,EAAE,IAAI,CAAC,KAAK;KAClB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,OAA2B,EAAE;IACpE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACf,MAAM,CAAC,kBAAkB,CAAC,CAAC;IAC7B,CAAC;IACD,OAAO,gBAAgB,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;AACjE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAoBH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;AAElD,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;CACzD;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CA+BxE;AAED,sFAAsF;AACtF,wBAAsB,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC,CAGrD;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,YAAY,CAAC,CAgZ7D"}
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAyBH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;AAElD,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;CACzD;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CA+BxE;AAED,sFAAsF;AACtF,wBAAsB,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC,CAGrD;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,YAAY,CAAC,CA0Z7D"}
@@ -16,8 +16,8 @@ import { colors, header, ok, warn, err, info } from "../util/logger.js";
16
16
  import { activeConfigPath, profilesDir, readActiveMode } from "../util/profiles.js";
17
17
  import { ensureToolsAlsoAllow, readAgenticrosContractTools, readOpenclawConfig, } from "../util/openclaw-config.js";
18
18
  import { listSkills } from "../util/skills.js";
19
- import { buildCodexDoctorChecks } from "../util/codex-config.js";
20
19
  import { findMcpEntry } from "../util/mcp-discovery.js";
20
+ import { buildMcpDoctorChecks, claudeOnPath, codexOnPath, hermesOnPath, } from "../util/mcp-setup.js";
21
21
  export async function doctorCommand(opts) {
22
22
  const report = await runDoctorChecks();
23
23
  if (opts.json) {
@@ -206,28 +206,36 @@ export async function runDoctorChecks() {
206
206
  : "Fine for real-robot mode if the value matches your robot's namespace.",
207
207
  });
208
208
  }
209
- // Codex CLI MCP config.
209
+ // MCP client configs (Codex, Hermes, Claude).
210
210
  const mcpEntry = findMcpEntry();
211
- checks.push(...buildCodexDoctorChecks(mcpEntry, paths.repoRoot));
212
- try {
213
- const { exitCode } = await execa("codex", ["--version"], { reject: false });
214
- checks.push({
215
- id: "codex-cli",
216
- label: exitCode === 0 ? "Codex CLI installed" : "Codex CLI not detected",
217
- severity: exitCode === 0 ? "green" : "yellow",
218
- hint: exitCode === 0
219
- ? undefined
220
- : "Install from https://developers.openai.com/codex/ then run `agenticros codex setup`.",
221
- });
222
- }
223
- catch {
224
- checks.push({
225
- id: "codex-cli",
226
- label: "Codex CLI not detected",
227
- severity: "yellow",
228
- hint: "Install from https://developers.openai.com/codex/ then run `agenticros codex setup`.",
229
- });
230
- }
211
+ checks.push(...buildMcpDoctorChecks(mcpEntry, paths.repoRoot));
212
+ const hasCodex = await codexOnPath();
213
+ checks.push({
214
+ id: "codex-cli",
215
+ label: hasCodex ? "Codex CLI installed" : "Codex CLI not detected",
216
+ severity: hasCodex ? "green" : "yellow",
217
+ hint: hasCodex
218
+ ? undefined
219
+ : "Install from https://developers.openai.com/codex/ then run `agenticros mcp setup --codex`.",
220
+ });
221
+ const hasHermes = await hermesOnPath();
222
+ checks.push({
223
+ id: "hermes-cli",
224
+ label: hasHermes ? "Hermes CLI installed" : "Hermes CLI not detected",
225
+ severity: hasHermes ? "green" : "yellow",
226
+ hint: hasHermes
227
+ ? undefined
228
+ : "Install from https://github.com/NousResearch/hermes-agent then run `agenticros mcp setup --hermes`.",
229
+ });
230
+ const hasClaude = await claudeOnPath();
231
+ checks.push({
232
+ id: "claude-cli",
233
+ label: hasClaude ? "Claude Code CLI installed" : "Claude Code CLI not detected",
234
+ severity: hasClaude ? "green" : "yellow",
235
+ hint: hasClaude
236
+ ? undefined
237
+ : "Install from https://claude.com/product/claude-code then run `agenticros mcp setup --claude`.",
238
+ });
231
239
  // OpenAI key.
232
240
  const home = process.env["HOME"] ?? "";
233
241
  const authFile = join(home, ".openclaw", "agents", "main", "agent", "auth-profiles.json");