tsunami-memory 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +501 -0
  3. package/README.zh-CN.md +485 -0
  4. package/package.json +46 -0
  5. package/server/api.ts +125 -0
  6. package/server/mcp.ts +221 -0
  7. package/src/bun_memory_store.ts +340 -0
  8. package/src/classifier_keywords.ts +115 -0
  9. package/src/core/project_state.ts +88 -0
  10. package/src/index.ts +54 -0
  11. package/src/legacy_compat/tsunami_compat.ts +22 -0
  12. package/src/legacy_compat/tsunami_legacy_identity.ts +13 -0
  13. package/src/legacy_compat/tsunami_legacy_taxonomy.ts +197 -0
  14. package/src/memory_audit.ts +32 -0
  15. package/src/memory_conflict_resolver.ts +14 -0
  16. package/src/memory_fabric.ts +31 -0
  17. package/src/memory_manager.ts +10 -0
  18. package/src/memory_promotion.ts +22 -0
  19. package/src/memory_recovery.ts +14 -0
  20. package/src/memory_runtime.ts +7 -0
  21. package/src/migration.ts +163 -0
  22. package/src/provider.ts +68 -0
  23. package/src/runtime/checkpoints/durable_recovery.ts +24 -0
  24. package/src/runtime/paths.ts +11 -0
  25. package/src/storm/basins.ts +57 -0
  26. package/src/storm/boundary.ts +52 -0
  27. package/src/storm/budget.ts +42 -0
  28. package/src/storm/center.ts +396 -0
  29. package/src/storm/confidence.ts +88 -0
  30. package/src/storm/coverage.ts +44 -0
  31. package/src/storm/directive.ts +94 -0
  32. package/src/storm/gate.ts +43 -0
  33. package/src/storm/helpers.ts +172 -0
  34. package/src/storm/horizon.ts +52 -0
  35. package/src/storm/intake.ts +80 -0
  36. package/src/storm/mode.ts +21 -0
  37. package/src/storm/pressure.ts +56 -0
  38. package/src/storm/readiness.ts +29 -0
  39. package/src/storm/saturation.ts +45 -0
  40. package/src/storm/selection.ts +49 -0
  41. package/src/storm/signals.ts +105 -0
  42. package/src/storm/types.ts +216 -0
  43. package/src/tsunami_bun_backend.ts +705 -0
  44. package/src/tsunami_chinese_dialect.ts +19 -0
  45. package/src/tsunami_classifier.ts +137 -0
  46. package/src/tsunami_client.ts +710 -0
  47. package/src/tsunami_execution_gate.ts +232 -0
  48. package/src/tsunami_graph_runtime.ts +359 -0
  49. package/src/tsunami_identity.ts +35 -0
  50. package/src/tsunami_routing.ts +169 -0
  51. package/src/tsunami_runtime_graph_sync.ts +17 -0
  52. package/src/tsunami_schema.ts +403 -0
  53. package/src/tsunami_storage_paths.ts +8 -0
  54. package/src/tsunami_storm_center.ts +53 -0
@@ -0,0 +1,485 @@
1
+ <p align="center">
2
+ <img src="./assets/tsunami-banner.png" width="100%" alt="TSUNAMI ๆจชๅน…"/>
3
+ </p>
4
+
5
+ <h1 align="center">๐ŸŒŠ TSUNAMI</h1>
6
+
7
+ <p align="center">
8
+ <strong>้ขๅ‘ AI Agent ็š„ๆตทๆด‹่ฎฐๅฟ†่ฟ่กŒๆ—ถ</strong>
9
+ </p>
10
+
11
+ <p align="center">
12
+ Bun ๅŽŸ็”Ÿ ยท ้ฃŽๆšดไธญๅฟƒๆƒ…ๅขƒๅผ•ๆ“Ž ยท ็ƒญ+ๅ†ทๆฃ€็ดข ยท ็Ÿฅ่ฏ†ๅ›พ่ฐฑๅŒๆญฅ
13
+ </p>
14
+
15
+ <p align="center">
16
+ <img src="https://img.shields.io/badge/Bun-1.0%2B-fbf0df?style=for-the-badge&logo=bun&logoColor=000" alt="Bun"/>
17
+ <img src="https://img.shields.io/badge/SQLite-FTS5-003B57?style=for-the-badge&logo=sqlite&logoColor=white" alt="SQLite"/>
18
+ <img src="https://img.shields.io/badge/MCP-ๅ…ผๅฎน-7C3AED?style=for-the-badge" alt="MCP"/>
19
+ <img src="https://img.shields.io/badge/้›ถไพ่ต–-blue?style=for-the-badge" alt="้›ถไพ่ต–"/>
20
+ <img src="https://img.shields.io/badge/ๅ่ฎฎ-MIT-10B981?style=for-the-badge" alt="MIT"/>
21
+ </p>
22
+
23
+ <p align="center">
24
+ <a href="README.md">English</a>
25
+ </p>
26
+
27
+ ---
28
+
29
+ <div align="center">
30
+
31
+ ## ไธบไป€ไนˆๆ˜ฏ TSUNAMI๏ผŸ
32
+
33
+ </div>
34
+
35
+ ๅคงๅคšๆ•ฐ AI ่ฎฐๅฟ†็ณป็ปŸๆ˜ฏ**ๆ‰ๅนณ็š„**ใ€**ๆ— ็Šถๆ€็š„**ใ€**ไธŠไธ‹ๆ–‡่„†ๅผฑ็š„**ใ€‚
36
+
37
+ TSUNAMI ๆŠŠ่ฎฐๅฟ†่ง†ไธบ**ๆตๅŠจ็š„ๆด‹ๆต** โ€” ไธๆ˜ฏ้™ๆ€ๆ–‡ๆœฌ๏ผŒ่€Œๆ˜ฏ**ๅŠจ้‡**ใ€‚ๆฏๆก่ฎฐๅฟ†ๆบๅธฆ่ƒฝ้‡ใ€ๅฝขๆˆๅŽ‹ๅŠ›ใ€้“พๆŽฅ่ฏๆฎ๏ผŒๅนถๆฑ‡ๅ…ฅไธ€ไธชๅฎžๆ—ถๅปบๆจก Agent ่ฎค็Ÿฅ็Šถๆ€็š„้ฃŽๆšดไธญๅฟƒใ€‚
38
+
39
+ > TSUNAMI ไธๅญ˜ๅ‚จๆ–‡ๅญ—๏ผŒๅฎƒๅปบๆจก**ๅŠจ้‡**ใ€‚
40
+
41
+ ---
42
+
43
+ <div align="center">
44
+
45
+ ## ๐ŸŒŠ ๆžถๆž„่ฎพ่ฎก
46
+
47
+ </div>
48
+
49
+ ```mermaid
50
+ graph TD
51
+ TSUNAMI["๐ŸŒŠ TSUNAMI ่ฟ่กŒๆ—ถ"]
52
+
53
+ TSUNAMI --> Basin["็›†ๅœฐ<br/>ไธป้ข˜ๅŒบๅŸŸ"]
54
+ TSUNAMI --> Storm["๐ŸŒ€ ้ฃŽๆšดไธญๅฟƒ<br/>ๆƒ…ๅขƒๅผ•ๆ“Ž"]
55
+ TSUNAMI --> Hot["โšก ็ƒญๆฃ€็ดข<br/>SQLite FTS5"]
56
+ TSUNAMI --> Cold["โ„๏ธ ๅ†ทๆฃ€็ดข<br/>่ฏญไน‰ๅ›พ่ฐฑ"]
57
+ TSUNAMI --> Graph["๐Ÿง  ็Ÿฅ่ฏ†ๅ›พ่ฐฑ<br/>ไธ‰ๅ…ƒ็ป„ๅญ˜ๅ‚จ"]
58
+
59
+ Basin --> Project["project"]
60
+ Basin --> Feedback["feedback"]
61
+ Basin --> Reference["reference"]
62
+ Basin --> User["user"]
63
+
64
+ Storm --> Signals["ไฟกๅท่ƒฝ้‡"]
65
+ Storm --> Pressure["ๅŽ‹ๅŠ›่ฏ„ๅˆ†"]
66
+ Storm --> Gate["ๆ‰ง่กŒ้—จๆŽง"]
67
+ Storm --> Budget["้ข„็ฎ—ๆŽงๅˆถ"]
68
+
69
+ Hot --> FTS5["ไบšๆฏซ็ง’ๅ…จๆ–‡ๆœ็ดข"]
70
+ Cold --> Traversal["ๅ›พ่ฐฑ้ๅކ"]
71
+
72
+ Graph --> Sync["่ทจไผš่ฏๅŒๆญฅ"]
73
+ Graph --> Conflict["ๅ†ฒ็ชๆฃ€ๆต‹"]
74
+ Graph --> Evidence["่ฏๆฎ้“พๆŽฅ"]
75
+
76
+ style TSUNAMI fill:#0d3b66,stroke:#1a73e8,color:#e8f4f8
77
+ style Storm fill:#1a237e,stroke:#5c6bc0,color:#e8eaf6
78
+ style Basin fill:#0d3b66,stroke:#1a73e8,color:#e8f4f8
79
+ style Hot fill:#01579b,stroke:#0288d1,color:#e1f5fe
80
+ style Cold fill:#01579b,stroke:#0288d1,color:#e1f5fe
81
+ style Graph fill:#004d40,stroke:#00897b,color:#e0f2f1
82
+ ```
83
+
84
+ ---
85
+
86
+ <div align="center">
87
+
88
+ ## ๐Ÿงฉ ๆ ธๅฟƒ็ณป็ปŸ
89
+
90
+ </div>
91
+
92
+ <table>
93
+ <tr>
94
+ <td width="50%">
95
+
96
+ ### ๐ŸŒ€ ้ฃŽๆšดไธญๅฟƒ
97
+
98
+ **ๆดป่ทƒไฟกๅทๆฑ‡่šๅผ•ๆ“Žใ€‚**
99
+
100
+ ้ฃŽๆšดไธญๅฟƒๆŒ็ปญ่ฏ„ไผฐ Agent ็š„ไธŠไธ‹ๆ–‡ โ€” ๆต‹้‡ไฟกๅท่ƒฝ้‡ใ€่ฎก็ฎ—ๅŽ‹ๅŠ›่ฏ„ๅˆ†ใ€ๆฃ€ๆต‹้ฃŽๆšดๆจกๅผใ€ๅ‘ๅธƒๆ‰ง่กŒ้—จๆŽงใ€‚ๅฎƒๆ˜ฏไธ€ไธชๅฎžๆ—ถ่ฎค็Ÿฅไปช่กจ็›˜๏ผŒๅ‘Š่ฏ‰ Agent *ๅฝ“ๅ‰ไป€ไนˆๆœ€้‡่ฆ*ใ€‚
101
+
102
+ - ๅคšๅ› ็ด ๅŽ‹ๅŠ›ๅˆ†ๆž
103
+ - ๆ‰ง่กŒ้—จๆŽง๏ผš`proceed`๏ผˆๅ…จ้€Ÿ๏ผ‰/ `guarded`๏ผˆ่ฐจๆ…Ž๏ผ‰/ `hold`๏ผˆๆš‚ๅœ๏ผ‰
104
+ - ็ฝฎไฟกๅบฆไธŽๅฐฑ็ปชๅบฆ่ฏ„ไผฐ
105
+ - ๆŒ‰ไปปๅŠกๅˆ†้…้ข„็ฎ—
106
+
107
+ </td>
108
+ <td width="50%">
109
+
110
+ ### ๐ŸŒŠ ็›†ๅœฐไธŽๆด‹ๆต
111
+
112
+ **ๆŒ‰ไธป้ข˜็ป„็ป‡็š„่ฎฐๅฟ†ๆตใ€‚**
113
+
114
+ ่ฎฐๅฟ†้šๆด‹ๆตๅ˜ๅŒ–ๅœจ็›†ๅœฐ๏ผˆไธป้ข˜ๅŒบๅŸŸ๏ผ‰ไน‹้—ดๆตๅŠจใ€‚ๆฏไธช็›†ๅœฐ่ฟฝ่ธชไธ€ไธชๆดป่ทƒ็„ฆ็‚น๏ผŒ็ณป็ปŸ่‡ชๅŠจๅฐ†ๆ–ฐ่ฎฐๅฟ†ๅˆ†็ฑปๅˆฐๆญฃ็กฎ็š„็›†ๅœฐ/ๆด‹ๆตๅฏนใ€‚ไธŠไธ‹ๆ–‡ไธๆ˜ฏๅญ˜ๅ‚จ็š„ โ€” ๅฎƒๆ˜ฏ*ๆตๅŠจ็š„*ใ€‚
115
+
116
+ - 6 ไธช็›†ๅœฐ๏ผšepicenterใ€surfaceใ€faultlineใ€abyssใ€surgeใ€harbor
117
+ - 24 ไธชๅ…ทๅๆด‹ๆต๏ผŒๅฎŒๆ•ดๅˆ†็ฑปๆ˜ ๅฐ„
118
+ - ่‡ชๅŠจๆ–‡ๆœฌๅˆ†็ฑป
119
+ - ๅ…ผๅฎนๆ—ง็‰ˆ wing/room ๅ‘ฝๅ็ฉบ้—ด
120
+
121
+ </td>
122
+ </tr>
123
+
124
+ <tr>
125
+ <td width="50%">
126
+
127
+ ### โšก ็ƒญ + ๅ†ทๆฃ€็ดข
128
+
129
+ **ๅŒ้€š้“ๅ›žๆƒณๅผ•ๆ“Žใ€‚**
130
+
131
+ ็ƒญๆฃ€็ดข่ตฐ SQLite FTS5 ๅ…จๆ–‡ๆœ็ดข๏ผŒไบšๆฏซ็ง’็บงๅ“ๅบ”ใ€‚ๅ†ทๆฃ€็ดข้ๅކ็Ÿฅ่ฏ†ๅ›พ่ฐฑ๏ผŒ่ฟ›่กŒ่ฏญไน‰็บงๅ…ณ่”ๅ‘็Žฐใ€‚ไธคๆก้€š้“ๅง‹็ปˆๅฏ็”จ๏ผŒๆŒ‰ไธŠไธ‹ๆ–‡ๅŠ ๆƒใ€‚
132
+
133
+ - FTS5 ๅ…จๆ–‡ๆœ็ดข๏ผˆไบšๆฏซ็ง’็บง๏ผ‰
134
+ - ็Ÿฅ่ฏ†ๅ›พ่ฐฑ BFS ้ๅކ
135
+ - ่ทจ็›†ๅœฐ้šง้“ๅ‘็Žฐ
136
+ - ๆ‰€ๆœ‰ไธ‰ๅ…ƒ็ป„ๅธฆๆ—ถ้—ดๆœ‰ๆ•ˆๆ€ง่ฟฝ่ธช
137
+
138
+ </td>
139
+ <td width="50%">
140
+
141
+ ### ๐Ÿง  ่ฟ่กŒๆ—ถๅ›พ่ฐฑๅŒๆญฅ
142
+
143
+ **ๆŒไน…ๅŒ–ๅˆ†ๅธƒๅผ่ฎค็Ÿฅใ€‚**
144
+
145
+ ่ฎฐๅฟ†ไธๆ˜ฏๅญค็ซ‹็š„ โ€” ๅฎƒไปฌๆž„ๆˆไธ€ๅผ ๅ›พ่ฐฑใ€‚ๆฏๆก่ฎฐๅฟ†ๅฏไปฅ้“พๆŽฅๅˆฐ่ฏๆฎใ€่ทจไผš่ฏๅ…ณ่”ใ€ๅนถๆŽฅๅ—ๅ†ฒ็ชๆฃ€ๆต‹ใ€‚ๆฏๆฌกๅ†™ๅ…ฅ่‡ชๅŠจๅŒๆญฅๅ›พ่ฐฑใ€‚
146
+
147
+ - ่ทจไผš่ฏ่ฎฐๅฟ†่ฟž็ปญๆ€ง
148
+ - ๅ†ฒ็ชๆฃ€ๆต‹ไธŽ็ฝฎไฟกๅบฆ่ฐƒๆ•ด
149
+ - ่ฏๆฎ้“พๆŽฅๅˆฐๆ–‡ไปถใ€ๅฏน่ฏๅ’Œ้…็ฝฎ
150
+ - ไธ‰ๅ…ƒ็ป„ๅญ˜ๅ‚จๅธฆ็ฝฎไฟกๅบฆใ€ๆœ‰ๆ•ˆๆ€งๅ’Œๆบฏๆบ
151
+
152
+ </td>
153
+ </tr>
154
+ </table>
155
+
156
+ ---
157
+
158
+ <div align="center">
159
+
160
+ ## โšก ๅฟซ้€ŸไธŠๆ‰‹
161
+
162
+ </div>
163
+
164
+ ```bash
165
+ bun install
166
+ ```
167
+
168
+ ```typescript
169
+ import {
170
+ tsunamiAdd, tsunamiSearch,
171
+ buildTsunamiStormCenter, formatTsunamiStormCenterText,
172
+ } from './src/index.ts';
173
+
174
+ // ๅญ˜ๅ‚จ่ฎฐๅฟ†
175
+ const id = await tsunamiAdd('project', 'tasks', 'ๅฎŒๆˆไบ†่ฎค่ฏๆจกๅ—็š„ API ้‡ๆž„', 5);
176
+
177
+ // ๅ…จๆ–‡ๆœ็ดข โ€” ไบšๆฏซ็ง’็บง FTS5
178
+ const hits = await tsunamiSearch('้‡ๆž„', 'project', undefined, 5);
179
+
180
+ // ้ฃŽๆšดไธญๅฟƒ โ€” ๅฎžๆ—ถไธŠไธ‹ๆ–‡ๅˆ†ๆž
181
+ const storm = buildTsunamiStormCenter({ query: '็ปง็ปญๅผ€ๅ‘ๅทฅไฝœ' });
182
+ console.log(formatTsunamiStormCenterText(storm));
183
+ ```
184
+
185
+ > ้›ถๅค–้ƒจไพ่ต–ใ€‚ๆ— ้œ€ๅฏๅŠจๆœๅŠกๅ™จใ€‚SQLite ๅ†…็ฝฎไบŽ Bunใ€‚
186
+ > ้œ€่ฆ HTTP ๆˆ– MCP ๆ–นๅผๆŽฅๅ…ฅ๏ผŸ่ฏท็œ‹ไธ‹ๆ–น[ๆŽฅๅฃ](#-ๆŽฅๅฃ)ใ€‚
187
+
188
+ ---
189
+
190
+ <div align="center">
191
+
192
+ ## ๐Ÿ”Œ ๆŽฅๅฃ
193
+
194
+ </div>
195
+
196
+ TSUNAMI ๆไพ›ไธ‰็งๆŽฅๅฃใ€‚ๆŒ‰ไฝ ็š„ๆŠ€ๆœฏๆ ˆ้€‰ๆ‹ฉใ€‚
197
+
198
+ ---
199
+
200
+ ### ๐Ÿค– MCP ๅทฅๅ…ท โ€” Claude Codeใ€Cursorใ€Windsurf
201
+
202
+ ๅœจ `~/.claude/mcp.json` ไธญ้…็ฝฎไธ€ๆฌก๏ผš
203
+
204
+ ```json
205
+ {
206
+ "mcpServers": {
207
+ "tsunami": {
208
+ "command": "bun",
209
+ "args": ["run", "/path/to/TSUNAMI/server/mcp.ts"],
210
+ "env": { "TSUNAMI_HOME": "~/.tsunami" }
211
+ }
212
+ }
213
+ }
214
+ ```
215
+
216
+ MCP ๆœๅŠก่‡ชๅŠจๅฏๅŠจใ€‚ๅ…ซไธชๅทฅๅ…ทๅฏ็”จ๏ผš
217
+
218
+ <details open>
219
+ <summary><strong>๐ŸŒ€ tsunami_storm</strong> โ€” ๆž„ๅปบ้ฃŽๆšดไธญๅฟƒไธŠไธ‹ๆ–‡</summary>
220
+
221
+ ```json
222
+ { "query": "็ปง็ปญ API ๅผ€ๅ‘ๅทฅไฝœ" }
223
+ ```
224
+
225
+ ่ฟ”ๅ›žๆตๅ‘ใ€้ฃŽๆšดๆจกๅผใ€ๅŽ‹ๅŠ›็ญ‰็บงใ€ๆ‰ง่กŒ้—จๆŽงใ€้ข„็ฎ—ๅ’Œไผ˜ๅ…ˆ่กŒๅŠจๆŒ‡ไปคใ€‚
226
+
227
+ </details>
228
+
229
+ <details>
230
+ <summary><strong>๐ŸŒŠ tsunami_add</strong> โ€” ๅญ˜ๅ‚จ่ฎฐๅฟ†</summary>
231
+
232
+ ```json
233
+ { "content": "ๅ†ณๅฎš็”จ Redis ๅš็ผ“ๅญ˜", "wing": "decision", "energy": 4 }
234
+ ```
235
+
236
+ ่ฟ”ๅ›žๅ”ฏไธ€ `bunmem_xxx` IDใ€‚ๆ”ฏๆŒไธญๆ–‡ใ€emojiใ€ไปปๆ„ Unicodeใ€‚
237
+
238
+ </details>
239
+
240
+ <details>
241
+ <summary><strong>๐Ÿ” tsunami_search</strong> โ€” FTS5 ๅ…จๆ–‡ๆœ็ดข</summary>
242
+
243
+ ```json
244
+ { "query": "Redis ็ผ“ๅญ˜", "wing": "project", "limit": 5 }
245
+ ```
246
+
247
+ ไบšๆฏซ็ง’็บง SQLite FTS5 ๆœ็ดข๏ผŒๆ”ฏๆŒ wing/room ่ฟ‡ๆปคใ€‚
248
+
249
+ </details>
250
+
251
+ <details>
252
+ <summary><strong>๐Ÿ“‹ tsunami_recall</strong> โ€” ไธŠไธ‹ๆ–‡ๅ›žๆƒณ</summary>
253
+
254
+ ```json
255
+ { "wing": "project", "limit": 10 }
256
+ ```
257
+
258
+ ๆŒ‰ไธป้ข˜ๆ‹‰ๅ–่ฟ‘ๆœŸ่ฎฐๅฟ†๏ผŒๆŒ‰้‡่ฆๆ€งๅ’Œๆ—ถ้—ดๆŽ’ๅบใ€‚
259
+
260
+ </details>
261
+
262
+ <details>
263
+ <summary><strong>๐Ÿ“œ tsunami_timeline</strong> โ€” ๆ—ถ้—ด็บฟ</summary>
264
+
265
+ ```json
266
+ { "limit": 20 }
267
+ ```
268
+
269
+ ๆŒ‰ๆ—ถ้—ด้กบๅบๆŽ’ๅˆ—ๆ‰€ๆœ‰่ฎฐๅฟ†ใ€‚
270
+
271
+ </details>
272
+
273
+ <details>
274
+ <summary><strong>๐Ÿ““ tsunami_diary</strong> โ€” ไผš่ฏๆ—ฅๅฟ—</summary>
275
+
276
+ ```json
277
+ { "entry": "ไปŠๅคฉๆž„ๅปบไบ†่ฎค่ฏๆจกๅ—", "agent": "claude" }
278
+ ```
279
+
280
+ ่‡ชๅŠจๅŠ ๆ—ถ้—ดๆˆณ็š„ๆ—ฅ่ฎฐๆก็›ฎใ€‚
281
+
282
+ </details>
283
+
284
+ <details>
285
+ <summary><strong>๐Ÿ“Š tsunami_status</strong> โ€” ็ณป็ปŸๅฅๅบท</summary>
286
+
287
+ ```json
288
+ {}
289
+ ```
290
+
291
+ ่ฎฐๅฟ†ๆ•ฐ้‡ใ€็›†ๅœฐ็ปŸ่ฎกใ€ๅŽ็ซฏไฟกๆฏใ€‚
292
+
293
+ </details>
294
+
295
+ <details>
296
+ <summary><strong>๐Ÿ—‚๏ธ tsunami_wings</strong> โ€” ไธป้ข˜ๅˆ†็ฑป</summary>
297
+
298
+ ```json
299
+ {}
300
+ ```
301
+
302
+ ๆ‰€ๆœ‰็›†ๅœฐ/ๅŒบๅŸŸๅŠๆก็›ฎๆ•ฐ้‡ใ€‚
303
+
304
+ </details>
305
+
306
+ ---
307
+
308
+ ### ๐ŸŒ HTTP API โ€” ไปปไฝ•่ฏญ่จ€
309
+
310
+ ```bash
311
+ TSUNAMI_PORT=18904 TSUNAMI_HOME=~/.tsunami bun run server/api.ts
312
+ ```
313
+
314
+ | ๆ–นๆณ• | ็ซฏ็‚น | ็”จ้€” |
315
+ |--------|----------|---------|
316
+ | `POST` | `/add` | ๐ŸŒŠ ๅญ˜ๅ‚จ่ฎฐๅฟ† |
317
+ | `GET` | `/search` | ๐Ÿ” FTS5 ๅ…จๆ–‡ๆœ็ดข |
318
+ | `GET` | `/recall` | ๐Ÿ“‹ ไธŠไธ‹ๆ–‡ๅ›žๆƒณ |
319
+ | `GET` | `/storm` | ๐ŸŒ€ ๆž„ๅปบ้ฃŽๆšดไธญๅฟƒ |
320
+ | `GET` | `/status` | ๐Ÿ“Š ็ณป็ปŸๅฅๅบท |
321
+ | `GET` | `/timeline` | ๐Ÿ“œ ๆ—ถ้—ดๆŽ’ๅˆ— |
322
+ | `POST` | `/diary` | ๐Ÿ““ ไผš่ฏๆ—ฅๅฟ— |
323
+ | `GET` | `/health` | โœ… ๅญ˜ๆดปๆฃ€ๆŸฅ |
324
+
325
+ <table>
326
+ <tr><td width="33%">
327
+
328
+ **Shell**
329
+
330
+ ```bash
331
+ curl -X POST localhost:18904/add \
332
+ -H 'Content-Type: application/json' \
333
+ -d '{"wing":"project",
334
+ "content":"้‡ๆž„ไบ†่ฎค่ฏๆจกๅ—",
335
+ "energy":4}'
336
+ ```
337
+
338
+ </td><td width="33%">
339
+
340
+ **Python**
341
+
342
+ ```python
343
+ import requests
344
+ r = requests.post(
345
+ 'http://localhost:18904/add',
346
+ json={'wing': 'feedback',
347
+ 'content': '็”จๆˆทๅๅฅฝๆทฑ่‰ฒๆจกๅผ',
348
+ 'energy': 5}
349
+ )
350
+ ```
351
+
352
+ </td><td width="33%">
353
+
354
+ **TypeScript**
355
+
356
+ ```typescript
357
+ const r = await fetch(
358
+ 'http://localhost:18904/add', {
359
+ method: 'POST',
360
+ headers: {'Content-Type': 'application/json'},
361
+ body: JSON.stringify({
362
+ wing: 'reference',
363
+ content: 'Bun sqlite API ๆ–‡ๆกฃ',
364
+ energy: 3})
365
+ });
366
+ ```
367
+
368
+ </td></tr>
369
+ </table>
370
+
371
+ ---
372
+
373
+ ### ๐Ÿ“ฆ TypeScript SDK โ€” ็ผ–็จ‹ๅผ่ฐƒ็”จ
374
+
375
+ ```typescript
376
+ import {
377
+ tsunamiAdd, tsunamiSearch, tsunamiRecall,
378
+ tsunamiKgAdd, tsunamiKgQuery,
379
+ buildTsunamiStormCenter, formatTsunamiStormCenterText,
380
+ buildTsunamiExecutionGate, applyTsunamiExecutionGateToTool,
381
+ classifyMemory,
382
+ } from './src/index.ts';
383
+
384
+ const id = await tsunamiAdd('project', 'tasks', 'ๅฎŒๆˆ่ฎค่ฏๆจกๅ—้‡ๆž„', 5);
385
+ const hits = await tsunamiSearch('้‡ๆž„', 'project', undefined, 10);
386
+
387
+ const storm = buildTsunamiStormCenter({
388
+ projectDir: './my-project',
389
+ query: '็ปง็ปญๅผ€ๅ‘ๅทฅไฝœ',
390
+ });
391
+ console.log(formatTsunamiStormCenterText(storm));
392
+ ```
393
+
394
+ ---
395
+
396
+ <div align="center">
397
+
398
+ ## ๐Ÿค– ่‡ชๅŠจ่ฎฐๅฟ†
399
+
400
+ </div>
401
+
402
+ ้ป˜่ฎคๆƒ…ๅ†ตไธ‹ TSUNAMI ไธบ**ๆ˜พๅผ่ฐƒ็”จ** โ€” ไฝ ๅ†ณๅฎšไฝ•ๆ—ถๅญ˜ๅ‚จๆˆ–ๅ›žๆƒณใ€‚่ฆๅ…ๆ‰‹ๅŠจ่ฎฐๅฟ†๏ผŒๅฏ้€š่ฟ‡ Claude Code hooks ๆŽฅๅ…ฅ็”Ÿๅ‘ฝๅ‘จๆœŸใ€‚
403
+
404
+ **ๅ‰ๆ๏ผš** HTTP API ไปฅๅฎˆๆŠค่ฟ›็จ‹่ฟ่กŒ๏ผˆ`bun run server/api.ts &` ๆˆ– PM2/launchd๏ผ‰ใ€‚
405
+
406
+ ### ไผš่ฏๅฏๅŠจ ยท ไธŠไธ‹ๆ–‡ๆณจๅ…ฅ
407
+
408
+ Claude ๅฏๅŠจๆ—ถ่‡ชๅŠจๆณจๅ…ฅ้ฃŽๆšดไธญๅฟƒไธŠไธ‹ๆ–‡๏ผš
409
+
410
+ ```json
411
+ {
412
+ "hooks": {
413
+ "SessionStart": [{
414
+ "matcher": "",
415
+ "hooks": [{
416
+ "type": "command",
417
+ "command": "STORM=$(curl -s 'http://localhost:18904/storm' | python3 -c \"import sys,json; d=json.load(sys.stdin); t=d.get('storm',{}).get('text',''); print(t[:3000])\" 2>/dev/null); if [ -n \"$STORM\" ]; then echo \"$STORM\"; fi"
418
+ }]
419
+ }]
420
+ }
421
+ }
422
+ ```
423
+
424
+ ### ไผš่ฏ็ป“ๆŸ ยท ่‡ชๅŠจๆ—ฅ่ฎฐ
425
+
426
+ ๆฏๆฌกไผš่ฏ็ป“ๆŸๅŽ่‡ชๅŠจ่ฎฐๅฝ•๏ผš
427
+
428
+ ```json
429
+ {
430
+ "hooks": {
431
+ "Stop": [{
432
+ "matcher": "",
433
+ "hooks": [{
434
+ "type": "command",
435
+ "command": "curl -s -X POST http://localhost:18904/diary -H 'Content-Type: application/json' -d '{\"entry\":\"ไผš่ฏ็ป“ๆŸ\",\"agent\":\"claude\",\"wing\":\"session\",\"importance\":3}' > /dev/null 2>&1"
436
+ }]
437
+ }]
438
+ }
439
+ }
440
+ ```
441
+
442
+ ### ๆฏๆฌก่พ“ๅ…ฅ ยท ๅ†ณ็ญ–ๆ•่Žท
443
+
444
+ ๆฃ€ๆต‹ๅˆฐ `ๅ†ณๅฎš`ใ€`ๅˆๅนถ`ใ€`้ƒจ็ฝฒ`ใ€`ๅ‘ๅธƒ`ใ€`ไธŠ็บฟ` ็ญ‰ๅ…ณ้”ฎ่ฏๆ—ถ่‡ชๅŠจๅฝ’ๆกฃๅˆฐๅ†ณ็ญ–็›†ๅœฐ๏ผš
445
+
446
+ ```json
447
+ {
448
+ "hooks": {
449
+ "UserPromptSubmit": [{
450
+ "matcher": "",
451
+ "hooks": [{
452
+ "type": "command",
453
+ "command": "PROMPT=$(cat); if echo \"$PROMPT\" | grep -qiE 'decid|chose|finaliz|merge|deploy|releas|shipp|ๅ†ณๅฎš|้€‰ๆ‹ฉ|ๅˆๅนถ|้ƒจ็ฝฒ|ๅ‘ๅธƒ|ไธŠ็บฟ'; then curl -s -X POST http://localhost:18904/add -H 'Content-Type: application/json' -d \"{\\\"wing\\\":\\\"decision\\\",\\\"content\\\":\\\"$(echo $PROMPT | tr '\\\"' ' ' | head -c 500)\\\",\\\"energy\\\":4}\" > /dev/null 2>&1; fi"
454
+ }]
455
+ }]
456
+ }
457
+ }
458
+ ```
459
+
460
+ ---
461
+
462
+ <div align="center">
463
+
464
+ ## โš™๏ธ ็Žฏๅขƒๅ˜้‡
465
+
466
+ </div>
467
+
468
+ | ๅ˜้‡ | ้ป˜่ฎคๅ€ผ | ่ฏดๆ˜Ž |
469
+ |----------|---------|-------------|
470
+ | `TSUNAMI_HOME` | `.tsunami` | ๆ•ฐๆฎๅญ˜ๅ‚จ็›ฎๅฝ• |
471
+ | `TSUNAMI_PORT` | `18904` | HTTP API ็ซฏๅฃ |
472
+ | `TSUNAMI_STORM_THRESHOLD` | `0.7` | ้ฃŽๆšดไฟกๅทๆœ€ไฝŽ่ƒฝ้‡้˜ˆๅ€ผ |
473
+ | `TSUNAMI_BUDGET_STEPS` | `99` | ้ป˜่ฎคๆ‰ง่กŒๆญฅๆ•ฐ้ข„็ฎ— |
474
+
475
+ ---
476
+
477
+ <div align="center">
478
+
479
+ ## ๐Ÿ“„ ๅ่ฎฎ
480
+
481
+ </div>
482
+
483
+ <p align="center">
484
+ MIT ยฉ TSUNAMI Memory System
485
+ </p>
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "tsunami-memory",
3
+ "version": "1.0.0",
4
+ "description": "TSUNAMI โ€” Bun-native oceanic memory system with basin/current flow, storm center, hot+cold retrieval, knowledge graph sync, and evidence linking.",
5
+ "main": "src/index.ts",
6
+ "files": [
7
+ "src/**/*.ts",
8
+ "server/**/*.ts",
9
+ "README.md"
10
+ ],
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/tsunami-memory/tsunami.git"
14
+ },
15
+ "bugs": {
16
+ "url": "https://github.com/tsunami-memory/tsunami/issues"
17
+ },
18
+ "type": "module",
19
+ "scripts": {
20
+ "start": "bun run server/api.ts",
21
+ "typecheck": "tsc --noEmit",
22
+ "smoke": "bun run src/index.ts"
23
+ },
24
+ "keywords": [
25
+ "memory",
26
+ "agent",
27
+ "ai",
28
+ "tsunami",
29
+ "bun",
30
+ "sqlite",
31
+ "knowledge-graph",
32
+ "storm-center",
33
+ "retrieval"
34
+ ],
35
+ "author": "TSUNAMI Memory System",
36
+ "license": "MIT",
37
+ "dependencies": {},
38
+ "devDependencies": {
39
+ "typescript": "^5.0.0",
40
+ "@types/node": "^20.0.0",
41
+ "bun-types": "^1.0.0"
42
+ },
43
+ "engines": {
44
+ "bun": ">=1.0.0"
45
+ }
46
+ }
package/server/api.ts ADDED
@@ -0,0 +1,125 @@
1
+ /**
2
+ * TSUNAMI HTTP API Server โ€” universal memory backend for any agent
3
+ *
4
+ * Start: bun run server/api.ts
5
+ * Port: 18904 (configurable via TSUNAMI_PORT)
6
+ *
7
+ * Endpoints:
8
+ * POST /add โ€” Add memory
9
+ * GET /search?q= โ€” Search memories
10
+ * GET /recall?wing=&limit= โ€” Recall by context
11
+ * GET /storm?project=&query= โ€” Storm center
12
+ * GET /status โ€” System status
13
+ * GET /timeline?limit= โ€” Timeline
14
+ * POST /diary โ€” Write diary entry
15
+ * GET /health โ€” Health check
16
+ */
17
+
18
+ const PORT = parseInt(process.env.TSUNAMI_PORT || '18904');
19
+
20
+ // Lightweight HTTP server โ€” zero external deps (Bun native)
21
+ const server = Bun.serve({
22
+ port: PORT,
23
+ async fetch(req) {
24
+ const url = new URL(req.url);
25
+ const cors = {
26
+ 'Access-Control-Allow-Origin': '*',
27
+ 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
28
+ 'Access-Control-Allow-Headers': 'Content-Type',
29
+ };
30
+
31
+ if (req.method === 'OPTIONS') return new Response(null, { headers: cors });
32
+
33
+ try {
34
+ // Dynamic import to defer heavy module loading
35
+ const { tsunamiAdd, tsunamiSearch, tsunamiRecall, tsunamiStatus, tsunamiTimeline, tsunamiDiary } = await import('../src/tsunami_client');
36
+ const { buildTsunamiStormCenter, formatTsunamiStormCenterText } = await import('../src/tsunami_storm_center');
37
+
38
+ // โ”€โ”€ Health โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
39
+ if (url.pathname === '/health') {
40
+ return json({ ok: true, service: 'tsunami-memory', port: PORT }, cors);
41
+ }
42
+
43
+ // โ”€โ”€ POST /add โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
44
+ if (url.pathname === '/add' && req.method === 'POST') {
45
+ const body = await req.json().catch(() => ({}));
46
+ const { wing, room, content, energy } = body;
47
+ if (!content) return json({ error: 'content required' }, cors, 400);
48
+ const result = await tsunamiAdd(wing || 'default', room || 'general', content, energy || 3);
49
+ return json({ ok: true, result }, cors);
50
+ }
51
+
52
+ // โ”€โ”€ GET /search?q=&wing=&limit= โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
53
+ if (url.pathname === '/search' && req.method === 'GET') {
54
+ const q = url.searchParams.get('q') || '';
55
+ const wing = url.searchParams.get('wing') || undefined;
56
+ const limit = parseInt(url.searchParams.get('limit') || '5');
57
+ if (!q) return json({ error: 'q required' }, cors, 400);
58
+ const result = await tsunamiSearch(q, wing, undefined, limit);
59
+ return json({ ok: true, query: q, result }, cors);
60
+ }
61
+
62
+ // โ”€โ”€ GET /recall?wing=&room=&limit= โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
63
+ if (url.pathname === '/recall' && req.method === 'GET') {
64
+ const wing = url.searchParams.get('wing') || undefined;
65
+ const room = url.searchParams.get('room') || undefined;
66
+ const limit = parseInt(url.searchParams.get('limit') || '10');
67
+ const result = await tsunamiRecall(wing, room, limit);
68
+ return json({ ok: true, result }, cors);
69
+ }
70
+
71
+ // โ”€โ”€ GET /storm?project=&query= โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
72
+ if (url.pathname === '/storm' && req.method === 'GET') {
73
+ const projectDir = url.searchParams.get('project') || process.cwd();
74
+ const query = url.searchParams.get('query') || '';
75
+ const center = buildTsunamiStormCenter({ projectDir, query, refreshGraph: false });
76
+ return json({ ok: true, storm: { flow: center.flow, mode: center.stormMode, pressure: center.stormPressure, gate: center.stormGate, budget: center.stormBudget, text: formatTsunamiStormCenterText(center) } }, cors);
77
+ }
78
+
79
+ // โ”€โ”€ GET /status โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
80
+ if (url.pathname === '/status' && req.method === 'GET') {
81
+ const result = await tsunamiStatus();
82
+ return json({ ok: true, ...result }, cors);
83
+ }
84
+
85
+ // โ”€โ”€ GET /timeline?limit= โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
86
+ if (url.pathname === '/timeline' && req.method === 'GET') {
87
+ const limit = parseInt(url.searchParams.get('limit') || '20');
88
+ const result = await tsunamiTimeline(limit);
89
+ return json({ ok: true, timeline: result }, cors);
90
+ }
91
+
92
+ // โ”€โ”€ POST /diary โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
93
+ if (url.pathname === '/diary' && req.method === 'POST') {
94
+ const body = await req.json().catch(() => ({}));
95
+ const { entry, agent, wing, importance } = body;
96
+ if (!entry) return json({ error: 'entry required' }, cors, 400);
97
+ const result = await tsunamiDiary(entry, agent || 'external', wing || 'diary', importance || 3);
98
+ return json({ ok: true, result }, cors);
99
+ }
100
+
101
+ // โ”€โ”€ GET / โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
102
+ if (url.pathname === '/' && req.method === 'GET') {
103
+ return json({
104
+ service: 'TSUNAMI Memory API',
105
+ version: '1.0.0',
106
+ endpoints: ['/health', '/add', '/search', '/recall', '/storm', '/status', '/timeline', '/diary'],
107
+ }, cors);
108
+ }
109
+
110
+ return new Response('Not Found', { status: 404, headers: cors });
111
+ } catch (err: any) {
112
+ return json({ error: err?.message || String(err) }, cors, 500);
113
+ }
114
+ },
115
+ });
116
+
117
+ function json(data: any, headers: Record<string, string>, status = 200): Response {
118
+ return new Response(JSON.stringify(data, null, 2), {
119
+ status,
120
+ headers: { ...headers, 'Content-Type': 'application/json' },
121
+ });
122
+ }
123
+
124
+ console.log(`๐ŸŒŠ TSUNAMI Memory API running on http://localhost:${PORT}`);
125
+ console.log(` Try: curl http://localhost:${PORT}/`);