@melra/cli 0.3.0-alpha.11 → 0.3.0-alpha.13

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 (48) hide show
  1. package/README.md +14 -7
  2. package/dist/activity.d.ts +26 -0
  3. package/dist/activity.d.ts.map +1 -0
  4. package/dist/activity.js +404 -0
  5. package/dist/activity.js.map +1 -0
  6. package/dist/approval-screen.d.ts +35 -0
  7. package/dist/approval-screen.d.ts.map +1 -0
  8. package/dist/approval-screen.js +130 -0
  9. package/dist/approval-screen.js.map +1 -0
  10. package/dist/client-status.d.ts +24 -0
  11. package/dist/client-status.d.ts.map +1 -0
  12. package/dist/client-status.js +273 -0
  13. package/dist/client-status.js.map +1 -0
  14. package/dist/clients.d.ts +32 -0
  15. package/dist/clients.d.ts.map +1 -0
  16. package/dist/clients.js +588 -0
  17. package/dist/clients.js.map +1 -0
  18. package/dist/conformance.d.ts +7 -0
  19. package/dist/conformance.d.ts.map +1 -1
  20. package/dist/conformance.js +134 -30
  21. package/dist/conformance.js.map +1 -1
  22. package/dist/demo-workflow.d.ts +46 -0
  23. package/dist/demo-workflow.d.ts.map +1 -0
  24. package/dist/demo-workflow.js +58 -0
  25. package/dist/demo-workflow.js.map +1 -0
  26. package/dist/environment.d.ts +15 -1
  27. package/dist/environment.d.ts.map +1 -1
  28. package/dist/environment.js +30 -4
  29. package/dist/environment.js.map +1 -1
  30. package/dist/human.d.ts +67 -0
  31. package/dist/human.d.ts.map +1 -0
  32. package/dist/human.js +266 -0
  33. package/dist/human.js.map +1 -0
  34. package/dist/index.js +432 -77
  35. package/dist/index.js.map +1 -1
  36. package/dist/isolation.d.ts +35 -0
  37. package/dist/isolation.d.ts.map +1 -0
  38. package/dist/isolation.js +66 -0
  39. package/dist/isolation.js.map +1 -0
  40. package/dist/jsonc.d.ts +24 -0
  41. package/dist/jsonc.d.ts.map +1 -0
  42. package/dist/jsonc.js +238 -0
  43. package/dist/jsonc.js.map +1 -0
  44. package/dist/output.d.ts +28 -0
  45. package/dist/output.d.ts.map +1 -0
  46. package/dist/output.js +84 -0
  47. package/dist/output.js.map +1 -0
  48. package/package.json +11 -10
@@ -0,0 +1,130 @@
1
+ // Copyright 2026 XAGI Labs Private Limited
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * Characters a terminal does not show as themselves: controls (C0, C1, DEL),
5
+ * format characters (bidi overrides, zero-width, soft hyphen, tag characters),
6
+ * line and paragraph separators, and the ones that render as nothing at all
7
+ * (variation selectors, Hangul fillers, the grapheme joiner).
8
+ */
9
+ const HIDDEN = /[\p{Cc}\p{Cf}\p{Zl}\p{Zp}\u034f\u115f\u1160\u17b4\u17b5\u180b-\u180f\u3164\ufe00-\ufe0f\uffa0\u{e0100}-\u{e01ef}]/gu;
10
+ /**
11
+ * Text a terminal shows as text and nothing else. Everything in an approval
12
+ * render except its labels was chosen by the agent asking for approval, and a
13
+ * raw escape sequence in it can erase the line saying so, paint a different
14
+ * effect, and hide the real one. Each hidden character is spelled out as
15
+ * `\uXXXX` per UTF-16 unit, which inside JSON is also a valid escape for it.
16
+ */
17
+ export function printable(text, keepNewlines = false) {
18
+ return text.replace(HIDDEN, (character) => keepNewlines && character === "\n"
19
+ ? character
20
+ : Array.from({ length: character.length }, (_, index) => `\\u${character.charCodeAt(index).toString(16).padStart(4, "0")}`).join(""));
21
+ }
22
+ /** At most `limit` characters, saying how many more there were. */
23
+ function bounded(text, limit = 160) {
24
+ const shown = printable(text);
25
+ return shown.length > limit ? `${shown.slice(0, limit)}…(+${shown.length - limit} chars)` : shown;
26
+ }
27
+ /**
28
+ * The operation, one bounded line per leaf, so what the effect actually does
29
+ * (a command's arguments and environment, a move's destination, a request's
30
+ * method and body) sits in the summary and not only in the dump above it.
31
+ *
32
+ * Every operation schema is strict, so its top-level fields are a fixed set.
33
+ * Each list or record (args, env, headers, values, fields, filePaths) shows
34
+ * whole entries from both ends, the first and last always, within its own
35
+ * budget of lines, and says how many entries it left out, so no entry is shown
36
+ * in part. Lists print first, then objects (a browser target, env, headers),
37
+ * then plain values (a url, a cwd, a typed value) right above the effect: the
38
+ * fields of fixed size sit below everything an agent can make longer.
39
+ * Planning refuses a browser list its action never reads, so a list on screen
40
+ * is the action's own and never padding.
41
+ */
42
+ function operationLines(operation, fieldLimit = 8) {
43
+ const leaf = (path, value) => `${bounded(path, 60)}: ${bounded(typeof value === "string" ? JSON.stringify(value) : String(value))}`;
44
+ const leaves = (value, path, into) => {
45
+ if (Array.isArray(value)) {
46
+ if (value.length === 0)
47
+ into.push(`${bounded(path, 60)}: []`);
48
+ value.forEach((item, index) => leaves(item, `${path}[${index}]`, into));
49
+ }
50
+ else if (value !== null && typeof value === "object") {
51
+ const entries = Object.entries(value);
52
+ if (entries.length === 0)
53
+ into.push(`${bounded(path, 60)}: {}`);
54
+ for (const [key, item] of entries)
55
+ leaves(item, `${path}.${key}`, into);
56
+ }
57
+ else {
58
+ into.push(leaf(path, value));
59
+ }
60
+ return into;
61
+ };
62
+ const summarise = (field, value) => {
63
+ if (value === null || typeof value !== "object")
64
+ return [leaf(field, value)];
65
+ const entries = Array.isArray(value)
66
+ ? value.map((item, index) => leaves(item, `${field}[${index}]`, []))
67
+ : Object.entries(value).map(([key, item]) => leaves(item, `${field}.${key}`, []));
68
+ if (entries.length === 0)
69
+ return [`${bounded(field, 60)}: ${Array.isArray(value) ? "[]" : "{}"}`];
70
+ // Whole entries, alternately from each end, while they fit; when one end's
71
+ // next entry does not, the other end goes on alone.
72
+ let head = 1;
73
+ let tail = entries.length > 1 ? 1 : 0;
74
+ let used = entries[0].length + (tail === 1 ? entries.at(-1).length : 0);
75
+ let headOpen = true;
76
+ let tailOpen = true;
77
+ while (head + tail < entries.length && (headOpen || tailOpen)) {
78
+ const fromHead = headOpen && (!tailOpen || head <= tail);
79
+ const next = entries[fromHead ? head : entries.length - 1 - tail];
80
+ if (used + next.length > fieldLimit) {
81
+ if (fromHead)
82
+ headOpen = false;
83
+ else
84
+ tailOpen = false;
85
+ continue;
86
+ }
87
+ used += next.length;
88
+ if (fromHead)
89
+ head += 1;
90
+ else
91
+ tail += 1;
92
+ }
93
+ const hidden = entries.slice(head, entries.length - tail);
94
+ return [
95
+ ...entries.slice(0, head).flat(),
96
+ // A note as tall as what it stands for saves nothing: show that instead.
97
+ ...(hidden.flat().length <= 1
98
+ ? hidden.flat()
99
+ : [`…(+${hidden.length} more ${bounded(field, 60)} entries, all in the JSON above)`]),
100
+ ...entries.slice(entries.length - tail).flat(),
101
+ ];
102
+ };
103
+ if (operation === null || typeof operation !== "object")
104
+ return operation === undefined ? [] : [leaf("operation", operation)];
105
+ const rank = (value) => (Array.isArray(value) ? 0 : value !== null && typeof value === "object" ? 1 : 2);
106
+ return Object.entries(operation)
107
+ .sort(([, a], [, b]) => rank(a) - rank(b))
108
+ .flatMap(([field, value]) => summarise(field, value));
109
+ }
110
+ /**
111
+ * The approval screen, ending with what MELRA itself vouches for: the full
112
+ * contract first, so however long the agent's content runs it cannot push the
113
+ * effect off the screen, then the operation and the summary, each line
114
+ * bounded, right above the question.
115
+ */
116
+ export function approvalScreen(view) {
117
+ const { contract } = view;
118
+ return [
119
+ printable(JSON.stringify(contract, null, 2), true),
120
+ "\u001b[0m",
121
+ `Task ${view.task.id}, waiting for approval until ${view.task.approval?.expiresAt ?? "unknown"}`,
122
+ "Operation:",
123
+ ...operationLines(contract.operation).map((line) => ` ${line}`),
124
+ `Effect: ${bounded(contract.capability, 60)} on ${bounded(contract.target)} (${bounded(contract.effect, 20)}, ${bounded(contract.risk, 20)} risk)`,
125
+ `Goal (stated by the agent, unverified): ${bounded(contract.metadata.goal, 200)}`,
126
+ `Contract digest: ${view.renderDigest}`,
127
+ "",
128
+ ].join("\n");
129
+ }
130
+ //# sourceMappingURL=approval-screen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval-screen.js","sourceRoot":"","sources":["../src/approval-screen.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ export interface ClientStatus {
2
+ client: string;
3
+ path: string;
4
+ state: "configured" | "not configured" | "unreadable" | "not inspected";
5
+ command?: string;
6
+ pin?: string;
7
+ note?: string;
8
+ problems: string[];
9
+ }
10
+ export declare function resolvesOnPath(command: string): boolean;
11
+ export declare function clientStatuses(workspace: string): Promise<ClientStatus[]>;
12
+ export interface ClientChoice {
13
+ client: string;
14
+ label: string;
15
+ path?: string;
16
+ detected?: string;
17
+ }
18
+ export declare function detectClients(workspace: string): ClientChoice[];
19
+ export declare function clientsCheck(statuses: ClientStatus[]): {
20
+ name: string;
21
+ status: "pass" | "warn";
22
+ detail: string;
23
+ };
24
+ //# sourceMappingURL=client-status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-status.d.ts","sourceRoot":"","sources":["../src/client-status.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IAGb,KAAK,EAAE,YAAY,GAAG,gBAAgB,GAAG,YAAY,GAAG,eAAe,CAAC;IAGxE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAgCD,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAcvD;AA+ID,wBAAsB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAiB/E;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAeD,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,EAAE,CAuB/D;AAID,wBAAgB,YAAY,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;CAChB,CAeA"}
@@ -0,0 +1,273 @@
1
+ // Copyright 2026 XAGI Labs Private Limited
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { accessSync, constants, existsSync, statSync } from "node:fs";
4
+ import { homedir } from "node:os";
5
+ import { readFile } from "node:fs/promises";
6
+ import { delimiter, dirname, extname, join } from "node:path";
7
+ import { PRODUCT_VERSION } from "@melra/protocol";
8
+ import { CLIENTS, isObject } from "./clients.js";
9
+ import { parseJsonc } from "./jsonc.js";
10
+ // Where each JSON shape keeps its servers, matching what `clientConfig` writes.
11
+ const SERVER_KEYS = {
12
+ mcpServers: ["mcpServers"],
13
+ vscode: ["servers"],
14
+ zed: ["context_servers"],
15
+ opencode: ["mcp"],
16
+ amp: ["amp.mcpServers"],
17
+ openclaw: ["mcp", "servers"],
18
+ copilot: ["mcpServers"],
19
+ droid: ["mcpServers"],
20
+ kilo: ["mcp"],
21
+ };
22
+ // The top-level YAML map each YAML shape keeps its servers under.
23
+ const YAML_KEYS = { goose: "extensions", hermes: "mcp_servers" };
24
+ function isExecutable(path) {
25
+ try {
26
+ // Windows has no execute bit; X_OK there is F_OK, so the extension is
27
+ // what makes a file runnable and PATHEXT below decides that.
28
+ accessSync(path, constants.X_OK);
29
+ return statSync(path).isFile();
30
+ }
31
+ catch {
32
+ return false;
33
+ }
34
+ }
35
+ // What the client would find when it spawns `command`. This sees doctor's own
36
+ // PATH, which a GUI client started from the dock may not share, so a hit is
37
+ // necessary rather than sufficient.
38
+ export function resolvesOnPath(command) {
39
+ if (/[\\/]/.test(command))
40
+ return isExecutable(command);
41
+ // Windows spawns `melra` as `melra.cmd`: a bare name is tried with every
42
+ // PATHEXT extension, a name that already has one is tried as written.
43
+ const extensions = process.platform === "win32" && extname(command) === ""
44
+ ? (process.env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean)
45
+ : [""];
46
+ return (process.env.PATH ?? "")
47
+ .split(delimiter)
48
+ .filter(Boolean)
49
+ .some((directory) => extensions.some((extension) => isExecutable(join(directory, command + extension))));
50
+ }
51
+ const strings = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
52
+ function launchOf(entry) {
53
+ if (!isObject(entry))
54
+ return undefined;
55
+ // OpenCode keeps the whole argv in `command`.
56
+ if (Array.isArray(entry.command))
57
+ return strings(entry.command);
58
+ return typeof entry.command === "string" ? [entry.command, ...strings(entry.args)] : undefined;
59
+ }
60
+ // Line-based rather than a TOML parser, to stay dependency-free: it reads the
61
+ // single-line `command =` / `args =` inside [mcp_servers.melra] that `setup`
62
+ // writes, and leaves anything fancier unchecked instead of guessing.
63
+ function codexLaunch(toml) {
64
+ let inside = false;
65
+ let command;
66
+ let args = [];
67
+ for (const line of toml.split(/\r?\n/)) {
68
+ const header = /^\s*\[\[?\s*([^\]]+?)\s*\]\]?\s*(#.*)?$/.exec(line);
69
+ if (header !== null) {
70
+ inside = header[1] === "mcp_servers.melra";
71
+ continue;
72
+ }
73
+ if (!inside)
74
+ continue;
75
+ const value = /^\s*(command|args)\s*=\s*(.+?)\s*$/.exec(line);
76
+ try {
77
+ // TOML basic strings and arrays of them are valid JSON.
78
+ if (value?.[1] === "command")
79
+ command = JSON.parse(value[2] ?? "");
80
+ if (value?.[1] === "args")
81
+ args = strings(JSON.parse(value[2] ?? ""));
82
+ }
83
+ catch {
84
+ // A literal string or multi-line array: leave it unchecked.
85
+ }
86
+ }
87
+ return typeof command === "string" ? [command, ...args] : undefined;
88
+ }
89
+ // The `cmd:`/`command:` and `args:` lines `setup` writes into Goose's,
90
+ // Hermes's, and Continue's YAML, whose values are JSON-quoted. Anything written another way
91
+ // is left unchecked rather than guessed at.
92
+ function yamlLaunch(lines) {
93
+ let command;
94
+ let args = [];
95
+ for (const line of lines) {
96
+ const value = /^\s*(?:-\s+)?(cmd|command|args)\s*:\s*(.+?)\s*$/.exec(line);
97
+ try {
98
+ if (value?.[1] === "args")
99
+ args = strings(JSON.parse(value[2] ?? ""));
100
+ else if (value !== null)
101
+ command = JSON.parse(value[2] ?? "");
102
+ }
103
+ catch {
104
+ // A plain or single-quoted scalar: leave it unchecked.
105
+ }
106
+ }
107
+ return typeof command === "string" ? [command, ...args] : undefined;
108
+ }
109
+ // The lines of the `<map>.melra` block (Goose's `extensions`, Hermes's
110
+ // `mcp_servers`), or undefined when there is none.
111
+ function yamlBlock(yaml, map) {
112
+ const lines = yaml.split(/\r?\n/);
113
+ const start = lines.findIndex((line) => line.replace(/\s*(#.*)?$/, "") === `${map}:`);
114
+ if (start < 0)
115
+ return undefined;
116
+ let block;
117
+ let depth = 0;
118
+ for (const line of lines.slice(start + 1)) {
119
+ if (/^\S/.test(line))
120
+ break; // the next top-level key
121
+ if (line.trim() === "")
122
+ continue;
123
+ const indent = /^ */.exec(line)?.[0].length ?? 0;
124
+ if (block !== undefined && indent <= depth)
125
+ break;
126
+ if (block !== undefined)
127
+ block.push(line);
128
+ else if (/^\s+["']?melra["']?:\s*(#.*)?$/.test(line)) {
129
+ block = [];
130
+ depth = indent;
131
+ }
132
+ }
133
+ return block;
134
+ }
135
+ function configured(base, launch) {
136
+ const [command] = launch ?? [];
137
+ if (command === undefined) {
138
+ return { ...base, state: "configured", note: "no command to check", problems: [] };
139
+ }
140
+ const problems = [];
141
+ if (!resolvesOnPath(command))
142
+ problems.push(`'${command}' not found on PATH`);
143
+ const pin = launch?.map((arg) => /^@melra\/cli@(\d\S*)$/.exec(arg)?.[1]).find(Boolean);
144
+ // A pin is what keeps an npx launch on one version, so after an upgrade it
145
+ // keeps launching the old server until the config is rewritten.
146
+ if (pin !== undefined && pin !== PRODUCT_VERSION) {
147
+ problems.push(`pinned to @melra/cli@${pin}, this is ${PRODUCT_VERSION}; fix: melra setup --client ${base.client} --write`);
148
+ }
149
+ return {
150
+ ...base,
151
+ state: "configured",
152
+ command,
153
+ ...(pin === undefined ? {} : { pin }),
154
+ problems,
155
+ };
156
+ }
157
+ function inspect(client, shape, path, text) {
158
+ const base = { client, path };
159
+ const map = YAML_KEYS[shape];
160
+ if (map !== undefined) {
161
+ const block = yamlBlock(text, map);
162
+ return block === undefined
163
+ ? { ...base, state: "not configured", problems: [] }
164
+ : configured(base, yamlLaunch(block));
165
+ }
166
+ // MELRA owns this file outright, so its existence is the configuration.
167
+ if (shape === "continue")
168
+ return configured(base, yamlLaunch(text.split(/\r?\n/)));
169
+ if (shape === "codex") {
170
+ return /^\s*\[\s*mcp_servers\.melra\s*\]/m.test(text)
171
+ ? configured(base, codexLaunch(text))
172
+ : { ...base, state: "not configured", problems: [] };
173
+ }
174
+ const key = SERVER_KEYS[shape];
175
+ if (key === undefined) {
176
+ return { ...base, state: "not inspected", note: `present; ${shape} format not inspected`, problems: [] };
177
+ }
178
+ let parsed;
179
+ try {
180
+ // JSONC, because Zed and VS Code settings usually carry comments and
181
+ // trailing commas; read with the same parser `setup --write` edits with.
182
+ parsed = parseJsonc(text).value;
183
+ }
184
+ catch {
185
+ // Not even JSONC. A text search still answers the question people ask,
186
+ // just not what the entry launches.
187
+ return /"melra"\s*:/.test(text)
188
+ ? { ...base, state: "configured", note: "not valid JSONC, found by text search; command not checked", problems: [] }
189
+ : { ...base, state: "not configured", note: "not valid JSONC, searched as text", problems: [] };
190
+ }
191
+ const servers = key.reduce((at, step) => (isObject(at) ? at[step] : undefined), parsed);
192
+ const entry = isObject(servers) ? servers.melra : undefined;
193
+ return entry === undefined
194
+ ? { ...base, state: "not configured", problems: [] }
195
+ : configured(base, launchOf(entry));
196
+ }
197
+ // Read-only by construction: this only ever reads the files `setup --write`
198
+ // would write, so doctor can run against a machine without changing it.
199
+ export async function clientStatuses(workspace) {
200
+ const statuses = [];
201
+ for (const [client, { shape, path: pathOf }] of Object.entries(CLIENTS)) {
202
+ const path = pathOf?.(workspace);
203
+ if (path === undefined)
204
+ continue;
205
+ let text;
206
+ try {
207
+ text = await readFile(path, "utf8");
208
+ }
209
+ catch (error) {
210
+ const code = error.code;
211
+ if (code === "ENOENT" || code === "ENOTDIR")
212
+ continue;
213
+ statuses.push({ client, path, state: "unreadable", problems: [`unreadable: ${code ?? String(error)}`] });
214
+ continue;
215
+ }
216
+ statuses.push(inspect(client, shape, path, text));
217
+ }
218
+ return statuses;
219
+ }
220
+ // Which clients look installed: a config file, the directory it would go in,
221
+ // or the client's own executable on PATH. Any one is enough — a fresh install
222
+ // has a directory and no file, and a CLI client may have neither yet. The
223
+ // directory test is skipped where it is the workspace itself, which always
224
+ // exists and so says nothing about Claude Code.
225
+ // `/Applications` or `~/Applications`, where drag-installed apps go.
226
+ function macAppInstalled(app) {
227
+ return (process.platform === "darwin" &&
228
+ [join("/Applications", app), join(homedir(), "Applications", app)].some((path) => existsSync(path)));
229
+ }
230
+ export function detectClients(workspace) {
231
+ return Object.entries(CLIENTS).flatMap(([client, { label, path: pathOf, bin, app }]) => {
232
+ if (client === "generic")
233
+ return [];
234
+ const path = pathOf?.(workspace);
235
+ const detected = path !== undefined && existsSync(path)
236
+ ? "config file found"
237
+ : path !== undefined && dirname(path) !== workspace && existsSync(dirname(path))
238
+ ? "config folder found"
239
+ : bin !== undefined && resolvesOnPath(bin)
240
+ ? `'${bin}' on PATH`
241
+ : app !== undefined && macAppInstalled(app)
242
+ ? `${app} installed`
243
+ : undefined;
244
+ return [
245
+ {
246
+ client,
247
+ label,
248
+ ...(path === undefined ? {} : { path }),
249
+ ...(detected === undefined ? {} : { detected }),
250
+ },
251
+ ];
252
+ });
253
+ }
254
+ // `warn` at worst: a machine with no client configured is how SDK users run,
255
+ // and a client problem never stops MELRA itself from working.
256
+ export function clientsCheck(statuses) {
257
+ const hint = "run 'melra setup --client <name> --write' to add MELRA to one";
258
+ if (statuses.length === 0) {
259
+ return { name: "clients", status: "pass", detail: `no MCP client config files found; ${hint}` };
260
+ }
261
+ const lines = statuses.map(({ client, state, note, problems }) => {
262
+ const extra = [...(note === undefined ? [] : [note]), ...problems];
263
+ return `${client}: ${state}${extra.length === 0 ? "" : ` (${extra.join("; ")})`}`;
264
+ });
265
+ if (!statuses.some((status) => status.state === "configured"))
266
+ lines.push(hint);
267
+ return {
268
+ name: "clients",
269
+ status: statuses.some((status) => status.problems.length > 0) ? "warn" : "pass",
270
+ detail: lines.join("; "),
271
+ };
272
+ }
273
+ //# sourceMappingURL=client-status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-status.js","sourceRoot":"","sources":["../src/client-status.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ export interface ServerEntry {
2
+ command: string;
3
+ args: string[];
4
+ env: Record<string, string>;
5
+ }
6
+ type Shape = "mcpServers" | "vscode" | "zed" | "opencode" | "codex" | "goose" | "continue" | "amp" | "openclaw" | "hermes" | "copilot" | "droid" | "kilo";
7
+ interface Client {
8
+ label: string;
9
+ shape: Shape;
10
+ path?: (workspace: string) => string;
11
+ bin?: string;
12
+ app?: string;
13
+ next?: string;
14
+ }
15
+ export declare const CLIENTS: Record<string, Client>;
16
+ export declare function resolveClient(name: string): string;
17
+ export declare function clientConfig(name: string, entry: ServerEntry): Record<string, unknown> | string;
18
+ export declare function clientConfigPath(name: string, workspace: string): string | undefined;
19
+ export declare const isObject: (value: unknown) => value is Record<string, unknown>;
20
+ /**
21
+ * Merge MELRA into the client's own config file, keeping everything else in
22
+ * it. The previous file is copied to `<file>.bak` first. JSON and JSONC files
23
+ * are edited in place by `withMelraJson`, so comments, trailing commas, and
24
+ * formatting outside MELRA's own entry survive; a file that is not valid JSONC
25
+ * is refused. Continue's file is MELRA's alone, so it is replaced whole.
26
+ */
27
+ export declare function writeClientConfig(path: string, config: Record<string, unknown> | string, name: string): Promise<{
28
+ backup?: string;
29
+ unchanged?: true;
30
+ }>;
31
+ export {};
32
+ //# sourceMappingURL=clients.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clients.d.ts","sourceRoot":"","sources":["../src/clients.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7B;AAMD,KAAK,KAAK,GACN,YAAY,GACZ,QAAQ,GACR,KAAK,GACL,UAAU,GACV,OAAO,GACP,OAAO,GACP,UAAU,GACV,KAAK,GACL,UAAU,GACV,QAAQ,GACR,SAAS,GACT,OAAO,GACP,MAAM,CAAC;AAEX,UAAU,MAAM;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,KAAK,CAAC;IAEb,IAAI,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;IAGrC,GAAG,CAAC,EAAE,MAAM,CAAC;IAGb,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAgBD,eAAO,MAAM,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CA+O1C,CAAC;AAoBF,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQlD;AAuED,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,WAAW,GACjB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAoDlC;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEpF;AAED,eAAO,MAAM,QAAQ,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CACH,CAAC;AAgKvE;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,EACxC,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,IAAI,CAAA;CAAE,CAAC,CA4BhD"}