@wipcomputer/memory-crystal 0.7.34-alpha.2 → 0.7.34-alpha.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.
Files changed (120) hide show
  1. package/LICENSE +1 -1
  2. package/dist/bridge.js +64 -7
  3. package/dist/bulk-copy.js +67 -16
  4. package/dist/cc-hook.js +2163 -62
  5. package/dist/cc-poller.js +1967 -70
  6. package/dist/cli.js +4538 -139
  7. package/dist/core.js +1789 -6
  8. package/dist/crypto.js +153 -14
  9. package/dist/crystal-serve.js +64 -12
  10. package/dist/doctor.js +517 -52
  11. package/dist/dream-weaver.js +1755 -7
  12. package/dist/file-sync.js +407 -9
  13. package/dist/installer.js +840 -145
  14. package/dist/ldm.js +231 -16
  15. package/dist/mcp-server.js +1882 -17
  16. package/dist/migrate.js +1707 -11
  17. package/dist/mirror-sync.js +2052 -34
  18. package/dist/openclaw.js +1895 -84
  19. package/dist/pair.js +112 -16
  20. package/dist/poller.js +2275 -80
  21. package/dist/role.js +159 -7
  22. package/dist/staging.js +235 -10
  23. package/dist/summarize.js +142 -5
  24. package/package.json +7 -4
  25. package/dist/chunk-25LXQJ4Z.js +0 -110
  26. package/dist/chunk-2DRXIRQW.js +0 -97
  27. package/dist/chunk-2GBYLMEF.js +0 -1385
  28. package/dist/chunk-2ZNH5F6E.js +0 -1281
  29. package/dist/chunk-3G3SFYYI.js +0 -288
  30. package/dist/chunk-3RG5ZIWI.js +0 -10
  31. package/dist/chunk-3S6TI23B.js +0 -97
  32. package/dist/chunk-3VFIJYS4.js +0 -818
  33. package/dist/chunk-437F27T6.js +0 -97
  34. package/dist/chunk-52QE3YI3.js +0 -1169
  35. package/dist/chunk-57RP3DIN.js +0 -1205
  36. package/dist/chunk-5HSZ4W2P.js +0 -62
  37. package/dist/chunk-5I7GMRDN.js +0 -146
  38. package/dist/chunk-645IPXW3.js +0 -290
  39. package/dist/chunk-7A7ELD4C.js +0 -1205
  40. package/dist/chunk-7FYY4GZM.js +0 -1205
  41. package/dist/chunk-7IUE7ODU.js +0 -254
  42. package/dist/chunk-7RMLKZIS.js +0 -108
  43. package/dist/chunk-AA3OPP4Z.js +0 -432
  44. package/dist/chunk-AEWLSYPH.js +0 -72
  45. package/dist/chunk-ASSZDR6I.js +0 -108
  46. package/dist/chunk-AYRJVWUC.js +0 -1205
  47. package/dist/chunk-CCYI5O3D.js +0 -148
  48. package/dist/chunk-CGIDSAJB.js +0 -288
  49. package/dist/chunk-D3I3ZSE2.js +0 -411
  50. package/dist/chunk-D3MACYZ4.js +0 -108
  51. package/dist/chunk-DACSKLY6.js +0 -219
  52. package/dist/chunk-DFQ72B7M.js +0 -248
  53. package/dist/chunk-DW5B4BL7.js +0 -108
  54. package/dist/chunk-EKSACBTJ.js +0 -1070
  55. package/dist/chunk-EXEZZADG.js +0 -248
  56. package/dist/chunk-F3Y7EL7K.js +0 -83
  57. package/dist/chunk-FBQWSDPC.js +0 -1328
  58. package/dist/chunk-FHRZNOMW.js +0 -1205
  59. package/dist/chunk-IM7N24MT.js +0 -129
  60. package/dist/chunk-IPNYIXFK.js +0 -1178
  61. package/dist/chunk-J7MRSZIO.js +0 -167
  62. package/dist/chunk-JITKI2OI.js +0 -106
  63. package/dist/chunk-JWZXYVET.js +0 -1068
  64. package/dist/chunk-KCQUXVYT.js +0 -108
  65. package/dist/chunk-KOQ43OX6.js +0 -1281
  66. package/dist/chunk-KYVWO6ZM.js +0 -1069
  67. package/dist/chunk-L3VHARQH.js +0 -413
  68. package/dist/chunk-LBWDS6BE.js +0 -288
  69. package/dist/chunk-LOVAHSQV.js +0 -411
  70. package/dist/chunk-LQOYCAGG.js +0 -446
  71. package/dist/chunk-LWAIPJ2W.js +0 -146
  72. package/dist/chunk-M5DHKW7M.js +0 -127
  73. package/dist/chunk-MBKCIJHM.js +0 -1328
  74. package/dist/chunk-MK42FMEG.js +0 -147
  75. package/dist/chunk-MOBMYHKL.js +0 -1205
  76. package/dist/chunk-MPLTNMRG.js +0 -67
  77. package/dist/chunk-NIJCVN3O.js +0 -147
  78. package/dist/chunk-NX647OM3.js +0 -310
  79. package/dist/chunk-NZCFSZQ7.js +0 -1205
  80. package/dist/chunk-O2UITJGH.js +0 -465
  81. package/dist/chunk-OCRA44AZ.js +0 -108
  82. package/dist/chunk-P3KJR66H.js +0 -117
  83. package/dist/chunk-PEK6JH65.js +0 -432
  84. package/dist/chunk-PJ6FFKEX.js +0 -77
  85. package/dist/chunk-PLUBBZYR.js +0 -800
  86. package/dist/chunk-PNKVD2UK.js +0 -26
  87. package/dist/chunk-PSQZURHO.js +0 -229
  88. package/dist/chunk-SGL6ISBJ.js +0 -1061
  89. package/dist/chunk-SJABZZT5.js +0 -97
  90. package/dist/chunk-TD3P3K32.js +0 -1199
  91. package/dist/chunk-TMDZJJKV.js +0 -288
  92. package/dist/chunk-UNHVZB5G.js +0 -411
  93. package/dist/chunk-VAFTWSTE.js +0 -1061
  94. package/dist/chunk-VNFXFQBB.js +0 -217
  95. package/dist/chunk-X3GVFKSJ.js +0 -1205
  96. package/dist/chunk-XZ3S56RQ.js +0 -1061
  97. package/dist/chunk-Y72C7F6O.js +0 -148
  98. package/dist/chunk-YLICP577.js +0 -1205
  99. package/dist/chunk-YX6AXLVK.js +0 -159
  100. package/dist/chunk-ZCQYHTNU.js +0 -146
  101. package/dist/cloud-crystal.js +0 -6
  102. package/dist/dev-update-SZ2Z4WCQ.js +0 -6
  103. package/dist/llm-XXLYPIOF.js +0 -16
  104. package/dist/mlx-setup-XKU67WCT.js +0 -289
  105. package/dist/search-pipeline-4K4OJSSS.js +0 -255
  106. package/dist/search-pipeline-4PRS6LI7.js +0 -280
  107. package/dist/search-pipeline-7UJMXPLO.js +0 -280
  108. package/dist/search-pipeline-CBV25NX7.js +0 -99
  109. package/dist/search-pipeline-DQTRLGBH.js +0 -74
  110. package/dist/search-pipeline-HNG37REH.js +0 -282
  111. package/dist/search-pipeline-IZFPLBUB.js +0 -280
  112. package/dist/search-pipeline-MID6F26Q.js +0 -73
  113. package/dist/search-pipeline-N52JZFNN.js +0 -282
  114. package/dist/search-pipeline-OPB2PRQQ.js +0 -280
  115. package/dist/search-pipeline-VXTE5HAD.js +0 -262
  116. package/dist/search-pipeline-XHFKADRG.js +0 -73
  117. package/dist/worker-demo.js +0 -186
  118. package/dist/worker-mcp.js +0 -404
  119. package/scripts/crystal-capture 2.sh +0 -29
  120. package/scripts/deploy-cloud 2.sh +0 -153
package/dist/doctor.js CHANGED
@@ -1,20 +1,485 @@
1
- import {
2
- detectRole
3
- } from "./chunk-437F27T6.js";
4
- import {
5
- isBridgeInstalled,
6
- isBridgeRegistered
7
- } from "./chunk-AEWLSYPH.js";
8
- import {
9
- ldmPaths,
10
- resolveStatePath
11
- } from "./chunk-DFQ72B7M.js";
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __esm = (fn, res) => function __init() {
4
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
5
+ };
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+
11
+ // src/mlx-setup.ts
12
+ var mlx_setup_exports = {};
13
+ __export(mlx_setup_exports, {
14
+ MLX_CONFIG: () => MLX_CONFIG,
15
+ canRunMlx: () => canRunMlx,
16
+ createLaunchAgent: () => createLaunchAgent,
17
+ detectPlatform: () => detectPlatform,
18
+ doctorCheck: () => doctorCheck,
19
+ installMlxLm: () => installMlxLm,
20
+ isMlxLmInstalled: () => isMlxLmInstalled,
21
+ isServerRunning: () => isServerRunning,
22
+ setupMlx: () => setupMlx,
23
+ startServer: () => startServer,
24
+ stopServer: () => stopServer,
25
+ verifyServer: () => verifyServer
26
+ });
27
+ import { existsSync as existsSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync3 } from "fs";
28
+ import { execSync as execSync3 } from "child_process";
29
+ import { join as join3 } from "path";
30
+ import { homedir } from "os";
31
+ function detectPlatform() {
32
+ const platform = process.platform;
33
+ const arch = process.arch;
34
+ if (platform === "darwin") {
35
+ return arch === "arm64" ? "apple-silicon" : "intel-mac";
36
+ }
37
+ if (platform === "linux") return "linux";
38
+ return "other";
39
+ }
40
+ function canRunMlx() {
41
+ return detectPlatform() === "apple-silicon";
42
+ }
43
+ function findPython() {
44
+ const candidates = ["python3", "/opt/homebrew/bin/python3", "/usr/local/bin/python3"];
45
+ for (const cmd of candidates) {
46
+ try {
47
+ const version = execSync3(`${cmd} --version 2>&1`, { encoding: "utf-8", timeout: 5e3 }).trim();
48
+ const match = version.match(/Python (\d+)\.(\d+)/);
49
+ if (match && parseInt(match[1]) >= 3 && parseInt(match[2]) >= 10) {
50
+ const realPath = execSync3(`which ${cmd} 2>/dev/null`, { encoding: "utf-8", timeout: 3e3 }).trim();
51
+ return realPath || cmd;
52
+ }
53
+ } catch {
54
+ }
55
+ }
56
+ return null;
57
+ }
58
+ function findInstaller() {
59
+ try {
60
+ execSync3("uv --version 2>/dev/null", { encoding: "utf-8", timeout: 3e3 });
61
+ return "uv";
62
+ } catch {
63
+ }
64
+ try {
65
+ execSync3("pip3 --version 2>/dev/null", { encoding: "utf-8", timeout: 3e3 });
66
+ return "pip3";
67
+ } catch {
68
+ }
69
+ return null;
70
+ }
71
+ function isMlxLmInstalled() {
72
+ try {
73
+ execSync3('python3 -c "import mlx_lm" 2>/dev/null', { timeout: 5e3 });
74
+ return true;
75
+ } catch {
76
+ return false;
77
+ }
78
+ }
79
+ function installMlxLm(steps) {
80
+ const installer = findInstaller();
81
+ if (!installer) {
82
+ steps.push("No pip3 or uv found. Cannot install mlx-lm.");
83
+ return false;
84
+ }
85
+ const cmd = installer === "uv" ? "uv pip install mlx-lm" : "pip3 install mlx-lm";
86
+ steps.push(`Installing mlx-lm via ${installer}...`);
87
+ try {
88
+ execSync3(cmd, { encoding: "utf-8", timeout: 12e4, stdio: "pipe" });
89
+ steps.push("mlx-lm installed successfully.");
90
+ return true;
91
+ } catch (err) {
92
+ if (installer === "pip3") {
93
+ try {
94
+ execSync3("pip3 install --user mlx-lm", { encoding: "utf-8", timeout: 12e4, stdio: "pipe" });
95
+ steps.push("mlx-lm installed (--user) successfully.");
96
+ return true;
97
+ } catch {
98
+ }
99
+ }
100
+ steps.push(`mlx-lm install failed: ${err.message.slice(0, 200)}`);
101
+ return false;
102
+ }
103
+ }
104
+ function isServerRunning() {
105
+ try {
106
+ const state = loadState();
107
+ const port = state?.port || MLX_PORT;
108
+ execSync3(`curl -s -o /dev/null -w "%{http_code}" http://localhost:${port}/v1/models`, {
109
+ encoding: "utf-8",
110
+ timeout: 3e3
111
+ });
112
+ return true;
113
+ } catch {
114
+ return false;
115
+ }
116
+ }
117
+ function createLaunchAgent(pythonPath, steps) {
118
+ const plist = `<?xml version="1.0" encoding="UTF-8"?>
119
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
120
+ <plist version="1.0">
121
+ <dict>
122
+ <key>Label</key>
123
+ <string>${MLX_PLIST_LABEL}</string>
124
+ <key>ProgramArguments</key>
125
+ <array>
126
+ <string>${pythonPath}</string>
127
+ <string>-m</string>
128
+ <string>mlx_lm.server</string>
129
+ <string>--model</string>
130
+ <string>${MLX_MODEL}</string>
131
+ <string>--port</string>
132
+ <string>${MLX_PORT}</string>
133
+ </array>
134
+ <key>RunAtLoad</key>
135
+ <true/>
136
+ <key>KeepAlive</key>
137
+ <true/>
138
+ <key>StandardOutPath</key>
139
+ <string>${MLX_LOG_PATH}</string>
140
+ <key>StandardErrorPath</key>
141
+ <string>${MLX_LOG_PATH}</string>
142
+ </dict>
143
+ </plist>`;
144
+ try {
145
+ writeFileSync4(MLX_PLIST_PATH, plist);
146
+ execSync3(`launchctl load "${MLX_PLIST_PATH}" 2>/dev/null`, { timeout: 5e3 });
147
+ steps.push(`LaunchAgent installed at ${MLX_PLIST_PATH}`);
148
+ steps.push(`MLX server will start on port ${MLX_PORT}`);
149
+ return true;
150
+ } catch (err) {
151
+ steps.push(`LaunchAgent install failed: ${err.message}`);
152
+ return false;
153
+ }
154
+ }
155
+ function startServer(steps) {
156
+ try {
157
+ execSync3(`launchctl kickstart -kp gui/$(id -u)/${MLX_PLIST_LABEL} 2>/dev/null`, { timeout: 1e4 });
158
+ steps.push("MLX server started.");
159
+ return true;
160
+ } catch {
161
+ steps.push("MLX server start failed. Check /tmp/mlx-server.log");
162
+ return false;
163
+ }
164
+ }
165
+ function stopServer() {
166
+ try {
167
+ execSync3(`launchctl unload "${MLX_PLIST_PATH}" 2>/dev/null`, { timeout: 5e3 });
168
+ return true;
169
+ } catch {
170
+ return false;
171
+ }
172
+ }
173
+ function loadState() {
174
+ try {
175
+ if (existsSync4(MLX_STATE_FILE)) {
176
+ return JSON.parse(readFileSync4(MLX_STATE_FILE, "utf-8"));
177
+ }
178
+ } catch {
179
+ }
180
+ return null;
181
+ }
182
+ function saveState(state) {
183
+ const dir = join3(HOME3, ".ldm", "state");
184
+ if (!existsSync4(dir)) mkdirSync3(dir, { recursive: true });
185
+ writeFileSync4(MLX_STATE_FILE, JSON.stringify(state, null, 2) + "\n");
186
+ }
187
+ async function verifyServer(steps) {
188
+ const state = loadState();
189
+ const port = state?.port || MLX_PORT;
190
+ for (let i = 0; i < 15; i++) {
191
+ try {
192
+ const resp = await fetch(`http://localhost:${port}/v1/models`, {
193
+ signal: AbortSignal.timeout(2e3)
194
+ });
195
+ if (resp.ok) {
196
+ const data = await resp.json();
197
+ const model = data?.data?.[0]?.id || "unknown";
198
+ steps.push(`MLX server verified: ${model} on port ${port}`);
199
+ return true;
200
+ }
201
+ } catch {
202
+ }
203
+ await new Promise((r) => setTimeout(r, 2e3));
204
+ }
205
+ steps.push("MLX server did not respond within 30 seconds. Check /tmp/mlx-server.log");
206
+ return false;
207
+ }
208
+ async function setupMlx(options) {
209
+ const steps = [];
210
+ const platform = detectPlatform();
211
+ if (platform !== "apple-silicon") {
212
+ steps.push(`Platform: ${platform}. MLX requires Apple Silicon. Skipping.`);
213
+ return { ok: false, steps };
214
+ }
215
+ steps.push("Platform: Apple Silicon detected.");
216
+ const pythonPath = findPython();
217
+ if (!pythonPath) {
218
+ steps.push("Python 3.10+ not found. Install via: brew install python3");
219
+ return { ok: false, steps };
220
+ }
221
+ steps.push(`Python: ${pythonPath}`);
222
+ if (!isMlxLmInstalled()) {
223
+ if (!options?.yes) {
224
+ steps.push("mlx-lm not installed. Run with --yes to auto-install, or: pip3 install mlx-lm");
225
+ return { ok: false, steps };
226
+ }
227
+ const installed = installMlxLm(steps);
228
+ if (!installed) return { ok: false, steps };
229
+ } else {
230
+ steps.push("mlx-lm: already installed.");
231
+ }
232
+ if (!existsSync4(MLX_PLIST_PATH)) {
233
+ const created = createLaunchAgent(pythonPath, steps);
234
+ if (!created) return { ok: false, steps };
235
+ } else {
236
+ steps.push("LaunchAgent: already installed.");
237
+ }
238
+ saveState({
239
+ installed: true,
240
+ port: MLX_PORT,
241
+ model: MLX_MODEL,
242
+ pythonPath,
243
+ installedAt: (/* @__PURE__ */ new Date()).toISOString()
244
+ });
245
+ if (!isServerRunning()) {
246
+ startServer(steps);
247
+ steps.push(`Waiting for model to load (~1.5 GB on first run)...`);
248
+ const verified = await verifyServer(steps);
249
+ if (!verified) {
250
+ steps.push("Server started but not yet responding. It may still be downloading the model.");
251
+ steps.push(`Check: tail -f ${MLX_LOG_PATH}`);
252
+ }
253
+ } else {
254
+ steps.push(`MLX server: already running on port ${MLX_PORT}`);
255
+ }
256
+ return { ok: true, steps };
257
+ }
258
+ function doctorCheck() {
259
+ const platform = detectPlatform();
260
+ if (platform !== "apple-silicon") {
261
+ return { status: "skip", detail: `${platform} (MLX requires Apple Silicon)` };
262
+ }
263
+ const state = loadState();
264
+ if (!state || !state.installed) {
265
+ return {
266
+ status: "warn",
267
+ detail: "not installed",
268
+ fix: "crystal init (will offer MLX setup)"
269
+ };
270
+ }
271
+ if (isServerRunning()) {
272
+ return { status: "ok", detail: `running on port ${state.port} (${state.model})` };
273
+ }
274
+ if (existsSync4(MLX_PLIST_PATH)) {
275
+ return {
276
+ status: "warn",
277
+ detail: "installed but not running",
278
+ fix: `launchctl kickstart -kp gui/$(id -u)/${MLX_PLIST_LABEL}`
279
+ };
280
+ }
281
+ return {
282
+ status: "warn",
283
+ detail: "installed but LaunchAgent missing",
284
+ fix: "crystal init (will recreate LaunchAgent)"
285
+ };
286
+ }
287
+ var HOME3, MLX_PORT, MLX_MODEL, MLX_STATE_FILE, MLX_PLIST_LABEL, MLX_PLIST_PATH, MLX_LOG_PATH, MLX_CONFIG;
288
+ var init_mlx_setup = __esm({
289
+ "src/mlx-setup.ts"() {
290
+ "use strict";
291
+ HOME3 = homedir();
292
+ MLX_PORT = 18791;
293
+ MLX_MODEL = "mlx-community/Qwen2.5-3B-Instruct-4bit";
294
+ MLX_STATE_FILE = join3(HOME3, ".ldm", "state", "mlx-server.json");
295
+ MLX_PLIST_LABEL = "ai.ldm.mlx-server";
296
+ MLX_PLIST_PATH = join3(HOME3, "Library", "LaunchAgents", `${MLX_PLIST_LABEL}.plist`);
297
+ MLX_LOG_PATH = "/tmp/mlx-server.log";
298
+ MLX_CONFIG = {
299
+ port: MLX_PORT,
300
+ model: MLX_MODEL,
301
+ plistPath: MLX_PLIST_PATH,
302
+ logPath: MLX_LOG_PATH,
303
+ stateFile: MLX_STATE_FILE
304
+ };
305
+ }
306
+ });
12
307
 
13
308
  // src/doctor.ts
14
- import { existsSync, readFileSync, readdirSync } from "fs";
309
+ import { existsSync as existsSync5, readFileSync as readFileSync5, readdirSync as readdirSync2 } from "fs";
310
+ import { execSync as execSync4 } from "child_process";
311
+ import { join as join4 } from "path";
312
+
313
+ // src/role.ts
314
+ import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
315
+
316
+ // src/ldm.ts
317
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, copyFileSync, chmodSync, readdirSync } from "fs";
318
+ import { join, dirname } from "path";
15
319
  import { execSync } from "child_process";
16
- import { join } from "path";
320
+ import { fileURLToPath } from "url";
17
321
  var HOME = process.env.HOME || "";
322
+ var LDM_ROOT = join(HOME, ".ldm");
323
+ function loadAgentConfig(id) {
324
+ const cfgPath = join(LDM_ROOT, "agents", id, "config.json");
325
+ try {
326
+ if (existsSync(cfgPath)) return JSON.parse(readFileSync(cfgPath, "utf-8"));
327
+ } catch {
328
+ }
329
+ return null;
330
+ }
331
+ function getAgentId(harnessHint) {
332
+ if (process.env.CRYSTAL_AGENT_ID) return process.env.CRYSTAL_AGENT_ID;
333
+ const agentsDir = join(LDM_ROOT, "agents");
334
+ if (existsSync(agentsDir)) {
335
+ try {
336
+ for (const d of readdirSync(agentsDir)) {
337
+ const cfg = loadAgentConfig(d);
338
+ if (!cfg || !cfg.agentId) continue;
339
+ if (!harnessHint) return cfg.agentId;
340
+ if (harnessHint === "claude-code" && cfg.harness === "claude-code-cli") return cfg.agentId;
341
+ if (harnessHint === "openclaw" && cfg.harness === "openclaw") return cfg.agentId;
342
+ }
343
+ } catch {
344
+ }
345
+ }
346
+ return harnessHint === "openclaw" ? "oc-lesa-mini" : "cc-mini";
347
+ }
348
+ function ldmPaths(agentId) {
349
+ const id = agentId || getAgentId();
350
+ const agentRoot = join(LDM_ROOT, "agents", id);
351
+ return {
352
+ root: LDM_ROOT,
353
+ bin: join(LDM_ROOT, "bin"),
354
+ secrets: join(LDM_ROOT, "secrets"),
355
+ state: join(LDM_ROOT, "state"),
356
+ config: join(LDM_ROOT, "config.json"),
357
+ crystalDb: join(LDM_ROOT, "memory", "crystal.db"),
358
+ crystalLance: join(LDM_ROOT, "memory", "lance"),
359
+ agentRoot,
360
+ transcripts: join(agentRoot, "memory", "transcripts"),
361
+ sessions: join(agentRoot, "memory", "sessions"),
362
+ daily: join(agentRoot, "memory", "daily"),
363
+ journals: join(agentRoot, "memory", "journals"),
364
+ workspace: join(agentRoot, "memory", "workspace")
365
+ };
366
+ }
367
+ var LEGACY_OC_DIR = join(HOME, ".openclaw");
368
+ function resolveStatePath(filename) {
369
+ const paths = ldmPaths();
370
+ const ldmPath = join(paths.state, filename);
371
+ if (existsSync(ldmPath)) return ldmPath;
372
+ const legacyPath = join(LEGACY_OC_DIR, "memory", filename);
373
+ if (existsSync(legacyPath)) return legacyPath;
374
+ return ldmPath;
375
+ }
376
+ function resolveSecretPath(filename) {
377
+ const paths = ldmPaths();
378
+ const ldmPath = join(paths.secrets, filename);
379
+ if (existsSync(ldmPath)) return ldmPath;
380
+ const legacyPath = join(LEGACY_OC_DIR, "secrets", filename);
381
+ if (existsSync(legacyPath)) return legacyPath;
382
+ return ldmPath;
383
+ }
384
+
385
+ // src/role.ts
386
+ var STATE_FILE = "crystal-role.json";
387
+ function loadRoleState() {
388
+ try {
389
+ const path = resolveStatePath(STATE_FILE);
390
+ if (existsSync2(path)) {
391
+ return JSON.parse(readFileSync2(path, "utf-8"));
392
+ }
393
+ } catch {
394
+ }
395
+ return null;
396
+ }
397
+ function hasLocalEmbeddingProvider() {
398
+ if (process.env.OPENAI_API_KEY) return true;
399
+ if (process.env.GOOGLE_API_KEY && process.env.CRYSTAL_EMBEDDING_PROVIDER === "google") return true;
400
+ if (process.env.CRYSTAL_EMBEDDING_PROVIDER === "ollama") return true;
401
+ return false;
402
+ }
403
+ function hasRelayKey() {
404
+ const keyPath = resolveSecretPath("crystal-relay-key");
405
+ return existsSync2(keyPath);
406
+ }
407
+ function detectRole() {
408
+ const agentId = getAgentId();
409
+ const paths = ldmPaths(agentId);
410
+ const relayUrl = process.env.CRYSTAL_RELAY_URL || null;
411
+ const relayToken = !!process.env.CRYSTAL_RELAY_TOKEN;
412
+ const relayKeyExists = hasRelayKey();
413
+ const localEmbeddings = hasLocalEmbeddingProvider();
414
+ const localDb = existsSync2(paths.crystalDb);
415
+ const state = loadRoleState();
416
+ if (state && state.override) {
417
+ return {
418
+ role: state.role,
419
+ source: "state-file",
420
+ relayUrl,
421
+ relayToken,
422
+ relayKeyExists,
423
+ agentId,
424
+ hasLocalEmbeddings: localEmbeddings,
425
+ hasLocalDb: localDb
426
+ };
427
+ }
428
+ let role = "core";
429
+ if ((relayUrl || relayKeyExists) && !localEmbeddings) {
430
+ role = "node";
431
+ } else if ((relayUrl || relayKeyExists) && localEmbeddings) {
432
+ role = "core";
433
+ }
434
+ return {
435
+ role,
436
+ source: "auto-detected",
437
+ relayUrl,
438
+ relayToken,
439
+ relayKeyExists,
440
+ agentId,
441
+ hasLocalEmbeddings: localEmbeddings,
442
+ hasLocalDb: localDb
443
+ };
444
+ }
445
+
446
+ // src/bridge.ts
447
+ import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
448
+ import { execSync as execSync2 } from "child_process";
449
+ import { join as join2 } from "path";
450
+ var HOME2 = process.env.HOME || "";
451
+ function _checkLocalBridge() {
452
+ if (existsSync3(join2(HOME2, ".openclaw", "extensions", "lesa-bridge", "dist", "index.js"))) return true;
453
+ if (existsSync3(join2(HOME2, ".ldm", "extensions", "lesa-bridge", "dist", "index.js"))) return true;
454
+ return false;
455
+ }
456
+ function isBridgeInstalled() {
457
+ try {
458
+ execSync2("which lesa 2>/dev/null", { encoding: "utf-8" });
459
+ return true;
460
+ } catch {
461
+ return _checkLocalBridge();
462
+ }
463
+ }
464
+ function isBridgeRegistered() {
465
+ const mcpPath = join2(HOME2, ".claude", ".mcp.json");
466
+ try {
467
+ if (existsSync3(mcpPath)) {
468
+ const config = JSON.parse(readFileSync3(mcpPath, "utf-8"));
469
+ if (config.mcpServers && config.mcpServers["lesa-bridge"]) return true;
470
+ }
471
+ } catch {
472
+ }
473
+ try {
474
+ const r = execSync2("claude mcp get lesa-bridge 2>&1", { encoding: "utf-8", timeout: 5e3 });
475
+ if (!r.includes("not found") && !r.includes("error")) return true;
476
+ } catch {
477
+ }
478
+ return false;
479
+ }
480
+
481
+ // src/doctor.ts
482
+ var HOME4 = process.env.HOME || "";
18
483
  async function runDoctor() {
19
484
  const checks = [];
20
485
  const role = detectRole();
@@ -36,8 +501,8 @@ async function runDoctor() {
36
501
  checks.push(checkLdmDirectory(paths));
37
502
  checks.push(checkPrivateMode());
38
503
  try {
39
- const { doctorCheck } = await import("./mlx-setup-XKU67WCT.js");
40
- const mlx = doctorCheck();
504
+ const { doctorCheck: doctorCheck2 } = await Promise.resolve().then(() => (init_mlx_setup(), mlx_setup_exports));
505
+ const mlx = doctorCheck2();
41
506
  if (mlx.status !== "skip") {
42
507
  checks.push({ name: "MLX LLM", status: mlx.status, detail: mlx.detail, fix: mlx.fix });
43
508
  }
@@ -46,13 +511,13 @@ async function runDoctor() {
46
511
  return checks;
47
512
  }
48
513
  function checkOpEmbeddings() {
49
- const saTokenLdm = join(HOME, ".ldm", "secrets", "op-sa-token");
50
- const saTokenOc = join(HOME, ".openclaw", "secrets", "op-sa-token");
51
- if (!existsSync(saTokenLdm) && !existsSync(saTokenOc)) return null;
52
- const saTokenPath = existsSync(saTokenLdm) ? saTokenLdm : saTokenOc;
514
+ const saTokenLdm = join4(HOME4, ".ldm", "secrets", "op-sa-token");
515
+ const saTokenOc = join4(HOME4, ".openclaw", "secrets", "op-sa-token");
516
+ if (!existsSync5(saTokenLdm) && !existsSync5(saTokenOc)) return null;
517
+ const saTokenPath = existsSync5(saTokenLdm) ? saTokenLdm : saTokenOc;
53
518
  try {
54
- const saToken = readFileSync(saTokenPath, "utf-8").trim();
55
- const result = execSync('op read "op://Agent Secrets/OpenAI API/api key" 2>/dev/null', {
519
+ const saToken = readFileSync5(saTokenPath, "utf-8").trim();
520
+ const result = execSync4('op read "op://Agent Secrets/OpenAI API/api key" 2>/dev/null', {
56
521
  encoding: "utf-8",
57
522
  env: { ...process.env, OP_SERVICE_ACCOUNT_TOKEN: saToken },
58
523
  timeout: 1e4
@@ -71,12 +536,12 @@ function checkOpEmbeddings() {
71
536
  return null;
72
537
  }
73
538
  function checkVersion() {
74
- const ldmExtPkg = join(HOME, ".ldm", "extensions", "memory-crystal", "package.json");
75
- const ocExtPkg = join(HOME, ".openclaw", "extensions", "memory-crystal", "package.json");
539
+ const ldmExtPkg = join4(HOME4, ".ldm", "extensions", "memory-crystal", "package.json");
540
+ const ocExtPkg = join4(HOME4, ".openclaw", "extensions", "memory-crystal", "package.json");
76
541
  let installedVersion = null;
77
542
  try {
78
- if (existsSync(ldmExtPkg)) {
79
- const pkg = JSON.parse(readFileSync(ldmExtPkg, "utf-8"));
543
+ if (existsSync5(ldmExtPkg)) {
544
+ const pkg = JSON.parse(readFileSync5(ldmExtPkg, "utf-8"));
80
545
  installedVersion = pkg.version;
81
546
  }
82
547
  } catch {
@@ -91,8 +556,8 @@ function checkVersion() {
91
556
  }
92
557
  let ocVersion = null;
93
558
  try {
94
- if (existsSync(ocExtPkg)) {
95
- const pkg = JSON.parse(readFileSync(ocExtPkg, "utf-8"));
559
+ if (existsSync5(ocExtPkg)) {
560
+ const pkg = JSON.parse(readFileSync5(ocExtPkg, "utf-8"));
96
561
  ocVersion = pkg.version;
97
562
  }
98
563
  } catch {
@@ -114,10 +579,10 @@ function checkVersion() {
114
579
  };
115
580
  }
116
581
  function checkCCHook() {
117
- const settingsPath = join(HOME, ".claude", "settings.json");
582
+ const settingsPath = join4(HOME4, ".claude", "settings.json");
118
583
  try {
119
- if (existsSync(settingsPath)) {
120
- const settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
584
+ if (existsSync5(settingsPath)) {
585
+ const settings = JSON.parse(readFileSync5(settingsPath, "utf-8"));
121
586
  const stopHooks = settings?.hooks?.Stop;
122
587
  if (Array.isArray(stopHooks)) {
123
588
  const found = stopHooks.some((entry) => {
@@ -140,7 +605,7 @@ function checkCCHook() {
140
605
  };
141
606
  }
142
607
  async function checkDatabase(dbPath) {
143
- if (!existsSync(dbPath)) {
608
+ if (!existsSync5(dbPath)) {
144
609
  return {
145
610
  name: "Database",
146
611
  status: "fail",
@@ -196,7 +661,7 @@ function checkEmbeddingProvider(role) {
196
661
  }
197
662
  function checkCaptureCron() {
198
663
  try {
199
- const crontab = execSync("crontab -l 2>/dev/null", { encoding: "utf-8" });
664
+ const crontab = execSync4("crontab -l 2>/dev/null", { encoding: "utf-8" });
200
665
  if (crontab.includes("crystal-capture")) {
201
666
  return { name: "Capture", status: "ok", detail: "cron installed" };
202
667
  }
@@ -232,26 +697,26 @@ function checkRelayConfig(role) {
232
697
  }
233
698
  function checkMcpServer() {
234
699
  const candidates = [
235
- join(HOME, ".claude", ".mcp.json"),
700
+ join4(HOME4, ".claude", ".mcp.json"),
236
701
  // user-level (legacy)
237
- join(HOME, ".openclaw", ".mcp.json"),
702
+ join4(HOME4, ".openclaw", ".mcp.json"),
238
703
  // OpenClaw project-level
239
- join(process.cwd(), ".mcp.json")
704
+ join4(process.cwd(), ".mcp.json")
240
705
  // current project
241
706
  ];
242
707
  for (const mcpPath of candidates) {
243
708
  try {
244
- if (existsSync(mcpPath)) {
245
- const config = JSON.parse(readFileSync(mcpPath, "utf-8"));
709
+ if (existsSync5(mcpPath)) {
710
+ const config = JSON.parse(readFileSync5(mcpPath, "utf-8"));
246
711
  if (config.mcpServers && config.mcpServers["memory-crystal"]) {
247
- return { name: "MCP Server", status: "ok", detail: `memory-crystal registered (${mcpPath.replace(HOME, "~")})` };
712
+ return { name: "MCP Server", status: "ok", detail: `memory-crystal registered (${mcpPath.replace(HOME4, "~")})` };
248
713
  }
249
714
  }
250
715
  } catch {
251
716
  }
252
717
  }
253
718
  try {
254
- const result = execSync("claude mcp get memory-crystal 2>&1", { encoding: "utf-8", timeout: 5e3 });
719
+ const result = execSync4("claude mcp get memory-crystal 2>&1", { encoding: "utf-8", timeout: 5e3 });
255
720
  if (!result.includes("not found") && !result.includes("error")) {
256
721
  return { name: "MCP Server", status: "ok", detail: "memory-crystal registered (user scope)" };
257
722
  }
@@ -265,21 +730,21 @@ function checkMcpServer() {
265
730
  };
266
731
  }
267
732
  function checkBackup() {
268
- const plistPath = join(HOME, "Library", "LaunchAgents", "ai.openclaw.ldm-backup.plist");
269
- if (existsSync(plistPath)) {
733
+ const plistPath = join4(HOME4, "Library", "LaunchAgents", "ai.openclaw.ldm-backup.plist");
734
+ if (existsSync5(plistPath)) {
270
735
  return { name: "Backup", status: "ok", detail: "LaunchAgent installed" };
271
736
  }
272
737
  try {
273
- const crontab = execSync("crontab -l 2>/dev/null", { encoding: "utf-8" });
738
+ const crontab = execSync4("crontab -l 2>/dev/null", { encoding: "utf-8" });
274
739
  if (crontab.includes("ldm-backup") || crontab.includes("LDMDevTools") && crontab.includes("backup")) {
275
740
  return { name: "Backup", status: "ok", detail: "cron installed" };
276
741
  }
277
742
  } catch {
278
743
  }
279
- const backupsDir = join(HOME, ".ldm", "backups");
280
- if (existsSync(backupsDir)) {
744
+ const backupsDir = join4(HOME4, ".ldm", "backups");
745
+ if (existsSync5(backupsDir)) {
281
746
  try {
282
- const entries = readdirSync(backupsDir).filter((e) => !e.startsWith("."));
747
+ const entries = readdirSync2(backupsDir).filter((e) => !e.startsWith("."));
283
748
  if (entries.length > 0) return { name: "Backup", status: "ok", detail: `${entries.length} backup(s) in ~/.ldm/backups/` };
284
749
  } catch {
285
750
  }
@@ -309,11 +774,11 @@ function checkBridge() {
309
774
  }
310
775
  function checkLdmDirectory(paths) {
311
776
  const missing = [];
312
- if (!existsSync(paths.root)) missing.push("~/.ldm");
313
- if (!existsSync(join(paths.root, "memory"))) missing.push("memory/");
314
- if (!existsSync(paths.state)) missing.push("state/");
315
- if (!existsSync(paths.bin)) missing.push("bin/");
316
- if (!existsSync(paths.transcripts)) missing.push("transcripts/");
777
+ if (!existsSync5(paths.root)) missing.push("~/.ldm");
778
+ if (!existsSync5(join4(paths.root, "memory"))) missing.push("memory/");
779
+ if (!existsSync5(paths.state)) missing.push("state/");
780
+ if (!existsSync5(paths.bin)) missing.push("bin/");
781
+ if (!existsSync5(paths.transcripts)) missing.push("transcripts/");
317
782
  if (missing.length === 0) {
318
783
  return { name: "LDM Directory", status: "ok", detail: "intact" };
319
784
  }
@@ -327,8 +792,8 @@ function checkLdmDirectory(paths) {
327
792
  function checkPrivateMode() {
328
793
  const statePath = resolveStatePath("memory-capture-state.json");
329
794
  try {
330
- if (existsSync(statePath)) {
331
- const state = JSON.parse(readFileSync(statePath, "utf-8"));
795
+ if (existsSync5(statePath)) {
796
+ const state = JSON.parse(readFileSync5(statePath, "utf-8"));
332
797
  if (state.enabled === false) {
333
798
  return { name: "Private Mode", status: "warn", detail: "capture disabled (private mode ON)" };
334
799
  }