@wipcomputer/memory-crystal 0.7.29 → 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 (146) hide show
  1. package/CHANGELOG.md +75 -0
  2. package/SKILL.md +1 -1
  3. package/package.json +1 -1
  4. package/scripts/migrate-lance-to-sqlite.mjs +2 -1
  5. package/_trash/RELEASE-NOTES-v0-7-23.md +0 -48
  6. package/_trash/RELEASE-NOTES-v0-7-25.md +0 -24
  7. package/_trash/RELEASE-NOTES-v0-7-26.md +0 -7
  8. package/_trash/RELEASE-NOTES-v0-7-28.md +0 -31
  9. package/_trash/RELEASE-NOTES-v0-7-29.md +0 -28
  10. package/_trash/RELEASE-NOTES-v0-7-4.md +0 -64
  11. package/_trash/RELEASE-NOTES-v0-7-5.md +0 -19
  12. package/dist/bridge.d.ts +0 -7
  13. package/dist/bridge.js +0 -14
  14. package/dist/bulk-copy.d.ts +0 -17
  15. package/dist/bulk-copy.js +0 -90
  16. package/dist/cc-hook.d.ts +0 -8
  17. package/dist/cc-hook.js +0 -368
  18. package/dist/cc-poller.d.ts +0 -1
  19. package/dist/cc-poller.js +0 -550
  20. package/dist/chunk-25LXQJ4Z.js +0 -110
  21. package/dist/chunk-2DRXIRQW.js +0 -97
  22. package/dist/chunk-2ZNH5F6E.js +0 -1281
  23. package/dist/chunk-3G3SFYYI.js +0 -288
  24. package/dist/chunk-3RG5ZIWI.js +0 -10
  25. package/dist/chunk-3S6TI23B.js +0 -97
  26. package/dist/chunk-3VFIJYS4.js +0 -818
  27. package/dist/chunk-52QE3YI3.js +0 -1169
  28. package/dist/chunk-57RP3DIN.js +0 -1205
  29. package/dist/chunk-5HSZ4W2P.js +0 -62
  30. package/dist/chunk-645IPXW3.js +0 -290
  31. package/dist/chunk-7A7ELD4C.js +0 -1205
  32. package/dist/chunk-7FYY4GZM.js +0 -1205
  33. package/dist/chunk-7IUE7ODU.js +0 -254
  34. package/dist/chunk-7RMLKZIS.js +0 -108
  35. package/dist/chunk-AA3OPP4Z.js +0 -432
  36. package/dist/chunk-AEWLSYPH.js +0 -72
  37. package/dist/chunk-ASSZDR6I.js +0 -108
  38. package/dist/chunk-AYRJVWUC.js +0 -1205
  39. package/dist/chunk-CCYI5O3D.js +0 -148
  40. package/dist/chunk-D3I3ZSE2.js +0 -411
  41. package/dist/chunk-DACSKLY6.js +0 -219
  42. package/dist/chunk-DW5B4BL7.js +0 -108
  43. package/dist/chunk-EKSACBTJ.js +0 -1070
  44. package/dist/chunk-EXEZZADG.js +0 -248
  45. package/dist/chunk-F3Y7EL7K.js +0 -83
  46. package/dist/chunk-FBQWSDPC.js +0 -1328
  47. package/dist/chunk-FHRZNOMW.js +0 -1205
  48. package/dist/chunk-IM7N24MT.js +0 -129
  49. package/dist/chunk-IPNYIXFK.js +0 -1178
  50. package/dist/chunk-J7MRSZIO.js +0 -167
  51. package/dist/chunk-JITKI2OI.js +0 -106
  52. package/dist/chunk-JWZXYVET.js +0 -1068
  53. package/dist/chunk-KCQUXVYT.js +0 -108
  54. package/dist/chunk-KOQ43OX6.js +0 -1281
  55. package/dist/chunk-KYVWO6ZM.js +0 -1069
  56. package/dist/chunk-L3VHARQH.js +0 -413
  57. package/dist/chunk-LBWDS6BE.js +0 -288
  58. package/dist/chunk-LOVAHSQV.js +0 -411
  59. package/dist/chunk-LQOYCAGG.js +0 -446
  60. package/dist/chunk-LWAIPJ2W.js +0 -146
  61. package/dist/chunk-M5DHKW7M.js +0 -127
  62. package/dist/chunk-MBKCIJHM.js +0 -1328
  63. package/dist/chunk-MK42FMEG.js +0 -147
  64. package/dist/chunk-MOBMYHKL.js +0 -1205
  65. package/dist/chunk-MPLTNMRG.js +0 -67
  66. package/dist/chunk-NIJCVN3O.js +0 -147
  67. package/dist/chunk-NZCFSZQ7.js +0 -1205
  68. package/dist/chunk-O2UITJGH.js +0 -465
  69. package/dist/chunk-OCRA44AZ.js +0 -108
  70. package/dist/chunk-P3KJR66H.js +0 -117
  71. package/dist/chunk-PEK6JH65.js +0 -432
  72. package/dist/chunk-PJ6FFKEX.js +0 -77
  73. package/dist/chunk-PLUBBZYR.js +0 -800
  74. package/dist/chunk-PNKVD2UK.js +0 -26
  75. package/dist/chunk-PSQZURHO.js +0 -229
  76. package/dist/chunk-SGL6ISBJ.js +0 -1061
  77. package/dist/chunk-SJABZZT5.js +0 -97
  78. package/dist/chunk-TD3P3K32.js +0 -1199
  79. package/dist/chunk-TMDZJJKV.js +0 -288
  80. package/dist/chunk-UNHVZB5G.js +0 -411
  81. package/dist/chunk-VAFTWSTE.js +0 -1061
  82. package/dist/chunk-VNFXFQBB.js +0 -217
  83. package/dist/chunk-X3GVFKSJ.js +0 -1205
  84. package/dist/chunk-XZ3S56RQ.js +0 -1061
  85. package/dist/chunk-Y72C7F6O.js +0 -148
  86. package/dist/chunk-YLICP577.js +0 -1205
  87. package/dist/chunk-YX6AXLVK.js +0 -159
  88. package/dist/chunk-ZCQYHTNU.js +0 -146
  89. package/dist/cli.d.ts +0 -1
  90. package/dist/cli.js +0 -1105
  91. package/dist/cloud-crystal.js +0 -6
  92. package/dist/core.d.ts +0 -232
  93. package/dist/core.js +0 -12
  94. package/dist/crypto.d.ts +0 -20
  95. package/dist/crypto.js +0 -27
  96. package/dist/crystal-capture.sh +0 -29
  97. package/dist/crystal-serve.d.ts +0 -4
  98. package/dist/crystal-serve.js +0 -252
  99. package/dist/dev-update-SZ2Z4WCQ.js +0 -6
  100. package/dist/discover.d.ts +0 -30
  101. package/dist/discover.js +0 -177
  102. package/dist/doctor.d.ts +0 -9
  103. package/dist/doctor.js +0 -334
  104. package/dist/dream-weaver.d.ts +0 -8
  105. package/dist/dream-weaver.js +0 -56
  106. package/dist/file-sync.d.ts +0 -48
  107. package/dist/file-sync.js +0 -18
  108. package/dist/installer.d.ts +0 -61
  109. package/dist/installer.js +0 -676
  110. package/dist/ldm-backup.sh +0 -116
  111. package/dist/ldm.d.ts +0 -50
  112. package/dist/ldm.js +0 -32
  113. package/dist/mcp-server.d.ts +0 -1
  114. package/dist/mcp-server.js +0 -265
  115. package/dist/migrate.d.ts +0 -1
  116. package/dist/migrate.js +0 -89
  117. package/dist/mirror-sync.d.ts +0 -1
  118. package/dist/mirror-sync.js +0 -159
  119. package/dist/oc-backfill.d.ts +0 -19
  120. package/dist/oc-backfill.js +0 -74
  121. package/dist/openclaw.d.ts +0 -5
  122. package/dist/openclaw.js +0 -423
  123. package/dist/pair.d.ts +0 -4
  124. package/dist/pair.js +0 -75
  125. package/dist/poller.d.ts +0 -1
  126. package/dist/poller.js +0 -634
  127. package/dist/role.d.ts +0 -24
  128. package/dist/role.js +0 -13
  129. package/dist/search-pipeline-4K4OJSSS.js +0 -255
  130. package/dist/search-pipeline-4PRS6LI7.js +0 -280
  131. package/dist/search-pipeline-7UJMXPLO.js +0 -280
  132. package/dist/search-pipeline-DQTRLGBH.js +0 -74
  133. package/dist/search-pipeline-HNG37REH.js +0 -282
  134. package/dist/search-pipeline-IZFPLBUB.js +0 -280
  135. package/dist/search-pipeline-MID6F26Q.js +0 -73
  136. package/dist/search-pipeline-N52JZFNN.js +0 -282
  137. package/dist/search-pipeline-OPB2PRQQ.js +0 -280
  138. package/dist/search-pipeline-VXTE5HAD.js +0 -262
  139. package/dist/search-pipeline-XHFKADRG.js +0 -73
  140. package/dist/staging.d.ts +0 -29
  141. package/dist/staging.js +0 -21
  142. package/dist/summarize.d.ts +0 -19
  143. package/dist/summarize.js +0 -10
  144. package/dist/worker-demo.js +0 -186
  145. package/dist/worker-mcp.js +0 -404
  146. package/dist/worker.js +0 -137
@@ -1,116 +0,0 @@
1
- #!/bin/bash
2
- # Job: ldm-backup
3
- # Backs up the LDM directory (~/.ldm/) to a timestamped snapshot.
4
- # Handles SQLite databases safely (sqlite3 .backup if available, cp otherwise).
5
- #
6
- # Source of truth: memory-crystal-private/scripts/ldm-backup.sh
7
- # Deployed to: ~/.ldm/bin/ldm-backup.sh (via crystal init)
8
- #
9
- # Usage:
10
- # ldm-backup.sh # backup to default location
11
- # ldm-backup.sh --keep 14 # keep last 14 backups (default: 7)
12
- # ldm-backup.sh --include-secrets # include secrets/ dir
13
- #
14
- # Destination: $LDM_BACKUP_DIR or ~/.ldm/backups/
15
-
16
- set -euo pipefail
17
-
18
- # Cron provides minimal PATH
19
- export PATH="/opt/homebrew/bin:/usr/local/bin:$PATH"
20
-
21
- LDM_HOME="$HOME/.ldm"
22
- BACKUP_ROOT="${LDM_BACKUP_DIR:-$LDM_HOME/backups}"
23
- KEEP=7
24
- INCLUDE_SECRETS=false
25
-
26
- # Parse flags
27
- while [[ $# -gt 0 ]]; do
28
- case "$1" in
29
- --keep)
30
- KEEP="$2"
31
- shift 2
32
- ;;
33
- --include-secrets)
34
- INCLUDE_SECRETS=true
35
- shift
36
- ;;
37
- *)
38
- echo "Unknown flag: $1" >&2
39
- exit 1
40
- ;;
41
- esac
42
- done
43
-
44
- if [ ! -d "$LDM_HOME" ]; then
45
- echo "ERROR: LDM home not found at $LDM_HOME" >&2
46
- exit 1
47
- fi
48
-
49
- TIMESTAMP=$(date +%Y-%m-%d-%H%M%S)
50
- DEST="$BACKUP_ROOT/$TIMESTAMP"
51
-
52
- echo "LDM Backup: $DEST"
53
- mkdir -p "$DEST"
54
-
55
- # ── Back up crystal.db (safe copy) ──
56
-
57
- CRYSTAL_DB="$LDM_HOME/memory/crystal.db"
58
- if [ -f "$CRYSTAL_DB" ]; then
59
- mkdir -p "$DEST/memory"
60
- if command -v sqlite3 &>/dev/null; then
61
- # Safe backup via sqlite3 .backup (handles WAL mode correctly)
62
- sqlite3 "$CRYSTAL_DB" ".backup '$DEST/memory/crystal.db'"
63
- echo " crystal.db: backed up (sqlite3 .backup)"
64
- else
65
- # Fallback: file copy (may include partial WAL state)
66
- cp "$CRYSTAL_DB" "$DEST/memory/crystal.db"
67
- # Copy WAL and SHM if present
68
- [ -f "$CRYSTAL_DB-wal" ] && cp "$CRYSTAL_DB-wal" "$DEST/memory/crystal.db-wal"
69
- [ -f "$CRYSTAL_DB-shm" ] && cp "$CRYSTAL_DB-shm" "$DEST/memory/crystal.db-shm"
70
- echo " crystal.db: backed up (file copy)"
71
- fi
72
- else
73
- echo " crystal.db: not found (skipped)"
74
- fi
75
-
76
- # ── Back up config ──
77
-
78
- if [ -f "$LDM_HOME/config.json" ]; then
79
- cp "$LDM_HOME/config.json" "$DEST/config.json"
80
- echo " config.json: backed up"
81
- fi
82
-
83
- # ── Back up state files ──
84
-
85
- if [ -d "$LDM_HOME/state" ]; then
86
- cp -a "$LDM_HOME/state" "$DEST/state"
87
- echo " state/: backed up"
88
- fi
89
-
90
- # ── Back up agents (transcripts, sessions, daily logs, journals) ──
91
-
92
- if [ -d "$LDM_HOME/agents" ]; then
93
- cp -a "$LDM_HOME/agents" "$DEST/agents"
94
- echo " agents/: backed up"
95
- fi
96
-
97
- # ── Back up secrets (optional) ──
98
-
99
- if [ "$INCLUDE_SECRETS" = true ] && [ -d "$LDM_HOME/secrets" ]; then
100
- cp -a "$LDM_HOME/secrets" "$DEST/secrets"
101
- chmod 700 "$DEST/secrets"
102
- echo " secrets/: backed up"
103
- fi
104
-
105
- # ── Retention: remove old backups ──
106
-
107
- BACKUP_COUNT=$(ls -1d "$BACKUP_ROOT"/????-??-??-?????? 2>/dev/null | wc -l | tr -d ' ')
108
- if [ "$BACKUP_COUNT" -gt "$KEEP" ]; then
109
- REMOVE_COUNT=$((BACKUP_COUNT - KEEP))
110
- ls -1d "$BACKUP_ROOT"/????-??-??-?????? | head -n "$REMOVE_COUNT" | while read OLD; do
111
- rm -rf "$OLD"
112
- echo " Removed old: $(basename "$OLD")"
113
- done
114
- fi
115
-
116
- echo "Done. $BACKUP_COUNT backups total (keeping $KEEP)."
package/dist/ldm.d.ts DELETED
@@ -1,50 +0,0 @@
1
- interface AgentConfig {
2
- agentId: string;
3
- agent?: string;
4
- harness?: string;
5
- model?: string;
6
- created?: string;
7
- memoryPaths?: Record<string, string>;
8
- dreamWeaver?: Record<string, unknown>;
9
- }
10
- declare function loadAgentConfig(id: string): AgentConfig | null;
11
- declare function saveAgentConfig(id: string, config: AgentConfig): void;
12
- declare function getAgentId(harnessHint?: 'claude-code' | 'openclaw'): string;
13
- interface LdmPaths {
14
- root: string;
15
- bin: string;
16
- secrets: string;
17
- state: string;
18
- config: string;
19
- crystalDb: string;
20
- crystalLance: string;
21
- agentRoot: string;
22
- transcripts: string;
23
- sessions: string;
24
- daily: string;
25
- journals: string;
26
- workspace: string;
27
- }
28
- declare function ldmPaths(agentId?: string): LdmPaths;
29
- declare function scaffoldLdm(agentId?: string): LdmPaths;
30
- /** Copy crystal-capture.sh from the package's scripts/ dir to ~/.ldm/bin/. */
31
- declare function deployCaptureScript(): string;
32
- /** Install the crystal-capture cron entry. Idempotent: replaces existing entry if present. */
33
- declare function installCron(): void;
34
- /** Remove the crystal-capture cron entry. */
35
- declare function removeCron(): void;
36
- /** Copy ldm-backup.sh from the package's scripts/ dir to ~/.ldm/bin/. */
37
- declare function deployBackupScript(): string;
38
- /** Install a LaunchAgent for daily backups at 03:00. */
39
- declare function installBackupLaunchAgent(): string;
40
- /** Resolve a path that might exist at the legacy .openclaw location.
41
- * Returns the LDM path if the file exists there, otherwise checks legacy.
42
- * For writing, always use the ldmPath directly. */
43
- declare function resolveStatePath(filename: string): string;
44
- /** Get the write path for state files (always LDM). */
45
- declare function stateWritePath(filename: string): string;
46
- /** Resolve a secrets path. Checks ~/.ldm/secrets first, then ~/.openclaw/secrets. */
47
- declare function resolveSecretPath(filename: string): string;
48
- declare function ensureLdm(agentId?: string): LdmPaths;
49
-
50
- export { type AgentConfig, type LdmPaths, deployBackupScript, deployCaptureScript, ensureLdm, getAgentId, installBackupLaunchAgent, installCron, ldmPaths, loadAgentConfig, removeCron, resolveSecretPath, resolveStatePath, saveAgentConfig, scaffoldLdm, stateWritePath };
package/dist/ldm.js DELETED
@@ -1,32 +0,0 @@
1
- import {
2
- deployBackupScript,
3
- deployCaptureScript,
4
- ensureLdm,
5
- getAgentId,
6
- installBackupLaunchAgent,
7
- installCron,
8
- ldmPaths,
9
- loadAgentConfig,
10
- removeCron,
11
- resolveSecretPath,
12
- resolveStatePath,
13
- saveAgentConfig,
14
- scaffoldLdm,
15
- stateWritePath
16
- } from "./chunk-EXEZZADG.js";
17
- export {
18
- deployBackupScript,
19
- deployCaptureScript,
20
- ensureLdm,
21
- getAgentId,
22
- installBackupLaunchAgent,
23
- installCron,
24
- ldmPaths,
25
- loadAgentConfig,
26
- removeCron,
27
- resolveSecretPath,
28
- resolveStatePath,
29
- saveAgentConfig,
30
- scaffoldLdm,
31
- stateWritePath
32
- };
@@ -1 +0,0 @@
1
- #!/usr/bin/env node
@@ -1,265 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- setSamplingServer
4
- } from "./chunk-7IUE7ODU.js";
5
- import {
6
- RemoteCrystal,
7
- createCrystal,
8
- resolveConfig
9
- } from "./chunk-FBQWSDPC.js";
10
- import {
11
- resolveStatePath,
12
- stateWritePath
13
- } from "./chunk-EXEZZADG.js";
14
-
15
- // src/mcp-server.ts
16
- import { Server } from "@modelcontextprotocol/sdk/server/index.js";
17
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
18
- import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
19
- import { existsSync, readFileSync, appendFileSync } from "fs";
20
- var PRIVATE_MODE_PATH = resolveStatePath("memory-capture-state.json");
21
- function isPrivateMode() {
22
- try {
23
- if (existsSync(PRIVATE_MODE_PATH)) {
24
- const state = JSON.parse(readFileSync(PRIVATE_MODE_PATH, "utf-8"));
25
- return state.enabled === false;
26
- }
27
- } catch {
28
- }
29
- return false;
30
- }
31
- var METRICS_PATH = stateWritePath("search-metrics.jsonl");
32
- function logSearchMetric(tool, query, resultCount) {
33
- try {
34
- const entry = JSON.stringify({
35
- ts: (/* @__PURE__ */ new Date()).toISOString(),
36
- tool,
37
- query,
38
- results: resultCount
39
- });
40
- appendFileSync(METRICS_PATH, entry + "\n");
41
- } catch {
42
- }
43
- }
44
- var config = resolveConfig();
45
- var crystal = createCrystal(config);
46
- var isRemote = crystal instanceof RemoteCrystal;
47
- if (isRemote) {
48
- process.stderr.write("[memory-crystal] Remote mode: " + config.remoteUrl + "\n");
49
- }
50
- var server = new Server(
51
- { name: "memory-crystal", version: "0.1.0" },
52
- { capabilities: { tools: {} } }
53
- );
54
- server.setRequestHandler(ListToolsRequestSchema, async () => ({
55
- tools: [
56
- {
57
- name: "crystal_search",
58
- description: "Search memory crystal \u2014 semantic search across all agent conversations, files, and stored memories. Returns ranked results with similarity scores.",
59
- inputSchema: {
60
- type: "object",
61
- properties: {
62
- query: { type: "string", description: "What to search for" },
63
- limit: { type: "number", description: "Max results (default: 5)" },
64
- agent_id: { type: "string", description: 'Filter by agent (e.g. "main", "claude-code")' },
65
- time_filter: { type: "string", description: 'Only return results newer than this. Relative ("24h", "7d", "30d") or ISO date.' },
66
- quality: { type: "string", enum: ["fast", "deep"], description: 'Search quality mode. "fast" (default) uses hybrid search. "deep" adds LLM query expansion + re-ranking.' }
67
- },
68
- required: ["query"]
69
- }
70
- },
71
- {
72
- name: "crystal_remember",
73
- description: "Store a fact, preference, or observation in memory crystal. Persists across sessions and compaction.",
74
- inputSchema: {
75
- type: "object",
76
- properties: {
77
- text: { type: "string", description: "The fact or observation to remember" },
78
- category: {
79
- type: "string",
80
- enum: ["fact", "preference", "event", "opinion", "skill"],
81
- description: "Category of memory (default: fact)"
82
- }
83
- },
84
- required: ["text"]
85
- }
86
- },
87
- {
88
- name: "crystal_forget",
89
- description: "Deprecate a memory by ID. Does not delete \u2014 marks as deprecated.",
90
- inputSchema: {
91
- type: "object",
92
- properties: {
93
- id: { type: "number", description: "Memory ID to deprecate" }
94
- },
95
- required: ["id"]
96
- }
97
- },
98
- {
99
- name: "crystal_status",
100
- description: "Show memory crystal status \u2014 chunk count, memory count, agents, embedding provider.",
101
- inputSchema: {
102
- type: "object",
103
- properties: {}
104
- }
105
- },
106
- {
107
- name: "crystal_sources_add",
108
- description: "Add a directory for source file indexing. Files are chunked, embedded, and searchable via crystal_search. Optional feature... does not affect existing memory capture.",
109
- inputSchema: {
110
- type: "object",
111
- properties: {
112
- path: { type: "string", description: "Absolute path to the directory to index" },
113
- name: { type: "string", description: 'Short name for this collection (e.g. "wipcomputer")' }
114
- },
115
- required: ["path", "name"]
116
- }
117
- },
118
- {
119
- name: "crystal_sources_sync",
120
- description: "Sync a source collection: scan for new/changed/deleted files and re-index. Run after adding a collection or when files change.",
121
- inputSchema: {
122
- type: "object",
123
- properties: {
124
- name: { type: "string", description: "Collection name to sync" },
125
- dry_run: { type: "boolean", description: "If true, report what would change without actually indexing" }
126
- },
127
- required: ["name"]
128
- }
129
- },
130
- {
131
- name: "crystal_sources_status",
132
- description: "Show status of all source file collections: file counts, chunk counts, last sync time.",
133
- inputSchema: {
134
- type: "object",
135
- properties: {}
136
- }
137
- }
138
- ]
139
- }));
140
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
141
- const { name, arguments: args } = request.params;
142
- try {
143
- await crystal.init();
144
- switch (name) {
145
- case "crystal_search": {
146
- const query = args?.query;
147
- const limit = args?.limit || 5;
148
- const filter = {};
149
- if (args?.agent_id) filter.agent_id = args.agent_id;
150
- if (args?.time_filter) filter.since = args.time_filter;
151
- const results = isRemote ? await crystal.search(query, limit, filter) : await crystal.deepSearch(query, limit, filter);
152
- logSearchMetric("crystal_search", query, results.length);
153
- if (results.length === 0) {
154
- return { content: [{ type: "text", text: "No results found." }] };
155
- }
156
- const freshnessIcon = { fresh: "\u{1F7E2}", recent: "\u{1F7E1}", aging: "\u{1F7E0}", stale: "\u{1F534}" };
157
- const formatted = results.map((r, i) => {
158
- const score = (r.score * 100).toFixed(1);
159
- const date = r.created_at?.slice(0, 10) || "unknown";
160
- const fresh = r.freshness ? `${freshnessIcon[r.freshness]} ${r.freshness}, ` : "";
161
- return `[${i + 1}] (${fresh}${score}% match, ${r.agent_id}, ${date}, ${r.role})
162
- ${r.text}`;
163
- }).join("\n\n---\n\n");
164
- const header = "(Recency-weighted. \u{1F7E2} fresh <3d, \u{1F7E1} recent <7d, \u{1F7E0} aging <14d, \u{1F534} stale 14d+)\n\n";
165
- return { content: [{ type: "text", text: header + formatted }] };
166
- }
167
- case "crystal_remember": {
168
- if (isPrivateMode()) {
169
- return { content: [{ type: "text", text: "Private mode is on. No memories are being stored. Toggle off to resume." }] };
170
- }
171
- const text = args?.text;
172
- const category = args?.category || "fact";
173
- const id = await crystal.remember(text, category);
174
- return { content: [{ type: "text", text: `Remembered (id: ${id}, category: ${category}): ${text}` }] };
175
- }
176
- case "crystal_forget": {
177
- const id = args?.id;
178
- const ok = crystal.forget(id);
179
- return {
180
- content: [{ type: "text", text: ok ? `Forgot memory ${id}` : `Memory ${id} not found or already deprecated` }]
181
- };
182
- }
183
- case "crystal_status": {
184
- const status = await crystal.status();
185
- const text = [
186
- `Memory Crystal Status${isRemote ? " (REMOTE)" : ""}`,
187
- ` Data dir: ${status.dataDir}`,
188
- ` Provider: ${status.embeddingProvider}`,
189
- ` Chunks: ${status.chunks.toLocaleString()}`,
190
- ` Memories: ${status.memories}`,
191
- ` Sources: ${status.sources}`,
192
- ` Agents: ${status.agents.length > 0 ? status.agents.join(", ") : "none yet"}`,
193
- ` Sessions: ${status.capturedSessions} captured`,
194
- ` Latest: ${status.latestCapture || "never"}`
195
- ].join("\n");
196
- return { content: [{ type: "text", text }] };
197
- }
198
- case "crystal_sources_add": {
199
- if (isRemote) {
200
- return { content: [{ type: "text", text: "Source indexing not available in remote mode. Index files on the Mac Mini." }] };
201
- }
202
- const path = args?.path;
203
- const collectionName = args?.name;
204
- const col = await crystal.sourcesAdd(path, collectionName);
205
- return {
206
- content: [{ type: "text", text: `Added collection "${col.name}" at ${col.root_path}
207
- Run crystal_sources_sync with name "${collectionName}" to index files.` }]
208
- };
209
- }
210
- case "crystal_sources_sync": {
211
- if (isRemote) {
212
- return { content: [{ type: "text", text: "Source indexing not available in remote mode. Sync files on the Mac Mini." }] };
213
- }
214
- const collectionName = args?.name;
215
- const dryRun = args?.dry_run;
216
- const result = await crystal.sourcesSync(collectionName, { dryRun });
217
- const lines = [
218
- dryRun ? `Dry run for "${result.collection}":` : `Synced "${result.collection}":`,
219
- ` Added: ${result.added} files`,
220
- ` Updated: ${result.updated} files`,
221
- ` Removed: ${result.removed} files`,
222
- ` Chunks: ${result.chunks_added} embedded`,
223
- ` Time: ${(result.duration_ms / 1e3).toFixed(1)}s`
224
- ];
225
- return { content: [{ type: "text", text: lines.join("\n") }] };
226
- }
227
- case "crystal_sources_status": {
228
- if (isRemote) {
229
- return { content: [{ type: "text", text: "Source indexing not available in remote mode." }] };
230
- }
231
- const sourcesStatus = crystal.sourcesStatus();
232
- if (sourcesStatus.collections.length === 0) {
233
- return { content: [{ type: "text", text: "No source collections. Use crystal_sources_add to add a directory." }] };
234
- }
235
- const lines = ["Source Collections:"];
236
- for (const col of sourcesStatus.collections) {
237
- const syncAgo = col.last_sync_at ? `${Math.round((Date.now() - new Date(col.last_sync_at).getTime()) / 6e4)}m ago` : "never";
238
- lines.push(` ${col.name}: ${col.file_count.toLocaleString()} files, ${col.chunk_count.toLocaleString()} chunks, last sync ${syncAgo}`);
239
- }
240
- lines.push(` Total: ${sourcesStatus.total_files.toLocaleString()} files, ${sourcesStatus.total_chunks.toLocaleString()} chunks`);
241
- return { content: [{ type: "text", text: lines.join("\n") }] };
242
- }
243
- default:
244
- return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
245
- }
246
- } catch (err) {
247
- return { content: [{ type: "text", text: `Error: ${err.message}` }], isError: true };
248
- }
249
- });
250
- async function main() {
251
- const transport = new StdioServerTransport();
252
- await server.connect(transport);
253
- try {
254
- const clientCapabilities = server.getClientCapabilities?.();
255
- if (clientCapabilities?.sampling) {
256
- setSamplingServer(server);
257
- process.stderr.write("[memory-crystal] MCP sampling available: using client LLM for deep search\n");
258
- }
259
- } catch {
260
- }
261
- }
262
- main().catch((err) => {
263
- console.error(`MCP server failed: ${err.message}`);
264
- process.exit(1);
265
- });
package/dist/migrate.d.ts DELETED
@@ -1 +0,0 @@
1
- #!/usr/bin/env node
package/dist/migrate.js DELETED
@@ -1,89 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- Crystal,
4
- resolveConfig
5
- } from "./chunk-FBQWSDPC.js";
6
-
7
- // src/migrate.ts
8
- import Database from "better-sqlite3";
9
- import { existsSync } from "fs";
10
- import { join } from "path";
11
- var BATCH_SIZE = 50;
12
- async function main() {
13
- const args = process.argv.slice(2);
14
- const dryRun = args.includes("--dry-run");
15
- const providerFlag = args.find((_, i) => args[i - 1] === "--provider");
16
- const openclawHome = process.env.OPENCLAW_HOME || join(process.env.HOME || "", ".openclaw");
17
- const sourcePath = join(openclawHome, "memory", "context-embeddings.sqlite");
18
- if (!existsSync(sourcePath)) {
19
- console.error(`Source not found: ${sourcePath}`);
20
- process.exit(1);
21
- }
22
- const sourceDb = new Database(sourcePath, { readonly: true });
23
- sourceDb.pragma("journal_mode = WAL");
24
- const total = sourceDb.prepare("SELECT COUNT(*) as count FROM conversation_chunks").get().count;
25
- console.log(`Found ${total} chunks in context-embeddings.sqlite`);
26
- if (dryRun) {
27
- const samples = sourceDb.prepare("SELECT chunk_text, role, session_key, timestamp FROM conversation_chunks ORDER BY timestamp DESC LIMIT 5").all();
28
- console.log("\nSample (5 most recent):");
29
- for (const s of samples) {
30
- const date = s.timestamp ? new Date(s.timestamp).toISOString().slice(0, 10) : "unknown";
31
- console.log(` [${date}] [${s.role}] ${s.chunk_text.slice(0, 80)}...`);
32
- }
33
- console.log(`
34
- Run without --dry-run to import all ${total} chunks.`);
35
- sourceDb.close();
36
- return;
37
- }
38
- const overrides = {};
39
- if (providerFlag) overrides.embeddingProvider = providerFlag;
40
- const config = resolveConfig(overrides);
41
- const crystal = new Crystal(config);
42
- await crystal.init();
43
- console.log(`Embedding provider: ${config.embeddingProvider}`);
44
- console.log(`Target: ${config.dataDir}`);
45
- console.log(`Migrating ${total} chunks in batches of ${BATCH_SIZE}...`);
46
- const rows = sourceDb.prepare(`
47
- SELECT chunk_text, role, agent_id, session_key, timestamp, compaction_number
48
- FROM conversation_chunks
49
- ORDER BY timestamp ASC
50
- `).all();
51
- let imported = 0;
52
- let failed = 0;
53
- for (let i = 0; i < rows.length; i += BATCH_SIZE) {
54
- const batch = rows.slice(i, i + BATCH_SIZE);
55
- const chunks = batch.map((row) => ({
56
- text: row.chunk_text,
57
- role: row.role || "assistant",
58
- source_type: "conversation",
59
- source_id: row.session_key || "unknown",
60
- agent_id: row.agent_id || "main",
61
- token_count: Math.ceil((row.chunk_text?.length || 0) / 4),
62
- created_at: row.timestamp ? new Date(row.timestamp).toISOString() : (/* @__PURE__ */ new Date()).toISOString()
63
- }));
64
- try {
65
- const count = await crystal.ingest(chunks);
66
- imported += count;
67
- const pct = Math.round(imported / total * 100);
68
- process.stdout.write(`\r ${imported}/${total} (${pct}%)`);
69
- } catch (err) {
70
- failed += batch.length;
71
- console.error(`
72
- Batch error at ${i}: ${err.message}`);
73
- }
74
- }
75
- console.log(`
76
-
77
- Migration complete:`);
78
- console.log(` Imported: ${imported}`);
79
- console.log(` Failed: ${failed}`);
80
- console.log(` Provider: ${config.embeddingProvider}`);
81
- const status = await crystal.status();
82
- console.log(` Total chunks in crystal: ${status.chunks}`);
83
- crystal.close();
84
- sourceDb.close();
85
- }
86
- main().catch((err) => {
87
- console.error(`Migration failed: ${err.message}`);
88
- process.exit(1);
89
- });
@@ -1 +0,0 @@
1
- #!/usr/bin/env node