agenticros 0.3.0 → 0.3.3

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 (45) hide show
  1. package/README.md +15 -5
  2. package/dist/__tests__/codex-config.test.d.ts +2 -0
  3. package/dist/__tests__/codex-config.test.d.ts.map +1 -0
  4. package/dist/__tests__/codex-config.test.js +76 -0
  5. package/dist/__tests__/codex-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/commands/codex.d.ts +18 -0
  11. package/dist/commands/codex.d.ts.map +1 -0
  12. package/dist/commands/codex.js +99 -0
  13. package/dist/commands/codex.js.map +1 -0
  14. package/dist/commands/doctor.d.ts.map +1 -1
  15. package/dist/commands/doctor.js +38 -1
  16. package/dist/commands/doctor.js.map +1 -1
  17. package/dist/commands/hermes.d.ts +14 -0
  18. package/dist/commands/hermes.d.ts.map +1 -0
  19. package/dist/commands/hermes.js +84 -0
  20. package/dist/commands/hermes.js.map +1 -0
  21. package/dist/commands/init.d.ts +3 -1
  22. package/dist/commands/init.d.ts.map +1 -1
  23. package/dist/commands/init.js +46 -1
  24. package/dist/commands/init.js.map +1 -1
  25. package/dist/commands/skills.js +2 -2
  26. package/dist/commands/skills.js.map +1 -1
  27. package/dist/index.js +39 -0
  28. package/dist/index.js.map +1 -1
  29. package/dist/menu.js +1 -1
  30. package/dist/menu.js.map +1 -1
  31. package/dist/util/codex-config.d.ts +56 -0
  32. package/dist/util/codex-config.d.ts.map +1 -0
  33. package/dist/util/codex-config.js +326 -0
  34. package/dist/util/codex-config.js.map +1 -0
  35. package/dist/util/hermes-config.d.ts +51 -0
  36. package/dist/util/hermes-config.d.ts.map +1 -0
  37. package/dist/util/hermes-config.js +277 -0
  38. package/dist/util/hermes-config.js.map +1 -0
  39. package/package.json +4 -1
  40. package/runtime/BUNDLE.json +1 -1
  41. package/runtime/README.md +104 -14
  42. package/runtime/docs/cli.md +50 -3
  43. package/runtime/packages/agenticros-claude-code/README.md +53 -8
  44. package/runtime/packages/agenticros-claude-code/package.json +11 -1
  45. package/runtime/packages/core/README.md +12 -2
@@ -0,0 +1,326 @@
1
+ /**
2
+ * Read/write helpers for OpenAI Codex CLI MCP config (`config.toml`).
3
+ *
4
+ * Codex stores MCP servers under `[mcp_servers.<name>]` in either
5
+ * `~/.codex/config.toml` (global) or `<project>/.codex/config.toml` (project).
6
+ * We only manage the `agenticros` entry — other servers are preserved.
7
+ */
8
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
9
+ import { homedir } from "node:os";
10
+ import { dirname, isAbsolute, join, resolve } from "node:path";
11
+ const AGENTICROS_BLOCK_START = "[mcp_servers.agenticros]";
12
+ const AGENTICROS_ENV_BLOCK = "[mcp_servers.agenticros.env]";
13
+ /** Global Codex config: `~/.codex/config.toml`. */
14
+ export function globalCodexConfigPath() {
15
+ return join(homedir(), ".codex", "config.toml");
16
+ }
17
+ /** Project-scoped Codex config: `<cwd>/.codex/config.toml`. */
18
+ export function projectCodexConfigPath(cwd = process.cwd()) {
19
+ return join(cwd, ".codex", "config.toml");
20
+ }
21
+ export function resolveCodexConfigPath(scope, cwd = process.cwd()) {
22
+ return scope === "global" ? globalCodexConfigPath() : projectCodexConfigPath(cwd);
23
+ }
24
+ /**
25
+ * Build the TOML block for the AgenticROS MCP server. Uses an absolute path
26
+ * to index.js (required by Codex) and leaves namespace empty so
27
+ * `~/.agenticros/config.json` / `agenticros mode` drives the active robot.
28
+ */
29
+ export function buildAgenticrosMcpTomlBlock(mcpEntryAbs, namespace = "") {
30
+ const escaped = mcpEntryAbs.replace(/\\/g, "\\\\");
31
+ const shellCmd = `node ${escaped} 2>>/tmp/agenticros-mcp.log`;
32
+ const nsValue = namespace.replace(/"/g, '\\"');
33
+ return `${AGENTICROS_BLOCK_START}
34
+ command = "sh"
35
+ args = ["-c", "${shellCmd.replace(/"/g, '\\"')}"]
36
+ enabled = true
37
+ startup_timeout_sec = 30
38
+
39
+ ${AGENTICROS_ENV_BLOCK}
40
+ AGENTICROS_ROBOT_NAMESPACE = "${nsValue}"
41
+ `;
42
+ }
43
+ /** Insert or replace the agenticros MCP block, preserving other TOML content. */
44
+ export function upsertAgenticrosBlock(existingContent, block) {
45
+ const trimmedBlock = block.trimEnd() + "\n";
46
+ if (!existingContent?.trim()) {
47
+ return trimmedBlock;
48
+ }
49
+ const lines = existingContent.split("\n");
50
+ const out = [];
51
+ let i = 0;
52
+ let replaced = false;
53
+ while (i < lines.length) {
54
+ const line = lines[i] ?? "";
55
+ if (line.trim() === AGENTICROS_BLOCK_START) {
56
+ if (!replaced) {
57
+ out.push(trimmedBlock.trimEnd());
58
+ replaced = true;
59
+ }
60
+ i++;
61
+ while (i < lines.length) {
62
+ const next = lines[i] ?? "";
63
+ const trimmed = next.trim();
64
+ if (/^\[mcp_servers\./.test(trimmed)) {
65
+ if (trimmed !== AGENTICROS_BLOCK_START && trimmed !== AGENTICROS_ENV_BLOCK) {
66
+ break;
67
+ }
68
+ }
69
+ i++;
70
+ }
71
+ continue;
72
+ }
73
+ out.push(line);
74
+ i++;
75
+ }
76
+ if (!replaced) {
77
+ const sep = out.length > 0 && out[out.length - 1]?.trim() !== "" ? "\n" : "";
78
+ return out.join("\n") + sep + trimmedBlock;
79
+ }
80
+ return out.join("\n").replace(/\n{3,}/g, "\n\n").trimEnd() + "\n";
81
+ }
82
+ /** Parse the agenticros MCP section from a Codex config.toml file. */
83
+ export function readCodexAgenticrosConfig(configPath) {
84
+ const base = { configPath, exists: existsSync(configPath) };
85
+ if (!base.exists)
86
+ return base;
87
+ let content;
88
+ try {
89
+ content = readFileSync(configPath, "utf8");
90
+ }
91
+ catch {
92
+ return base;
93
+ }
94
+ const serverSection = extractSection(content, AGENTICROS_BLOCK_START, AGENTICROS_ENV_BLOCK);
95
+ const envSection = extractSection(content, AGENTICROS_ENV_BLOCK, /^\[/);
96
+ base.command = parseTomlString(serverSection, "command");
97
+ base.args = parseTomlStringArray(serverSection, "args");
98
+ base.enabled = parseTomlBoolean(serverSection, "enabled");
99
+ base.env = parseTomlEnvBlock(envSection);
100
+ return base;
101
+ }
102
+ export function writeCodexAgenticrosConfig(configPath, mcpEntryAbs, options) {
103
+ const abs = resolve(mcpEntryAbs);
104
+ const block = buildAgenticrosMcpTomlBlock(abs, options?.namespace ?? "");
105
+ const existing = existsSync(configPath) ? readFileSync(configPath, "utf8") : null;
106
+ const merged = upsertAgenticrosBlock(existing, block);
107
+ mkdirSync(dirname(configPath), { recursive: true });
108
+ writeFileSync(configPath, merged, "utf8");
109
+ }
110
+ /** Validate Codex agenticros MCP config against expected MCP binary path. */
111
+ export function validateCodexAgenticrosConfig(cfg, mcpEntryExpected) {
112
+ const issues = [];
113
+ if (!cfg.exists) {
114
+ issues.push({
115
+ severity: "yellow",
116
+ message: `Codex config missing (${cfg.configPath})`,
117
+ hint: "Run `agenticros codex setup` to register the AgenticROS MCP server.",
118
+ });
119
+ return { ok: false, issues };
120
+ }
121
+ if (!cfg.command && (!cfg.args || cfg.args.length === 0)) {
122
+ issues.push({
123
+ severity: "red",
124
+ message: "Codex [mcp_servers.agenticros] has no command or args",
125
+ hint: "Run `agenticros codex setup` to repair the entry.",
126
+ });
127
+ }
128
+ const mcpPathInArgs = extractMcpPathFromArgs(cfg.args ?? []);
129
+ if (mcpPathInArgs && !isAbsolute(mcpPathInArgs.split(/\s/)[0] ?? "")) {
130
+ issues.push({
131
+ severity: "red",
132
+ message: "Codex MCP path is relative — Codex cwd is not the repo root",
133
+ hint: "Run `agenticros codex setup` to rewrite with an absolute path.",
134
+ });
135
+ }
136
+ if (mcpEntryExpected && mcpPathInArgs) {
137
+ const expected = resolve(mcpEntryExpected);
138
+ const actual = resolve(mcpPathInArgs.split(/\s/)[0] ?? mcpPathInArgs);
139
+ if (actual !== expected && !existsSync(actual)) {
140
+ issues.push({
141
+ severity: "red",
142
+ message: "Codex MCP path does not point to a built server",
143
+ hint: `Expected ${expected}. Run \`agenticros codex setup\`.`,
144
+ });
145
+ }
146
+ else if (actual !== expected) {
147
+ issues.push({
148
+ severity: "yellow",
149
+ message: "Codex MCP path differs from the CLI-resolved MCP entry",
150
+ hint: `CLI expects ${expected}. Run \`agenticros codex setup\` to sync.`,
151
+ });
152
+ }
153
+ }
154
+ else if (mcpEntryExpected && !mcpPathInArgs) {
155
+ issues.push({
156
+ severity: "yellow",
157
+ message: "Could not parse MCP server path from Codex config",
158
+ hint: "Run `agenticros codex setup` to rewrite the entry.",
159
+ });
160
+ }
161
+ const ns = (cfg.env?.["AGENTICROS_ROBOT_NAMESPACE"] ?? "").trim();
162
+ if (ns.length > 0) {
163
+ issues.push({
164
+ severity: "yellow",
165
+ message: `Codex AGENTICROS_ROBOT_NAMESPACE is hardcoded ('${ns}')`,
166
+ hint: 'Leave it empty in ~/.codex/config.toml so `agenticros mode real|sim` drives the namespace (same as .mcp.json).',
167
+ });
168
+ }
169
+ if (cfg.enabled === false) {
170
+ issues.push({
171
+ severity: "yellow",
172
+ message: "Codex agenticros MCP server is disabled (enabled = false)",
173
+ hint: "Set enabled = true or re-run `agenticros codex setup`.",
174
+ });
175
+ }
176
+ const hasRed = issues.some((i) => i.severity === "red");
177
+ return { ok: !hasRed && issues.length === 0, issues };
178
+ }
179
+ /** Collect Codex config paths to inspect (global + project when in a workspace). */
180
+ export function listCodexConfigCandidates(repoRoot) {
181
+ const paths = [globalCodexConfigPath()];
182
+ if (repoRoot) {
183
+ paths.push(projectCodexConfigPath(repoRoot));
184
+ }
185
+ const cwdProject = projectCodexConfigPath(process.cwd());
186
+ if (!paths.includes(cwdProject)) {
187
+ paths.push(cwdProject);
188
+ }
189
+ return paths;
190
+ }
191
+ function extractSection(content, startMarker, endPattern) {
192
+ const lines = content.split("\n");
193
+ const out = [];
194
+ let inSection = false;
195
+ for (const line of lines) {
196
+ const trimmed = line.trim();
197
+ if (trimmed === startMarker) {
198
+ inSection = true;
199
+ continue;
200
+ }
201
+ if (inSection) {
202
+ if (typeof endPattern === "string") {
203
+ if (trimmed === endPattern)
204
+ break;
205
+ }
206
+ else if (endPattern.test(trimmed) && trimmed !== startMarker) {
207
+ break;
208
+ }
209
+ out.push(line);
210
+ }
211
+ }
212
+ return out.join("\n");
213
+ }
214
+ function parseTomlString(section, key) {
215
+ const re = new RegExp(`^${key}\\s*=\\s*"([^"]*)"`, "m");
216
+ const m = section.match(re);
217
+ return m?.[1];
218
+ }
219
+ function parseTomlBoolean(section, key) {
220
+ const re = new RegExp(`^${key}\\s*=\\s*(true|false)`, "m");
221
+ const m = section.match(re);
222
+ if (!m)
223
+ return undefined;
224
+ return m[1] === "true";
225
+ }
226
+ function parseTomlStringArray(section, key) {
227
+ const inline = section.match(new RegExp(`^${key}\\s*=\\s*\\[([^\\]]*)\\]`, "m"));
228
+ if (inline?.[1]) {
229
+ return [...inline[1].matchAll(/"((?:\\.|[^"\\])*)"/g)].map((m) => m[1].replace(/\\"/g, '"').replace(/\\\\/g, "\\"));
230
+ }
231
+ const start = section.match(new RegExp(`^${key}\\s*=\\s*\\[`, "m"));
232
+ if (!start)
233
+ return undefined;
234
+ const after = section.slice(start.index ?? 0);
235
+ const values = [];
236
+ for (const m of after.matchAll(/"((?:\\.|[^"\\])*)"/g)) {
237
+ values.push(m[1].replace(/\\"/g, '"').replace(/\\\\/g, "\\"));
238
+ }
239
+ return values.length > 0 ? values : undefined;
240
+ }
241
+ function parseTomlEnvBlock(section) {
242
+ const env = {};
243
+ for (const line of section.split("\n")) {
244
+ const m = line.match(/^([A-Z0-9_]+)\s*=\s*"([^"]*)"/);
245
+ if (m)
246
+ env[m[1]] = m[2];
247
+ }
248
+ return env;
249
+ }
250
+ /** Doctor check entries for Codex MCP config (used by `agenticros doctor`). */
251
+ export function buildCodexDoctorChecks(mcpEntryExpected, repoRoot) {
252
+ const checks = [];
253
+ const globalPath = globalCodexConfigPath();
254
+ const globalCfg = readCodexAgenticrosConfig(globalPath);
255
+ if (!globalCfg.exists) {
256
+ checks.push({
257
+ id: "codex-config-global",
258
+ label: "Codex global MCP config missing (~/.codex/config.toml)",
259
+ severity: "yellow",
260
+ hint: "Run `agenticros codex setup` to register the AgenticROS MCP server.",
261
+ });
262
+ }
263
+ else {
264
+ const v = validateCodexAgenticrosConfig(globalCfg, mcpEntryExpected);
265
+ if (v.ok) {
266
+ checks.push({
267
+ id: "codex-config-global",
268
+ label: "Codex global MCP config OK",
269
+ severity: "green",
270
+ detail: globalPath,
271
+ });
272
+ }
273
+ else {
274
+ const worst = v.issues.some((i) => i.severity === "red") ? "red" : "yellow";
275
+ const first = v.issues[0];
276
+ checks.push({
277
+ id: "codex-config-global",
278
+ label: `Codex global MCP: ${first.message}`,
279
+ severity: worst,
280
+ hint: first.hint ?? "Run `agenticros codex setup`.",
281
+ });
282
+ }
283
+ }
284
+ if (repoRoot) {
285
+ const projectPath = projectCodexConfigPath(repoRoot);
286
+ const projectCfg = readCodexAgenticrosConfig(projectPath);
287
+ if (projectCfg.exists) {
288
+ const v = validateCodexAgenticrosConfig(projectCfg, mcpEntryExpected);
289
+ if (v.ok) {
290
+ checks.push({
291
+ id: "codex-config-project",
292
+ label: "Codex project MCP config OK",
293
+ severity: "green",
294
+ detail: projectPath,
295
+ });
296
+ }
297
+ else {
298
+ const worst = v.issues.some((i) => i.severity === "red") ? "red" : "yellow";
299
+ const first = v.issues[0];
300
+ checks.push({
301
+ id: "codex-config-project",
302
+ label: `Codex project MCP: ${first.message}`,
303
+ severity: worst,
304
+ hint: first.hint ?? "Run `agenticros codex setup --project`.",
305
+ });
306
+ }
307
+ }
308
+ }
309
+ return checks;
310
+ }
311
+ function extractMcpPathFromArgs(args) {
312
+ if (args.length === 0)
313
+ return undefined;
314
+ if (args[0] === "-c" && args[1]) {
315
+ const cmd = args[1];
316
+ const nodeMatch = cmd.match(/node\s+(\S+)/);
317
+ return nodeMatch?.[1];
318
+ }
319
+ if (args[0] === "node" || args[0]?.endsWith("/node")) {
320
+ return args[1];
321
+ }
322
+ const joined = args.join(" ");
323
+ const nodeMatch = joined.match(/node\s+(\S+)/);
324
+ return nodeMatch?.[1];
325
+ }
326
+ //# sourceMappingURL=codex-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-config.js","sourceRoot":"","sources":["../../src/util/codex-config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAwB/D,MAAM,sBAAsB,GAAG,0BAA0B,CAAC;AAC1D,MAAM,oBAAoB,GAAG,8BAA8B,CAAC;AAE5D,mDAAmD;AACnD,MAAM,UAAU,qBAAqB;IACnC,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC;AAClD,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,sBAAsB,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE;IACxD,OAAO,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,KAAuB,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE;IACjF,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,qBAAqB,EAAE,CAAC,CAAC,CAAC,sBAAsB,CAAC,GAAG,CAAC,CAAC;AACpF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,2BAA2B,CAAC,WAAmB,EAAE,SAAS,GAAG,EAAE;IAC7E,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACnD,MAAM,QAAQ,GAAG,QAAQ,OAAO,6BAA6B,CAAC;IAC9D,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC/C,OAAO,GAAG,sBAAsB;;iBAEjB,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC;;;;EAI5C,oBAAoB;gCACU,OAAO;CACtC,CAAC;AACF,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,qBAAqB,CAAC,eAA8B,EAAE,KAAa;IACjF,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC;IAC5C,IAAI,CAAC,eAAe,EAAE,IAAI,EAAE,EAAE,CAAC;QAC7B,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1C,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,IAAI,QAAQ,GAAG,KAAK,CAAC;IAErB,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,sBAAsB,EAAE,CAAC;YAC3C,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC;gBACjC,QAAQ,GAAG,IAAI,CAAC;YAClB,CAAC;YACD,CAAC,EAAE,CAAC;YACJ,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;gBACxB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;gBAC5B,IAAI,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;oBACrC,IAAI,OAAO,KAAK,sBAAsB,IAAI,OAAO,KAAK,oBAAoB,EAAE,CAAC;wBAC3E,MAAM;oBACR,CAAC;gBACH,CAAC;gBACD,CAAC,EAAE,CAAC;YACN,CAAC;YACD,SAAS;QACX,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACf,CAAC,EAAE,CAAC;IACN,CAAC;IAED,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7E,OAAO,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,GAAG,YAAY,CAAC;IAC7C,CAAC;IAED,OAAO,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC;AACpE,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,yBAAyB,CAAC,UAAkB;IAC1D,MAAM,IAAI,GAA0B,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;IACnF,IAAI,CAAC,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAE9B,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,aAAa,GAAG,cAAc,CAAC,OAAO,EAAE,sBAAsB,EAAE,oBAAoB,CAAC,CAAC;IAC5F,MAAM,UAAU,GAAG,cAAc,CAAC,OAAO,EAAE,oBAAoB,EAAE,KAAK,CAAC,CAAC;IAExE,IAAI,CAAC,OAAO,GAAG,eAAe,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;IACzD,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;IACxD,IAAI,CAAC,OAAO,GAAG,gBAAgB,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;IAC1D,IAAI,CAAC,GAAG,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAC;IACzC,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,0BAA0B,CACxC,UAAkB,EAClB,WAAmB,EACnB,OAAgC;IAEhC,MAAM,GAAG,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACjC,MAAM,KAAK,GAAG,2BAA2B,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,IAAI,EAAE,CAAC,CAAC;IACzE,MAAM,QAAQ,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAClF,MAAM,MAAM,GAAG,qBAAqB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IACtD,SAAS,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAC5C,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,6BAA6B,CAC3C,GAA0B,EAC1B,gBAAyB;IAEzB,MAAM,MAAM,GAAuB,EAAE,CAAC;IAEtC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;QAChB,MAAM,CAAC,IAAI,CAAC;YACV,QAAQ,EAAE,QAAQ;YAClB,OAAO,EAAE,yBAAyB,GAAG,CAAC,UAAU,GAAG;YACnD,IAAI,EAAE,qEAAqE;SAC5E,CAAC,CAAC;QACH,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAC/B,CAAC;IAED,IAAI,CAAC,GAAG,CAAC,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC;QACzD,MAAM,CAAC,IAAI,CAAC;YACV,QAAQ,EAAE,KAAK;YACf,OAAO,EAAE,uDAAuD;YAChE,IAAI,EAAE,mDAAmD;SAC1D,CAAC,CAAC;IACL,CAAC;IAED,MAAM,aAAa,GAAG,sBAAsB,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;IAC7D,IAAI,aAAa,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;QACrE,MAAM,CAAC,IAAI,CAAC;YACV,QAAQ,EAAE,KAAK;YACf,OAAO,EAAE,6DAA6D;YACtE,IAAI,EAAE,gEAAgE;SACvE,CAAC,CAAC;IACL,CAAC;IAED,IAAI,gBAAgB,IAAI,aAAa,EAAE,CAAC;QACtC,MAAM,QAAQ,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;QAC3C,MAAM,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,aAAa,CAAC,CAAC;QACtE,IAAI,MAAM,KAAK,QAAQ,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAC/C,MAAM,CAAC,IAAI,CAAC;gBACV,QAAQ,EAAE,KAAK;gBACf,OAAO,EAAE,iDAAiD;gBAC1D,IAAI,EAAE,YAAY,QAAQ,mCAAmC;aAC9D,CAAC,CAAC;QACL,CAAC;aAAM,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC/B,MAAM,CAAC,IAAI,CAAC;gBACV,QAAQ,EAAE,QAAQ;gBAClB,OAAO,EAAE,wDAAwD;gBACjE,IAAI,EAAE,eAAe,QAAQ,2CAA2C;aACzE,CAAC,CAAC;QACL,CAAC;IACH,CAAC;SAAM,IAAI,gBAAgB,IAAI,CAAC,aAAa,EAAE,CAAC;QAC9C,MAAM,CAAC,IAAI,CAAC;YACV,QAAQ,EAAE,QAAQ;YAClB,OAAO,EAAE,mDAAmD;YAC5D,IAAI,EAAE,oDAAoD;SAC3D,CAAC,CAAC;IACL,CAAC;IAED,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,4BAA4B,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAClE,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClB,MAAM,CAAC,IAAI,CAAC;YACV,QAAQ,EAAE,QAAQ;YAClB,OAAO,EAAE,mDAAmD,EAAE,IAAI;YAClE,IAAI,EACF,gHAAgH;SACnH,CAAC,CAAC;IACL,CAAC;IAED,IAAI,GAAG,CAAC,OAAO,KAAK,KAAK,EAAE,CAAC;QAC1B,MAAM,CAAC,IAAI,CAAC;YACV,QAAQ,EAAE,QAAQ;YAClB,OAAO,EAAE,2DAA2D;YACpE,IAAI,EAAE,wDAAwD;SAC/D,CAAC,CAAC;IACL,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,KAAK,CAAC,CAAC;IACxD,OAAO,EAAE,EAAE,EAAE,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;AACxD,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,yBAAyB,CAAC,QAAiB;IACzD,MAAM,KAAK,GAAG,CAAC,qBAAqB,EAAE,CAAC,CAAC;IACxC,IAAI,QAAQ,EAAE,CAAC;QACb,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC/C,CAAC;IACD,MAAM,UAAU,GAAG,sBAAsB,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACzD,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QAChC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACzB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,cAAc,CAAC,OAAe,EAAE,WAAmB,EAAE,UAA2B;IACvF,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,OAAO,KAAK,WAAW,EAAE,CAAC;YAC5B,SAAS,GAAG,IAAI,CAAC;YACjB,SAAS;QACX,CAAC;QACD,IAAI,SAAS,EAAE,CAAC;YACd,IAAI,OAAO,UAAU,KAAK,QAAQ,EAAE,CAAC;gBACnC,IAAI,OAAO,KAAK,UAAU;oBAAE,MAAM;YACpC,CAAC;iBAAM,IAAI,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,OAAO,KAAK,WAAW,EAAE,CAAC;gBAC/D,MAAM;YACR,CAAC;YACD,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjB,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACxB,CAAC;AAED,SAAS,eAAe,CAAC,OAAe,EAAE,GAAW;IACnD,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,IAAI,GAAG,oBAAoB,EAAE,GAAG,CAAC,CAAC;IACxD,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC5B,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAChB,CAAC;AAED,SAAS,gBAAgB,CAAC,OAAe,EAAE,GAAW;IACpD,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,IAAI,GAAG,uBAAuB,EAAE,GAAG,CAAC,CAAC;IAC3D,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC5B,IAAI,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IACzB,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC;AACzB,CAAC;AAED,SAAS,oBAAoB,CAAC,OAAe,EAAE,GAAW;IACxD,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,IAAI,GAAG,0BAA0B,EAAE,GAAG,CAAC,CAAC,CAAC;IACjF,IAAI,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChB,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAC/D,CAAC,CAAC,CAAC,CAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAClD,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,IAAI,GAAG,cAAc,EAAE,GAAG,CAAC,CAAC,CAAC;IACpE,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAE7B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,sBAAsB,CAAC,EAAE,CAAC;QACvD,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;IACjE,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AAChD,CAAC;AAED,SAAS,iBAAiB,CAAC,OAAe;IACxC,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACvC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;QACtD,IAAI,CAAC;YAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;IAC5B,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,sBAAsB,CACpC,gBAAoC,EACpC,QAAiB;IAEjB,MAAM,MAAM,GAMP,EAAE,CAAC;IAER,MAAM,UAAU,GAAG,qBAAqB,EAAE,CAAC;IAC3C,MAAM,SAAS,GAAG,yBAAyB,CAAC,UAAU,CAAC,CAAC;IACxD,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;QACtB,MAAM,CAAC,IAAI,CAAC;YACV,EAAE,EAAE,qBAAqB;YACzB,KAAK,EAAE,wDAAwD;YAC/D,QAAQ,EAAE,QAAQ;YAClB,IAAI,EAAE,qEAAqE;SAC5E,CAAC,CAAC;IACL,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,GAAG,6BAA6B,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;QACrE,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC;YACT,MAAM,CAAC,IAAI,CAAC;gBACV,EAAE,EAAE,qBAAqB;gBACzB,KAAK,EAAE,4BAA4B;gBACnC,QAAQ,EAAE,OAAO;gBACjB,MAAM,EAAE,UAAU;aACnB,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;YAC5E,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC;YAC3B,MAAM,CAAC,IAAI,CAAC;gBACV,EAAE,EAAE,qBAAqB;gBACzB,KAAK,EAAE,qBAAqB,KAAK,CAAC,OAAO,EAAE;gBAC3C,QAAQ,EAAE,KAAK;gBACf,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,+BAA+B;aACpD,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,WAAW,GAAG,sBAAsB,CAAC,QAAQ,CAAC,CAAC;QACrD,MAAM,UAAU,GAAG,yBAAyB,CAAC,WAAW,CAAC,CAAC;QAC1D,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC;YACtB,MAAM,CAAC,GAAG,6BAA6B,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAC;YACtE,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC;gBACT,MAAM,CAAC,IAAI,CAAC;oBACV,EAAE,EAAE,sBAAsB;oBAC1B,KAAK,EAAE,6BAA6B;oBACpC,QAAQ,EAAE,OAAO;oBACjB,MAAM,EAAE,WAAW;iBACpB,CAAC,CAAC;YACL,CAAC;iBAAM,CAAC;gBACN,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;gBAC5E,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC;gBAC3B,MAAM,CAAC,IAAI,CAAC;oBACV,EAAE,EAAE,sBAAsB;oBAC1B,KAAK,EAAE,sBAAsB,KAAK,CAAC,OAAO,EAAE;oBAC5C,QAAQ,EAAE,KAAK;oBACf,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,yCAAyC;iBAC9D,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,sBAAsB,CAAC,IAAc;IAC5C,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAExC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAChC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QAC5C,OAAO,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC;IACxB,CAAC;IAED,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QACrD,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC;IACjB,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9B,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IAC/C,OAAO,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC;AACxB,CAAC"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Read/write helpers for Hermes Agent MCP config (`~/.hermes/config.yaml`).
3
+ *
4
+ * Hermes stores MCP servers under `mcp_servers.<name>` in YAML. We only
5
+ * manage the `agenticros` entry — other servers are preserved.
6
+ */
7
+ export interface HermesAgenticrosConfig {
8
+ configPath: string;
9
+ exists: boolean;
10
+ command?: string;
11
+ args?: string[];
12
+ env?: Record<string, string>;
13
+ connectTimeout?: number;
14
+ timeout?: number;
15
+ enabled?: boolean;
16
+ }
17
+ export interface HermesConfigIssue {
18
+ severity: "red" | "yellow";
19
+ message: string;
20
+ hint?: string;
21
+ }
22
+ export interface HermesConfigValidation {
23
+ ok: boolean;
24
+ issues: HermesConfigIssue[];
25
+ }
26
+ /** Global Hermes config: `~/.hermes/config.yaml`. */
27
+ export declare function globalHermesConfigPath(): string;
28
+ /**
29
+ * Build the YAML block for the AgenticROS MCP server. Uses an absolute path
30
+ * to index.js (required by Hermes stdio transport) and leaves namespace empty
31
+ * so `~/.agenticros/config.json` / `agenticros mode` drives the active robot.
32
+ */
33
+ export declare function buildAgenticrosMcpYamlBlock(mcpEntryAbs: string, namespace?: string): string;
34
+ /** Insert or replace the agenticros MCP block, preserving other YAML content. */
35
+ export declare function upsertAgenticrosBlock(existingContent: string | null, block: string): string;
36
+ /** Parse the agenticros MCP section from a Hermes config.yaml file. */
37
+ export declare function readHermesAgenticrosConfig(configPath: string): HermesAgenticrosConfig;
38
+ export declare function writeHermesAgenticrosConfig(configPath: string, mcpEntryAbs: string, options?: {
39
+ namespace?: string;
40
+ }): void;
41
+ /** Validate Hermes agenticros MCP config against expected MCP binary path. */
42
+ export declare function validateHermesAgenticrosConfig(cfg: HermesAgenticrosConfig, mcpEntryExpected?: string): HermesConfigValidation;
43
+ /** Doctor check entries for Hermes MCP config (used by `agenticros doctor`). */
44
+ export declare function buildHermesDoctorChecks(mcpEntryExpected: string | undefined): Array<{
45
+ id: string;
46
+ label: string;
47
+ severity: "green" | "yellow" | "red";
48
+ hint?: string;
49
+ detail?: string;
50
+ }>;
51
+ //# sourceMappingURL=hermes-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hermes-config.d.ts","sourceRoot":"","sources":["../../src/util/hermes-config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,KAAK,GAAG,QAAQ,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,iBAAiB,EAAE,CAAC;CAC7B;AAKD,qDAAqD;AACrD,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,SAAK,GAAG,MAAM,CAYvF;AAED,iFAAiF;AACjF,wBAAgB,qBAAqB,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CA+B3F;AAED,uEAAuE;AACvE,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,GAAG,sBAAsB,CA4BrF;AAED,wBAAgB,2BAA2B,CACzC,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/B,IAAI,CAON;AAED,8EAA8E;AAC9E,wBAAgB,8BAA8B,CAC5C,GAAG,EAAE,sBAAsB,EAC3B,gBAAgB,CAAC,EAAE,MAAM,GACxB,sBAAsB,CAyExB;AAED,gFAAgF;AAChF,wBAAgB,uBAAuB,CACrC,gBAAgB,EAAE,MAAM,GAAG,SAAS,GACnC,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAyC5G"}
@@ -0,0 +1,277 @@
1
+ /**
2
+ * Read/write helpers for Hermes Agent MCP config (`~/.hermes/config.yaml`).
3
+ *
4
+ * Hermes stores MCP servers under `mcp_servers.<name>` in YAML. We only
5
+ * manage the `agenticros` entry — other servers are preserved.
6
+ */
7
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
8
+ import { homedir } from "node:os";
9
+ import { dirname, isAbsolute, join, resolve } from "node:path";
10
+ const MCP_SERVERS_KEY = "mcp_servers:";
11
+ const AGENTICROS_KEY = "agenticros:";
12
+ /** Global Hermes config: `~/.hermes/config.yaml`. */
13
+ export function globalHermesConfigPath() {
14
+ return join(homedir(), ".hermes", "config.yaml");
15
+ }
16
+ /**
17
+ * Build the YAML block for the AgenticROS MCP server. Uses an absolute path
18
+ * to index.js (required by Hermes stdio transport) and leaves namespace empty
19
+ * so `~/.agenticros/config.json` / `agenticros mode` drives the active robot.
20
+ */
21
+ export function buildAgenticrosMcpYamlBlock(mcpEntryAbs, namespace = "") {
22
+ const escaped = mcpEntryAbs.replace(/\\/g, "\\\\");
23
+ const nsYaml = namespace.replace(/"/g, '\\"');
24
+ return `${MCP_SERVERS_KEY}
25
+ ${AGENTICROS_KEY}
26
+ command: "node"
27
+ args: ["${escaped}"]
28
+ env:
29
+ AGENTICROS_ROBOT_NAMESPACE: "${nsYaml}"
30
+ connect_timeout: 60
31
+ timeout: 120
32
+ `;
33
+ }
34
+ /** Insert or replace the agenticros MCP block, preserving other YAML content. */
35
+ export function upsertAgenticrosBlock(existingContent, block) {
36
+ const trimmedBlock = block.trimEnd() + "\n";
37
+ if (!existingContent?.trim()) {
38
+ return trimmedBlock;
39
+ }
40
+ const lines = existingContent.split("\n");
41
+ const mcpIdx = lines.findIndex((l) => l.trim() === MCP_SERVERS_KEY);
42
+ if (mcpIdx < 0) {
43
+ const sep = lines.length > 0 && lines[lines.length - 1]?.trim() !== "" ? "\n" : "";
44
+ return lines.join("\n") + sep + trimmedBlock;
45
+ }
46
+ const agentIdx = findAgenticrosLineIndex(lines, mcpIdx);
47
+ if (agentIdx < 0) {
48
+ const insertAt = findMcpServersInsertPoint(lines, mcpIdx);
49
+ const agentLines = trimmedBlock
50
+ .split("\n")
51
+ .slice(1)
52
+ .filter((l) => l.trim().length > 0);
53
+ const out = [...lines.slice(0, insertAt), ...agentLines, ...lines.slice(insertAt)];
54
+ return out.join("\n").replace(/\n{3,}/g, "\n\n").trimEnd() + "\n";
55
+ }
56
+ const endIdx = findAgenticrosEndIndex(lines, agentIdx);
57
+ const agentLines = trimmedBlock
58
+ .split("\n")
59
+ .slice(1)
60
+ .filter((l) => l.startsWith(" "));
61
+ const out = [...lines.slice(0, agentIdx), ...agentLines, ...lines.slice(endIdx)];
62
+ return out.join("\n").replace(/\n{3,}/g, "\n\n").trimEnd() + "\n";
63
+ }
64
+ /** Parse the agenticros MCP section from a Hermes config.yaml file. */
65
+ export function readHermesAgenticrosConfig(configPath) {
66
+ const base = { configPath, exists: existsSync(configPath) };
67
+ if (!base.exists)
68
+ return base;
69
+ let content;
70
+ try {
71
+ content = readFileSync(configPath, "utf8");
72
+ }
73
+ catch {
74
+ return base;
75
+ }
76
+ const lines = content.split("\n");
77
+ const mcpIdx = lines.findIndex((l) => l.trim() === MCP_SERVERS_KEY);
78
+ if (mcpIdx < 0)
79
+ return base;
80
+ const agentIdx = findAgenticrosLineIndex(lines, mcpIdx);
81
+ if (agentIdx < 0)
82
+ return base;
83
+ const endIdx = findAgenticrosEndIndex(lines, agentIdx);
84
+ const section = lines.slice(agentIdx, endIdx).join("\n");
85
+ base.command = parseYamlString(section, "command");
86
+ base.args = parseYamlStringArray(section, "args");
87
+ base.env = parseYamlEnvBlock(section);
88
+ base.connectTimeout = parseYamlNumber(section, "connect_timeout");
89
+ base.timeout = parseYamlNumber(section, "timeout");
90
+ base.enabled = parseYamlBoolean(section, "enabled");
91
+ return base;
92
+ }
93
+ export function writeHermesAgenticrosConfig(configPath, mcpEntryAbs, options) {
94
+ const abs = resolve(mcpEntryAbs);
95
+ const block = buildAgenticrosMcpYamlBlock(abs, options?.namespace ?? "");
96
+ const existing = existsSync(configPath) ? readFileSync(configPath, "utf8") : null;
97
+ const merged = upsertAgenticrosBlock(existing, block);
98
+ mkdirSync(dirname(configPath), { recursive: true });
99
+ writeFileSync(configPath, merged, "utf8");
100
+ }
101
+ /** Validate Hermes agenticros MCP config against expected MCP binary path. */
102
+ export function validateHermesAgenticrosConfig(cfg, mcpEntryExpected) {
103
+ const issues = [];
104
+ if (!cfg.exists) {
105
+ issues.push({
106
+ severity: "yellow",
107
+ message: `Hermes config missing (${cfg.configPath})`,
108
+ hint: "Run `agenticros hermes setup` to register the AgenticROS MCP server.",
109
+ });
110
+ return { ok: false, issues };
111
+ }
112
+ if (!cfg.command && (!cfg.args || cfg.args.length === 0)) {
113
+ issues.push({
114
+ severity: "red",
115
+ message: "Hermes mcp_servers.agenticros has no command or args",
116
+ hint: "Run `agenticros hermes setup` to repair the entry.",
117
+ });
118
+ }
119
+ const mcpPath = cfg.args?.[0];
120
+ if (mcpPath && !isAbsolute(mcpPath)) {
121
+ issues.push({
122
+ severity: "red",
123
+ message: "Hermes MCP path is relative — Hermes cwd is not the repo root",
124
+ hint: "Run `agenticros hermes setup` to rewrite with an absolute path.",
125
+ });
126
+ }
127
+ if (mcpEntryExpected && mcpPath) {
128
+ const expected = resolve(mcpEntryExpected);
129
+ const actual = resolve(mcpPath);
130
+ if (actual !== expected && !existsSync(actual)) {
131
+ issues.push({
132
+ severity: "red",
133
+ message: "Hermes MCP path does not point to a built server",
134
+ hint: `Expected ${expected}. Run \`agenticros hermes setup\`.`,
135
+ });
136
+ }
137
+ else if (actual !== expected) {
138
+ issues.push({
139
+ severity: "yellow",
140
+ message: "Hermes MCP path differs from the CLI-resolved MCP entry",
141
+ hint: `CLI expects ${expected}. Run \`agenticros hermes setup\` to sync.`,
142
+ });
143
+ }
144
+ }
145
+ else if (mcpEntryExpected && !mcpPath) {
146
+ issues.push({
147
+ severity: "yellow",
148
+ message: "Could not parse MCP server path from Hermes config",
149
+ hint: "Run `agenticros hermes setup` to rewrite the entry.",
150
+ });
151
+ }
152
+ const ns = (cfg.env?.["AGENTICROS_ROBOT_NAMESPACE"] ?? "").trim();
153
+ if (ns.length > 0) {
154
+ issues.push({
155
+ severity: "yellow",
156
+ message: `Hermes AGENTICROS_ROBOT_NAMESPACE is hardcoded ('${ns}')`,
157
+ hint: 'Leave it empty in ~/.hermes/config.yaml so `agenticros mode real|sim` drives the namespace (same as Codex).',
158
+ });
159
+ }
160
+ if (cfg.enabled === false) {
161
+ issues.push({
162
+ severity: "yellow",
163
+ message: "Hermes agenticros MCP server is disabled (enabled: false)",
164
+ hint: "Remove enabled: false or re-run `agenticros hermes setup`.",
165
+ });
166
+ }
167
+ const hasRed = issues.some((i) => i.severity === "red");
168
+ return { ok: !hasRed && issues.length === 0, issues };
169
+ }
170
+ /** Doctor check entries for Hermes MCP config (used by `agenticros doctor`). */
171
+ export function buildHermesDoctorChecks(mcpEntryExpected) {
172
+ const checks = [];
173
+ const configPath = globalHermesConfigPath();
174
+ const cfg = readHermesAgenticrosConfig(configPath);
175
+ if (!cfg.exists) {
176
+ checks.push({
177
+ id: "hermes-config",
178
+ label: "Hermes MCP config missing (~/.hermes/config.yaml)",
179
+ severity: "yellow",
180
+ hint: "Run `agenticros hermes setup` to register the AgenticROS MCP server.",
181
+ });
182
+ return checks;
183
+ }
184
+ const v = validateHermesAgenticrosConfig(cfg, mcpEntryExpected);
185
+ if (v.ok) {
186
+ checks.push({
187
+ id: "hermes-config",
188
+ label: "Hermes MCP config OK",
189
+ severity: "green",
190
+ detail: configPath,
191
+ });
192
+ }
193
+ else {
194
+ const worst = v.issues.some((i) => i.severity === "red") ? "red" : "yellow";
195
+ const first = v.issues[0];
196
+ checks.push({
197
+ id: "hermes-config",
198
+ label: `Hermes MCP: ${first.message}`,
199
+ severity: worst,
200
+ hint: first.hint ?? "Run `agenticros hermes setup`.",
201
+ });
202
+ }
203
+ return checks;
204
+ }
205
+ function findAgenticrosLineIndex(lines, mcpIdx) {
206
+ for (let i = mcpIdx + 1; i < lines.length; i++) {
207
+ const trimmed = lines[i]?.trim() ?? "";
208
+ if (/^\S/.test(lines[i] ?? "") && trimmed !== MCP_SERVERS_KEY)
209
+ break;
210
+ if (trimmed === AGENTICROS_KEY)
211
+ return i;
212
+ }
213
+ return -1;
214
+ }
215
+ function findMcpServersInsertPoint(lines, mcpIdx) {
216
+ let insertAt = mcpIdx + 1;
217
+ for (let i = mcpIdx + 1; i < lines.length; i++) {
218
+ const line = lines[i] ?? "";
219
+ if (/^\S/.test(line) && line.trim() !== MCP_SERVERS_KEY)
220
+ break;
221
+ if (/^ \S/.test(line))
222
+ insertAt = i + 1;
223
+ }
224
+ return insertAt;
225
+ }
226
+ function findAgenticrosEndIndex(lines, agentIdx) {
227
+ for (let i = agentIdx + 1; i < lines.length; i++) {
228
+ const line = lines[i] ?? "";
229
+ if (/^ \S/.test(line) && !line.startsWith(" ") && line.trim() !== AGENTICROS_KEY) {
230
+ return i;
231
+ }
232
+ if (/^\S/.test(line))
233
+ return i;
234
+ }
235
+ return lines.length;
236
+ }
237
+ function parseYamlString(section, key) {
238
+ const re = new RegExp(`^\\s*${key}:\\s*"([^"]*)"`, "m");
239
+ const m = section.match(re);
240
+ return m?.[1];
241
+ }
242
+ function parseYamlBoolean(section, key) {
243
+ const re = new RegExp(`^\\s*${key}:\\s*(true|false)`, "m");
244
+ const m = section.match(re);
245
+ if (!m)
246
+ return undefined;
247
+ return m[1] === "true";
248
+ }
249
+ function parseYamlNumber(section, key) {
250
+ const re = new RegExp(`^\\s*${key}:\\s*(\\d+)`, "m");
251
+ const m = section.match(re);
252
+ if (!m)
253
+ return undefined;
254
+ return Number(m[1]);
255
+ }
256
+ function parseYamlStringArray(section, key) {
257
+ const inline = section.match(new RegExp(`^\\s*${key}:\\s*\\[([^\\]]*)\\]`, "m"));
258
+ if (inline?.[1]) {
259
+ return [...inline[1].matchAll(/"((?:\\.|[^"\\])*)"/g)].map((m) => m[1].replace(/\\"/g, '"').replace(/\\\\/g, "\\"));
260
+ }
261
+ return undefined;
262
+ }
263
+ function parseYamlEnvBlock(section) {
264
+ const env = {};
265
+ const envMatch = section.match(/^(\s*)env:\s*$/m);
266
+ if (!envMatch)
267
+ return env;
268
+ const baseIndent = envMatch[1]?.length ?? 0;
269
+ const envKeyIndent = baseIndent + 2;
270
+ for (const line of section.split("\n")) {
271
+ const m = line.match(new RegExp(`^\\s{${envKeyIndent}}([A-Z0-9_]+):\\s*"([^"]*)"`));
272
+ if (m)
273
+ env[m[1]] = m[2];
274
+ }
275
+ return env;
276
+ }
277
+ //# sourceMappingURL=hermes-config.js.map