rex-claude 4.0.0 → 6.0.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 (38) hide show
  1. package/dist/agents-JIZXXASP.js +853 -0
  2. package/dist/app-3VWDSH5F.js +248 -0
  3. package/dist/audio-US2J627E.js +196 -0
  4. package/dist/audit-ZVTGE4L4.js +8 -0
  5. package/dist/call-AQZ3Z5SE.js +143 -0
  6. package/dist/chunk-5ND7JYY3.js +62 -0
  7. package/dist/chunk-6SRV2I2H.js +56 -0
  8. package/dist/{setup-AO3MW46W.js → chunk-A7ZLQUOX.js} +93 -16
  9. package/dist/chunk-E5UYN3W7.js +105 -0
  10. package/dist/chunk-HAHJD3QH.js +147 -0
  11. package/dist/{init-DLFEGD6O.js → chunk-KR7ISYZH.js} +328 -29
  12. package/dist/chunk-LTOM55UV.js +154 -0
  13. package/dist/chunk-PDX44BCA.js +11 -0
  14. package/dist/chunk-PPGYFMU5.js +67 -0
  15. package/dist/{chunk-7AGI43F5.js → chunk-WBMVBMWB.js} +4 -2
  16. package/dist/{context-FN5O5YBI.js → context-XNCG2M5Q.js} +2 -1
  17. package/dist/daemon-5KNSNFTD.js +208 -0
  18. package/dist/gateway-YLP66MCQ.js +2273 -0
  19. package/dist/hammerspoon/rex-call-watcher.lua +186 -0
  20. package/dist/index.js +309 -15
  21. package/dist/init-RDZFIBLA.js +30 -0
  22. package/dist/install-63JBDPRU.js +41 -0
  23. package/dist/{llm-YRORUH7E.js → llm-RALIPIMI.js} +2 -1
  24. package/dist/mcp_registry-DX4GGSP6.js +514 -0
  25. package/dist/migrate-GDO37TI5.js +87 -0
  26. package/dist/{optimize-UKMAGQQE.js → optimize-5TE5RKZV.js} +2 -1
  27. package/dist/paths-4SECM6E6.js +38 -0
  28. package/dist/preload-I3MYBVNU.js +78 -0
  29. package/dist/projects-V6TSLO7E.js +17 -0
  30. package/dist/{prune-2PPIVDXK.js → prune-B7F5B5OF.js} +2 -1
  31. package/dist/recategorize-YXYIMQLZ.js +155 -0
  32. package/dist/router-2JD34COX.js +12 -0
  33. package/dist/self-improve-YK7RCYF4.js +197 -0
  34. package/dist/setup-KNDTVFO6.js +8 -0
  35. package/dist/skills-AIWFY5NH.js +374 -0
  36. package/dist/voice-RITC3EVC.js +248 -0
  37. package/package.json +12 -3
  38. package/dist/gateway-EKMU5D7J.js +0 -784
@@ -2,7 +2,8 @@
2
2
  import {
3
3
  detectModel,
4
4
  llm
5
- } from "./chunk-7AGI43F5.js";
5
+ } from "./chunk-WBMVBMWB.js";
6
+ import "./chunk-PDX44BCA.js";
6
7
  export {
7
8
  detectModel,
8
9
  llm
@@ -0,0 +1,514 @@
1
+ #!/usr/bin/env node
2
+ import "./chunk-PDX44BCA.js";
3
+
4
+ // src/mcp_registry.ts
5
+ import { homedir } from "os";
6
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
7
+ import { join } from "path";
8
+ import { execSync, execFileSync } from "child_process";
9
+ var HOME = homedir();
10
+ var ROOT_DIR = join(HOME, ".rex-memory");
11
+ var REGISTRY_FILE = join(ROOT_DIR, "mcp-registry.json");
12
+ function ensureDir() {
13
+ if (!existsSync(ROOT_DIR)) mkdirSync(ROOT_DIR, { recursive: true });
14
+ }
15
+ function readRegistry() {
16
+ ensureDir();
17
+ try {
18
+ if (existsSync(REGISTRY_FILE)) {
19
+ const parsed = JSON.parse(readFileSync(REGISTRY_FILE, "utf-8"));
20
+ if (Array.isArray(parsed.servers)) return parsed;
21
+ }
22
+ } catch {
23
+ }
24
+ return { servers: [] };
25
+ }
26
+ function writeRegistry(registry) {
27
+ ensureDir();
28
+ writeFileSync(REGISTRY_FILE, JSON.stringify(registry, null, 2));
29
+ }
30
+ function slug(text) {
31
+ return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "mcp";
32
+ }
33
+ function parseFlag(args, name) {
34
+ const idx = args.findIndex((a) => a === name);
35
+ if (idx < 0) return null;
36
+ return args[idx + 1] || null;
37
+ }
38
+ function findServer(registry, idOrName) {
39
+ return registry.servers.find((s) => s.id === idOrName || s.name === idOrName) || null;
40
+ }
41
+ function printList(jsonMode) {
42
+ const registry = readRegistry();
43
+ if (jsonMode) {
44
+ console.log(JSON.stringify(registry, null, 2));
45
+ return;
46
+ }
47
+ if (registry.servers.length === 0) {
48
+ console.log("No MCP servers in registry.");
49
+ return;
50
+ }
51
+ for (const s of registry.servers) {
52
+ const target = s.type === "stdio" ? `${s.command || "n/a"} ${(s.args || []).join(" ")}`.trim() : s.url || "n/a";
53
+ console.log(`${s.id} ${s.name} type=${s.type} enabled=${s.enabled} target=${target}`);
54
+ }
55
+ }
56
+ function addStdio(args) {
57
+ const name = args[0];
58
+ if (!name) {
59
+ console.log("Usage: rex mcp add <name> --command <cmd> [--args a,b,c] [--cwd path] [--tags t1,t2]");
60
+ process.exit(1);
61
+ }
62
+ const command = parseFlag(args, "--command");
63
+ if (!command) {
64
+ console.log("Missing --command");
65
+ process.exit(1);
66
+ }
67
+ const argsCsv = parseFlag(args, "--args");
68
+ const cwd = parseFlag(args, "--cwd");
69
+ const tagsCsv = parseFlag(args, "--tags");
70
+ const registry = readRegistry();
71
+ const now = (/* @__PURE__ */ new Date()).toISOString();
72
+ const entry = {
73
+ id: `${slug(name)}-${Date.now().toString().slice(-6)}`,
74
+ name,
75
+ type: "stdio",
76
+ command,
77
+ args: argsCsv ? argsCsv.split(",").map((v) => v.trim()).filter(Boolean) : [],
78
+ cwd: cwd || void 0,
79
+ enabled: true,
80
+ tags: tagsCsv ? tagsCsv.split(",").map((v) => v.trim()).filter(Boolean) : [],
81
+ createdAt: now,
82
+ updatedAt: now
83
+ };
84
+ registry.servers.push(entry);
85
+ writeRegistry(registry);
86
+ console.log(JSON.stringify({ ok: true, server: entry }, null, 2));
87
+ }
88
+ function addUrl(args) {
89
+ const name = args[0];
90
+ const url = args[1];
91
+ if (!name || !url) {
92
+ console.log("Usage: rex mcp add-url <name> <url> [--type sse|http] [--tags t1,t2]");
93
+ process.exit(1);
94
+ }
95
+ const typeRaw = (parseFlag(args, "--type") || "sse").toLowerCase();
96
+ const type = typeRaw === "http" ? "http" : "sse";
97
+ const tagsCsv = parseFlag(args, "--tags");
98
+ const registry = readRegistry();
99
+ const now = (/* @__PURE__ */ new Date()).toISOString();
100
+ const entry = {
101
+ id: `${slug(name)}-${Date.now().toString().slice(-6)}`,
102
+ name,
103
+ type,
104
+ url,
105
+ enabled: true,
106
+ tags: tagsCsv ? tagsCsv.split(",").map((v) => v.trim()).filter(Boolean) : [],
107
+ createdAt: now,
108
+ updatedAt: now
109
+ };
110
+ registry.servers.push(entry);
111
+ writeRegistry(registry);
112
+ console.log(JSON.stringify({ ok: true, server: entry }, null, 2));
113
+ }
114
+ function removeServer(args) {
115
+ const idOrName = args[0];
116
+ if (!idOrName) {
117
+ console.log("Usage: rex mcp remove <id|name>");
118
+ process.exit(1);
119
+ }
120
+ const registry = readRegistry();
121
+ const idx = registry.servers.findIndex((s) => s.id === idOrName || s.name === idOrName);
122
+ if (idx < 0) {
123
+ console.log(`Server not found: ${idOrName}`);
124
+ process.exit(1);
125
+ }
126
+ const removed = registry.servers[idx];
127
+ registry.servers.splice(idx, 1);
128
+ writeRegistry(registry);
129
+ console.log(JSON.stringify({ ok: true, removed }, null, 2));
130
+ }
131
+ function setEnabled(args, enabled) {
132
+ const idOrName = args[0];
133
+ if (!idOrName) {
134
+ console.log(`Usage: rex mcp ${enabled ? "enable" : "disable"} <id|name>`);
135
+ process.exit(1);
136
+ }
137
+ const registry = readRegistry();
138
+ const server = findServer(registry, idOrName);
139
+ if (!server) {
140
+ console.log(`Server not found: ${idOrName}`);
141
+ process.exit(1);
142
+ }
143
+ server.enabled = enabled;
144
+ server.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
145
+ writeRegistry(registry);
146
+ console.log(JSON.stringify({ ok: true, id: server.id, enabled }, null, 2));
147
+ }
148
+ async function checkServer(args) {
149
+ const idOrName = args[0];
150
+ if (!idOrName) {
151
+ console.log("Usage: rex mcp check <id|name>");
152
+ process.exit(1);
153
+ }
154
+ const registry = readRegistry();
155
+ const server = findServer(registry, idOrName);
156
+ if (!server) {
157
+ console.log(`Server not found: ${idOrName}`);
158
+ process.exit(1);
159
+ }
160
+ if (server.type === "stdio") {
161
+ if (!server.command) {
162
+ console.log(JSON.stringify({ ok: false, reason: "missing command" }, null, 2));
163
+ process.exit(1);
164
+ }
165
+ try {
166
+ execFileSync("which", [server.command], { stdio: "ignore" });
167
+ console.log(JSON.stringify({ ok: true, type: "stdio", command: server.command }, null, 2));
168
+ } catch {
169
+ console.log(JSON.stringify({ ok: false, type: "stdio", reason: `command not found: ${server.command}` }, null, 2));
170
+ process.exitCode = 1;
171
+ }
172
+ return;
173
+ }
174
+ if (!server.url) {
175
+ console.log(JSON.stringify({ ok: false, reason: "missing url" }, null, 2));
176
+ process.exit(1);
177
+ }
178
+ const controller = new AbortController();
179
+ const t = setTimeout(() => controller.abort(), 8e3);
180
+ try {
181
+ const res = await fetch(server.url, { signal: controller.signal });
182
+ clearTimeout(t);
183
+ console.log(JSON.stringify({ ok: res.ok, status: res.status, type: server.type, url: server.url }, null, 2));
184
+ if (!res.ok) process.exitCode = 1;
185
+ } catch (e) {
186
+ clearTimeout(t);
187
+ const err = e instanceof Error ? e.message : String(e);
188
+ console.log(JSON.stringify({ ok: false, type: server.type, url: server.url, error: err }, null, 2));
189
+ process.exitCode = 1;
190
+ }
191
+ }
192
+ function syncClaudeSettings() {
193
+ const registry = readRegistry();
194
+ const settingsPath = join(HOME, ".claude", "settings.json");
195
+ const claudeDir = join(HOME, ".claude");
196
+ if (!existsSync(claudeDir)) mkdirSync(claudeDir, { recursive: true });
197
+ let settings = {};
198
+ try {
199
+ settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
200
+ } catch {
201
+ }
202
+ if (!settings.mcpServers) settings.mcpServers = {};
203
+ const enabledStdio = registry.servers.filter((s) => s.enabled && s.type === "stdio" && s.command);
204
+ for (const s of enabledStdio) {
205
+ settings.mcpServers[s.name] = {
206
+ command: s.command,
207
+ args: s.args || [],
208
+ ...s.cwd ? { cwd: s.cwd } : {}
209
+ };
210
+ }
211
+ writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
212
+ console.log(JSON.stringify({ ok: true, synced: enabledStdio.length, settingsPath }, null, 2));
213
+ }
214
+ var MARKETPLACE_DIR = join(HOME, ".claude", "rex");
215
+ var MARKETPLACE_FILE = join(MARKETPLACE_DIR, "mcp-marketplace.json");
216
+ var DEFAULT_MARKETPLACE = [
217
+ { name: "context7", description: "Versioned docs for any library (npm, PyPI)", command: "npx", args: ["-y", "@upstash/context7-mcp"], installCmd: "npx -y @upstash/context7-mcp", type: "stdio", tags: ["docs", "libraries"], source: "builtin" },
218
+ { name: "playwright", description: "Browser automation and testing", command: "npx", args: ["-y", "@anthropic-ai/mcp-server-playwright"], installCmd: "npx -y @anthropic-ai/mcp-server-playwright", type: "stdio", tags: ["browser", "testing", "automation"], source: "builtin" },
219
+ { name: "filesystem", description: "Local filesystem access (read/write/search)", command: "npx", args: ["-y", "@anthropic-ai/mcp-server-filesystem"], installCmd: "npx -y @anthropic-ai/mcp-server-filesystem", type: "stdio", tags: ["files", "local"], source: "builtin" },
220
+ { name: "github", description: "GitHub API (repos, issues, PRs, actions)", command: "npx", args: ["-y", "@anthropic-ai/mcp-server-github"], installCmd: "npm install -g @anthropic-ai/mcp-server-github", type: "stdio", tags: ["git", "github", "ci"], source: "builtin" },
221
+ { name: "slack", description: "Slack messaging and channel management", command: "npx", args: ["-y", "@anthropic-ai/mcp-server-slack"], installCmd: "npx -y @anthropic-ai/mcp-server-slack", type: "stdio", tags: ["messaging", "slack"], source: "builtin" },
222
+ { name: "linear", description: "Linear issue tracker integration", command: "npx", args: ["-y", "mcp-linear"], installCmd: "npx -y mcp-linear", type: "stdio", tags: ["issues", "project-management"], source: "builtin" },
223
+ { name: "figma", description: "Figma design file access and inspection", command: "npx", args: ["-y", "@anthropic-ai/mcp-server-figma"], installCmd: "npx -y @anthropic-ai/mcp-server-figma", type: "stdio", tags: ["design", "figma", "ui"], source: "builtin" },
224
+ { name: "brave-search", description: "Web search via Brave Search API", command: "npx", args: ["-y", "@anthropic-ai/mcp-server-brave-search"], installCmd: "npx -y @anthropic-ai/mcp-server-brave-search", type: "stdio", tags: ["search", "web"], source: "builtin" },
225
+ { name: "puppeteer", description: "Headless Chrome browser automation", command: "npx", args: ["-y", "@anthropic-ai/mcp-server-puppeteer"], installCmd: "npx -y @anthropic-ai/mcp-server-puppeteer", type: "stdio", tags: ["browser", "scraping"], source: "builtin" },
226
+ { name: "sequential-thinking", description: "Step-by-step reasoning and problem solving", command: "npx", args: ["-y", "@anthropic-ai/mcp-server-sequential-thinking"], installCmd: "npx -y @anthropic-ai/mcp-server-sequential-thinking", type: "stdio", tags: ["reasoning", "thinking"], source: "builtin" },
227
+ { name: "memory", description: "Persistent memory via knowledge graph", command: "npx", args: ["-y", "@anthropic-ai/mcp-server-memory"], installCmd: "npx -y @anthropic-ai/mcp-server-memory", type: "stdio", tags: ["memory", "knowledge"], source: "builtin" },
228
+ { name: "postgres", description: "PostgreSQL database access", command: "npx", args: ["-y", "@anthropic-ai/mcp-server-postgres"], installCmd: "npx -y @anthropic-ai/mcp-server-postgres", type: "stdio", tags: ["database", "postgres", "sql"], source: "builtin" },
229
+ { name: "sqlite", description: "SQLite database access", command: "npx", args: ["-y", "@anthropic-ai/mcp-server-sqlite"], installCmd: "npx -y @anthropic-ai/mcp-server-sqlite", type: "stdio", tags: ["database", "sqlite", "sql"], source: "builtin" },
230
+ { name: "docker", description: "Docker container management", command: "npx", args: ["-y", "mcp-docker"], installCmd: "npx -y mcp-docker", type: "stdio", tags: ["docker", "containers", "devops"], source: "builtin" },
231
+ { name: "kubernetes", description: "Kubernetes cluster management", command: "npx", args: ["-y", "mcp-kubernetes"], installCmd: "npx -y mcp-kubernetes", type: "stdio", tags: ["kubernetes", "k8s", "devops"], source: "builtin" },
232
+ { name: "sentry", description: "Sentry error tracking integration", command: "npx", args: ["-y", "mcp-sentry"], installCmd: "npx -y mcp-sentry", type: "stdio", tags: ["monitoring", "errors", "sentry"], source: "builtin" },
233
+ { name: "notion", description: "Notion workspace access", command: "npx", args: ["-y", "mcp-notion"], installCmd: "npx -y mcp-notion", type: "stdio", tags: ["notion", "docs", "wiki"], source: "builtin" },
234
+ { name: "google-drive", description: "Google Drive file access", command: "npx", args: ["-y", "mcp-google-drive"], installCmd: "npx -y mcp-google-drive", type: "stdio", tags: ["google", "drive", "files"], source: "builtin" },
235
+ { name: "exa", description: "Exa AI-powered web search", command: "npx", args: ["-y", "mcp-exa"], installCmd: "npx -y mcp-exa", type: "stdio", tags: ["search", "web", "ai"], source: "builtin" },
236
+ { name: "firecrawl", description: "Web scraping and crawling", command: "npx", args: ["-y", "mcp-firecrawl"], installCmd: "npx -y mcp-firecrawl", type: "stdio", tags: ["scraping", "crawling", "web"], source: "builtin" }
237
+ ];
238
+ function readMarketplace() {
239
+ try {
240
+ if (existsSync(MARKETPLACE_FILE)) {
241
+ const parsed = JSON.parse(readFileSync(MARKETPLACE_FILE, "utf-8"));
242
+ if (Array.isArray(parsed) && parsed.length > 0) return parsed;
243
+ }
244
+ } catch {
245
+ }
246
+ if (!existsSync(MARKETPLACE_DIR)) mkdirSync(MARKETPLACE_DIR, { recursive: true });
247
+ writeFileSync(MARKETPLACE_FILE, JSON.stringify(DEFAULT_MARKETPLACE, null, 2));
248
+ return DEFAULT_MARKETPLACE;
249
+ }
250
+ async function discoverServer(args, jsonMode) {
251
+ const idOrName = args[0];
252
+ if (!idOrName) {
253
+ console.log("Usage: rex mcp discover <id|name>");
254
+ process.exit(1);
255
+ }
256
+ const registry = readRegistry();
257
+ const server = findServer(registry, idOrName);
258
+ if (!server) {
259
+ console.log(`Server not found: ${idOrName}`);
260
+ process.exit(1);
261
+ }
262
+ if (server.type !== "stdio" && server.url) {
263
+ const controller = new AbortController();
264
+ const t = setTimeout(() => controller.abort(), 1e4);
265
+ try {
266
+ const res = await fetch(server.url, {
267
+ method: "POST",
268
+ headers: { "Content-Type": "application/json" },
269
+ body: JSON.stringify({ jsonrpc: "2.0", method: "tools/list", id: 1 }),
270
+ signal: controller.signal
271
+ });
272
+ clearTimeout(t);
273
+ if (!res.ok) {
274
+ console.log(`Could not discover tools for ${server.name} (HTTP ${res.status})`);
275
+ return;
276
+ }
277
+ const body = await res.json();
278
+ const tools = body?.result?.tools || [];
279
+ if (jsonMode) {
280
+ console.log(JSON.stringify(tools, null, 2));
281
+ } else if (tools.length === 0) {
282
+ console.log(`No tools found for ${server.name}`);
283
+ } else {
284
+ for (const tool of tools) {
285
+ console.log(` ${tool.name || "unnamed"} ${tool.description || ""}`);
286
+ }
287
+ }
288
+ } catch {
289
+ clearTimeout(t);
290
+ console.log(`Could not discover tools for ${server.name}`);
291
+ }
292
+ return;
293
+ }
294
+ if (!server.command) {
295
+ console.log(`Could not discover tools for ${server.name} (no command)`);
296
+ return;
297
+ }
298
+ try {
299
+ const { spawn } = await import("child_process");
300
+ const child = spawn(server.command, [...server.args || []], {
301
+ cwd: server.cwd || void 0,
302
+ stdio: ["pipe", "pipe", "pipe"]
303
+ });
304
+ let output = "";
305
+ let done = false;
306
+ const timeout = setTimeout(() => {
307
+ if (!done) {
308
+ done = true;
309
+ child.kill();
310
+ }
311
+ }, 1e4);
312
+ child.stdout.on("data", (chunk) => {
313
+ output += chunk.toString();
314
+ });
315
+ const initMsg = JSON.stringify({ jsonrpc: "2.0", method: "initialize", id: 0, params: { protocolVersion: "2024-11-05", capabilities: {}, clientInfo: { name: "rex", version: "1.0" } } }) + "\n";
316
+ const toolsMsg = JSON.stringify({ jsonrpc: "2.0", method: "tools/list", id: 1 }) + "\n";
317
+ child.stdin.write(initMsg);
318
+ setTimeout(() => {
319
+ child.stdin.write(toolsMsg);
320
+ }, 500);
321
+ setTimeout(() => {
322
+ if (!done) {
323
+ done = true;
324
+ clearTimeout(timeout);
325
+ child.kill();
326
+ const lines = output.split("\n").filter(Boolean);
327
+ let tools = [];
328
+ for (const line of lines) {
329
+ try {
330
+ const parsed = JSON.parse(line);
331
+ if (parsed.id === 1 && parsed.result?.tools) {
332
+ tools = parsed.result.tools;
333
+ break;
334
+ }
335
+ } catch {
336
+ }
337
+ }
338
+ if (jsonMode) {
339
+ console.log(JSON.stringify(tools, null, 2));
340
+ } else if (tools.length === 0) {
341
+ console.log(`Could not discover tools for ${server.name}`);
342
+ } else {
343
+ console.log(`Tools for ${server.name}:`);
344
+ for (const tool of tools) {
345
+ console.log(` ${tool.name || "unnamed"} ${tool.description || ""}`);
346
+ }
347
+ }
348
+ }
349
+ }, 3e3);
350
+ await new Promise((resolve) => {
351
+ child.on("close", () => resolve());
352
+ child.on("error", () => {
353
+ if (!done) {
354
+ done = true;
355
+ clearTimeout(timeout);
356
+ }
357
+ ;
358
+ resolve();
359
+ });
360
+ setTimeout(() => resolve(), 12e3);
361
+ });
362
+ } catch {
363
+ console.log(`Could not discover tools for ${server.name}`);
364
+ }
365
+ }
366
+ function searchMarketplace(args, jsonMode) {
367
+ const query = args.filter((a) => !a.startsWith("--")).join(" ").toLowerCase();
368
+ if (!query) {
369
+ console.log("Usage: rex mcp search <query>");
370
+ process.exit(1);
371
+ }
372
+ const marketplace = readMarketplace();
373
+ const matches = marketplace.filter((entry) => {
374
+ const haystack = `${entry.name} ${entry.description} ${entry.tags.join(" ")}`.toLowerCase();
375
+ return query.split(/\s+/).every((word) => haystack.includes(word));
376
+ });
377
+ if (jsonMode) {
378
+ console.log(JSON.stringify(matches, null, 2));
379
+ return;
380
+ }
381
+ if (matches.length === 0) {
382
+ console.log(`No servers found matching "${query}"`);
383
+ return;
384
+ }
385
+ console.log(`Found ${matches.length} server(s):
386
+ `);
387
+ for (const entry of matches) {
388
+ console.log(` ${entry.name.padEnd(22)} ${entry.description}`);
389
+ if (entry.installCmd) console.log(` install: ${entry.installCmd}`);
390
+ if (entry.tags.length) console.log(` tags: ${entry.tags.join(", ")}`);
391
+ console.log("");
392
+ }
393
+ }
394
+ async function installFromMarketplace(args) {
395
+ const name = args[0];
396
+ if (!name) {
397
+ console.log("Usage: rex mcp install <name>");
398
+ process.exit(1);
399
+ }
400
+ const marketplace = readMarketplace();
401
+ const entry = marketplace.find((e) => e.name === name);
402
+ if (!entry) {
403
+ console.log(`Server "${name}" not found in marketplace. Run "rex mcp search ${name}" to check.`);
404
+ process.exit(1);
405
+ }
406
+ if (!entry.installCmd) {
407
+ console.log(`No install command for "${name}".`);
408
+ if (entry.command) {
409
+ console.log(`You can add it manually: rex mcp add ${name} --command ${entry.command} --args ${(entry.args || []).join(",")}`);
410
+ }
411
+ return;
412
+ }
413
+ console.log(`Installing ${name}...`);
414
+ console.log(` $ ${entry.installCmd}
415
+ `);
416
+ const safePrefix = ["npx ", "npm ", "pip ", "pip3 ", "brew ", "docker "];
417
+ if (!safePrefix.some((p) => entry.installCmd.startsWith(p))) {
418
+ console.log(`
419
+ \u26A0\uFE0F Install command rejected (unsafe prefix): ${entry.installCmd}`);
420
+ return;
421
+ }
422
+ try {
423
+ execSync(entry.installCmd, { stdio: "inherit", timeout: 12e4 });
424
+ } catch {
425
+ console.log(`
426
+ Install command failed. You may need to run it manually: ${entry.installCmd}`);
427
+ return;
428
+ }
429
+ const registry = readRegistry();
430
+ const existing = findServer(registry, name);
431
+ if (existing) {
432
+ console.log(`
433
+ Server "${name}" already in registry (id=${existing.id}). Skipping auto-add.`);
434
+ return;
435
+ }
436
+ const now = (/* @__PURE__ */ new Date()).toISOString();
437
+ const newEntry = {
438
+ id: `${slug(name)}-${Date.now().toString().slice(-6)}`,
439
+ name: entry.name,
440
+ type: entry.type,
441
+ command: entry.command,
442
+ args: entry.args || [],
443
+ enabled: true,
444
+ tags: entry.tags,
445
+ createdAt: now,
446
+ updatedAt: now
447
+ };
448
+ registry.servers.push(newEntry);
449
+ writeRegistry(registry);
450
+ console.log(`
451
+ Added to registry: ${newEntry.id}`);
452
+ console.log(JSON.stringify({ ok: true, server: newEntry }, null, 2));
453
+ }
454
+ function showExport() {
455
+ const registry = readRegistry();
456
+ const enabledStdio = registry.servers.filter((s) => s.enabled && s.type === "stdio" && s.command);
457
+ const exported = {};
458
+ for (const s of enabledStdio) {
459
+ exported[s.name] = {
460
+ command: s.command,
461
+ args: s.args || [],
462
+ ...s.cwd ? { cwd: s.cwd } : {}
463
+ };
464
+ }
465
+ console.log(JSON.stringify({ mcpServers: exported }, null, 2));
466
+ }
467
+ async function mcpRegistry(args) {
468
+ const sub = args[0] || "list";
469
+ const rest = args.slice(1);
470
+ const jsonMode = args.includes("--json");
471
+ switch (sub) {
472
+ case "list":
473
+ printList(jsonMode);
474
+ return;
475
+ case "add":
476
+ addStdio(rest);
477
+ return;
478
+ case "add-url":
479
+ addUrl(rest);
480
+ return;
481
+ case "remove":
482
+ removeServer(rest);
483
+ return;
484
+ case "enable":
485
+ setEnabled(rest, true);
486
+ return;
487
+ case "disable":
488
+ setEnabled(rest, false);
489
+ return;
490
+ case "check":
491
+ await checkServer(rest);
492
+ return;
493
+ case "sync-claude":
494
+ syncClaudeSettings();
495
+ return;
496
+ case "export":
497
+ showExport();
498
+ return;
499
+ case "discover":
500
+ await discoverServer(rest, jsonMode);
501
+ return;
502
+ case "search":
503
+ searchMarketplace(rest, jsonMode);
504
+ return;
505
+ case "install":
506
+ await installFromMarketplace(rest);
507
+ return;
508
+ default:
509
+ console.log("Usage: rex mcp <list|add|add-url|remove|enable|disable|check|sync-claude|export|discover|search|install> ...");
510
+ }
511
+ }
512
+ export {
513
+ mcpRegistry
514
+ };
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ createLogger
4
+ } from "./chunk-5ND7JYY3.js";
5
+ import {
6
+ LEGACY_DB_PATH,
7
+ LEGACY_MEMORY_DIR,
8
+ MEMORY_DB_PATH,
9
+ MEMORY_DIR,
10
+ PENDING_DIR,
11
+ ensureRexDirs
12
+ } from "./chunk-6SRV2I2H.js";
13
+ import "./chunk-PDX44BCA.js";
14
+
15
+ // src/migrate.ts
16
+ import { existsSync, copyFileSync, mkdirSync, symlinkSync, renameSync, readdirSync, lstatSync } from "fs";
17
+ import { join } from "path";
18
+ import { execSync } from "child_process";
19
+ var log = createLogger("migrate");
20
+ var COLORS = { green: "\x1B[32m", yellow: "\x1B[33m", dim: "\x1B[2m", reset: "\x1B[0m" };
21
+ async function migrate() {
22
+ log.info("Migration started");
23
+ ensureRexDirs();
24
+ if (existsSync(LEGACY_DB_PATH) && !existsSync(MEMORY_DB_PATH)) {
25
+ console.log(`${COLORS.yellow}Migrating${COLORS.reset} rex.sqlite to ~/.claude/rex/memory/`);
26
+ copyFileSync(LEGACY_DB_PATH, MEMORY_DB_PATH);
27
+ for (const ext of ["-wal", "-shm"]) {
28
+ const src = LEGACY_DB_PATH + ext;
29
+ if (existsSync(src)) copyFileSync(src, MEMORY_DB_PATH + ext);
30
+ }
31
+ console.log(`${COLORS.green}Done${COLORS.reset} \u2014 DB migrated`);
32
+ } else if (existsSync(MEMORY_DB_PATH)) {
33
+ console.log(`${COLORS.dim}DB already at ~/.claude/rex/memory/ \u2014 skipping${COLORS.reset}`);
34
+ } else {
35
+ console.log(`${COLORS.dim}No legacy DB found \u2014 fresh install${COLORS.reset}`);
36
+ }
37
+ const legacyPending = join(LEGACY_MEMORY_DIR, "pending");
38
+ if (existsSync(legacyPending)) {
39
+ const files = readdirSync(legacyPending).filter((f) => f.endsWith(".json"));
40
+ for (const f of files) {
41
+ const src = join(legacyPending, f);
42
+ const dest = join(PENDING_DIR, f);
43
+ if (!existsSync(dest)) copyFileSync(src, dest);
44
+ }
45
+ if (files.length) console.log(`${COLORS.green}Migrated${COLORS.reset} ${files.length} pending files`);
46
+ }
47
+ if (existsSync(LEGACY_MEMORY_DIR)) {
48
+ try {
49
+ const stat = lstatSync(LEGACY_MEMORY_DIR);
50
+ if (!stat.isSymbolicLink()) {
51
+ renameSync(LEGACY_MEMORY_DIR, LEGACY_MEMORY_DIR + ".bak");
52
+ console.log(`${COLORS.dim}Renamed ~/.rex-memory/ to ~/.rex-memory.bak/${COLORS.reset}`);
53
+ }
54
+ } catch {
55
+ }
56
+ }
57
+ if (!existsSync(LEGACY_MEMORY_DIR)) {
58
+ mkdirSync(LEGACY_MEMORY_DIR, { recursive: true });
59
+ const legacyDbDir = join(LEGACY_MEMORY_DIR, "db");
60
+ if (!existsSync(legacyDbDir)) {
61
+ symlinkSync(MEMORY_DIR, legacyDbDir);
62
+ console.log(`${COLORS.green}Symlinked${COLORS.reset} ~/.rex-memory/db/ -> ~/.claude/rex/memory/`);
63
+ }
64
+ }
65
+ if (existsSync(MEMORY_DB_PATH)) {
66
+ try {
67
+ const colsRaw = execSync(`sqlite3 "${MEMORY_DB_PATH}" "PRAGMA table_info(memories)"`, { encoding: "utf-8" });
68
+ const colNames = colsRaw.split("\n").map((line) => line.split("|")[1]).filter(Boolean);
69
+ if (!colNames.includes("summary")) {
70
+ execSync(`sqlite3 "${MEMORY_DB_PATH}" "ALTER TABLE memories ADD COLUMN summary TEXT"`);
71
+ console.log(`${COLORS.green}Added${COLORS.reset} summary column`);
72
+ }
73
+ if (!colNames.includes("needs_reprocess")) {
74
+ execSync(`sqlite3 "${MEMORY_DB_PATH}" "ALTER TABLE memories ADD COLUMN needs_reprocess INTEGER DEFAULT 0"`);
75
+ console.log(`${COLORS.green}Added${COLORS.reset} needs_reprocess column`);
76
+ }
77
+ } catch (e) {
78
+ console.log(`${COLORS.yellow}Schema upgrade skipped${COLORS.reset} \u2014 sqlite3 CLI not available: ${e.message?.slice(0, 80)}`);
79
+ }
80
+ }
81
+ log.info("Migration complete");
82
+ console.log(`
83
+ ${COLORS.green}Migration complete.${COLORS.reset} REX hub at ~/.claude/rex/`);
84
+ }
85
+ export {
86
+ migrate
87
+ };
@@ -2,7 +2,8 @@
2
2
  import {
3
3
  detectModel,
4
4
  llm
5
- } from "./chunk-7AGI43F5.js";
5
+ } from "./chunk-WBMVBMWB.js";
6
+ import "./chunk-PDX44BCA.js";
6
7
 
7
8
  // src/optimize.ts
8
9
  import { readFileSync, writeFileSync, existsSync, readdirSync } from "fs";
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ BACKUPS_DIR,
4
+ CONFIG_PATH,
5
+ DAEMON_LOG_PATH,
6
+ INSPIRATIONS_DIR,
7
+ LEGACY_DB_PATH,
8
+ LEGACY_MEMORY_DIR,
9
+ MEMORY_DB_PATH,
10
+ MEMORY_DIR,
11
+ PENDING_DIR,
12
+ PROJECTS_DIR,
13
+ REFERENCES_DIR,
14
+ REX_DIR,
15
+ SELF_IMPROVEMENT_DIR,
16
+ SUMMARIES_DIR,
17
+ VAULT_PATH,
18
+ ensureRexDirs
19
+ } from "./chunk-6SRV2I2H.js";
20
+ import "./chunk-PDX44BCA.js";
21
+ export {
22
+ BACKUPS_DIR,
23
+ CONFIG_PATH,
24
+ DAEMON_LOG_PATH,
25
+ INSPIRATIONS_DIR,
26
+ LEGACY_DB_PATH,
27
+ LEGACY_MEMORY_DIR,
28
+ MEMORY_DB_PATH,
29
+ MEMORY_DIR,
30
+ PENDING_DIR,
31
+ PROJECTS_DIR,
32
+ REFERENCES_DIR,
33
+ REX_DIR,
34
+ SELF_IMPROVEMENT_DIR,
35
+ SUMMARIES_DIR,
36
+ VAULT_PATH,
37
+ ensureRexDirs
38
+ };