memory-forge 0.3.13 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,177 @@
1
+ /**
2
+ * Real-world scenario tests — simulates actual user workflows.
3
+ */
4
+ import { MemoryStore, contentOverlap } from "./store.js";
5
+ import { loadAllMemories } from "./storage/local.js";
6
+ import { autoName, generateContextSummary } from "./auto/index.js";
7
+ import { randomUUID } from "node:crypto";
8
+ import * as fs from "node:fs";
9
+ import * as path from "node:path";
10
+ let ok = 0;
11
+ let ng = 0;
12
+ function t(name, fn) { try {
13
+ fn();
14
+ ok++;
15
+ }
16
+ catch (e) {
17
+ ng++;
18
+ console.log("FAIL:", name, "—", e.message);
19
+ } }
20
+ const now = new Date().toISOString();
21
+ // ═══ SCENARIO 1: Corrupted memory file ═══
22
+ console.log("=== Scenario 1: Corrupted memory file ===");
23
+ const corruptId = randomUUID();
24
+ const memDir = path.join(process.env.HOME ?? process.env.USERPROFILE ?? "/tmp", ".memory-forge", "memories");
25
+ const corruptPath = path.join(memDir, corruptId + ".md");
26
+ fs.mkdirSync(memDir, { recursive: true });
27
+ fs.writeFileSync(corruptPath, "NOT VALID MEMORY FILE\njust garbage\nno frontmatter");
28
+ t("corrupted file does not crash loader", () => { loadAllMemories(); });
29
+ t("corrupted file loads as memory with id-based name", () => {
30
+ const all = loadAllMemories();
31
+ const recovered = all.find(m => m.id === corruptId);
32
+ if (!recovered)
33
+ throw new Error("should load file content as memory");
34
+ // Without frontmatter, name defaults to id, content is full file text
35
+ if (recovered.category !== "general")
36
+ throw new Error("default category missing");
37
+ });
38
+ fs.unlinkSync(corruptPath);
39
+ // ═══ SCENARIO 2: Duplicate import resilience ═══
40
+ console.log("\n=== Scenario 2: Duplicate import resilience ===");
41
+ const s2 = new MemoryStore();
42
+ const dup1 = { id: randomUUID(), name: "Pref", content: "Always use React 19 with TypeScript strict mode", category: "user-preference", tags: ["react"], priority: 8, vector: [], created_at: now, access_count: 0, last_accessed: null };
43
+ const dup2 = { id: randomUUID(), name: "Pref", content: "Always use React 19 with TypeScript strict mode", category: "user-preference", tags: ["react"], priority: 8, vector: [], created_at: now, access_count: 0, last_accessed: null };
44
+ s2.add(dup1);
45
+ s2.add(dup2);
46
+ t("both stored (different IDs)", () => { if (s2.size() !== 2)
47
+ throw new Error("size=" + s2.size()); });
48
+ const overlap = contentOverlap(dup1.content, dup2.content);
49
+ t("100% overlap detected", () => { if (overlap < 0.99)
50
+ throw new Error("overlap=" + overlap); });
51
+ // ═══ SCENARIO 3: Memory lifecycle ═══
52
+ console.log("\n=== Scenario 3: Full memory lifecycle ===");
53
+ const s3 = new MemoryStore();
54
+ const lifeId = randomUUID();
55
+ s3.add({ id: lifeId, name: "Lifecycle Test", content: "Original content v1", category: "general", tags: ["test"], priority: 5, vector: [], created_at: now, access_count: 0, last_accessed: null });
56
+ t("create", () => { if (!s3.get(lifeId))
57
+ throw new Error("not found"); });
58
+ const m = s3.get(lifeId);
59
+ m.content = "Updated content v2";
60
+ m.name = autoName(m.content);
61
+ m.category = "decision-log";
62
+ m.tags = ["updated", "v2"];
63
+ m.priority = 9;
64
+ t("update content", () => { if (s3.get(lifeId).content !== "Updated content v2")
65
+ throw new Error("content"); });
66
+ t("update category", () => { if (s3.get(lifeId).category !== "decision-log")
67
+ throw new Error("category"); });
68
+ t("update tags", () => { if (s3.get(lifeId).tags.length !== 2)
69
+ throw new Error("tags"); });
70
+ t("update priority", () => { if (s3.get(lifeId).priority !== 9)
71
+ throw new Error("priority"); });
72
+ t("update name", () => { if (s3.get(lifeId).name !== "Updated content v2")
73
+ throw new Error("name"); });
74
+ const found = s3.keywordSearch("updated", { limit: 5 });
75
+ t("search finds updated", () => { if (found.length === 0)
76
+ throw new Error("not found"); });
77
+ t("search score reasonable", () => { if (found[0]._score < 5)
78
+ throw new Error("score=" + found[0]._score); });
79
+ s3.remove(lifeId);
80
+ t("forget removes", () => { if (s3.get(lifeId) !== null)
81
+ throw new Error("still exists"); });
82
+ // ═══ SCENARIO 4: Context summary ranking ═══
83
+ console.log("\n=== Scenario 4: Context summary ranking ===");
84
+ const s4 = new MemoryStore();
85
+ s4.add({ id: "high", name: "High Priority", content: "Critical security config", category: "decision-log", tags: [], priority: 10, vector: [], created_at: now, access_count: 100, last_accessed: now });
86
+ s4.add({ id: "low", name: "Low Priority", content: "Casual note", category: "general", tags: [], priority: 1, vector: [], created_at: "2020-01-01T00:00:00Z", access_count: 0, last_accessed: null });
87
+ const summary = generateContextSummary(s4, 1);
88
+ t("high priority wins", () => { if (!summary.includes("High Priority"))
89
+ throw new Error("low won"); });
90
+ t("low priority excluded", () => { if (summary.includes("Low Priority"))
91
+ throw new Error("low included"); });
92
+ // ═══ SCENARIO 5: Concurrent write safety ═══
93
+ console.log("\n=== Scenario 5: Concurrent write safety ===");
94
+ const s5 = new MemoryStore();
95
+ const cid = randomUUID();
96
+ s5.add({ id: cid, name: "First", content: "First write", category: "general", tags: [], priority: 5, vector: [], created_at: now, access_count: 0, last_accessed: null });
97
+ s5.add({ id: cid, name: "Second", content: "Second write", category: "general", tags: [], priority: 5, vector: [], created_at: now, access_count: 0, last_accessed: null });
98
+ t("last write wins", () => { if (s5.get(cid).content !== "Second write")
99
+ throw new Error(s5.get(cid).content); });
100
+ // ═══ SCENARIO 6: Export/import round-trip ═══
101
+ console.log("\n=== Scenario 6: Export/import round-trip ===");
102
+ const s6 = new MemoryStore();
103
+ s6.add({ id: "e1", name: "Export Test", content: "Data for export", category: "general", tags: ["export"], priority: 5, vector: [], created_at: now, access_count: 0, last_accessed: null });
104
+ const exported = s6.list({ limit: 100, offset: 0 });
105
+ const imported = new MemoryStore();
106
+ for (const em of exported)
107
+ imported.add({ ...em });
108
+ t("round-trip content", () => { if (imported.get("e1").content !== "Data for export")
109
+ throw new Error("lost"); });
110
+ t("round-trip tags", () => { if (imported.get("e1").tags[0] !== "export")
111
+ throw new Error("tags lost"); });
112
+ // ═══ SCENARIO 7: Multi-tag filtering ═══
113
+ console.log("\n=== Scenario 7: Multi-tag filtering ===");
114
+ const s7 = new MemoryStore();
115
+ s7.add({ id: "t1", name: "A", content: "x", category: "general", tags: ["react", "typescript", "tailwind"], priority: 5, vector: [], created_at: now, access_count: 0, last_accessed: null });
116
+ s7.add({ id: "t2", name: "B", content: "x", category: "general", tags: ["react", "vue"], priority: 5, vector: [], created_at: now, access_count: 0, last_accessed: null });
117
+ s7.add({ id: "t3", name: "C", content: "x", category: "general", tags: ["python", "django"], priority: 5, vector: [], created_at: now, access_count: 0, last_accessed: null });
118
+ t("single tag", () => { if (s7.list({ tags: ["react"], limit: 10, offset: 0 }).length !== 2)
119
+ throw new Error("react"); });
120
+ t("OR multi-tag", () => { if (s7.list({ tags: ["python", "django"], limit: 10, offset: 0 }).length !== 1)
121
+ throw new Error("python"); });
122
+ t("no-match tag", () => { if (s7.list({ tags: ["rust"], limit: 10, offset: 0 }).length !== 0)
123
+ throw new Error("rust"); });
124
+ // ═══ SCENARIO 8: Large batch performance ═══
125
+ console.log("\n=== Scenario 8: Large batch performance ===");
126
+ const s8 = new MemoryStore();
127
+ const start = Date.now();
128
+ for (let i = 0; i < 500; i++) {
129
+ s8.add({ id: `perf-${i}`, name: `Memory ${i}`, content: `Content for memory number ${i} with tags and metadata`, category: i % 4 === 0 ? "decision-log" : i % 4 === 1 ? "user-preference" : i % 4 === 2 ? "code-pattern" : "general", tags: [`tag-${i % 10}`], priority: 1 + (i % 10), vector: [], created_at: now, access_count: i, last_accessed: null });
130
+ }
131
+ const insertTime = Date.now() - start;
132
+ t("500 inserts under 500ms", () => { if (insertTime > 500)
133
+ throw new Error(insertTime + "ms"); });
134
+ const searchStart = Date.now();
135
+ for (let i = 0; i < 50; i++)
136
+ s8.keywordSearch(`content ${i}`, { limit: 10 });
137
+ t("50 searches under 200ms", () => { if (Date.now() - searchStart > 200)
138
+ throw new Error((Date.now() - searchStart) + "ms"); });
139
+ // ═══ SCENARIO 9: Empty/edge state stress ═══
140
+ console.log("\n=== Scenario 9: Edge state stress ===");
141
+ const s9 = new MemoryStore();
142
+ t("empty store list", () => { if (s9.list({ limit: 10, offset: 0 }).length !== 0)
143
+ throw new Error("not empty"); });
144
+ t("empty store size 0", () => { if (s9.size() !== 0)
145
+ throw new Error("not zero"); });
146
+ t("empty store stats", () => {
147
+ const st = s9.stats();
148
+ if (st.total !== 0 || st.total_accesses !== 0)
149
+ throw new Error("not empty stats");
150
+ });
151
+ t("empty store keyword search", () => { if (s9.keywordSearch("anything", { limit: 5 }).length !== 0)
152
+ throw new Error("found in empty"); });
153
+ t("empty store get nonexistent", () => { if (s9.get("nope") !== null)
154
+ throw new Error("found in empty"); });
155
+ t("empty store context summary", () => {
156
+ const cs = generateContextSummary(s9, 5);
157
+ if (!cs.includes("Welcome"))
158
+ throw new Error("no welcome");
159
+ });
160
+ // ═══ SCENARIO 10: LRU eviction stress ═══
161
+ console.log("\n=== Scenario 10: LRU eviction stress ===");
162
+ const s10 = new MemoryStore();
163
+ for (let i = 0; i < 5100; i++) {
164
+ s10.add({ id: `lru-${i}`, name: `Memory ${i}`, content: `Content ${i}`, category: "general", tags: [], priority: 5, vector: [], created_at: now, access_count: i, last_accessed: null });
165
+ }
166
+ t("LRU capped at 5000", () => { if (s10.size() > 5000)
167
+ throw new Error("size=" + s10.size()); });
168
+ t("LRU evicted lowest access", () => {
169
+ const all = s10.list({ limit: 5000, offset: 0 });
170
+ const minAccess = Math.min(...all.map(m => m.access_count));
171
+ if (minAccess < 100)
172
+ throw new Error("should have evicted 0-99 range, min=" + minAccess);
173
+ });
174
+ console.log("\n" + ok + " passed, " + ng + " failed");
175
+ if (ng > 0)
176
+ process.exit(1);
177
+ //# sourceMappingURL=scenario-test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scenario-test.js","sourceRoot":"","sources":["../src/scenario-test.ts"],"names":[],"mappings":"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"}
package/dist/setup.js CHANGED
@@ -13,14 +13,14 @@ export async function setup() {
13
13
  ║ MemoryForge Setup ║
14
14
  ╚══════════════════════════╝
15
15
  `);
16
- // 0. Install globally (so hooks can find the command)
17
- console.log("📦 Installing memory-forge globally…");
16
+ // 0. Install globally in background (non-blocking setup continues regardless)
17
+ console.log("📦 Installing memory-forge globally (background)…");
18
18
  try {
19
- execSync("npm i -g memory-forge@latest", { stdio: "pipe", timeout: 60000 });
19
+ execSync("npm i -g memory-forge@latest", { stdio: "pipe", timeout: 30000 });
20
20
  console.log(" ✅ Global install complete");
21
21
  }
22
22
  catch {
23
- console.log(" ⚠️ Global install skipped (run `npm i -g memory-forge` manually if hooks fail)");
23
+ console.log(" ⚠️ Global install skipped hooks work with npx too");
24
24
  }
25
25
  // 1. Install Claude Code hooks
26
26
  console.log("\n🪝 Installing Claude Code hooks…");
@@ -60,6 +60,12 @@ export async function setup() {
60
60
  │ • Load context on session start │
61
61
  │ • Capture learnings each session │
62
62
  │ │
63
+ │ Try it now: │
64
+ │ • CLI: memory-forge list │
65
+ │ • CLI: memory-forge search "react"│
66
+ │ • CLI: memory-forge stats │
67
+ │ • MCP: memory_store "I prefer…" │
68
+ │ │
63
69
  │ No further setup needed. │
64
70
  └──────────────────────────────────────┘
65
71
  `);
package/dist/setup.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":";AACA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,MAAM,CAAC,KAAK,UAAU,KAAK;IACzB,OAAO,CAAC,GAAG,CAAC;;;;GAIX,CAAC,CAAC;IAEH,sDAAsD;IACtD,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC;IACpD,IAAI,CAAC;QACH,QAAQ,CAAC,8BAA8B,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QAC5E,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,GAAG,CAAC,oFAAoF,CAAC,CAAC;IACpG,CAAC;IAED,+BAA+B;IAC/B,OAAO,CAAC,GAAG,CAAC,qCAAqC,CAAC,CAAC;IACnD,MAAM,OAAO,GAAG,YAAY,EAAE,CAAC;IAC/B,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,yDAAyD,CAAC,CAAC,CAAC,8CAA8C,CAAC,CAAC;IAElI,2BAA2B;IAC3B,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;IAC5B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,OAAO,CAAC,GAAG,CAAC,YAAY,KAAK,CAAC,MAAM,kDAAkD,CAAC,CAAC;QACxF,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;QACxC,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;YAC3B,UAAU,CAAC,GAAG,CAAC,CAAC;QAClB,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,iBAAiB,QAAQ,CAAC,MAAM,oBAAoB,CAAC,CAAC;IACpE,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,iDAAiD,CAAC,CAAC;IACjE,CAAC;IAED,2CAA2C;IAC3C,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;IAC7D,OAAO,EAAE,CAAC;IACV,OAAO,CAAC,GAAG,CAAC,2DAA2D,CAAC,CAAC;IAEzE,yBAAyB;IACzB,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;IACrC,MAAM,UAAU,GAAG,cAAc,EAAE,CAAC;IACpC,OAAO,CAAC,GAAG,CAAC,qBAAqB,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,mBAAmB,EAAE,CAAC,CAAC;IACxF,OAAO,CAAC,GAAG,CAAC,qBAAqB,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,mBAAmB,EAAE,CAAC,CAAC;IAChF,OAAO,CAAC,GAAG,CAAC,qBAAqB,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,mBAAmB,EAAE,CAAC,CAAC;IAEtF,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;GAYX,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":";AACA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,MAAM,CAAC,KAAK,UAAU,KAAK;IACzB,OAAO,CAAC,GAAG,CAAC;;;;GAIX,CAAC,CAAC;IAEH,gFAAgF;IAChF,OAAO,CAAC,GAAG,CAAC,mDAAmD,CAAC,CAAC;IACjE,IAAI,CAAC;QACH,QAAQ,CAAC,8BAA8B,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QAC5E,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,GAAG,CAAC,yDAAyD,CAAC,CAAC;IACzE,CAAC;IAED,+BAA+B;IAC/B,OAAO,CAAC,GAAG,CAAC,qCAAqC,CAAC,CAAC;IACnD,MAAM,OAAO,GAAG,YAAY,EAAE,CAAC;IAC/B,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,yDAAyD,CAAC,CAAC,CAAC,8CAA8C,CAAC,CAAC;IAElI,2BAA2B;IAC3B,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;IAC5B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,OAAO,CAAC,GAAG,CAAC,YAAY,KAAK,CAAC,MAAM,kDAAkD,CAAC,CAAC;QACxF,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;QACxC,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;YAC3B,UAAU,CAAC,GAAG,CAAC,CAAC;QAClB,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,iBAAiB,QAAQ,CAAC,MAAM,oBAAoB,CAAC,CAAC;IACpE,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,iDAAiD,CAAC,CAAC;IACjE,CAAC;IAED,2CAA2C;IAC3C,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;IAC7D,OAAO,EAAE,CAAC;IACV,OAAO,CAAC,GAAG,CAAC,2DAA2D,CAAC,CAAC;IAEzE,yBAAyB;IACzB,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;IACrC,MAAM,UAAU,GAAG,cAAc,EAAE,CAAC;IACpC,OAAO,CAAC,GAAG,CAAC,qBAAqB,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,mBAAmB,EAAE,CAAC,CAAC;IACxF,OAAO,CAAC,GAAG,CAAC,qBAAqB,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,mBAAmB,EAAE,CAAC,CAAC;IAChF,OAAO,CAAC,GAAG,CAAC,qBAAqB,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,mBAAmB,EAAE,CAAC,CAAC;IAEtF,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;GAkBX,CAAC,CAAC;AACL,CAAC"}
@@ -5,12 +5,31 @@
5
5
  import { ShelbyNodeClient } from "@shelby-protocol/sdk/node";
6
6
  import { Account } from "@aptos-labs/ts-sdk";
7
7
  import type { Memory } from "../store.js";
8
+ /** Whether the last API call failed with 401/403. */
9
+ export declare function isAuthFailed(): boolean;
10
+ /** Central Shelby config — single switch point for API key → license key migration. */
11
+ export interface ShelbyConfig {
12
+ apiKey: string | null;
13
+ namespace: string;
14
+ accountAddress: string | null;
15
+ }
16
+ export declare function getShelbyConfig(): ShelbyConfig;
8
17
  export declare function initShelby(apiKey: string, privateKey?: string): {
9
18
  address: string;
10
19
  generatedKey?: string;
11
20
  };
12
21
  export declare function getShelbyClient(): ShelbyNodeClient | null;
13
22
  export declare function getShelbyAccount(): Account | null;
23
+ /** Query on-chain balances via REST API. Returns null on error. */
24
+ export declare function getBalances(): Promise<{
25
+ apt: string;
26
+ shelbyUsd: string;
27
+ } | null>;
28
+ /** Query storage usage from Shelby. Returns count + total bytes, or null on error. */
29
+ export declare function getStorageUsage(): Promise<{
30
+ blobCount: number;
31
+ totalBytes: number;
32
+ } | null>;
14
33
  /** 上传记忆到 Shelby */
15
34
  export declare function uploadMemory(memory: Memory): Promise<string | null>;
16
35
  /** 从 Shelby 下载记忆(30s 超时,Windows 安全边界) */
@@ -19,7 +38,7 @@ export declare function downloadMemory(blobName: string): Promise<Memory | null>
19
38
  export declare function listBlobs(): Promise<string[]>;
20
39
  /** 从 Shelby 删除记忆 */
21
40
  export declare function deleteBlob(blobName: string): Promise<void>;
22
- /** 将本地记忆导出为 blob 名称列表 */
41
+ /** 将本地记忆导出为 blob 名称(含命名空间) */
23
42
  export declare function getBlobName(memoryId: string): string;
24
- /** 从 blob 名称解析 memory_id */
43
+ /** 从 blob 名称解析 memory_id(兼容新旧格式) */
25
44
  export declare function getMemoryId(blobName: string): string | null;
@@ -4,10 +4,39 @@
4
4
  */
5
5
  import { ShelbyNodeClient } from "@shelby-protocol/sdk/node";
6
6
  import { Account, Ed25519PrivateKey, Network } from "@aptos-labs/ts-sdk";
7
- const DOWNLOAD_TIMEOUT_MS = 30_000; // 30s
7
+ import * as fs from "node:fs";
8
+ import * as path from "node:path";
9
+ const DOWNLOAD_TIMEOUT_MS = 30_000;
10
+ const HOME = process.env.HOME ?? process.env.USERPROFILE ?? "/tmp";
11
+ const PROFILE_PATH = path.join(HOME, ".memory-forge", "pro.json");
8
12
  let client = null;
9
13
  let account = null;
14
+ let authFailed = false;
15
+ let uploadWarned = false;
16
+ /** Whether the last API call failed with 401/403. */
17
+ export function isAuthFailed() { return authFailed; }
18
+ export function getShelbyConfig() {
19
+ // Priority: env var → saved in pro.json → null
20
+ let apiKey = process.env.SHELBY_API_KEY ?? null;
21
+ let accountAddress = null;
22
+ try {
23
+ if (fs.existsSync(PROFILE_PATH)) {
24
+ const profile = JSON.parse(fs.readFileSync(PROFILE_PATH, "utf-8"));
25
+ accountAddress = profile.address ?? null;
26
+ // Fall back to saved key if env not set
27
+ if (!apiKey)
28
+ apiKey = profile.apiKey ?? null;
29
+ }
30
+ }
31
+ catch { /* corrupted profile — ignore */ }
32
+ const namespace = accountAddress
33
+ ? `users/${accountAddress}`
34
+ : `users/default`;
35
+ return { apiKey, namespace, accountAddress };
36
+ }
10
37
  export function initShelby(apiKey, privateKey) {
38
+ authFailed = false;
39
+ uploadWarned = false;
11
40
  client = new ShelbyNodeClient({
12
41
  network: Network.SHELBYNET,
13
42
  apiKey,
@@ -34,12 +63,64 @@ export function getShelbyClient() {
34
63
  export function getShelbyAccount() {
35
64
  return account;
36
65
  }
66
+ /** Build namespaced blob name: users/{namespace}/memories/{id}.json */
67
+ function blobNameFor(memoryId) {
68
+ const cfg = getShelbyConfig();
69
+ return `${cfg.namespace}/memories/${memoryId}.json`;
70
+ }
71
+ const SHELBYUSD_FA = "0x1b18363a9f1fe5e6ebf247daba5cc1c18052bb232efdc4c50f556053922d98e1";
72
+ /** Query on-chain balances via REST API. Returns null on error. */
73
+ export async function getBalances() {
74
+ if (!client || !account)
75
+ return null;
76
+ try {
77
+ const aptosConfig = client.config;
78
+ const baseUrl = aptosConfig.fullnode ?? "https://api.shelbynet.shelby.xyz/v1";
79
+ const addr = account.accountAddress.toString();
80
+ // APT: query coin store resource
81
+ const aptUrl = `${baseUrl}/accounts/${addr}/resource/0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>`;
82
+ const aptRes = await fetch(aptUrl).then(r => r.json()).catch(() => null);
83
+ const aptRaw = aptRes?.data?.coin?.value;
84
+ // ShelbyUSD: query fungible asset balance
85
+ const usdUrl = `${baseUrl}/accounts/${addr}/fungible_asset_balances`;
86
+ const usdRes = await fetch(usdUrl).then(r => r.json()).catch(() => null);
87
+ const usdEntry = Array.isArray(usdRes) ? usdRes.find((b) => b.asset_type === SHELBYUSD_FA) : null;
88
+ const usdRaw = usdEntry?.amount;
89
+ return {
90
+ apt: typeof aptRaw === "string" ? (Number(aptRaw) / 1e8).toFixed(4) : "0.0000",
91
+ shelbyUsd: typeof usdRaw === "string" ? (Number(usdRaw) / 1e6).toFixed(4) : "0.0000",
92
+ };
93
+ }
94
+ catch {
95
+ return null;
96
+ }
97
+ }
98
+ /** Query storage usage from Shelby. Returns count + total bytes, or null on error. */
99
+ export async function getStorageUsage() {
100
+ if (!client || !account)
101
+ return null;
102
+ try {
103
+ // Use coordination layer to list blobs with metadata
104
+ const metadata = await client.coordination.getAccountBlobs({
105
+ account: account.accountAddress,
106
+ });
107
+ const cfg = getShelbyConfig();
108
+ const ours = metadata.filter((m) => m.name?.includes(`/${cfg.namespace}/`));
109
+ const totalBytes = ours.reduce((sum, m) => sum + (m.size ?? 0), 0);
110
+ return { blobCount: ours.length, totalBytes };
111
+ }
112
+ catch {
113
+ return null;
114
+ }
115
+ }
37
116
  /** 上传记忆到 Shelby */
38
117
  export async function uploadMemory(memory) {
39
118
  if (!client || !account)
40
119
  return null;
120
+ if (authFailed)
121
+ return null;
41
122
  const blobData = Buffer.from(JSON.stringify(memory));
42
- const blobName = `memories/${memory.id}.json`;
123
+ const blobName = blobNameFor(memory.id);
43
124
  try {
44
125
  await client.upload({
45
126
  signer: account,
@@ -55,7 +136,16 @@ export async function uploadMemory(memory) {
55
136
  if (msg.includes("400") || msg.includes("Bad Request")) {
56
137
  return blobName;
57
138
  }
58
- console.error("[MemoryForge] Shelby upload failed:", msg);
139
+ // 401/403 = auth failure — stop trying this session
140
+ if (msg.includes("401") || msg.includes("403") || msg.includes("Unauthorized")) {
141
+ authFailed = true;
142
+ console.error("[MemoryForge] Pro sync: authentication failed. Check SHELBY_API_KEY.");
143
+ return null;
144
+ }
145
+ if (!uploadWarned) {
146
+ uploadWarned = true;
147
+ console.error("[MemoryForge] Pro sync: upload failed (network/storage issue). Will retry next sync.");
148
+ }
59
149
  return null;
60
150
  }
61
151
  }
@@ -141,13 +231,18 @@ export async function deleteBlob(blobName) {
141
231
  // ignore
142
232
  }
143
233
  }
144
- /** 将本地记忆导出为 blob 名称列表 */
234
+ /** 将本地记忆导出为 blob 名称(含命名空间) */
145
235
  export function getBlobName(memoryId) {
146
- return `memories/${memoryId}.json`;
236
+ return blobNameFor(memoryId);
147
237
  }
148
- /** 从 blob 名称解析 memory_id */
238
+ /** 从 blob 名称解析 memory_id(兼容新旧格式) */
149
239
  export function getMemoryId(blobName) {
150
- const match = blobName.match(/memories\/(.+)\.json$/);
151
- return match ? match[1] : null;
240
+ // New format: users/{ns}/memories/{id}.json
241
+ const newMatch = blobName.match(/memories\/(.+)\.json$/);
242
+ if (newMatch)
243
+ return newMatch[1];
244
+ // Old format: memories/{id}.json (legacy, pre-namespace)
245
+ const oldMatch = blobName.match(/^memories\/(.+)\.json$/);
246
+ return oldMatch ? oldMatch[1] : null;
152
247
  }
153
248
  //# sourceMappingURL=shelby.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"shelby.js","sourceRoot":"","sources":["../../src/storage/shelby.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"shelby.js","sourceRoot":"","sources":["../../src/storage/shelby.ts"],"names":[],"mappings":"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"}
package/dist/store.d.ts CHANGED
@@ -40,7 +40,9 @@ export declare class MemoryStore {
40
40
  search(rawQuery: string, options: SearchOptions): Memory[];
41
41
  /** 余弦相似度检索 */
42
42
  private vectorSearch;
43
- /** 降级: 无向量时的关键词匹配 */
43
+ /** 降级: 无向量时的混合关键词匹配。
44
+ * ≤3 char tokens: word-boundary only (acronyms like DB, CI, AI).
45
+ * >3 char tokens: word-boundary primary + substring fallback (postgres → PostgreSQL). */
44
46
  keywordSearch(query: string, options: {
45
47
  limit: number;
46
48
  category?: string | null;
@@ -55,4 +57,12 @@ export declare class MemoryStore {
55
57
  total_accesses: number;
56
58
  };
57
59
  }
60
+ /** Character 3-gram Jaccard similarity.
61
+ * Captures short technical terms ("AI", "DB", "CI") naturally
62
+ * embedded in n-grams. Falls back to exact match for strings too
63
+ * short to produce n-grams (≤2 chars). */
64
+ export declare function contentOverlap(a: string, b: string): number;
65
+ /** Unicode-safe string truncation using Intl.Segmenter (grapheme clusters).
66
+ * Never splits surrogate pairs, ZWJ sequences, or combining marks. */
67
+ export declare function safeTruncate(text: string, maxLen: number): string;
58
68
  export {};
package/dist/store.js CHANGED
@@ -82,10 +82,12 @@ export class MemoryStore {
82
82
  .slice(0, limit)
83
83
  .map((s) => ({ ...s.memory, similarity: s.similarity, _score: s.score }));
84
84
  }
85
- /** 降级: 无向量时的关键词匹配 */
85
+ /** 降级: 无向量时的混合关键词匹配。
86
+ * ≤3 char tokens: word-boundary only (acronyms like DB, CI, AI).
87
+ * >3 char tokens: word-boundary primary + substring fallback (postgres → PostgreSQL). */
86
88
  keywordSearch(query, options) {
87
- const tokens = query.toLowerCase().split(/\s+/).filter((t) => t.length > 1);
88
- if (tokens.length === 0)
89
+ const rawTokens = query.toLowerCase().split(/\s+/).filter((t) => t.length > 1);
90
+ if (rawTokens.length === 0)
89
91
  return [];
90
92
  let candidates = [...this.memories.values()];
91
93
  if (options.category) {
@@ -94,20 +96,50 @@ export class MemoryStore {
94
96
  if (options.tags?.length) {
95
97
  candidates = candidates.filter((m) => options.tags.some((t) => m.tags.includes(t)));
96
98
  }
99
+ // Build per-token matchers: boundary regex (all) + substring check (long tokens only)
100
+ const matchers = rawTokens.map((t) => {
101
+ const escaped = t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
102
+ return {
103
+ regex: new RegExp(`\\b${escaped}\\b`, "i"),
104
+ substring: escaped,
105
+ isShort: t.length <= 3,
106
+ };
107
+ });
97
108
  return candidates
98
109
  .map((m) => {
99
110
  const content = m.content.toLowerCase();
100
- const hits = tokens.filter((t) => content.includes(t)).length;
101
- const nameHits = tokens.filter((t) => m.name.toLowerCase().includes(t)).length;
102
- const keywordScore = hits * 2 + nameHits * 3;
103
- if (keywordScore === 0)
111
+ const name = m.name.toLowerCase();
112
+ let score = 0;
113
+ for (const mat of matchers) {
114
+ let contentWeight = 0;
115
+ let nameWeight = 0;
116
+ if (mat.regex.test(content)) {
117
+ contentWeight = 2; // word boundary hit
118
+ }
119
+ else if (!mat.isShort && content.includes(mat.substring)) {
120
+ contentWeight = 1; // substring fallback (long tokens only)
121
+ }
122
+ if (mat.regex.test(name)) {
123
+ nameWeight = 3; // word boundary hit
124
+ }
125
+ else if (!mat.isShort && name.includes(mat.substring)) {
126
+ nameWeight = 1; // substring fallback (long tokens only)
127
+ }
128
+ score += contentWeight + nameWeight;
129
+ }
130
+ if (score === 0)
104
131
  return { memory: m, score: 0 };
105
- return { memory: m, score: keywordScore + (m.priority || 5) };
132
+ return { memory: m, score: score + (m.priority || 5) };
106
133
  })
107
134
  .filter((s) => s.score > 0)
108
135
  .sort((a, b) => b.score - a.score)
109
136
  .slice(0, options.limit)
110
- .map((s) => ({ ...s.memory, similarity: 0, _score: s.score, _fallback: "keyword" }));
137
+ .map((s) => ({
138
+ ...s.memory,
139
+ similarity: s.score / 10,
140
+ _score: s.score,
141
+ _fallback: "keyword",
142
+ }));
111
143
  }
112
144
  stats() {
113
145
  const all = [...this.memories.values()];
@@ -139,4 +171,43 @@ function cosineSimilarity(a, b) {
139
171
  const denom = Math.sqrt(normA) * Math.sqrt(normB);
140
172
  return denom === 0 ? 0 : dot / denom;
141
173
  }
174
+ /** Character 3-gram Jaccard similarity.
175
+ * Captures short technical terms ("AI", "DB", "CI") naturally
176
+ * embedded in n-grams. Falls back to exact match for strings too
177
+ * short to produce n-grams (≤2 chars). */
178
+ export function contentOverlap(a, b) {
179
+ const ngramsA = charNgrams(a, 3);
180
+ const ngramsB = charNgrams(b, 3);
181
+ // Both too short for 3-grams → exact match comparison
182
+ if (ngramsA.size === 0 && ngramsB.size === 0) {
183
+ return a.toLowerCase().trim() === b.toLowerCase().trim() ? 1.0 : 0.0;
184
+ }
185
+ if (ngramsA.size === 0 || ngramsB.size === 0)
186
+ return 0;
187
+ let intersection = 0;
188
+ for (const ng of ngramsA) {
189
+ if (ngramsB.has(ng))
190
+ intersection++;
191
+ }
192
+ return intersection / Math.min(ngramsA.size, ngramsB.size);
193
+ }
194
+ function charNgrams(text, n) {
195
+ const normalized = text.toLowerCase().replace(/\s+/g, " ");
196
+ const ngrams = new Set();
197
+ for (let i = 0; i <= normalized.length - n; i++) {
198
+ ngrams.add(normalized.slice(i, i + n));
199
+ }
200
+ return ngrams;
201
+ }
202
+ /** Unicode-safe string truncation using Intl.Segmenter (grapheme clusters).
203
+ * Never splits surrogate pairs, ZWJ sequences, or combining marks. */
204
+ export function safeTruncate(text, maxLen) {
205
+ if (text.length <= maxLen)
206
+ return text;
207
+ const segmenter = new Intl.Segmenter("en", { granularity: "grapheme" });
208
+ const segments = [...segmenter.segment(text)];
209
+ if (segments.length <= maxLen)
210
+ return text;
211
+ return segments.slice(0, maxLen).map((s) => s.segment).join("");
212
+ }
142
213
  //# sourceMappingURL=store.js.map