clef-mcp 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
 
@@ -63,6 +66,18 @@ args = []
63
66
  }
64
67
  ```
65
68
 
69
+ **ZCode** — `~/.zcode/cli/config.json` (user scope; servers auto-connect in new sessions):
70
+
71
+ ```json
72
+ {
73
+ "mcp": {
74
+ "servers": {
75
+ "clef-mcp": { "command": "clef-mcp", "args": [], "type": "stdio" }
76
+ }
77
+ }
78
+ }
79
+ ```
80
+
66
81
  **Generic MCP client** — any client that speaks MCP over stdio: run `clef-mcp` as the server command.
67
82
 
68
83
  Ready-made snippets live in [`examples/`](examples/).
@@ -131,11 +146,29 @@ Strictly structured — the server never turns the result into prose:
131
146
 
132
147
  `state` is treated strictly as **data**: it is never interpreted as instructions for the MCP server itself (see [Security](#security--data-handling)).
133
148
 
149
+ ## Teach your agent (skill)
150
+
151
+ The tool schema tells the client *what* `clef_decide` accepts; agents also need to know *when* to reach for it and *how* to frame decisions. The bundled skill covers that: decision patterns (next action / routing / classification / noul / score), batching up to 64 questions into one forward pass, writing mutually exclusive criteria, interpreting distributions (argmax vs flat), thresholds for safety-adjacent calls, and error recovery.
152
+
153
+ Install it for your agent(s):
154
+
155
+ ```bash
156
+ # automatic (registers the MCP server too)
157
+ clef-mcp setup
158
+
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
162
+ ```
163
+
164
+ `~/.agents/skills/` is the shared location for ZCode / Claude Code / Codex-style agents.
165
+
134
166
  ## CLI
135
167
 
136
168
  ```bash
137
169
  clef-mcp # run the MCP server on stdio (default command)
138
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
139
172
  clef-mcp models # list models/quantizations and install status
140
173
  clef-mcp status # runtime, model, memory summary
141
174
  clef-mcp doctor # full diagnosis (platform, RAM, GPU, binary, model, checksum*, inference, MCP config)
@@ -143,7 +176,7 @@ clef-mcp uninstall # remove the model (and optionally the managed runtime)
143
176
  clef-mcp evals # run the evaluation dataset against the installed model
144
177
  ```
145
178
 
146
- 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`.
147
180
 
148
181
  ## Configuration (environment variables)
149
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;
@@ -802,6 +1047,7 @@ ${tail}` : ""),
802
1047
  };
803
1048
 
804
1049
  // src/mcp/schema.ts
1050
+ init_errors();
805
1051
  import { z } from "zod";
806
1052
  function criteriaDescription(limits) {
807
1053
  return z.string().min(1).max(limits.maxCriteriaDescChars);
@@ -1021,6 +1267,7 @@ function createClefServer(deps = {}) {
1021
1267
  import { Command } from "commander";
1022
1268
 
1023
1269
  // src/cli/doctor.ts
1270
+ init_errors();
1024
1271
  import { execFile as execFile2 } from "child_process";
1025
1272
  import os3 from "os";
1026
1273
  import { promisify } from "util";
@@ -1028,6 +1275,7 @@ import fsp2 from "fs/promises";
1028
1275
  import path5 from "path";
1029
1276
 
1030
1277
  // src/models/platform.ts
1278
+ init_errors();
1031
1279
  import { execFile } from "child_process";
1032
1280
  import os2 from "os";
1033
1281
  function exec(cmd, args, timeoutMs) {
@@ -1105,6 +1353,7 @@ function formatBytes(bytes) {
1105
1353
  }
1106
1354
 
1107
1355
  // src/runtime/probe.ts
1356
+ init_errors();
1108
1357
  import fs3 from "fs/promises";
1109
1358
  async function probeInference(cfg, manifest, log, loadTimeoutMs = 12e4) {
1110
1359
  await fs3.access(manifest.modelPath).catch(() => {
@@ -1315,6 +1564,7 @@ ${failed.length} critical check(s) failed.`
1315
1564
  }
1316
1565
 
1317
1566
  // src/cli/evals.ts
1567
+ init_errors();
1318
1568
  import fsp3 from "fs/promises";
1319
1569
  import fsSync from "fs";
1320
1570
  import { fileURLToPath } from "url";
@@ -1424,11 +1674,13 @@ ${passed}/${results.length} passed (${(rate * 100).toFixed(1)}%), required >= ${
1424
1674
  }
1425
1675
 
1426
1676
  // src/models/llama-install.ts
1677
+ init_errors();
1427
1678
  import { execFile as execFile3 } from "child_process";
1428
1679
  import fsp5 from "fs/promises";
1429
1680
  import path8 from "path";
1430
1681
 
1431
1682
  // src/models/hf.ts
1683
+ init_errors();
1432
1684
  import { createHash as createHash2 } from "crypto";
1433
1685
  import fsp4 from "fs/promises";
1434
1686
  import path7 from "path";
@@ -1726,28 +1978,11 @@ async function removeManagedRuntime(cfg) {
1726
1978
  return true;
1727
1979
  }
1728
1980
 
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
- }
1981
+ // src/cli/install.ts
1982
+ init_prompt();
1748
1983
 
1749
1984
  // src/version.ts
1750
- var VERSION = "0.1.2";
1985
+ var VERSION = "0.1.4";
1751
1986
 
1752
1987
  // src/cli/install.ts
1753
1988
  var OS_NAMES = {
@@ -1817,11 +2052,18 @@ Model license: ${spec.licenseId} \u2014 ${spec.licenseUrl}`);
1817
2052
  const probe = await probeInference(config, manifest, log);
1818
2053
  console.log(` Inference OK (${(probe.latencyMs / 1e3).toFixed(1)}s incl. model load, via ${probe.binarySource} binary)`);
1819
2054
  }
2055
+ if (opts.setup) {
2056
+ const { runSetup: runSetup2 } = await Promise.resolve().then(() => (init_setup(), setup_exports));
2057
+ console.log("");
2058
+ await runSetup2({ yes: opts.yes });
2059
+ return;
2060
+ }
1820
2061
  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");
2062
+ console.log("Register it with your agents (or run `clef-mcp setup` to do it automatically):\n");
1822
2063
  console.log(" Claude Code : claude mcp add clef-mcp -- clef-mcp");
1823
2064
  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");
2065
+ console.log(" Cursor : add clef-mcp to .cursor/mcp.json (see README)");
2066
+ console.log(" ZCode : add clef-mcp to ~/.zcode/cli/config.json (see README)\n");
1825
2067
  }
1826
2068
 
1827
2069
  // src/cli/models-cmd.ts
@@ -1841,7 +2083,11 @@ async function runModels() {
1841
2083
  }
1842
2084
  }
1843
2085
 
2086
+ // src/cli/index.ts
2087
+ init_setup();
2088
+
1844
2089
  // src/cli/status.ts
2090
+ init_errors();
1845
2091
  async function runStatus() {
1846
2092
  const config = loadConfig();
1847
2093
  const info = await detectPlatform();
@@ -1881,7 +2127,9 @@ async function runStatus() {
1881
2127
  }
1882
2128
 
1883
2129
  // src/cli/uninstall.ts
1884
- import fsp6 from "fs/promises";
2130
+ init_errors();
2131
+ import fsp7 from "fs/promises";
2132
+ init_prompt();
1885
2133
  async function runUninstall(opts) {
1886
2134
  const config = loadConfig();
1887
2135
  const spec = getModelSpec(opts.model ?? config.model);
@@ -1905,7 +2153,7 @@ async function runUninstall(opts) {
1905
2153
  return;
1906
2154
  }
1907
2155
  if (target) {
1908
- await fsp6.rm(target, { recursive: true, force: true });
2156
+ await fsp7.rm(target, { recursive: true, force: true });
1909
2157
  console.log(`Removed: ${target}`);
1910
2158
  }
1911
2159
  if (opts.runtime) {
@@ -1932,13 +2180,20 @@ program.action(async () => {
1932
2180
  handleCliError(err);
1933
2181
  }
1934
2182
  });
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) => {
2183
+ 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
2184
  try {
1937
2185
  await runInstall(opts);
1938
2186
  } catch (err) {
1939
2187
  handleCliError(err);
1940
2188
  }
1941
2189
  });
2190
+ 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) => {
2191
+ try {
2192
+ await runSetup(opts);
2193
+ } catch (err) {
2194
+ handleCliError(err);
2195
+ }
2196
+ });
1942
2197
  program.command("models").description("List known Clef models, quantizations and install status.").action(async () => {
1943
2198
  try {
1944
2199
  await runModels();