clef-mcp 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -26,11 +26,14 @@ Clef does **not** generate prose. It reads a `state` plus a set of typed questio
26
26
  # 1. Detect hardware, download the model (~6 GB) + llama.cpp runtime, verify checksum + inference
27
27
  npx clef-mcp install
28
28
 
29
- # 2. Run the MCP server (stdio)
29
+ # 2. Register the MCP server + agent skill in your clients (zcode, claude-code, codex, cursor)
30
+ npx clef-mcp setup
31
+
32
+ # 3. Run the MCP server (stdio)
30
33
  npx clef-mcp
31
34
  ```
32
35
 
33
- `clef-mcp` (step 2) never downloads anything. If the model is missing, tool calls return a structured `MODEL_NOT_INSTALLED` error with a hint.
36
+ `clef-mcp` (step 3) never downloads anything. If the model is missing, tool calls return a structured `MODEL_NOT_INSTALLED` error with a hint. Steps 1 and 2 can be combined: `npx clef-mcp install --setup`.
34
37
 
35
38
  ### Register with your MCP client
36
39
 
@@ -150,11 +153,12 @@ The tool schema tells the client *what* `clef_decide` accepts; agents also need
150
153
  Install it for your agent(s):
151
154
 
152
155
  ```bash
153
- # from this repo
154
- cp -r skills/clef-decisions ~/.agents/skills/
156
+ # automatic (registers the MCP server too)
157
+ clef-mcp setup
155
158
 
156
- # or from the npm package
157
- cp -r "$(npm root -g)/clef-mcp/skills/clef-decisions" ~/.agents/skills/
159
+ # or copy the skill manually
160
+ cp -r skills/clef-decisions ~/.agents/skills/ # from this repo
161
+ cp -r "$(npm root -g)/clef-mcp/skills/clef-decisions" ~/.agents/skills/ # from the npm package
158
162
  ```
159
163
 
160
164
  `~/.agents/skills/` is the shared location for ZCode / Claude Code / Codex-style agents.
@@ -164,6 +168,7 @@ cp -r "$(npm root -g)/clef-mcp/skills/clef-decisions" ~/.agents/skills/
164
168
  ```bash
165
169
  clef-mcp # run the MCP server on stdio (default command)
166
170
  clef-mcp install # detect hardware → download model + runtime → verify checksum → verify inference
171
+ clef-mcp setup # register the MCP server + agent skill in zcode / claude-code / codex / cursor
167
172
  clef-mcp models # list models/quantizations and install status
168
173
  clef-mcp status # runtime, model, memory summary
169
174
  clef-mcp doctor # full diagnosis (platform, RAM, GPU, binary, model, checksum*, inference, MCP config)
@@ -171,7 +176,7 @@ clef-mcp uninstall # remove the model (and optionally the managed runtime)
171
176
  clef-mcp evals # run the evaluation dataset against the installed model
172
177
  ```
173
178
 
174
- Useful flags: `install --quant Q8_0 --yes --skip-probe`, `doctor --deep` (re-hashes the model file), `uninstall --runtime --yes`.
179
+ Useful flags: `install --quant Q8_0 --yes --skip-probe`, `install --setup` (runs setup right after install), `setup --clients zcode,cursor --no-skill`, `doctor --deep` (re-hashes the model file), `uninstall --runtime --yes`.
175
180
 
176
181
  ## Configuration (environment variables)
177
182
 
package/dist/cli.js CHANGED
@@ -1,29 +1,15 @@
1
1
  #!/usr/bin/env node
2
-
3
- // src/clef/errors.ts
4
- var ClefErrorCode = {
5
- MODEL_NOT_INSTALLED: "MODEL_NOT_INSTALLED",
6
- MODEL_LOAD_FAILED: "MODEL_LOAD_FAILED",
7
- RUNTIME_NOT_FOUND: "RUNTIME_NOT_FOUND",
8
- RUNTIME_INIT_FAILED: "RUNTIME_INIT_FAILED",
9
- RUNTIME_NOT_SUPPORTED: "RUNTIME_NOT_SUPPORTED",
10
- INVALID_INPUT: "INVALID_INPUT",
11
- CLEF_INFERENCE_FAILED: "CLEF_INFERENCE_FAILED",
12
- UNSUPPORTED_PLATFORM: "UNSUPPORTED_PLATFORM",
13
- OUT_OF_MEMORY: "OUT_OF_MEMORY",
14
- CHECKSUM_MISMATCH: "CHECKSUM_MISMATCH",
15
- DOWNLOAD_FAILED: "DOWNLOAD_FAILED"
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __esm = (fn, res) => function __init() {
5
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
16
6
  };
17
- var ClefError = class extends Error {
18
- code;
19
- hint;
20
- constructor(code, message, hint) {
21
- super(message);
22
- this.name = "ClefError";
23
- this.code = code;
24
- this.hint = hint;
25
- }
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
26
10
  };
11
+
12
+ // src/clef/errors.ts
27
13
  function errorJson(err) {
28
14
  if (err instanceof ClefError) {
29
15
  return {
@@ -53,12 +39,268 @@ function exitCodeFor(err) {
53
39
  }
54
40
  return 1;
55
41
  }
42
+ var ClefErrorCode, ClefError;
43
+ var init_errors = __esm({
44
+ "src/clef/errors.ts"() {
45
+ "use strict";
46
+ ClefErrorCode = {
47
+ MODEL_NOT_INSTALLED: "MODEL_NOT_INSTALLED",
48
+ MODEL_LOAD_FAILED: "MODEL_LOAD_FAILED",
49
+ RUNTIME_NOT_FOUND: "RUNTIME_NOT_FOUND",
50
+ RUNTIME_INIT_FAILED: "RUNTIME_INIT_FAILED",
51
+ RUNTIME_NOT_SUPPORTED: "RUNTIME_NOT_SUPPORTED",
52
+ INVALID_INPUT: "INVALID_INPUT",
53
+ CLEF_INFERENCE_FAILED: "CLEF_INFERENCE_FAILED",
54
+ UNSUPPORTED_PLATFORM: "UNSUPPORTED_PLATFORM",
55
+ OUT_OF_MEMORY: "OUT_OF_MEMORY",
56
+ CHECKSUM_MISMATCH: "CHECKSUM_MISMATCH",
57
+ DOWNLOAD_FAILED: "DOWNLOAD_FAILED"
58
+ };
59
+ ClefError = class extends Error {
60
+ code;
61
+ hint;
62
+ constructor(code, message, hint) {
63
+ super(message);
64
+ this.name = "ClefError";
65
+ this.code = code;
66
+ this.hint = hint;
67
+ }
68
+ };
69
+ }
70
+ });
71
+
72
+ // src/cli/prompt.ts
73
+ import readline from "readline/promises";
74
+ async function confirm(question, yes) {
75
+ if (yes) return true;
76
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
77
+ throw new ClefError(
78
+ ClefErrorCode.INVALID_INPUT,
79
+ "Refusing to proceed interactively without a terminal.",
80
+ "Re-run with --yes to confirm non-interactively."
81
+ );
82
+ }
83
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
84
+ try {
85
+ const answer = (await rl.question(`${question} [Y/n] `)).trim().toLowerCase();
86
+ return answer === "" || answer === "y" || answer === "yes";
87
+ } finally {
88
+ rl.close();
89
+ }
90
+ }
91
+ var init_prompt = __esm({
92
+ "src/cli/prompt.ts"() {
93
+ "use strict";
94
+ init_errors();
95
+ }
96
+ });
97
+
98
+ // src/cli/setup.ts
99
+ var setup_exports = {};
100
+ __export(setup_exports, {
101
+ SERVER_ENTRY: () => SERVER_ENTRY,
102
+ installSkill: () => installSkill,
103
+ runSetup: () => runSetup
104
+ });
105
+ import { execFile as execFile4 } from "child_process";
106
+ import fsSync2 from "fs";
107
+ import fsp6 from "fs/promises";
108
+ import os4 from "os";
109
+ import path9 from "path";
110
+ import { fileURLToPath as fileURLToPath2 } from "url";
111
+ function bundledSkillPath() {
112
+ return fileURLToPath2(new URL("../skills/clef-decisions/SKILL.md", import.meta.url));
113
+ }
114
+ async function mergeJsonServerEntry(file, serverKey, container) {
115
+ let doc = {};
116
+ try {
117
+ doc = JSON.parse(await fsp6.readFile(file, "utf8"));
118
+ } catch {
119
+ doc = {};
120
+ }
121
+ if (container === "mcp.servers") {
122
+ const mcp = doc.mcp ?? {};
123
+ const servers = mcp.servers ?? {};
124
+ if (servers[serverKey]) return "already-configured";
125
+ servers[serverKey] = { ...SERVER_ENTRY };
126
+ mcp.servers = servers;
127
+ doc.mcp = mcp;
128
+ } else {
129
+ const servers = doc.mcpServers ?? {};
130
+ if (servers[serverKey]) return "already-configured";
131
+ servers[serverKey] = { command: SERVER_ENTRY.command, args: [...SERVER_ENTRY.args] };
132
+ doc.mcpServers = servers;
133
+ }
134
+ await fsp6.mkdir(path9.dirname(file), { recursive: true });
135
+ await fsp6.writeFile(file, JSON.stringify(doc, null, 2) + "\n", "utf8");
136
+ return "configured";
137
+ }
138
+ async function setupCodex() {
139
+ const file = path9.join(HOME(), ".codex", "config.toml");
140
+ let content = "";
141
+ try {
142
+ content = await fsp6.readFile(file, "utf8");
143
+ } catch {
144
+ content = "";
145
+ }
146
+ if (content.includes("[mcp_servers.clef-mcp]")) {
147
+ return { client: "codex", status: "already-configured", detail: file };
148
+ }
149
+ const next = (content && !content.endsWith("\n") ? content + "\n" : content) + "\n" + CODEX_SECTION;
150
+ await fsp6.mkdir(path9.dirname(file), { recursive: true });
151
+ await fsp6.writeFile(file, next, "utf8");
152
+ return { client: "codex", status: "configured", detail: file };
153
+ }
154
+ async function setupZcode() {
155
+ const file = path9.join(HOME(), ".zcode", "cli", "config.json");
156
+ const status = await mergeJsonServerEntry(file, "clef-mcp", "mcp.servers");
157
+ return { client: "zcode", status, detail: file };
158
+ }
159
+ async function setupCursor() {
160
+ const file = path9.join(HOME(), ".cursor", "mcp.json");
161
+ const status = await mergeJsonServerEntry(file, "clef-mcp", "mcpServers");
162
+ return { client: "cursor", status, detail: file };
163
+ }
164
+ function whichCli(bin) {
165
+ const dirs = (process.env.PATH ?? "").split(path9.delimiter).filter(Boolean);
166
+ for (const dir of dirs) {
167
+ const candidate = path9.join(dir, bin);
168
+ try {
169
+ fsSync2.accessSync(candidate, fsSync2.constants.X_OK);
170
+ return candidate;
171
+ } catch {
172
+ }
173
+ }
174
+ return void 0;
175
+ }
176
+ async function setupClaudeCode() {
177
+ const claude = whichCli("claude");
178
+ if (!claude) {
179
+ return {
180
+ client: "claude-code",
181
+ status: "manual-hint",
182
+ detail: "claude CLI not found \u2014 run manually: claude mcp add clef-mcp -- clef-mcp"
183
+ };
184
+ }
185
+ const existing = await new Promise((resolve) => {
186
+ execFile4(claude, ["mcp", "list"], { timeout: 3e4, encoding: "utf8" }, (_err, stdout) => resolve(String(stdout)));
187
+ });
188
+ if (existing.includes("clef-mcp")) {
189
+ return { client: "claude-code", status: "already-configured", detail: "claude mcp list" };
190
+ }
191
+ await new Promise((resolve, reject) => {
192
+ execFile4(
193
+ claude,
194
+ ["mcp", "add", "--scope", "user", "clef-mcp", "--", "clef-mcp"],
195
+ { timeout: 6e4, encoding: "utf8" },
196
+ (err) => err ? reject(err) : resolve()
197
+ );
198
+ });
199
+ return { client: "claude-code", status: "configured", detail: "claude mcp add --scope user" };
200
+ }
201
+ async function installSkill() {
202
+ const src = bundledSkillPath();
203
+ const destDir = path9.join(HOME(), ".agents", "skills", "clef-decisions");
204
+ const dest = path9.join(destDir, "SKILL.md");
205
+ let content = "";
206
+ try {
207
+ content = await fsp6.readFile(dest, "utf8");
208
+ } catch {
209
+ }
210
+ const incoming = await fsp6.readFile(src, "utf8");
211
+ if (content === incoming) {
212
+ return { client: "skill", status: "already-configured", detail: dest };
213
+ }
214
+ await fsp6.mkdir(destDir, { recursive: true });
215
+ await fsp6.writeFile(dest, incoming, "utf8");
216
+ return { client: "skill", status: "configured", detail: dest };
217
+ }
218
+ function parseClients(raw) {
219
+ const all = ["zcode", "claude-code", "codex", "cursor"];
220
+ if (!raw || raw === "all") return all;
221
+ const wanted = raw.split(",").map((s) => s.trim().toLowerCase()).filter(Boolean);
222
+ for (const w of wanted) {
223
+ if (!all.includes(w)) {
224
+ throw new ClefError(
225
+ ClefErrorCode.INVALID_INPUT,
226
+ `Unknown client "${w}".`,
227
+ `Available: ${all.join(", ")} (or "all")`
228
+ );
229
+ }
230
+ }
231
+ return wanted;
232
+ }
233
+ async function runSetup(opts) {
234
+ const wantSkill = opts.skill === true || opts.noSkill !== true;
235
+ const clients = parseClients(opts.clients);
236
+ const plan = [...clients, ...wantSkill ? ["skill"] : []];
237
+ console.log(`Setup will register clef-mcp with: ${plan.join(", ")}
238
+ `);
239
+ const ok = await confirm("Continue?", opts.yes === true);
240
+ if (!ok) {
241
+ console.log("Aborted. Nothing was changed.");
242
+ return;
243
+ }
244
+ const reports = [];
245
+ for (const client of clients) {
246
+ try {
247
+ if (client === "zcode") reports.push(await setupZcode());
248
+ else if (client === "cursor") reports.push(await setupCursor());
249
+ else if (client === "codex") reports.push(await setupCodex());
250
+ else if (client === "claude-code") reports.push(await setupClaudeCode());
251
+ } catch (err) {
252
+ reports.push({
253
+ client,
254
+ status: "manual-hint",
255
+ detail: `failed: ${err instanceof Error ? err.message : String(err)}`
256
+ });
257
+ }
258
+ }
259
+ if (wantSkill) {
260
+ try {
261
+ reports.push(await installSkill());
262
+ } catch (err) {
263
+ reports.push({
264
+ client: "skill",
265
+ status: "manual-hint",
266
+ detail: `failed: ${err instanceof Error ? err.message : String(err)}`
267
+ });
268
+ }
269
+ }
270
+ console.log("");
271
+ for (const r of reports) {
272
+ const mark2 = r.status === "configured" ? "+" : r.status === "already-configured" ? "=" : "!";
273
+ console.log(`${mark2} ${r.client.padEnd(12)} ${r.status.padEnd(20)} ${r.detail}`);
274
+ }
275
+ console.log("\nDone. Restart your MCP clients (new agent sessions) to pick up the server.");
276
+ }
277
+ var SERVER_ENTRY, HOME, CODEX_SECTION;
278
+ var init_setup = __esm({
279
+ "src/cli/setup.ts"() {
280
+ "use strict";
281
+ init_errors();
282
+ init_prompt();
283
+ SERVER_ENTRY = { command: "clef-mcp", args: [], type: "stdio" };
284
+ HOME = () => os4.homedir();
285
+ CODEX_SECTION = [
286
+ "[mcp_servers.clef-mcp]",
287
+ 'command = "clef-mcp"',
288
+ "args = []",
289
+ ""
290
+ ].join("\n");
291
+ }
292
+ });
293
+
294
+ // src/cli/index.ts
295
+ init_errors();
56
296
 
57
297
  // src/mcp/server.ts
298
+ init_errors();
58
299
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
59
300
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
60
301
 
61
302
  // src/clef/systemone.ts
303
+ init_errors();
62
304
  function stateToString(state) {
63
305
  if (typeof state === "string") return state;
64
306
  try {
@@ -369,6 +611,7 @@ function llamaServerName(platform) {
369
611
  }
370
612
 
371
613
  // src/models/registry.ts
614
+ init_errors();
372
615
  var GB = 1024 ** 3;
373
616
  var CLEF_FLASH = {
374
617
  id: "clef-flash",
@@ -516,6 +759,7 @@ function readRuntimeManifest(manifestPath) {
516
759
  }
517
760
 
518
761
  // src/runtime/binary.ts
762
+ init_errors();
519
763
  import fs2 from "fs";
520
764
  import path4 from "path";
521
765
  function existsExecutable(p) {
@@ -571,6 +815,7 @@ function resolveLlamaServerBinary(cfg, deps = {}) {
571
815
  }
572
816
 
573
817
  // src/runtime/llama-cpp.ts
818
+ init_errors();
574
819
  import { spawn } from "child_process";
575
820
  import net from "net";
576
821
  var STDERR_TAIL_LIMIT = 4e3;
@@ -608,6 +853,7 @@ var LlamaCppRuntime = class {
608
853
  this.host = opts.host ?? "127.0.0.1";
609
854
  this.loadTimeoutMs = opts.loadTimeoutMs ?? 12e4;
610
855
  this.requestTimeoutMs = opts.requestTimeoutMs ?? 6e4;
856
+ this.batchSize = opts.batchSize ?? (Number.parseInt(process.env.CLEF_LLAMA_BATCH ?? "", 10) || 8192);
611
857
  }
612
858
  opts;
613
859
  proc;
@@ -617,6 +863,7 @@ var LlamaCppRuntime = class {
617
863
  requestTimeoutMs;
618
864
  /** Serializes decide() calls: the llama.cpp clef path handles one sequence per batch. */
619
865
  queue = Promise.resolve();
866
+ batchSize;
620
867
  get endpoint() {
621
868
  if (!this.resolvedPort) throw new ClefError(ClefErrorCode.RUNTIME_INIT_FAILED, "Runtime is not started");
622
869
  return `http://${this.host}:${this.resolvedPort}`;
@@ -636,6 +883,10 @@ var LlamaCppRuntime = class {
636
883
  "--port",
637
884
  String(port),
638
885
  "--no-webui",
886
+ "-b",
887
+ String(this.batchSize),
888
+ "-ub",
889
+ String(this.batchSize),
639
890
  ...this.opts.alias ? ["--alias", this.opts.alias] : []
640
891
  ];
641
892
  this.opts.log?.debug("spawning llama-server", { bin: this.opts.serverBin, args });
@@ -753,7 +1004,8 @@ ${tail}` : ""),
753
1004
  }
754
1005
  throw new ClefError(
755
1006
  ClefErrorCode.CLEF_INFERENCE_FAILED,
756
- `Inference failed with HTTP ${res.status}: ${apiMessage.slice(0, 2e3)}`
1007
+ `Inference failed with HTTP ${res.status}: ${apiMessage.slice(0, 2e3)}`,
1008
+ /physical batch size/i.test(apiMessage) ? "Too many/too large questions for one request. Split into several calls, reduce criteria text, or raise the batch with CLEF_LLAMA_BATCH." : void 0
757
1009
  );
758
1010
  }
759
1011
  if (!body || typeof body !== "object") {
@@ -802,6 +1054,7 @@ ${tail}` : ""),
802
1054
  };
803
1055
 
804
1056
  // src/mcp/schema.ts
1057
+ init_errors();
805
1058
  import { z } from "zod";
806
1059
  function criteriaDescription(limits) {
807
1060
  return z.string().min(1).max(limits.maxCriteriaDescChars);
@@ -1021,6 +1274,7 @@ function createClefServer(deps = {}) {
1021
1274
  import { Command } from "commander";
1022
1275
 
1023
1276
  // src/cli/doctor.ts
1277
+ init_errors();
1024
1278
  import { execFile as execFile2 } from "child_process";
1025
1279
  import os3 from "os";
1026
1280
  import { promisify } from "util";
@@ -1028,6 +1282,7 @@ import fsp2 from "fs/promises";
1028
1282
  import path5 from "path";
1029
1283
 
1030
1284
  // src/models/platform.ts
1285
+ init_errors();
1031
1286
  import { execFile } from "child_process";
1032
1287
  import os2 from "os";
1033
1288
  function exec(cmd, args, timeoutMs) {
@@ -1105,6 +1360,7 @@ function formatBytes(bytes) {
1105
1360
  }
1106
1361
 
1107
1362
  // src/runtime/probe.ts
1363
+ init_errors();
1108
1364
  import fs3 from "fs/promises";
1109
1365
  async function probeInference(cfg, manifest, log, loadTimeoutMs = 12e4) {
1110
1366
  await fs3.access(manifest.modelPath).catch(() => {
@@ -1315,6 +1571,7 @@ ${failed.length} critical check(s) failed.`
1315
1571
  }
1316
1572
 
1317
1573
  // src/cli/evals.ts
1574
+ init_errors();
1318
1575
  import fsp3 from "fs/promises";
1319
1576
  import fsSync from "fs";
1320
1577
  import { fileURLToPath } from "url";
@@ -1424,11 +1681,13 @@ ${passed}/${results.length} passed (${(rate * 100).toFixed(1)}%), required >= ${
1424
1681
  }
1425
1682
 
1426
1683
  // src/models/llama-install.ts
1684
+ init_errors();
1427
1685
  import { execFile as execFile3 } from "child_process";
1428
1686
  import fsp5 from "fs/promises";
1429
1687
  import path8 from "path";
1430
1688
 
1431
1689
  // src/models/hf.ts
1690
+ init_errors();
1432
1691
  import { createHash as createHash2 } from "crypto";
1433
1692
  import fsp4 from "fs/promises";
1434
1693
  import path7 from "path";
@@ -1726,28 +1985,11 @@ async function removeManagedRuntime(cfg) {
1726
1985
  return true;
1727
1986
  }
1728
1987
 
1729
- // src/cli/prompt.ts
1730
- import readline from "readline/promises";
1731
- async function confirm(question, yes) {
1732
- if (yes) return true;
1733
- if (!process.stdin.isTTY || !process.stdout.isTTY) {
1734
- throw new ClefError(
1735
- ClefErrorCode.INVALID_INPUT,
1736
- "Refusing to proceed interactively without a terminal.",
1737
- "Re-run with --yes to confirm non-interactively."
1738
- );
1739
- }
1740
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
1741
- try {
1742
- const answer = (await rl.question(`${question} [Y/n] `)).trim().toLowerCase();
1743
- return answer === "" || answer === "y" || answer === "yes";
1744
- } finally {
1745
- rl.close();
1746
- }
1747
- }
1988
+ // src/cli/install.ts
1989
+ init_prompt();
1748
1990
 
1749
1991
  // src/version.ts
1750
- var VERSION = "0.1.3";
1992
+ var VERSION = "0.1.5";
1751
1993
 
1752
1994
  // src/cli/install.ts
1753
1995
  var OS_NAMES = {
@@ -1817,11 +2059,18 @@ Model license: ${spec.licenseId} \u2014 ${spec.licenseUrl}`);
1817
2059
  const probe = await probeInference(config, manifest, log);
1818
2060
  console.log(` Inference OK (${(probe.latencyMs / 1e3).toFixed(1)}s incl. model load, via ${probe.binarySource} binary)`);
1819
2061
  }
2062
+ if (opts.setup) {
2063
+ const { runSetup: runSetup2 } = await Promise.resolve().then(() => (init_setup(), setup_exports));
2064
+ console.log("");
2065
+ await runSetup2({ yes: opts.yes });
2066
+ return;
2067
+ }
1820
2068
  console.log("\nDone. Start the MCP server with:\n\n clef-mcp\n");
1821
- console.log("Then register it with your MCP client, e.g.:\n");
2069
+ console.log("Register it with your agents (or run `clef-mcp setup` to do it automatically):\n");
1822
2070
  console.log(" Claude Code : claude mcp add clef-mcp -- clef-mcp");
1823
2071
  console.log(" Codex : add [mcp_servers.clef-mcp] to ~/.codex/config.toml (see README)");
1824
- console.log(" Cursor : add clef-mcp to .cursor/mcp.json (see README)\n");
2072
+ console.log(" Cursor : add clef-mcp to .cursor/mcp.json (see README)");
2073
+ console.log(" ZCode : add clef-mcp to ~/.zcode/cli/config.json (see README)\n");
1825
2074
  }
1826
2075
 
1827
2076
  // src/cli/models-cmd.ts
@@ -1841,7 +2090,11 @@ async function runModels() {
1841
2090
  }
1842
2091
  }
1843
2092
 
2093
+ // src/cli/index.ts
2094
+ init_setup();
2095
+
1844
2096
  // src/cli/status.ts
2097
+ init_errors();
1845
2098
  async function runStatus() {
1846
2099
  const config = loadConfig();
1847
2100
  const info = await detectPlatform();
@@ -1881,7 +2134,9 @@ async function runStatus() {
1881
2134
  }
1882
2135
 
1883
2136
  // src/cli/uninstall.ts
1884
- import fsp6 from "fs/promises";
2137
+ init_errors();
2138
+ import fsp7 from "fs/promises";
2139
+ init_prompt();
1885
2140
  async function runUninstall(opts) {
1886
2141
  const config = loadConfig();
1887
2142
  const spec = getModelSpec(opts.model ?? config.model);
@@ -1905,7 +2160,7 @@ async function runUninstall(opts) {
1905
2160
  return;
1906
2161
  }
1907
2162
  if (target) {
1908
- await fsp6.rm(target, { recursive: true, force: true });
2163
+ await fsp7.rm(target, { recursive: true, force: true });
1909
2164
  console.log(`Removed: ${target}`);
1910
2165
  }
1911
2166
  if (opts.runtime) {
@@ -1932,13 +2187,20 @@ program.action(async () => {
1932
2187
  handleCliError(err);
1933
2188
  }
1934
2189
  });
1935
- program.command("install").description("Detect the machine, download a Clef model + runtime, verify checksum and inference.").option("--model <id>", "model to install (default: clef-flash)").option("--quant <id>", "quantization override: Q4_K_M | Q8_0 | BF16").option("-y, --yes", "assume yes for all prompts (non-interactive)").option("--skip-runtime", "do not download/verify the llama.cpp runtime").option("--skip-probe", "skip the post-install inference verification").action(async (opts) => {
2190
+ program.command("install").description("Detect the machine, download a Clef model + runtime, verify checksum and inference.").option("--model <id>", "model to install (default: clef-flash)").option("--quant <id>", "quantization override: Q4_K_M | Q8_0 | BF16").option("-y, --yes", "assume yes for all prompts (non-interactive)").option("--skip-runtime", "do not download/verify the llama.cpp runtime").option("--skip-probe", "skip the post-install inference verification").option("--setup", "also register the MCP server + agent skill in detected clients (same as running `clef-mcp setup`)").action(async (opts) => {
1936
2191
  try {
1937
2192
  await runInstall(opts);
1938
2193
  } catch (err) {
1939
2194
  handleCliError(err);
1940
2195
  }
1941
2196
  });
2197
+ program.command("setup").description("Register the MCP server + agent skill in your clients (zcode, claude-code, codex, cursor).").option("--clients <list>", "comma-separated subset: zcode,claude-code,codex,cursor (default: all)").option("--skill", "install the agent skill (default)").option("--no-skill", "do not touch the agent skill").option("-y, --yes", "assume yes for all prompts (non-interactive)").action(async (opts) => {
2198
+ try {
2199
+ await runSetup(opts);
2200
+ } catch (err) {
2201
+ handleCliError(err);
2202
+ }
2203
+ });
1942
2204
  program.command("models").description("List known Clef models, quantizations and install status.").action(async () => {
1943
2205
  try {
1944
2206
  await runModels();