@dahch/muninn 0.0.0-stage → 0.2.0

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 (92) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +395 -2
  3. package/dist/cli.d.ts +23 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +186 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/commands/check.d.ts +3 -0
  8. package/dist/commands/check.d.ts.map +1 -0
  9. package/dist/commands/check.js +56 -0
  10. package/dist/commands/check.js.map +1 -0
  11. package/dist/commands/memory.d.ts +6 -0
  12. package/dist/commands/memory.d.ts.map +1 -0
  13. package/dist/commands/memory.js +374 -0
  14. package/dist/commands/memory.js.map +1 -0
  15. package/dist/commands/setup.d.ts +3 -0
  16. package/dist/commands/setup.d.ts.map +1 -0
  17. package/dist/commands/setup.js +397 -0
  18. package/dist/commands/setup.js.map +1 -0
  19. package/dist/contracts/compiler.d.ts +71 -0
  20. package/dist/contracts/compiler.d.ts.map +1 -0
  21. package/dist/contracts/compiler.js +362 -0
  22. package/dist/contracts/compiler.js.map +1 -0
  23. package/dist/contracts/index.d.ts +2 -0
  24. package/dist/contracts/index.d.ts.map +1 -0
  25. package/dist/contracts/index.js +2 -0
  26. package/dist/contracts/index.js.map +1 -0
  27. package/dist/db/client.d.ts +100 -0
  28. package/dist/db/client.d.ts.map +1 -0
  29. package/dist/db/client.js +318 -0
  30. package/dist/db/client.js.map +1 -0
  31. package/dist/db/schema.sql +99 -0
  32. package/dist/index.d.ts +23 -0
  33. package/dist/index.d.ts.map +1 -0
  34. package/dist/index.js +23 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/indexer/ast-indexer.d.ts +55 -0
  37. package/dist/indexer/ast-indexer.d.ts.map +1 -0
  38. package/dist/indexer/ast-indexer.js +445 -0
  39. package/dist/indexer/ast-indexer.js.map +1 -0
  40. package/dist/indexer/index.d.ts +2 -0
  41. package/dist/indexer/index.d.ts.map +1 -0
  42. package/dist/indexer/index.js +2 -0
  43. package/dist/indexer/index.js.map +1 -0
  44. package/dist/mcp/index.d.ts +2 -0
  45. package/dist/mcp/index.d.ts.map +1 -0
  46. package/dist/mcp/index.js +2 -0
  47. package/dist/mcp/index.js.map +1 -0
  48. package/dist/mcp/server.d.ts +254 -0
  49. package/dist/mcp/server.d.ts.map +1 -0
  50. package/dist/mcp/server.js +636 -0
  51. package/dist/mcp/server.js.map +1 -0
  52. package/dist/service/index.d.ts +2 -0
  53. package/dist/service/index.d.ts.map +1 -0
  54. package/dist/service/index.js +2 -0
  55. package/dist/service/index.js.map +1 -0
  56. package/dist/service/memory-service.d.ts +320 -0
  57. package/dist/service/memory-service.d.ts.map +1 -0
  58. package/dist/service/memory-service.js +1511 -0
  59. package/dist/service/memory-service.js.map +1 -0
  60. package/dist/setup/index.d.ts +6 -0
  61. package/dist/setup/index.d.ts.map +1 -0
  62. package/dist/setup/index.js +6 -0
  63. package/dist/setup/index.js.map +1 -0
  64. package/dist/setup/json-target.d.ts +30 -0
  65. package/dist/setup/json-target.d.ts.map +1 -0
  66. package/dist/setup/json-target.js +263 -0
  67. package/dist/setup/json-target.js.map +1 -0
  68. package/dist/setup/portable.d.ts +56 -0
  69. package/dist/setup/portable.d.ts.map +1 -0
  70. package/dist/setup/portable.js +365 -0
  71. package/dist/setup/portable.js.map +1 -0
  72. package/dist/setup/registry.d.ts +54 -0
  73. package/dist/setup/registry.d.ts.map +1 -0
  74. package/dist/setup/registry.js +225 -0
  75. package/dist/setup/registry.js.map +1 -0
  76. package/dist/setup/rules-target.d.ts +31 -0
  77. package/dist/setup/rules-target.d.ts.map +1 -0
  78. package/dist/setup/rules-target.js +270 -0
  79. package/dist/setup/rules-target.js.map +1 -0
  80. package/dist/setup/toml-target.d.ts +62 -0
  81. package/dist/setup/toml-target.d.ts.map +1 -0
  82. package/dist/setup/toml-target.js +869 -0
  83. package/dist/setup/toml-target.js.map +1 -0
  84. package/dist/util/path-safety.d.ts +94 -0
  85. package/dist/util/path-safety.d.ts.map +1 -0
  86. package/dist/util/path-safety.js +162 -0
  87. package/dist/util/path-safety.js.map +1 -0
  88. package/dist/util/text.d.ts +9 -0
  89. package/dist/util/text.d.ts.map +1 -0
  90. package/dist/util/text.js +19 -0
  91. package/dist/util/text.js.map +1 -0
  92. package/package.json +87 -4
@@ -0,0 +1,365 @@
1
+ /**
2
+ * Portable MCP configuration setup.
3
+ *
4
+ * Iteration 1 of the setup feature owns exactly one destination:
5
+ * `{home}/.muninn/mcp.json`, using the standard `mcpServers` container. The
6
+ * portable entry never pins a project path; project-scoped destinations are
7
+ * handled by later setup iterations.
8
+ *
9
+ * Everything here is deliberately dependency-free and uses the same path-safety
10
+ * helper as the rest of Muninn. Reads and writes are per-file, writes are
11
+ * atomic, and a no-op keeps the original bytes untouched.
12
+ */
13
+ import fs from "node:fs";
14
+ import os from "node:os";
15
+ import { basename, dirname, join, resolve } from "node:path";
16
+ import { randomBytes } from "node:crypto";
17
+ import { checkDocPath, lstatOrUndefined } from "../util/path-safety.js";
18
+ export function canonicalPortableEntry() {
19
+ return { command: "muninn", args: ["mcp", "run"] };
20
+ }
21
+ export function resolvePortablePaths(homeDir) {
22
+ const selectedHome = resolve(homeDir ?? os.homedir());
23
+ return {
24
+ homeDir: selectedHome,
25
+ configPath: join(selectedHome, ".muninn", "mcp.json"),
26
+ legacyPath: join(selectedHome, ".huginn", "mcp.json"),
27
+ };
28
+ }
29
+ function isPlainObject(value) {
30
+ return typeof value === "object" && value !== null && !Array.isArray(value);
31
+ }
32
+ function hasOwn(target, key) {
33
+ return Object.prototype.hasOwnProperty.call(target, key);
34
+ }
35
+ function isStringArray(value) {
36
+ return Array.isArray(value) && value.every((item) => typeof item === "string");
37
+ }
38
+ /**
39
+ * A syntactically usable Muninn entry. It may still differ from the canonical
40
+ * command line; that is classified as a conflict, not malformed input.
41
+ */
42
+ function isUsableEntry(entry) {
43
+ if (hasOwn(entry, "command") && typeof entry.command !== "string")
44
+ return false;
45
+ if (hasOwn(entry, "args") && !isStringArray(entry.args))
46
+ return false;
47
+ return true;
48
+ }
49
+ function isCanonicalEntry(entry) {
50
+ if (!isPlainObject(entry))
51
+ return false;
52
+ const keys = Object.keys(entry).sort();
53
+ if (keys.length !== 2 || keys[0] !== "args" || keys[1] !== "command")
54
+ return false;
55
+ return (entry.command === "muninn" &&
56
+ Array.isArray(entry.args) &&
57
+ entry.args.length === 2 &&
58
+ entry.args[0] === "mcp" &&
59
+ entry.args[1] === "run");
60
+ }
61
+ function classifyRoot(data) {
62
+ if (!isPlainObject(data)) {
63
+ return { state: "malformed", error: "JSON root must be an object" };
64
+ }
65
+ if (!hasOwn(data, "mcpServers"))
66
+ return { state: "absent" };
67
+ const servers = data.mcpServers;
68
+ if (!isPlainObject(servers)) {
69
+ return { state: "malformed", error: "`mcpServers` must be an object" };
70
+ }
71
+ if (!hasOwn(servers, "muninn"))
72
+ return { state: "absent" };
73
+ const entry = servers.muninn;
74
+ if (!isPlainObject(entry)) {
75
+ return { state: "malformed", error: "`mcpServers.muninn` must be an object" };
76
+ }
77
+ if (!isUsableEntry(entry)) {
78
+ return {
79
+ state: "malformed",
80
+ error: "`mcpServers.muninn` must use a string `command` and a string-array `args`",
81
+ };
82
+ }
83
+ return { state: isCanonicalEntry(entry) ? "registered" : "conflict" };
84
+ }
85
+ function inspectPortable(options = {}) {
86
+ const paths = resolvePortablePaths(options.homeDir ?? options.home);
87
+ const errors = [];
88
+ const configCheck = checkDocPath(paths.configPath, {
89
+ label: "portable MCP configuration",
90
+ action: "read or write",
91
+ });
92
+ if (!configCheck.ok) {
93
+ return {
94
+ paths,
95
+ state: "malformed",
96
+ legacyPresent: false,
97
+ error: configCheck.reason,
98
+ errors: [configCheck.reason],
99
+ };
100
+ }
101
+ let legacyPresent = false;
102
+ const legacyCheck = checkDocPath(paths.legacyPath, {
103
+ label: "legacy MCP configuration",
104
+ action: "read",
105
+ });
106
+ if (legacyCheck.ok) {
107
+ legacyPresent = lstatOrUndefined(legacyCheck.path) !== undefined;
108
+ }
109
+ else {
110
+ errors.push(legacyCheck.reason);
111
+ }
112
+ const configStat = lstatOrUndefined(configCheck.path);
113
+ if (configStat === undefined) {
114
+ return {
115
+ paths,
116
+ state: legacyPresent ? "legacy" : "absent",
117
+ legacyPresent,
118
+ errors,
119
+ };
120
+ }
121
+ if (!configStat.isFile()) {
122
+ const error = `Portable MCP configuration ${paths.configPath} is not a regular file`;
123
+ return {
124
+ paths,
125
+ state: "malformed",
126
+ legacyPresent,
127
+ error,
128
+ errors: [...errors, error],
129
+ };
130
+ }
131
+ let raw;
132
+ try {
133
+ raw = fs.readFileSync(configCheck.path, "utf8");
134
+ }
135
+ catch (err) {
136
+ const error = `Cannot read portable MCP configuration ${paths.configPath}: ${err.message}`;
137
+ return {
138
+ paths,
139
+ state: "malformed",
140
+ legacyPresent,
141
+ error,
142
+ errors: [...errors, error],
143
+ };
144
+ }
145
+ let parsed;
146
+ try {
147
+ parsed = JSON.parse(raw);
148
+ }
149
+ catch (err) {
150
+ const error = `Malformed JSON in ${paths.configPath}: ${err.message}`;
151
+ return {
152
+ paths,
153
+ state: "malformed",
154
+ legacyPresent,
155
+ raw,
156
+ error,
157
+ errors: [...errors, error],
158
+ };
159
+ }
160
+ const classified = classifyRoot(parsed);
161
+ if (classified.state === "malformed") {
162
+ const error = `Malformed portable MCP configuration ${paths.configPath}: ${classified.error}`;
163
+ return {
164
+ paths,
165
+ state: "malformed",
166
+ legacyPresent,
167
+ raw,
168
+ error,
169
+ errors: [...errors, error],
170
+ };
171
+ }
172
+ const state = classified.state === "absent" && legacyPresent ? "legacy" : classified.state;
173
+ return {
174
+ paths,
175
+ state,
176
+ legacyPresent,
177
+ raw,
178
+ data: parsed,
179
+ errors,
180
+ };
181
+ }
182
+ /** Read-only diagnostic used by `muninn setup --status`. */
183
+ export function getPortableStatus(options = {}) {
184
+ const inspected = inspectPortable(options);
185
+ return {
186
+ path: inspected.paths.configPath,
187
+ legacyPath: inspected.paths.legacyPath,
188
+ state: inspected.state,
189
+ legacyPresent: inspected.legacyPresent,
190
+ changed: false,
191
+ error: inspected.error,
192
+ errors: inspected.errors,
193
+ };
194
+ }
195
+ export function indentFrom(raw) {
196
+ if (!raw)
197
+ return " ";
198
+ const match = raw.match(/\n([ \t]+)"/);
199
+ return match?.[1] ?? " ";
200
+ }
201
+ export function renderConfig(data, raw) {
202
+ const body = JSON.stringify(data, null, indentFrom(raw));
203
+ if (raw === undefined)
204
+ return `${body}\n`;
205
+ // Preserve the original trailing-newline convention when updating a file.
206
+ return raw.endsWith("\n") ? `${body}\n` : body;
207
+ }
208
+ function buildUpdatedConfig(data) {
209
+ const next = { ...data };
210
+ const currentServers = isPlainObject(data.mcpServers) ? data.mcpServers : {};
211
+ next.mcpServers = {
212
+ ...currentServers,
213
+ muninn: canonicalPortableEntry(),
214
+ };
215
+ return next;
216
+ }
217
+ export function safeWriteAtomic(targetPath, content, mode) {
218
+ const directory = dirname(targetPath);
219
+ fs.mkdirSync(directory, { recursive: true, mode: 0o700 });
220
+ const temporaryPath = join(directory, `.${basename(targetPath)}.${process.pid}.${randomBytes(8).toString("hex")}.tmp`);
221
+ let fd;
222
+ try {
223
+ fd = fs.openSync(temporaryPath, "wx", mode);
224
+ fs.writeFileSync(fd, content, "utf8");
225
+ // `openSync` honours umask on some platforms; make the intended mode explicit.
226
+ fs.fchmodSync(fd, mode);
227
+ fs.fsyncSync(fd);
228
+ fs.closeSync(fd);
229
+ fd = undefined;
230
+ fs.renameSync(temporaryPath, targetPath);
231
+ }
232
+ catch (err) {
233
+ if (fd !== undefined) {
234
+ try {
235
+ fs.closeSync(fd);
236
+ }
237
+ catch {
238
+ // ignore cleanup failure
239
+ }
240
+ }
241
+ try {
242
+ fs.unlinkSync(temporaryPath);
243
+ }
244
+ catch {
245
+ // temporary file may not have been created
246
+ }
247
+ throw err;
248
+ }
249
+ }
250
+ /**
251
+ * Apply (or, with `dryRun`, only plan) the portable configuration update.
252
+ *
253
+ * Returns a structured report. Malformed input and protected paths are reported
254
+ * as `failed` with `error` set; callers turn that into exit code 1. A conflicting
255
+ * entry without `--force` is a nonfatal `skipped`.
256
+ */
257
+ export function setupPortable(options = {}) {
258
+ const inspected = inspectPortable(options);
259
+ const dryRun = options.dryRun === true;
260
+ const base = {
261
+ path: inspected.paths.configPath,
262
+ legacyPath: inspected.paths.legacyPath,
263
+ state: inspected.state,
264
+ legacyPresent: inspected.legacyPresent,
265
+ dryRun,
266
+ errors: inspected.errors,
267
+ };
268
+ if (inspected.state === "malformed") {
269
+ return {
270
+ ...base,
271
+ outcome: "failed",
272
+ changed: false,
273
+ error: inspected.error,
274
+ };
275
+ }
276
+ // A protected legacy path is still a fatal setup error even though normal
277
+ // setup never modifies the legacy file.
278
+ if (inspected.errors.length > 0) {
279
+ return {
280
+ ...base,
281
+ outcome: "failed",
282
+ changed: false,
283
+ error: inspected.errors[0],
284
+ };
285
+ }
286
+ if (inspected.state === "registered") {
287
+ return {
288
+ ...base,
289
+ outcome: "present",
290
+ changed: false,
291
+ };
292
+ }
293
+ if (inspected.state === "conflict" && options.force !== true) {
294
+ return {
295
+ ...base,
296
+ outcome: "skipped",
297
+ changed: false,
298
+ };
299
+ }
300
+ const updated = buildUpdatedConfig(inspected.data ?? {});
301
+ const content = renderConfig(updated, inspected.raw);
302
+ if (dryRun) {
303
+ return {
304
+ ...base,
305
+ outcome: "written",
306
+ changed: true,
307
+ };
308
+ }
309
+ const configCheck = checkDocPath(inspected.paths.configPath, {
310
+ label: "portable MCP configuration",
311
+ action: "write",
312
+ });
313
+ if (!configCheck.ok) {
314
+ return {
315
+ ...base,
316
+ outcome: "failed",
317
+ changed: false,
318
+ error: configCheck.reason,
319
+ errors: [...inspected.errors, configCheck.reason],
320
+ };
321
+ }
322
+ // Re-check immediately before writing so a path swapped for a symlink between
323
+ // inspection and the write is still refused.
324
+ const existing = lstatOrUndefined(configCheck.path);
325
+ if (existing?.isSymbolicLink()) {
326
+ const error = `Portable MCP configuration ${inspected.paths.configPath} is a symlink; refusing to write through it`;
327
+ return {
328
+ ...base,
329
+ outcome: "failed",
330
+ changed: false,
331
+ error,
332
+ errors: [...inspected.errors, error],
333
+ };
334
+ }
335
+ if (existing !== undefined && !existing.isFile()) {
336
+ const error = `Portable MCP configuration ${inspected.paths.configPath} is not a regular file`;
337
+ return {
338
+ ...base,
339
+ outcome: "failed",
340
+ changed: false,
341
+ error,
342
+ errors: [...inspected.errors, error],
343
+ };
344
+ }
345
+ const mode = existing === undefined ? 0o600 : existing.mode & 0o777;
346
+ try {
347
+ safeWriteAtomic(configCheck.path, content, mode);
348
+ }
349
+ catch (err) {
350
+ const error = `Cannot write portable MCP configuration ${inspected.paths.configPath}: ${err.message}`;
351
+ return {
352
+ ...base,
353
+ outcome: "failed",
354
+ changed: false,
355
+ error,
356
+ errors: [...inspected.errors, error],
357
+ };
358
+ }
359
+ return {
360
+ ...base,
361
+ outcome: "written",
362
+ changed: true,
363
+ };
364
+ }
365
+ //# sourceMappingURL=portable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"portable.js","sourceRoot":"","sources":["../../src/setup/portable.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ export type AgentFormat = "mcpServers" | "opencode" | "toml";
2
+ export type AgentId = "cursor" | "claude" | "opencode" | "devin" | "qwen" | "codex" | "agy" | "kimi" | "pi" | "commandcode" | "omp" | "mcode" | "mimo";
3
+ export interface AgentTarget {
4
+ id: AgentId;
5
+ label: string;
6
+ format: AgentFormat;
7
+ /** Path templates; `{project}`, `{home}` and `{opencodeConfigDir}` expand. */
8
+ mcpPaths: string[];
9
+ /** Rules-file path relative to the project root. */
10
+ rulesFile: string;
11
+ /**
12
+ * CLI binary used only for the nonfatal `not installed` diagnostic.
13
+ * `null` means the target has no meaningful local executable (for example an
14
+ * IDE or web-hosted agent), so the warning is not applicable.
15
+ */
16
+ executable: string | null;
17
+ }
18
+ export interface ResolveMcpPathsOptions {
19
+ projectPath?: string;
20
+ homeDir?: string;
21
+ opencodeConfigDir?: string;
22
+ env?: Record<string, string | undefined>;
23
+ }
24
+ export declare const AGENT_REGISTRY: Record<AgentId, AgentTarget>;
25
+ export declare const AGENT_IDS: AgentId[];
26
+ /**
27
+ * Explicit executable name used only for the nonfatal `not installed`
28
+ * diagnostic. It is intentionally declared per catalog entry and never inferred
29
+ * from the agent ID or from whether a config file exists. `null` means the
30
+ * target has no applicable local executable and must not warn.
31
+ */
32
+ export declare function agentExecutable(id: AgentId): string | null;
33
+ export declare function isAgentId(value: string): value is AgentId;
34
+ /**
35
+ * Resolve a target's MCP config paths. A nonempty
36
+ * `MUNINN_AGENT_<ID>_MCP_PATH` replaces the catalog paths; empty segments are
37
+ * ignored and an override that resolves to no paths is rejected.
38
+ */
39
+ export declare function resolveMcpPaths(target: AgentId | AgentTarget, options?: ResolveMcpPathsOptions): string[];
40
+ /** Rules path under the selected project root (or the catalog path without one). */
41
+ export declare function resolveRulesPath(target: AgentId | AgentTarget, options?: Pick<ResolveMcpPathsOptions, "projectPath">): string;
42
+ export type AgentSelection = {
43
+ ok: true;
44
+ ids: AgentId[];
45
+ } | {
46
+ ok: false;
47
+ unknown: string[];
48
+ valid: AgentId[];
49
+ };
50
+ /** Parse one ID, `all`, or a comma-separated list; deduplicate in catalog order. */
51
+ export declare function parseAgentSelection(value: string): AgentSelection;
52
+ /** True only when `child` is inside (or equal to) `root`, using path.relative. */
53
+ export declare function isProjectContained(child: string, root: string): boolean;
54
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/setup/registry.ts"],"names":[],"mappings":"AAWA,MAAM,MAAM,WAAW,GAAG,YAAY,GAAG,UAAU,GAAG,MAAM,CAAC;AAE7D,MAAM,MAAM,OAAO,GACf,QAAQ,GACR,QAAQ,GACR,UAAU,GACV,OAAO,GACP,MAAM,GACN,OAAO,GACP,KAAK,GACL,MAAM,GACN,IAAI,GACJ,aAAa,GACb,KAAK,GACL,OAAO,GACP,MAAM,CAAC;AAEX,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,WAAW,CAAC;IACpB,8EAA8E;IAC9E,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,oDAAoD;IACpD,SAAS,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,sBAAsB;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;CAC1C;AAED,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,OAAO,EAAE,WAAW,CA6GvD,CAAC;AAEF,eAAO,MAAM,SAAS,EAAkC,OAAO,EAAE,CAAC;AAElE;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAE1D;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,OAAO,CAEzD;AAgDD;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,OAAO,GAAG,WAAW,EAC7B,OAAO,GAAE,sBAA2B,GACnC,MAAM,EAAE,CAgBV;AAED,oFAAoF;AACpF,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,OAAO,GAAG,WAAW,EAC7B,OAAO,GAAE,IAAI,CAAC,sBAAsB,EAAE,aAAa,CAAM,GACxD,MAAM,CAKR;AAED,MAAM,MAAM,cAAc,GACtB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,GAAG,EAAE,OAAO,EAAE,CAAA;CAAE,GAC5B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,OAAO,EAAE,CAAA;CAAE,CAAC;AAEvD,oFAAoF;AACpF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,CAgBjE;AAED,kFAAkF;AAClF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAGvE"}
@@ -0,0 +1,225 @@
1
+ /**
2
+ * Catalog of supported agent destinations.
3
+ *
4
+ * The routes and formats are the Huginn integrator reference's definitions,
5
+ * reproduced here without importing Huginn. Paths are templates so callers can
6
+ * inject a home directory, project root, OpenCode config directory, or an
7
+ * environment override.
8
+ */
9
+ import { homedir } from "node:os";
10
+ import { isAbsolute, join, normalize, relative, resolve } from "node:path";
11
+ export const AGENT_REGISTRY = {
12
+ cursor: {
13
+ id: "cursor",
14
+ label: "Cursor",
15
+ format: "mcpServers",
16
+ mcpPaths: ["{project}/.cursor/mcp.json", "{home}/.cursor/mcp.json"],
17
+ rulesFile: ".cursorrules",
18
+ executable: null,
19
+ },
20
+ claude: {
21
+ id: "claude",
22
+ label: "Claude Code / Desktop",
23
+ format: "mcpServers",
24
+ mcpPaths: [
25
+ "{project}/.mcp.json",
26
+ "{home}/.claude.json",
27
+ "{home}/.claude/claude_desktop_config.json",
28
+ ],
29
+ rulesFile: "CLAUDE.md",
30
+ executable: "claude",
31
+ },
32
+ opencode: {
33
+ id: "opencode",
34
+ label: "OpenCode",
35
+ format: "opencode",
36
+ mcpPaths: ["{opencodeConfigDir}/opencode.json"],
37
+ rulesFile: "AGENTS.md",
38
+ executable: "opencode",
39
+ },
40
+ devin: {
41
+ id: "devin",
42
+ label: "Devin",
43
+ format: "mcpServers",
44
+ mcpPaths: ["{project}/.devin/mcp_config.json", "{home}/.config/devin/mcp_config.json"],
45
+ rulesFile: ".windsurf/rules/muninn.md",
46
+ executable: null,
47
+ },
48
+ qwen: {
49
+ id: "qwen",
50
+ label: "Qwen Code",
51
+ format: "mcpServers",
52
+ mcpPaths: ["{home}/.qwen/settings.json"],
53
+ rulesFile: "QWEN.md",
54
+ executable: "qwen",
55
+ },
56
+ codex: {
57
+ id: "codex",
58
+ label: "OpenAI Codex CLI",
59
+ format: "toml",
60
+ mcpPaths: ["{home}/.codex/config.toml"],
61
+ rulesFile: "AGENTS.md",
62
+ executable: "codex",
63
+ },
64
+ agy: {
65
+ id: "agy",
66
+ label: "Antigravity CLI (agy)",
67
+ format: "mcpServers",
68
+ mcpPaths: ["{home}/.gemini/config/mcp_config.json", "{project}/.agents/mcp_config.json"],
69
+ rulesFile: "AGENTS.md",
70
+ executable: "agy",
71
+ },
72
+ kimi: {
73
+ id: "kimi",
74
+ label: "Kimi Code CLI",
75
+ format: "mcpServers",
76
+ mcpPaths: ["{home}/.kimi-code/mcp.json", "{project}/.kimi/mcp.json"],
77
+ rulesFile: "AGENTS.md",
78
+ executable: "kimi",
79
+ },
80
+ pi: {
81
+ id: "pi",
82
+ label: "Pi coding agent",
83
+ format: "mcpServers",
84
+ mcpPaths: ["{home}/.pi/agent/mcp.json", "{project}/.pi/mcp.json"],
85
+ rulesFile: "AGENTS.md",
86
+ executable: "pi",
87
+ },
88
+ commandcode: {
89
+ id: "commandcode",
90
+ label: "Command Code",
91
+ format: "mcpServers",
92
+ mcpPaths: ["{home}/.commandcode/mcp.json", "{project}/.mcp.json"],
93
+ rulesFile: "AGENTS.md",
94
+ executable: "commandcode",
95
+ },
96
+ omp: {
97
+ id: "omp",
98
+ label: "Oh My Pi",
99
+ format: "mcpServers",
100
+ mcpPaths: ["{home}/.omp/mcp.json", "{project}/.omp/mcp.json"],
101
+ rulesFile: "AGENTS.md",
102
+ executable: "omp",
103
+ },
104
+ mcode: {
105
+ id: "mcode",
106
+ label: "MiniMax Code",
107
+ format: "mcpServers",
108
+ mcpPaths: ["{project}/.mcp.json"],
109
+ rulesFile: "AGENTS.md",
110
+ executable: "mcode",
111
+ },
112
+ mimo: {
113
+ id: "mimo",
114
+ label: "MiMo Code",
115
+ format: "opencode",
116
+ mcpPaths: ["{home}/.config/mimocode/mimocode.json"],
117
+ rulesFile: "AGENTS.md",
118
+ executable: "mimo",
119
+ },
120
+ };
121
+ export const AGENT_IDS = Object.keys(AGENT_REGISTRY);
122
+ /**
123
+ * Explicit executable name used only for the nonfatal `not installed`
124
+ * diagnostic. It is intentionally declared per catalog entry and never inferred
125
+ * from the agent ID or from whether a config file exists. `null` means the
126
+ * target has no applicable local executable and must not warn.
127
+ */
128
+ export function agentExecutable(id) {
129
+ return AGENT_REGISTRY[id].executable;
130
+ }
131
+ export function isAgentId(value) {
132
+ return Object.prototype.hasOwnProperty.call(AGENT_REGISTRY, value);
133
+ }
134
+ function envFor(options) {
135
+ return options.env ?? process.env;
136
+ }
137
+ function opencodeConfigDirFor(options) {
138
+ if (options.opencodeConfigDir)
139
+ return resolve(options.opencodeConfigDir);
140
+ const env = envFor(options);
141
+ const fromEnv = env.MUNINN_OPENCODE_CONFIG_DIR ?? env.HUGINN_OPENCODE_CONFIG_DIR;
142
+ if (fromEnv && fromEnv.trim().length > 0)
143
+ return resolve(fromEnv);
144
+ return join(options.homeDir ?? homedir(), ".config", "opencode");
145
+ }
146
+ function expandTemplate(template, options) {
147
+ const homeDir = options.homeDir ?? homedir();
148
+ const projectPath = options.projectPath === undefined ? undefined : resolve(options.projectPath);
149
+ let expanded = template
150
+ .replaceAll("{home}", homeDir)
151
+ .replaceAll("{opencodeConfigDir}", opencodeConfigDirFor(options));
152
+ if (projectPath !== undefined)
153
+ expanded = expanded.replaceAll("{project}", projectPath);
154
+ return normalize(expanded);
155
+ }
156
+ /**
157
+ * Split a colon-separated override without breaking a Windows drive letter
158
+ * (`C:\path:D:\path`). Empty segments are ignored.
159
+ */
160
+ function splitOverride(value) {
161
+ const raw = value.split(":");
162
+ const out = [];
163
+ for (let i = 0; i < raw.length; i++) {
164
+ const entry = raw[i];
165
+ if (/^[A-Za-z]$/.test(entry) && i + 1 < raw.length) {
166
+ const next = raw[i + 1];
167
+ if (next.startsWith("\\") || next.startsWith("/")) {
168
+ out.push(`${entry}:${next}`);
169
+ i++;
170
+ continue;
171
+ }
172
+ }
173
+ out.push(entry);
174
+ }
175
+ return out.map((entry) => entry.trim()).filter((entry) => entry.length > 0);
176
+ }
177
+ /**
178
+ * Resolve a target's MCP config paths. A nonempty
179
+ * `MUNINN_AGENT_<ID>_MCP_PATH` replaces the catalog paths; empty segments are
180
+ * ignored and an override that resolves to no paths is rejected.
181
+ */
182
+ export function resolveMcpPaths(target, options = {}) {
183
+ const spec = typeof target === "string" ? AGENT_REGISTRY[target] : target;
184
+ const env = envFor(options);
185
+ const override = env[`MUNINN_AGENT_${spec.id.toUpperCase()}_MCP_PATH`] ??
186
+ env[`HUGINN_AGENT_${spec.id.toUpperCase()}_MCP_PATH`];
187
+ const templates = override !== undefined && override.trim().length > 0
188
+ ? splitOverride(override)
189
+ : spec.mcpPaths;
190
+ if (templates.length === 0) {
191
+ throw new Error(`MUNINN_AGENT_${spec.id.toUpperCase()}_MCP_PATH contains no usable paths`);
192
+ }
193
+ return templates.map((template) => expandTemplate(template, options));
194
+ }
195
+ /** Rules path under the selected project root (or the catalog path without one). */
196
+ export function resolveRulesPath(target, options = {}) {
197
+ const spec = typeof target === "string" ? AGENT_REGISTRY[target] : target;
198
+ return options.projectPath === undefined
199
+ ? spec.rulesFile
200
+ : normalize(join(resolve(options.projectPath), spec.rulesFile));
201
+ }
202
+ /** Parse one ID, `all`, or a comma-separated list; deduplicate in catalog order. */
203
+ export function parseAgentSelection(value) {
204
+ const requested = value
205
+ .split(",")
206
+ .map((entry) => entry.trim().toLowerCase())
207
+ .filter((entry) => entry.length > 0);
208
+ if (requested.length === 0) {
209
+ return { ok: false, unknown: [value.trim() || "<empty>"], valid: [...AGENT_IDS] };
210
+ }
211
+ const unknown = requested.filter((entry) => entry !== "all" && !isAgentId(entry));
212
+ if (unknown.length > 0) {
213
+ return { ok: false, unknown: [...new Set(unknown)], valid: [...AGENT_IDS] };
214
+ }
215
+ if (requested.includes("all")) {
216
+ return { ok: true, ids: [...AGENT_IDS] };
217
+ }
218
+ return { ok: true, ids: AGENT_IDS.filter((id) => requested.includes(id)) };
219
+ }
220
+ /** True only when `child` is inside (or equal to) `root`, using path.relative. */
221
+ export function isProjectContained(child, root) {
222
+ const rel = relative(resolve(root), resolve(child));
223
+ return rel === "" || (rel !== ".." && !rel.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) && !isAbsolute(rel));
224
+ }
225
+ //# sourceMappingURL=registry.js.map