@wipcomputer/memory-crystal 0.7.30 → 0.7.32

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 (211) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/SKILL.md +1 -1
  3. package/package.json +1 -1
  4. package/.worktrees/memory-crystal-private--cc-mini-fix-home-fallback/.env.example +0 -20
  5. package/.worktrees/memory-crystal-private--cc-mini-fix-home-fallback/.publish-skill.json +0 -1
  6. package/.worktrees/memory-crystal-private--cc-mini-fix-home-fallback/CHANGELOG.md +0 -1297
  7. package/.worktrees/memory-crystal-private--cc-mini-fix-home-fallback/CLA.md +0 -19
  8. package/.worktrees/memory-crystal-private--cc-mini-fix-home-fallback/LICENSE +0 -52
  9. package/.worktrees/memory-crystal-private--cc-mini-fix-home-fallback/README-ENTERPRISE.md +0 -226
  10. package/.worktrees/memory-crystal-private--cc-mini-fix-home-fallback/README.md +0 -151
  11. package/.worktrees/memory-crystal-private--cc-mini-fix-home-fallback/RELAY.md +0 -199
  12. package/.worktrees/memory-crystal-private--cc-mini-fix-home-fallback/SKILL.md +0 -462
  13. package/.worktrees/memory-crystal-private--cc-mini-fix-home-fallback/TECHNICAL.md +0 -656
  14. package/.worktrees/memory-crystal-private--cc-mini-fix-home-fallback/_trash/RELEASE-NOTES-v0-7-23.md +0 -48
  15. package/.worktrees/memory-crystal-private--cc-mini-fix-home-fallback/_trash/RELEASE-NOTES-v0-7-25.md +0 -24
  16. package/.worktrees/memory-crystal-private--cc-mini-fix-home-fallback/_trash/RELEASE-NOTES-v0-7-26.md +0 -7
  17. package/.worktrees/memory-crystal-private--cc-mini-fix-home-fallback/_trash/RELEASE-NOTES-v0-7-28.md +0 -31
  18. package/.worktrees/memory-crystal-private--cc-mini-fix-home-fallback/_trash/RELEASE-NOTES-v0-7-29.md +0 -28
  19. package/.worktrees/memory-crystal-private--cc-mini-fix-home-fallback/_trash/RELEASE-NOTES-v0-7-4.md +0 -64
  20. package/.worktrees/memory-crystal-private--cc-mini-fix-home-fallback/_trash/RELEASE-NOTES-v0-7-5.md +0 -19
  21. package/.worktrees/memory-crystal-private--cc-mini-fix-home-fallback/cloud/README.md +0 -116
  22. package/.worktrees/memory-crystal-private--cc-mini-fix-home-fallback/cloud/docs/gpt-system-instructions.md +0 -69
  23. package/.worktrees/memory-crystal-private--cc-mini-fix-home-fallback/cloud/migrations/0001_init.sql +0 -52
  24. package/.worktrees/memory-crystal-private--cc-mini-fix-home-fallback/migrations/0001_init.sql +0 -51
  25. package/.worktrees/memory-crystal-private--cc-mini-fix-home-fallback/migrations/0002_cloud_storage.sql +0 -49
  26. package/.worktrees/memory-crystal-private--cc-mini-fix-home-fallback/openclaw.plugin.json +0 -11
  27. package/.worktrees/memory-crystal-private--cc-mini-fix-home-fallback/package-lock.json +0 -4169
  28. package/.worktrees/memory-crystal-private--cc-mini-fix-home-fallback/package.json +0 -61
  29. package/.worktrees/memory-crystal-private--cc-mini-fix-home-fallback/scripts/crystal-capture.sh +0 -29
  30. package/.worktrees/memory-crystal-private--cc-mini-fix-home-fallback/scripts/deploy-cloud.sh +0 -153
  31. package/.worktrees/memory-crystal-private--cc-mini-fix-home-fallback/scripts/ldm-backup.sh +0 -116
  32. package/.worktrees/memory-crystal-private--cc-mini-fix-home-fallback/scripts/migrate-lance-to-sqlite.mjs +0 -218
  33. package/.worktrees/memory-crystal-private--cc-mini-fix-home-fallback/skills/memory/SKILL.md +0 -438
  34. package/.worktrees/memory-crystal-private--cc-mini-fix-home-fallback/wrangler-demo.toml +0 -8
  35. package/.worktrees/memory-crystal-private--cc-mini-fix-home-fallback/wrangler-mcp.toml +0 -24
  36. package/.worktrees/memory-crystal-private--cc-mini-release-notes-v0.7.30/.env.example +0 -20
  37. package/.worktrees/memory-crystal-private--cc-mini-release-notes-v0.7.30/.publish-skill.json +0 -1
  38. package/.worktrees/memory-crystal-private--cc-mini-release-notes-v0.7.30/CHANGELOG.md +0 -1297
  39. package/.worktrees/memory-crystal-private--cc-mini-release-notes-v0.7.30/CLA.md +0 -19
  40. package/.worktrees/memory-crystal-private--cc-mini-release-notes-v0.7.30/LICENSE +0 -52
  41. package/.worktrees/memory-crystal-private--cc-mini-release-notes-v0.7.30/README-ENTERPRISE.md +0 -226
  42. package/.worktrees/memory-crystal-private--cc-mini-release-notes-v0.7.30/README.md +0 -151
  43. package/.worktrees/memory-crystal-private--cc-mini-release-notes-v0.7.30/RELAY.md +0 -199
  44. package/.worktrees/memory-crystal-private--cc-mini-release-notes-v0.7.30/RELEASE-NOTES-v0.7.30.md +0 -29
  45. package/.worktrees/memory-crystal-private--cc-mini-release-notes-v0.7.30/SKILL.md +0 -462
  46. package/.worktrees/memory-crystal-private--cc-mini-release-notes-v0.7.30/TECHNICAL.md +0 -656
  47. package/.worktrees/memory-crystal-private--cc-mini-release-notes-v0.7.30/_trash/RELEASE-NOTES-v0-7-23.md +0 -48
  48. package/.worktrees/memory-crystal-private--cc-mini-release-notes-v0.7.30/_trash/RELEASE-NOTES-v0-7-25.md +0 -24
  49. package/.worktrees/memory-crystal-private--cc-mini-release-notes-v0.7.30/_trash/RELEASE-NOTES-v0-7-26.md +0 -7
  50. package/.worktrees/memory-crystal-private--cc-mini-release-notes-v0.7.30/_trash/RELEASE-NOTES-v0-7-28.md +0 -31
  51. package/.worktrees/memory-crystal-private--cc-mini-release-notes-v0.7.30/_trash/RELEASE-NOTES-v0-7-29.md +0 -28
  52. package/.worktrees/memory-crystal-private--cc-mini-release-notes-v0.7.30/_trash/RELEASE-NOTES-v0-7-4.md +0 -64
  53. package/.worktrees/memory-crystal-private--cc-mini-release-notes-v0.7.30/_trash/RELEASE-NOTES-v0-7-5.md +0 -19
  54. package/.worktrees/memory-crystal-private--cc-mini-release-notes-v0.7.30/cloud/README.md +0 -116
  55. package/.worktrees/memory-crystal-private--cc-mini-release-notes-v0.7.30/cloud/docs/gpt-system-instructions.md +0 -69
  56. package/.worktrees/memory-crystal-private--cc-mini-release-notes-v0.7.30/cloud/migrations/0001_init.sql +0 -52
  57. package/.worktrees/memory-crystal-private--cc-mini-release-notes-v0.7.30/migrations/0001_init.sql +0 -51
  58. package/.worktrees/memory-crystal-private--cc-mini-release-notes-v0.7.30/migrations/0002_cloud_storage.sql +0 -49
  59. package/.worktrees/memory-crystal-private--cc-mini-release-notes-v0.7.30/openclaw.plugin.json +0 -11
  60. package/.worktrees/memory-crystal-private--cc-mini-release-notes-v0.7.30/package-lock.json +0 -4169
  61. package/.worktrees/memory-crystal-private--cc-mini-release-notes-v0.7.30/package.json +0 -61
  62. package/.worktrees/memory-crystal-private--cc-mini-release-notes-v0.7.30/scripts/crystal-capture.sh +0 -29
  63. package/.worktrees/memory-crystal-private--cc-mini-release-notes-v0.7.30/scripts/deploy-cloud.sh +0 -153
  64. package/.worktrees/memory-crystal-private--cc-mini-release-notes-v0.7.30/scripts/ldm-backup.sh +0 -116
  65. package/.worktrees/memory-crystal-private--cc-mini-release-notes-v0.7.30/scripts/migrate-lance-to-sqlite.mjs +0 -218
  66. package/.worktrees/memory-crystal-private--cc-mini-release-notes-v0.7.30/skills/memory/SKILL.md +0 -438
  67. package/.worktrees/memory-crystal-private--cc-mini-release-notes-v0.7.30/wrangler-demo.toml +0 -8
  68. package/.worktrees/memory-crystal-private--cc-mini-release-notes-v0.7.30/wrangler-mcp.toml +0 -24
  69. package/_trash/RELEASE-NOTES-v0-7-23.md +0 -48
  70. package/_trash/RELEASE-NOTES-v0-7-25.md +0 -24
  71. package/_trash/RELEASE-NOTES-v0-7-26.md +0 -7
  72. package/_trash/RELEASE-NOTES-v0-7-28.md +0 -31
  73. package/_trash/RELEASE-NOTES-v0-7-29.md +0 -28
  74. package/_trash/RELEASE-NOTES-v0-7-4.md +0 -64
  75. package/_trash/RELEASE-NOTES-v0-7-5.md +0 -19
  76. package/_trash/RELEASE-NOTES-v0.7.30.md +0 -29
  77. package/dist/bridge.d.ts +0 -7
  78. package/dist/bridge.js +0 -14
  79. package/dist/bulk-copy.d.ts +0 -17
  80. package/dist/bulk-copy.js +0 -90
  81. package/dist/cc-hook.d.ts +0 -8
  82. package/dist/cc-hook.js +0 -368
  83. package/dist/cc-poller.d.ts +0 -1
  84. package/dist/cc-poller.js +0 -550
  85. package/dist/chunk-25LXQJ4Z.js +0 -110
  86. package/dist/chunk-2DRXIRQW.js +0 -97
  87. package/dist/chunk-2ZNH5F6E.js +0 -1281
  88. package/dist/chunk-3G3SFYYI.js +0 -288
  89. package/dist/chunk-3RG5ZIWI.js +0 -10
  90. package/dist/chunk-3S6TI23B.js +0 -97
  91. package/dist/chunk-3VFIJYS4.js +0 -818
  92. package/dist/chunk-52QE3YI3.js +0 -1169
  93. package/dist/chunk-57RP3DIN.js +0 -1205
  94. package/dist/chunk-5HSZ4W2P.js +0 -62
  95. package/dist/chunk-645IPXW3.js +0 -290
  96. package/dist/chunk-7A7ELD4C.js +0 -1205
  97. package/dist/chunk-7FYY4GZM.js +0 -1205
  98. package/dist/chunk-7IUE7ODU.js +0 -254
  99. package/dist/chunk-7RMLKZIS.js +0 -108
  100. package/dist/chunk-AA3OPP4Z.js +0 -432
  101. package/dist/chunk-AEWLSYPH.js +0 -72
  102. package/dist/chunk-ASSZDR6I.js +0 -108
  103. package/dist/chunk-AYRJVWUC.js +0 -1205
  104. package/dist/chunk-CCYI5O3D.js +0 -148
  105. package/dist/chunk-D3I3ZSE2.js +0 -411
  106. package/dist/chunk-DACSKLY6.js +0 -219
  107. package/dist/chunk-DW5B4BL7.js +0 -108
  108. package/dist/chunk-EKSACBTJ.js +0 -1070
  109. package/dist/chunk-EXEZZADG.js +0 -248
  110. package/dist/chunk-F3Y7EL7K.js +0 -83
  111. package/dist/chunk-FBQWSDPC.js +0 -1328
  112. package/dist/chunk-FHRZNOMW.js +0 -1205
  113. package/dist/chunk-IM7N24MT.js +0 -129
  114. package/dist/chunk-IPNYIXFK.js +0 -1178
  115. package/dist/chunk-J7MRSZIO.js +0 -167
  116. package/dist/chunk-JITKI2OI.js +0 -106
  117. package/dist/chunk-JWZXYVET.js +0 -1068
  118. package/dist/chunk-KCQUXVYT.js +0 -108
  119. package/dist/chunk-KOQ43OX6.js +0 -1281
  120. package/dist/chunk-KYVWO6ZM.js +0 -1069
  121. package/dist/chunk-L3VHARQH.js +0 -413
  122. package/dist/chunk-LBWDS6BE.js +0 -288
  123. package/dist/chunk-LOVAHSQV.js +0 -411
  124. package/dist/chunk-LQOYCAGG.js +0 -446
  125. package/dist/chunk-LWAIPJ2W.js +0 -146
  126. package/dist/chunk-M5DHKW7M.js +0 -127
  127. package/dist/chunk-MBKCIJHM.js +0 -1328
  128. package/dist/chunk-MK42FMEG.js +0 -147
  129. package/dist/chunk-MOBMYHKL.js +0 -1205
  130. package/dist/chunk-MPLTNMRG.js +0 -67
  131. package/dist/chunk-NIJCVN3O.js +0 -147
  132. package/dist/chunk-NZCFSZQ7.js +0 -1205
  133. package/dist/chunk-O2UITJGH.js +0 -465
  134. package/dist/chunk-OCRA44AZ.js +0 -108
  135. package/dist/chunk-P3KJR66H.js +0 -117
  136. package/dist/chunk-PEK6JH65.js +0 -432
  137. package/dist/chunk-PJ6FFKEX.js +0 -77
  138. package/dist/chunk-PLUBBZYR.js +0 -800
  139. package/dist/chunk-PNKVD2UK.js +0 -26
  140. package/dist/chunk-PSQZURHO.js +0 -229
  141. package/dist/chunk-SGL6ISBJ.js +0 -1061
  142. package/dist/chunk-SJABZZT5.js +0 -97
  143. package/dist/chunk-TD3P3K32.js +0 -1199
  144. package/dist/chunk-TMDZJJKV.js +0 -288
  145. package/dist/chunk-UNHVZB5G.js +0 -411
  146. package/dist/chunk-VAFTWSTE.js +0 -1061
  147. package/dist/chunk-VNFXFQBB.js +0 -217
  148. package/dist/chunk-X3GVFKSJ.js +0 -1205
  149. package/dist/chunk-XZ3S56RQ.js +0 -1061
  150. package/dist/chunk-Y72C7F6O.js +0 -148
  151. package/dist/chunk-YLICP577.js +0 -1205
  152. package/dist/chunk-YX6AXLVK.js +0 -159
  153. package/dist/chunk-ZCQYHTNU.js +0 -146
  154. package/dist/cli.d.ts +0 -1
  155. package/dist/cli.js +0 -1105
  156. package/dist/cloud-crystal.js +0 -6
  157. package/dist/core.d.ts +0 -232
  158. package/dist/core.js +0 -12
  159. package/dist/crypto.d.ts +0 -20
  160. package/dist/crypto.js +0 -27
  161. package/dist/crystal-capture.sh +0 -29
  162. package/dist/crystal-serve.d.ts +0 -4
  163. package/dist/crystal-serve.js +0 -252
  164. package/dist/dev-update-SZ2Z4WCQ.js +0 -6
  165. package/dist/discover.d.ts +0 -30
  166. package/dist/discover.js +0 -177
  167. package/dist/doctor.d.ts +0 -9
  168. package/dist/doctor.js +0 -334
  169. package/dist/dream-weaver.d.ts +0 -8
  170. package/dist/dream-weaver.js +0 -56
  171. package/dist/file-sync.d.ts +0 -48
  172. package/dist/file-sync.js +0 -18
  173. package/dist/installer.d.ts +0 -61
  174. package/dist/installer.js +0 -676
  175. package/dist/ldm-backup.sh +0 -116
  176. package/dist/ldm.d.ts +0 -50
  177. package/dist/ldm.js +0 -32
  178. package/dist/mcp-server.d.ts +0 -1
  179. package/dist/mcp-server.js +0 -265
  180. package/dist/migrate.d.ts +0 -1
  181. package/dist/migrate.js +0 -89
  182. package/dist/mirror-sync.d.ts +0 -1
  183. package/dist/mirror-sync.js +0 -159
  184. package/dist/oc-backfill.d.ts +0 -19
  185. package/dist/oc-backfill.js +0 -74
  186. package/dist/openclaw.d.ts +0 -5
  187. package/dist/openclaw.js +0 -423
  188. package/dist/pair.d.ts +0 -4
  189. package/dist/pair.js +0 -75
  190. package/dist/poller.d.ts +0 -1
  191. package/dist/poller.js +0 -634
  192. package/dist/role.d.ts +0 -24
  193. package/dist/role.js +0 -13
  194. package/dist/search-pipeline-4K4OJSSS.js +0 -255
  195. package/dist/search-pipeline-4PRS6LI7.js +0 -280
  196. package/dist/search-pipeline-7UJMXPLO.js +0 -280
  197. package/dist/search-pipeline-DQTRLGBH.js +0 -74
  198. package/dist/search-pipeline-HNG37REH.js +0 -282
  199. package/dist/search-pipeline-IZFPLBUB.js +0 -280
  200. package/dist/search-pipeline-MID6F26Q.js +0 -73
  201. package/dist/search-pipeline-N52JZFNN.js +0 -282
  202. package/dist/search-pipeline-OPB2PRQQ.js +0 -280
  203. package/dist/search-pipeline-VXTE5HAD.js +0 -262
  204. package/dist/search-pipeline-XHFKADRG.js +0 -73
  205. package/dist/staging.d.ts +0 -29
  206. package/dist/staging.js +0 -21
  207. package/dist/summarize.d.ts +0 -19
  208. package/dist/summarize.js +0 -10
  209. package/dist/worker-demo.js +0 -186
  210. package/dist/worker-mcp.js +0 -404
  211. package/dist/worker.js +0 -137
@@ -1,446 +0,0 @@
1
- // src/core.ts
2
- import * as lancedb from "@lancedb/lancedb";
3
- import Database from "better-sqlite3";
4
- import { readFileSync, existsSync, mkdirSync } from "fs";
5
- import { execSync } from "child_process";
6
- import { join } from "path";
7
- import http from "http";
8
- import https from "https";
9
- async function embedOpenAI(texts, apiKey, model) {
10
- return new Promise((resolve, reject) => {
11
- const body = JSON.stringify({ input: texts, model });
12
- const req = https.request({
13
- hostname: "api.openai.com",
14
- path: "/v1/embeddings",
15
- method: "POST",
16
- headers: {
17
- "Content-Type": "application/json",
18
- "Authorization": `Bearer ${apiKey}`,
19
- "Content-Length": Buffer.byteLength(body)
20
- },
21
- timeout: 3e4
22
- }, (res) => {
23
- let data = "";
24
- res.on("data", (chunk) => data += chunk);
25
- res.on("end", () => {
26
- if (res.statusCode !== 200) {
27
- reject(new Error(`OpenAI API error ${res.statusCode}: ${data.slice(0, 200)}`));
28
- return;
29
- }
30
- const parsed = JSON.parse(data);
31
- resolve(parsed.data.map((d) => d.embedding));
32
- });
33
- });
34
- req.on("error", reject);
35
- req.on("timeout", () => {
36
- req.destroy();
37
- reject(new Error("OpenAI timeout"));
38
- });
39
- req.write(body);
40
- req.end();
41
- });
42
- }
43
- async function embedOllama(texts, host, model) {
44
- const results = [];
45
- for (const text of texts) {
46
- const result = await new Promise((resolve, reject) => {
47
- const url = new URL("/api/embeddings", host);
48
- const body = JSON.stringify({ model, prompt: text });
49
- const req = http.request({
50
- hostname: url.hostname,
51
- port: url.port,
52
- path: url.pathname,
53
- method: "POST",
54
- headers: {
55
- "Content-Type": "application/json",
56
- "Content-Length": Buffer.byteLength(body)
57
- },
58
- timeout: 15e3
59
- }, (res) => {
60
- let data = "";
61
- res.on("data", (chunk) => data += chunk);
62
- res.on("end", () => {
63
- if (res.statusCode !== 200) {
64
- reject(new Error(`Ollama error ${res.statusCode}: ${data.slice(0, 200)}`));
65
- return;
66
- }
67
- resolve(JSON.parse(data).embedding);
68
- });
69
- });
70
- req.on("error", reject);
71
- req.on("timeout", () => {
72
- req.destroy();
73
- reject(new Error("Ollama timeout"));
74
- });
75
- req.write(body);
76
- req.end();
77
- });
78
- results.push(result);
79
- }
80
- return results;
81
- }
82
- async function embedGoogle(texts, apiKey, model) {
83
- return new Promise((resolve, reject) => {
84
- const body = JSON.stringify({
85
- requests: texts.map((text) => ({ model: `models/${model}`, content: { parts: [{ text }] } }))
86
- });
87
- const req = https.request({
88
- hostname: "generativelanguage.googleapis.com",
89
- path: `/v1beta/models/${model}:batchEmbedContents?key=${apiKey}`,
90
- method: "POST",
91
- headers: {
92
- "Content-Type": "application/json",
93
- "Content-Length": Buffer.byteLength(body)
94
- },
95
- timeout: 3e4
96
- }, (res) => {
97
- let data = "";
98
- res.on("data", (chunk) => data += chunk);
99
- res.on("end", () => {
100
- if (res.statusCode !== 200) {
101
- reject(new Error(`Google API error ${res.statusCode}: ${data.slice(0, 200)}`));
102
- return;
103
- }
104
- const parsed = JSON.parse(data);
105
- resolve(parsed.embeddings.map((e) => e.values));
106
- });
107
- });
108
- req.on("error", reject);
109
- req.on("timeout", () => {
110
- req.destroy();
111
- reject(new Error("Google timeout"));
112
- });
113
- req.write(body);
114
- req.end();
115
- });
116
- }
117
- var Crystal = class {
118
- config;
119
- lanceDb = null;
120
- sqliteDb = null;
121
- chunksTable = null;
122
- constructor(config) {
123
- this.config = config;
124
- if (!existsSync(config.dataDir)) {
125
- mkdirSync(config.dataDir, { recursive: true });
126
- }
127
- }
128
- // ── Initialization ──
129
- async init() {
130
- const lanceDir = join(this.config.dataDir, "lance");
131
- const sqlitePath = join(this.config.dataDir, "crystal.db");
132
- if (!existsSync(lanceDir)) mkdirSync(lanceDir, { recursive: true });
133
- this.lanceDb = await lancedb.connect(lanceDir);
134
- this.sqliteDb = new Database(sqlitePath);
135
- this.sqliteDb.pragma("journal_mode = WAL");
136
- this.initSqliteTables();
137
- await this.initLanceTables();
138
- }
139
- initSqliteTables() {
140
- const db = this.sqliteDb;
141
- db.exec(`
142
- CREATE TABLE IF NOT EXISTS sources (
143
- id INTEGER PRIMARY KEY AUTOINCREMENT,
144
- type TEXT NOT NULL,
145
- uri TEXT NOT NULL,
146
- title TEXT,
147
- agent_id TEXT NOT NULL,
148
- metadata TEXT DEFAULT '{}',
149
- ingested_at TEXT NOT NULL,
150
- chunk_count INTEGER DEFAULT 0
151
- );
152
-
153
- CREATE TABLE IF NOT EXISTS capture_state (
154
- agent_id TEXT NOT NULL,
155
- source_id TEXT NOT NULL,
156
- last_message_count INTEGER DEFAULT 0,
157
- capture_count INTEGER DEFAULT 0,
158
- last_capture_at TEXT,
159
- PRIMARY KEY (agent_id, source_id)
160
- );
161
-
162
- CREATE TABLE IF NOT EXISTS memories (
163
- id INTEGER PRIMARY KEY AUTOINCREMENT,
164
- text TEXT NOT NULL,
165
- category TEXT NOT NULL DEFAULT 'fact',
166
- confidence REAL NOT NULL DEFAULT 1.0,
167
- source_ids TEXT DEFAULT '[]',
168
- status TEXT NOT NULL DEFAULT 'active',
169
- created_at TEXT NOT NULL,
170
- updated_at TEXT NOT NULL
171
- );
172
-
173
- CREATE TABLE IF NOT EXISTS entities (
174
- id INTEGER PRIMARY KEY AUTOINCREMENT,
175
- name TEXT NOT NULL UNIQUE,
176
- type TEXT NOT NULL DEFAULT 'concept',
177
- description TEXT,
178
- properties TEXT DEFAULT '{}',
179
- created_at TEXT NOT NULL,
180
- updated_at TEXT NOT NULL
181
- );
182
-
183
- CREATE TABLE IF NOT EXISTS relationships (
184
- id INTEGER PRIMARY KEY AUTOINCREMENT,
185
- source_id INTEGER NOT NULL REFERENCES entities(id),
186
- target_id INTEGER NOT NULL REFERENCES entities(id),
187
- type TEXT NOT NULL,
188
- description TEXT,
189
- weight REAL DEFAULT 1.0,
190
- valid_from TEXT NOT NULL,
191
- valid_until TEXT,
192
- created_at TEXT NOT NULL
193
- );
194
-
195
- CREATE INDEX IF NOT EXISTS idx_sources_agent ON sources(agent_id);
196
- CREATE INDEX IF NOT EXISTS idx_memories_status ON memories(status);
197
- CREATE INDEX IF NOT EXISTS idx_entities_name ON entities(name);
198
- CREATE INDEX IF NOT EXISTS idx_relationships_source ON relationships(source_id);
199
- CREATE INDEX IF NOT EXISTS idx_relationships_target ON relationships(target_id);
200
- `);
201
- }
202
- async initLanceTables() {
203
- const db = this.lanceDb;
204
- const tableNames = await db.tableNames();
205
- if (tableNames.includes("chunks")) {
206
- this.chunksTable = await db.openTable("chunks");
207
- }
208
- }
209
- // ── Embedding ──
210
- async embed(texts) {
211
- if (texts.length === 0) return [];
212
- const cfg = this.config;
213
- switch (cfg.embeddingProvider) {
214
- case "openai":
215
- if (!cfg.openaiApiKey) throw new Error("OpenAI API key required");
216
- return embedOpenAI(texts, cfg.openaiApiKey, cfg.openaiModel || "text-embedding-3-small");
217
- case "ollama":
218
- return embedOllama(texts, cfg.ollamaHost || "http://localhost:11434", cfg.ollamaModel || "nomic-embed-text");
219
- case "google":
220
- if (!cfg.googleApiKey) throw new Error("Google API key required");
221
- return embedGoogle(texts, cfg.googleApiKey, cfg.googleModel || "text-embedding-004");
222
- default:
223
- throw new Error(`Unknown embedding provider: ${cfg.embeddingProvider}`);
224
- }
225
- }
226
- // ── Chunking ──
227
- chunkText(text, targetTokens = 400, overlapTokens = 80) {
228
- const targetChars = targetTokens * 4;
229
- const overlapChars = overlapTokens * 4;
230
- const chunks = [];
231
- let start = 0;
232
- while (start < text.length) {
233
- let end = Math.min(start + targetChars, text.length);
234
- if (end < text.length) {
235
- const minBreak = start + Math.floor(targetChars * 0.5);
236
- const paraBreak = text.lastIndexOf("\n\n", end);
237
- if (paraBreak > minBreak) {
238
- end = paraBreak;
239
- } else {
240
- const sentBreak = text.lastIndexOf(". ", end);
241
- if (sentBreak > minBreak) {
242
- end = sentBreak + 1;
243
- }
244
- }
245
- }
246
- const chunk = text.slice(start, end).trim();
247
- if (chunk.length > 0) chunks.push(chunk);
248
- if (end >= text.length) break;
249
- start = end - overlapChars;
250
- if (start <= (chunks.length > 0 ? end - targetChars : 0)) {
251
- start = end;
252
- }
253
- }
254
- return chunks;
255
- }
256
- // ── Ingest ──
257
- async ingest(chunks) {
258
- if (chunks.length === 0) return 0;
259
- const texts = chunks.map((c) => c.text);
260
- const embeddings = await this.embed(texts);
261
- const records = chunks.map((chunk, i) => ({
262
- text: chunk.text,
263
- vector: embeddings[i],
264
- role: chunk.role,
265
- source_type: chunk.source_type,
266
- source_id: chunk.source_id,
267
- agent_id: chunk.agent_id,
268
- token_count: chunk.token_count,
269
- created_at: chunk.created_at || (/* @__PURE__ */ new Date()).toISOString()
270
- }));
271
- if (!this.chunksTable) {
272
- this.chunksTable = await this.lanceDb.createTable("chunks", records);
273
- } else {
274
- await this.chunksTable.add(records);
275
- }
276
- return records.length;
277
- }
278
- // ── Search ──
279
- async search(query, limit = 5, filter) {
280
- if (!this.chunksTable) return [];
281
- const [embedding] = await this.embed([query]);
282
- let queryBuilder = this.chunksTable.vectorSearch(embedding).distanceType("cosine").limit(limit);
283
- if (filter?.agent_id) {
284
- queryBuilder = queryBuilder.where(`agent_id = '${filter.agent_id}'`);
285
- }
286
- if (filter?.source_type) {
287
- queryBuilder = queryBuilder.where(`source_type = '${filter.source_type}'`);
288
- }
289
- const results = await queryBuilder.toArray();
290
- return results.map((row) => ({
291
- text: row.text,
292
- role: row.role,
293
- score: row._distance != null ? 1 - row._distance : 0,
294
- source_type: row.source_type,
295
- source_id: row.source_id,
296
- agent_id: row.agent_id,
297
- created_at: row.created_at
298
- }));
299
- }
300
- // ── Remember (explicit fact storage) ──
301
- async remember(text, category = "fact") {
302
- const db = this.sqliteDb;
303
- const now = (/* @__PURE__ */ new Date()).toISOString();
304
- const stmt = db.prepare(`
305
- INSERT INTO memories (text, category, confidence, source_ids, status, created_at, updated_at)
306
- VALUES (?, ?, 1.0, '[]', 'active', ?, ?)
307
- `);
308
- const result = stmt.run(text, category, now, now);
309
- await this.ingest([{
310
- text,
311
- role: "system",
312
- source_type: "manual",
313
- source_id: `memory:${result.lastInsertRowid}`,
314
- agent_id: "system",
315
- token_count: Math.ceil(text.length / 4),
316
- created_at: now
317
- }]);
318
- return result.lastInsertRowid;
319
- }
320
- // ── Forget (deprecate a memory) ──
321
- forget(memoryId) {
322
- const db = this.sqliteDb;
323
- const now = (/* @__PURE__ */ new Date()).toISOString();
324
- const result = db.prepare(`
325
- UPDATE memories SET status = 'deprecated', updated_at = ? WHERE id = ? AND status = 'active'
326
- `).run(now, memoryId);
327
- return result.changes > 0;
328
- }
329
- // ── Status ──
330
- async status() {
331
- const db = this.sqliteDb;
332
- let chunks = 0;
333
- let oldestChunk = null;
334
- let newestChunk = null;
335
- const agents = [];
336
- if (this.chunksTable) {
337
- chunks = await this.chunksTable.countRows();
338
- try {
339
- const sample = await this.chunksTable.search([]).limit(1).toArray();
340
- } catch {
341
- }
342
- }
343
- const memories = db.prepare("SELECT COUNT(*) as count FROM memories WHERE status = ?").get("active")?.count || 0;
344
- const sources = db.prepare("SELECT COUNT(*) as count FROM sources").get()?.count || 0;
345
- const sourceAgentRows = db.prepare("SELECT DISTINCT agent_id FROM sources").all();
346
- const captureAgentRows = db.prepare("SELECT DISTINCT agent_id FROM capture_state").all();
347
- const allAgents = [.../* @__PURE__ */ new Set([
348
- ...sourceAgentRows.map((r) => r.agent_id),
349
- ...captureAgentRows.map((r) => r.agent_id)
350
- ])];
351
- agents.push(...allAgents);
352
- const captureInfo = db.prepare(
353
- "SELECT COUNT(*) as count, MAX(last_capture_at) as latest FROM capture_state"
354
- ).get();
355
- return {
356
- chunks,
357
- memories,
358
- sources,
359
- agents,
360
- oldestChunk,
361
- newestChunk,
362
- embeddingProvider: this.config.embeddingProvider,
363
- dataDir: this.config.dataDir,
364
- capturedSessions: captureInfo?.count || 0,
365
- latestCapture: captureInfo?.latest || null
366
- };
367
- }
368
- // ── Capture State (for incremental ingestion) ──
369
- getCaptureState(agentId, sourceId) {
370
- const db = this.sqliteDb;
371
- const row = db.prepare("SELECT last_message_count, capture_count FROM capture_state WHERE agent_id = ? AND source_id = ?").get(agentId, sourceId);
372
- if (!row) return { lastMessageCount: 0, captureCount: 0 };
373
- return {
374
- lastMessageCount: row.last_message_count,
375
- captureCount: row.capture_count
376
- };
377
- }
378
- setCaptureState(agentId, sourceId, messageCount, captureCount) {
379
- const db = this.sqliteDb;
380
- db.prepare(`
381
- INSERT OR REPLACE INTO capture_state (agent_id, source_id, last_message_count, capture_count, last_capture_at)
382
- VALUES (?, ?, ?, ?, ?)
383
- `).run(agentId, sourceId, messageCount, captureCount, (/* @__PURE__ */ new Date()).toISOString());
384
- }
385
- // ── Cleanup ──
386
- close() {
387
- this.sqliteDb?.close();
388
- }
389
- };
390
- function resolveConfig(overrides) {
391
- const openclawHome = process.env.OPENCLAW_HOME || join(process.env.HOME || "/Users/lesa", ".openclaw");
392
- const dataDir = overrides?.dataDir || join(openclawHome, "memory-crystal");
393
- loadEnvFile(join(dataDir, ".env"));
394
- const openaiApiKey = overrides?.openaiApiKey || process.env.OPENAI_API_KEY || opRead(openclawHome, "OpenAI API", "api key");
395
- const googleApiKey = overrides?.googleApiKey || process.env.GOOGLE_API_KEY || opRead(openclawHome, "Google AI", "api key");
396
- const remoteToken = overrides?.remoteToken || process.env.CRYSTAL_REMOTE_TOKEN || opRead(openclawHome, "Memory Crystal Remote", "token");
397
- return {
398
- dataDir,
399
- embeddingProvider: overrides?.embeddingProvider || process.env.CRYSTAL_EMBEDDING_PROVIDER || "openai",
400
- openaiApiKey,
401
- openaiModel: overrides?.openaiModel || process.env.CRYSTAL_OPENAI_MODEL || "text-embedding-3-small",
402
- ollamaHost: overrides?.ollamaHost || process.env.CRYSTAL_OLLAMA_HOST || "http://localhost:11434",
403
- ollamaModel: overrides?.ollamaModel || process.env.CRYSTAL_OLLAMA_MODEL || "nomic-embed-text",
404
- googleApiKey,
405
- googleModel: overrides?.googleModel || process.env.CRYSTAL_GOOGLE_MODEL || "text-embedding-004",
406
- remoteUrl: overrides?.remoteUrl || process.env.CRYSTAL_REMOTE_URL,
407
- remoteToken
408
- };
409
- }
410
- function loadEnvFile(path) {
411
- if (!existsSync(path)) return;
412
- const content = readFileSync(path, "utf8");
413
- for (const line of content.split("\n")) {
414
- const trimmed = line.trim();
415
- if (!trimmed || trimmed.startsWith("#")) continue;
416
- const eqIdx = trimmed.indexOf("=");
417
- if (eqIdx === -1) continue;
418
- const key = trimmed.slice(0, eqIdx).trim();
419
- let value = trimmed.slice(eqIdx + 1).trim();
420
- if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
421
- value = value.slice(1, -1);
422
- }
423
- if (key && !process.env[key]) {
424
- process.env[key] = value;
425
- }
426
- }
427
- }
428
- function opRead(openclawHome, item, field) {
429
- try {
430
- const saTokenPath = join(openclawHome, "secrets", "op-sa-token");
431
- if (!existsSync(saTokenPath)) return void 0;
432
- const saToken = readFileSync(saTokenPath, "utf8").trim();
433
- return execSync(`op read "op://Agent Secrets/${item}/${field}" 2>/dev/null`, {
434
- encoding: "utf8",
435
- env: { ...process.env, OP_SERVICE_ACCOUNT_TOKEN: saToken },
436
- timeout: 1e4
437
- }).trim() || void 0;
438
- } catch {
439
- return void 0;
440
- }
441
- }
442
-
443
- export {
444
- Crystal,
445
- resolveConfig
446
- };
@@ -1,146 +0,0 @@
1
- import {
2
- ensureLdm,
3
- ldmPaths
4
- } from "./chunk-DACSKLY6.js";
5
-
6
- // src/staging.ts
7
- import {
8
- existsSync,
9
- mkdirSync,
10
- readdirSync,
11
- renameSync,
12
- unlinkSync,
13
- writeFileSync
14
- } from "fs";
15
- import { join } from "path";
16
- import { execSync } from "child_process";
17
- var HOME = process.env.HOME || "";
18
- var STAGING_ROOT = join(HOME, ".ldm", "staging");
19
- function stagingPaths(agentId) {
20
- const root = join(STAGING_ROOT, agentId);
21
- return {
22
- root,
23
- transcripts: join(root, "transcripts"),
24
- readyFile: join(root, "READY")
25
- };
26
- }
27
- function ensureStaging(agentId) {
28
- const paths = stagingPaths(agentId);
29
- mkdirSync(paths.transcripts, { recursive: true });
30
- return paths;
31
- }
32
- function markReady(agentId) {
33
- const paths = stagingPaths(agentId);
34
- writeFileSync(paths.readyFile, JSON.stringify({
35
- markedAt: (/* @__PURE__ */ new Date()).toISOString(),
36
- agentId
37
- }));
38
- }
39
- function isNewAgent(agentId) {
40
- const paths = ldmPaths(agentId);
41
- return !existsSync(paths.agentRoot);
42
- }
43
- function hasStagedData(agentId) {
44
- const paths = stagingPaths(agentId);
45
- return existsSync(paths.readyFile);
46
- }
47
- function listStagedAgents() {
48
- if (!existsSync(STAGING_ROOT)) return [];
49
- const agents = [];
50
- for (const entry of readdirSync(STAGING_ROOT, { withFileTypes: true })) {
51
- if (!entry.isDirectory()) continue;
52
- if (existsSync(join(STAGING_ROOT, entry.name, "READY"))) {
53
- agents.push(entry.name);
54
- }
55
- }
56
- return agents;
57
- }
58
- async function processStagedAgent(agentId) {
59
- const startTime = Date.now();
60
- const staging = stagingPaths(agentId);
61
- if (!existsSync(staging.readyFile)) {
62
- throw new Error(`No READY file for agent ${agentId}`);
63
- }
64
- const agentPaths = ensureLdm(agentId);
65
- const stagedFiles = existsSync(staging.transcripts) ? readdirSync(staging.transcripts).filter((f) => f.endsWith(".jsonl")) : [];
66
- if (stagedFiles.length === 0) {
67
- unlinkSync(staging.readyFile);
68
- return {
69
- agentId,
70
- transcriptsProcessed: 0,
71
- backfillChunks: 0,
72
- dreamWeaverRan: false,
73
- durationMs: Date.now() - startTime
74
- };
75
- }
76
- for (const file of stagedFiles) {
77
- const src = join(staging.transcripts, file);
78
- const dest = join(agentPaths.transcripts, file);
79
- try {
80
- renameSync(src, dest);
81
- } catch {
82
- const { copyFileSync } = await import("fs");
83
- copyFileSync(src, dest);
84
- unlinkSync(src);
85
- }
86
- }
87
- let backfillChunks = 0;
88
- let dreamWeaverRan = false;
89
- try {
90
- const output = execSync(
91
- `crystal backfill --agent ${agentId}`,
92
- { encoding: "utf-8", timeout: 6e5 }
93
- );
94
- const match = output.match(/(\d+) chunks embedded/);
95
- if (match) backfillChunks = parseInt(match[1], 10);
96
- } catch (err) {
97
- process.stderr.write(`[staging] backfill failed for ${agentId}: ${err.message}
98
- `);
99
- }
100
- try {
101
- execSync(
102
- `crystal dream-weave --agent ${agentId} --mode full`,
103
- { encoding: "utf-8", timeout: 6e5 }
104
- );
105
- dreamWeaverRan = true;
106
- } catch (err) {
107
- process.stderr.write(`[staging] dream-weave failed for ${agentId}: ${err.message}
108
- `);
109
- }
110
- try {
111
- unlinkSync(staging.readyFile);
112
- } catch {
113
- }
114
- return {
115
- agentId,
116
- transcriptsProcessed: stagedFiles.length,
117
- backfillChunks,
118
- dreamWeaverRan,
119
- durationMs: Date.now() - startTime
120
- };
121
- }
122
- async function processAllStaged() {
123
- const agents = listStagedAgents();
124
- const results = [];
125
- for (const agentId of agents) {
126
- try {
127
- const result = await processStagedAgent(agentId);
128
- results.push(result);
129
- } catch (err) {
130
- process.stderr.write(`[staging] failed to process ${agentId}: ${err.message}
131
- `);
132
- }
133
- }
134
- return results;
135
- }
136
-
137
- export {
138
- stagingPaths,
139
- ensureStaging,
140
- markReady,
141
- isNewAgent,
142
- hasStagedData,
143
- listStagedAgents,
144
- processStagedAgent,
145
- processAllStaged
146
- };