toolnet-memory 0.2.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 (329) hide show
  1. package/.env.example +28 -0
  2. package/README.md +147 -0
  3. package/bin/toolnet-memory +415 -0
  4. package/dist/packages/cli/commands.js +1 -0
  5. package/dist/packages/cli/index.js +1 -0
  6. package/dist/packages/sdk/client.js +78 -0
  7. package/dist/packages/sdk/index.js +1 -0
  8. package/dist/packages/sdk/types.js +1 -0
  9. package/dist/src/api/index.js +1 -0
  10. package/dist/src/api/routes/health.js +1 -0
  11. package/dist/src/api/routes/index.js +1 -0
  12. package/dist/src/api/routes/memory.js +1 -0
  13. package/dist/src/api/routes/projects.js +1 -0
  14. package/dist/src/api/routes/search.js +1 -0
  15. package/dist/src/api/server.js +1 -0
  16. package/dist/src/capture/activity-capture.js +21 -0
  17. package/dist/src/capture/command-capture.js +12 -0
  18. package/dist/src/capture/error-capture.js +14 -0
  19. package/dist/src/capture/event-deduplicator.js +28 -0
  20. package/dist/src/capture/event-queue.js +20 -0
  21. package/dist/src/capture/file-capture.js +23 -0
  22. package/dist/src/capture/index.js +8 -0
  23. package/dist/src/capture/session-capture.js +18 -0
  24. package/dist/src/capture/tool-capture.js +13 -0
  25. package/dist/src/code-intelligence/analysis/analysis-engine.js +26 -0
  26. package/dist/src/code-intelligence/analysis/dead-code-analyzer.js +127 -0
  27. package/dist/src/code-intelligence/analysis/dependency-analyzer.js +66 -0
  28. package/dist/src/code-intelligence/analysis/index.js +4 -0
  29. package/dist/src/code-intelligence/analysis/types.js +1 -0
  30. package/dist/src/code-intelligence/architecture/architecture-engine.js +48 -0
  31. package/dist/src/code-intelligence/architecture/clusters.js +322 -0
  32. package/dist/src/code-intelligence/architecture/entry-points.js +150 -0
  33. package/dist/src/code-intelligence/architecture/hotspots.js +136 -0
  34. package/dist/src/code-intelligence/architecture/index.js +6 -0
  35. package/dist/src/code-intelligence/architecture/layers.js +197 -0
  36. package/dist/src/code-intelligence/architecture/types.js +1 -0
  37. package/dist/src/code-intelligence/chunks/index.js +2 -0
  38. package/dist/src/code-intelligence/chunks/smart-chunker.js +125 -0
  39. package/dist/src/code-intelligence/chunks/types.js +1 -0
  40. package/dist/src/code-intelligence/git/git-diff.js +109 -0
  41. package/dist/src/code-intelligence/git/index.js +1 -0
  42. package/dist/src/code-intelligence/graph/architecture.js +26 -0
  43. package/dist/src/code-intelligence/graph/graph-builder.js +213 -0
  44. package/dist/src/code-intelligence/graph/graph-store.js +57 -0
  45. package/dist/src/code-intelligence/graph/index.js +1 -0
  46. package/dist/src/code-intelligence/graph/relationships.js +1 -0
  47. package/dist/src/code-intelligence/graph/trace.js +65 -0
  48. package/dist/src/code-intelligence/impact/blast-radius.js +160 -0
  49. package/dist/src/code-intelligence/impact/change-mapper.js +69 -0
  50. package/dist/src/code-intelligence/impact/edit-tool-detector.js +92 -0
  51. package/dist/src/code-intelligence/impact/impact-analyzer.js +60 -0
  52. package/dist/src/code-intelligence/impact/impact-guard.js +33 -0
  53. package/dist/src/code-intelligence/impact/index.js +5 -0
  54. package/dist/src/code-intelligence/incremental/file-hash.js +8 -0
  55. package/dist/src/code-intelligence/incremental/incremental-indexer.js +106 -0
  56. package/dist/src/code-intelligence/incremental/manifest-builder.js +19 -0
  57. package/dist/src/code-intelligence/incremental/manifest.js +31 -0
  58. package/dist/src/code-intelligence/index.js +23 -0
  59. package/dist/src/code-intelligence/indexer/file-watcher.js +1 -0
  60. package/dist/src/code-intelligence/indexer/incremental-indexer.js +1 -0
  61. package/dist/src/code-intelligence/indexer/index.js +1 -0
  62. package/dist/src/code-intelligence/indexer/repository-indexer.js +31 -0
  63. package/dist/src/code-intelligence/indexer/repository-scanner.js +50 -0
  64. package/dist/src/code-intelligence/parsers/index.js +1 -0
  65. package/dist/src/code-intelligence/parsers/tree-sitter/index.js +1 -0
  66. package/dist/src/code-intelligence/parsers/tree-sitter/languages.js +1 -0
  67. package/dist/src/code-intelligence/parsers/tree-sitter/parser.js +1 -0
  68. package/dist/src/code-intelligence/parsers/typescript-parser.js +190 -0
  69. package/dist/src/code-intelligence/query/graph-query-engine.js +275 -0
  70. package/dist/src/code-intelligence/query/index.js +2 -0
  71. package/dist/src/code-intelligence/query/types.js +1 -0
  72. package/dist/src/code-intelligence/resolution/index.js +2 -0
  73. package/dist/src/code-intelligence/resolution/types.js +1 -0
  74. package/dist/src/code-intelligence/resolution/typescript-resolver.js +316 -0
  75. package/dist/src/code-intelligence/rich/index.js +1 -0
  76. package/dist/src/code-intelligence/rich/rich-graph-enricher.js +463 -0
  77. package/dist/src/code-intelligence/semantic/index.js +2 -0
  78. package/dist/src/code-intelligence/semantic/semantic-code-engine.js +213 -0
  79. package/dist/src/code-intelligence/semantic/source-priority.js +22 -0
  80. package/dist/src/code-intelligence/symbols/index.js +1 -0
  81. package/dist/src/code-intelligence/symbols/reference-resolver.js +21 -0
  82. package/dist/src/code-intelligence/symbols/symbol-extractor.js +1 -0
  83. package/dist/src/code-intelligence/test-analysis.js +72 -0
  84. package/dist/src/code-intelligence/test-architecture.js +67 -0
  85. package/dist/src/code-intelligence/test-impact.js +47 -0
  86. package/dist/src/code-intelligence/test-incremental.js +24 -0
  87. package/dist/src/code-intelligence/test-index.js +39 -0
  88. package/dist/src/code-intelligence/test-resolution.js +54 -0
  89. package/dist/src/code-intelligence/test-rich-graph.js +48 -0
  90. package/dist/src/code-intelligence/test-semantic.js +57 -0
  91. package/dist/src/code-intelligence/test-visualization.js +36 -0
  92. package/dist/src/code-intelligence/types.js +1 -0
  93. package/dist/src/code-intelligence/visualization/index.js +2 -0
  94. package/dist/src/code-intelligence/visualization/types.js +1 -0
  95. package/dist/src/code-intelligence/visualization/visualization-builder.js +104 -0
  96. package/dist/src/core/config.js +66 -0
  97. package/dist/src/core/global-env.js +70 -0
  98. package/dist/src/core/importance.js +30 -0
  99. package/dist/src/core/index.js +5 -0
  100. package/dist/src/core/memory-engine.js +183 -0
  101. package/dist/src/core/project-manager.js +243 -0
  102. package/dist/src/core/types.js +1 -0
  103. package/dist/src/embeddings/batch-embedder.js +1 -0
  104. package/dist/src/embeddings/cache.js +1 -0
  105. package/dist/src/embeddings/embedder.js +51 -0
  106. package/dist/src/embeddings/index.js +4 -0
  107. package/dist/src/embeddings/local.js +37 -0
  108. package/dist/src/embeddings/provider.js +1 -0
  109. package/dist/src/embeddings/remote.js +76 -0
  110. package/dist/src/embeddings/test-connection.js +16 -0
  111. package/dist/src/hooks/after-edit.js +3 -0
  112. package/dist/src/hooks/after-tool.js +3 -0
  113. package/dist/src/hooks/auto-context.js +68 -0
  114. package/dist/src/hooks/auto-impact-guard.js +94 -0
  115. package/dist/src/hooks/auto-retrieval.js +27 -0
  116. package/dist/src/hooks/before-agent.js +18 -0
  117. package/dist/src/hooks/before-compact.js +3 -0
  118. package/dist/src/hooks/before-edit.js +20 -0
  119. package/dist/src/hooks/index.js +11 -0
  120. package/dist/src/hooks/runtime.js +110 -0
  121. package/dist/src/hooks/session-end.js +3 -0
  122. package/dist/src/hooks/session-start.js +3 -0
  123. package/dist/src/index.js +22 -0
  124. package/dist/src/mcp/bootstrap.js +68 -0
  125. package/dist/src/mcp/context.js +1 -0
  126. package/dist/src/mcp/index.js +3 -0
  127. package/dist/src/mcp/server.js +45 -0
  128. package/dist/src/mcp/tools/analyze-impact.js +41 -0
  129. package/dist/src/mcp/tools/dead-code.js +55 -0
  130. package/dist/src/mcp/tools/find-callers.js +24 -0
  131. package/dist/src/mcp/tools/find-dependencies.js +57 -0
  132. package/dist/src/mcp/tools/find-symbol.js +7 -0
  133. package/dist/src/mcp/tools/get-architecture.js +11 -0
  134. package/dist/src/mcp/tools/graph-dependents.js +24 -0
  135. package/dist/src/mcp/tools/graph-neighborhood.js +58 -0
  136. package/dist/src/mcp/tools/graph-path.js +43 -0
  137. package/dist/src/mcp/tools/graph-query-utils.js +32 -0
  138. package/dist/src/mcp/tools/impact-guard.js +34 -0
  139. package/dist/src/mcp/tools/index-repository.js +1 -0
  140. package/dist/src/mcp/tools/index.js +20 -0
  141. package/dist/src/mcp/tools/memory-decisions.js +1 -0
  142. package/dist/src/mcp/tools/memory-forget.js +14 -0
  143. package/dist/src/mcp/tools/memory-recent.js +1 -0
  144. package/dist/src/mcp/tools/memory-remember.js +33 -0
  145. package/dist/src/mcp/tools/memory-rules.js +1 -0
  146. package/dist/src/mcp/tools/memory-search.js +18 -0
  147. package/dist/src/mcp/tools/memory-todos.js +1 -0
  148. package/dist/src/mcp/tools/project-context.js +25 -0
  149. package/dist/src/mcp/tools/search-code.js +21 -0
  150. package/dist/src/mcp/tools/semantic-code-search.js +33 -0
  151. package/dist/src/mcp/tools/snapshot-create.js +13 -0
  152. package/dist/src/mcp/tools/snapshot-list.js +7 -0
  153. package/dist/src/mcp/tools/snapshot-restore.js +13 -0
  154. package/dist/src/mcp/tools/trace-calls.js +37 -0
  155. package/dist/src/memory/activity.js +5 -0
  156. package/dist/src/memory/conflict-detector.js +105 -0
  157. package/dist/src/memory/consolidator.js +104 -0
  158. package/dist/src/memory/decay.js +59 -0
  159. package/dist/src/memory/decisions.js +3 -0
  160. package/dist/src/memory/deduplicate.js +25 -0
  161. package/dist/src/memory/index.js +11 -0
  162. package/dist/src/memory/maintenance.js +16 -0
  163. package/dist/src/memory/remember.js +3 -0
  164. package/dist/src/memory/rules.js +3 -0
  165. package/dist/src/memory/search.js +3 -0
  166. package/dist/src/memory/summaries.js +1 -0
  167. package/dist/src/memory/todos.js +3 -0
  168. package/dist/src/processor/decision-extractor.js +13 -0
  169. package/dist/src/processor/importance-scorer.js +22 -0
  170. package/dist/src/processor/index.js +7 -0
  171. package/dist/src/processor/memory-extractor.js +59 -0
  172. package/dist/src/processor/memory-processor.js +105 -0
  173. package/dist/src/processor/rule-extractor.js +13 -0
  174. package/dist/src/processor/summarizer.js +71 -0
  175. package/dist/src/processor/todo-extractor.js +12 -0
  176. package/dist/src/production/config-check.js +34 -0
  177. package/dist/src/production/doctor.js +58 -0
  178. package/dist/src/production/full-index.js +114 -0
  179. package/dist/src/production/health.js +58 -0
  180. package/dist/src/production/index-pipeline.js +151 -0
  181. package/dist/src/production/index.js +4 -0
  182. package/dist/src/production/project-lock.js +95 -0
  183. package/dist/src/production/project-status.js +16 -0
  184. package/dist/src/production/recovery.js +15 -0
  185. package/dist/src/production/snapshot-cli.js +58 -0
  186. package/dist/src/project-manual/cli.js +77 -0
  187. package/dist/src/project-manual/index.js +2 -0
  188. package/dist/src/project-manual/manager.js +147 -0
  189. package/dist/src/project-manual/types.js +1 -0
  190. package/dist/src/retrieval/bm25/index.js +1 -0
  191. package/dist/src/retrieval/bm25/search.js +1 -0
  192. package/dist/src/retrieval/bm25.js +30 -0
  193. package/dist/src/retrieval/context-budget.js +1 -0
  194. package/dist/src/retrieval/context-builder.js +22 -0
  195. package/dist/src/retrieval/graph/index.js +1 -0
  196. package/dist/src/retrieval/graph/search.js +1 -0
  197. package/dist/src/retrieval/hybrid/hybrid-search.js +1 -0
  198. package/dist/src/retrieval/hybrid/index.js +1 -0
  199. package/dist/src/retrieval/hybrid-search.js +68 -0
  200. package/dist/src/retrieval/importance.js +16 -0
  201. package/dist/src/retrieval/index.js +12 -0
  202. package/dist/src/retrieval/query-analyzer.js +32 -0
  203. package/dist/src/retrieval/query-classifier.js +1 -0
  204. package/dist/src/retrieval/query-expansion.js +1 -0
  205. package/dist/src/retrieval/recency.js +12 -0
  206. package/dist/src/retrieval/reranker/index.js +1 -0
  207. package/dist/src/retrieval/reranker/reranker.js +1 -0
  208. package/dist/src/retrieval/retrieval-engine.js +17 -0
  209. package/dist/src/retrieval/tokenizer.js +9 -0
  210. package/dist/src/retrieval/type-priority.js +10 -0
  211. package/dist/src/retrieval/types.js +1 -0
  212. package/dist/src/retrieval/vector/index.js +4 -0
  213. package/dist/src/retrieval/vector/metadata-filter.js +1 -0
  214. package/dist/src/retrieval/vector/persistence.js +67 -0
  215. package/dist/src/retrieval/vector/search.js +12 -0
  216. package/dist/src/retrieval/vector/test-persistence.js +36 -0
  217. package/dist/src/retrieval/vector/upsert.js +40 -0
  218. package/dist/src/retrieval/vector/vector-store.js +89 -0
  219. package/dist/src/retrieval/vector-hybrid-engine.js +91 -0
  220. package/dist/src/runtime/bootstrap.js +28 -0
  221. package/dist/src/runtime/graceful.js +17 -0
  222. package/dist/src/runtime/index.js +3 -0
  223. package/dist/src/runtime/toolnet-memory-runtime.js +156 -0
  224. package/dist/src/security/encryption.js +1 -0
  225. package/dist/src/security/file-filter.js +30 -0
  226. package/dist/src/security/index.js +3 -0
  227. package/dist/src/security/sanitizer.js +49 -0
  228. package/dist/src/security/secret-scanner.js +56 -0
  229. package/dist/src/session/agy/adapter.js +159 -0
  230. package/dist/src/session/agy/cli.js +87 -0
  231. package/dist/src/session/agy/hook-installer.js +62 -0
  232. package/dist/src/session/agy/hook.js +167 -0
  233. package/dist/src/session/agy/index.js +5 -0
  234. package/dist/src/session/agy/project-resolver.js +27 -0
  235. package/dist/src/session/agy/recovery.js +112 -0
  236. package/dist/src/session/agy/transcript.js +191 -0
  237. package/dist/src/session/codex/adapter.js +138 -0
  238. package/dist/src/session/codex/cli.js +236 -0
  239. package/dist/src/session/codex/context-hook-installer.js +70 -0
  240. package/dist/src/session/codex/context-hook.js +69 -0
  241. package/dist/src/session/codex/discovery.js +138 -0
  242. package/dist/src/session/codex/index.js +6 -0
  243. package/dist/src/session/codex/notify-installer.js +135 -0
  244. package/dist/src/session/codex/project-resolver.js +25 -0
  245. package/dist/src/session/codex/recovery.js +27 -0
  246. package/dist/src/session/codex/rollout.js +186 -0
  247. package/dist/src/session/core.js +239 -0
  248. package/dist/src/session/identity.js +57 -0
  249. package/dist/src/session/index.js +9 -0
  250. package/dist/src/session/learner/cli.js +62 -0
  251. package/dist/src/session/learner/extractor.js +461 -0
  252. package/dist/src/session/learner/index.js +4 -0
  253. package/dist/src/session/learner/journal.js +159 -0
  254. package/dist/src/session/learner/learner.js +124 -0
  255. package/dist/src/session/learner/types.js +1 -0
  256. package/dist/src/session/opencode/adapter.js +553 -0
  257. package/dist/src/session/opencode/cli.js +121 -0
  258. package/dist/src/session/opencode/index.js +2 -0
  259. package/dist/src/session/opencode/plugin-installer.js +230 -0
  260. package/dist/src/session/store.js +242 -0
  261. package/dist/src/session/types.js +1 -0
  262. package/dist/src/session/utils.js +47 -0
  263. package/dist/src/session/wal.js +303 -0
  264. package/dist/src/snapshot/index.js +2 -0
  265. package/dist/src/snapshot/manager.js +130 -0
  266. package/dist/src/snapshot/test-snapshot.js +28 -0
  267. package/dist/src/snapshot/types.js +1 -0
  268. package/dist/src/storage/architecture-store.js +37 -0
  269. package/dist/src/storage/cleanup-health.js +20 -0
  270. package/dist/src/storage/code-analysis-store.js +35 -0
  271. package/dist/src/storage/code-chunk-store.js +25 -0
  272. package/dist/src/storage/code-graph-store.js +24 -0
  273. package/dist/src/storage/code-manifest-store.js +24 -0
  274. package/dist/src/storage/code-vector-store.js +25 -0
  275. package/dist/src/storage/github/client.js +1 -0
  276. package/dist/src/storage/github/index.js +1 -0
  277. package/dist/src/storage/google-drive/client.js +1 -0
  278. package/dist/src/storage/google-drive/index.js +1 -0
  279. package/dist/src/storage/huggingface/client.js +116 -0
  280. package/dist/src/storage/huggingface/index.js +1 -0
  281. package/dist/src/storage/index.js +16 -0
  282. package/dist/src/storage/list-bucket-raw.js +14 -0
  283. package/dist/src/storage/list-bucket-tree.js +38 -0
  284. package/dist/src/storage/local/client.js +99 -0
  285. package/dist/src/storage/local/index.js +1 -0
  286. package/dist/src/storage/memory-store.js +30 -0
  287. package/dist/src/storage/project/cleanup-layout-v1.js +72 -0
  288. package/dist/src/storage/project/folder.js +15 -0
  289. package/dist/src/storage/project/index.js +3 -0
  290. package/dist/src/storage/project/layout.js +74 -0
  291. package/dist/src/storage/project/migrate-layout-v2.js +101 -0
  292. package/dist/src/storage/project/migrate.js +73 -0
  293. package/dist/src/storage/project/scoped-provider.js +165 -0
  294. package/dist/src/storage/provider.js +26 -0
  295. package/dist/src/storage/retrying-provider.js +23 -0
  296. package/dist/src/storage/test-connection.js +32 -0
  297. package/dist/src/storage/type-resolution-store.js +26 -0
  298. package/dist/src/storage/types.js +1 -0
  299. package/dist/src/storage/vector-store.js +30 -0
  300. package/dist/src/storage/visualization-store.js +25 -0
  301. package/dist/src/sync/compressor.js +1 -0
  302. package/dist/src/sync/conflict-resolver.js +1 -0
  303. package/dist/src/sync/downloader.js +1 -0
  304. package/dist/src/sync/index.js +1 -0
  305. package/dist/src/sync/sync-engine.js +1 -0
  306. package/dist/src/sync/upload-queue.js +1 -0
  307. package/dist/src/utils/retry.js +29 -0
  308. package/dist/src/visualization/server.js +270 -0
  309. package/dist/src/work-continuity/brief-cache.js +107 -0
  310. package/dist/src/work-continuity/brief.js +349 -0
  311. package/dist/src/work-continuity/cli.js +96 -0
  312. package/dist/src/work-continuity/context-cli.js +106 -0
  313. package/dist/src/work-continuity/context-runtime-cli.js +88 -0
  314. package/dist/src/work-continuity/extractor.js +339 -0
  315. package/dist/src/work-continuity/handoff.js +185 -0
  316. package/dist/src/work-continuity/index.js +14 -0
  317. package/dist/src/work-continuity/injection.js +84 -0
  318. package/dist/src/work-continuity/journal.js +49 -0
  319. package/dist/src/work-continuity/learner.js +127 -0
  320. package/dist/src/work-continuity/reducer.js +316 -0
  321. package/dist/src/work-continuity/semantic-extractor.js +360 -0
  322. package/dist/src/work-continuity/semantic-journal.js +55 -0
  323. package/dist/src/work-continuity/semantic-learner.js +125 -0
  324. package/dist/src/work-continuity/semantic-reducer.js +268 -0
  325. package/dist/src/work-continuity/semantic-types.js +1 -0
  326. package/dist/src/work-continuity/types.js +1 -0
  327. package/dist/visualization/public/index.html +2896 -0
  328. package/dist/visualization/public/vendor/3d-force-graph.min.js +5 -0
  329. package/package.json +69 -0
@@ -0,0 +1,76 @@
1
+ export class HuggingFaceEmbeddingProvider {
2
+ options;
3
+ name = "huggingface";
4
+ dimensions = 384;
5
+ constructor(options) {
6
+ this.options = options;
7
+ }
8
+ async embed(text) {
9
+ const [vector] = await this.embedMany([text]);
10
+ return vector;
11
+ }
12
+ async embedMany(texts) {
13
+ if (texts.length === 0) {
14
+ return [];
15
+ }
16
+ const url = `https://router.huggingface.co/hf-inference/models/${this.options.model}/pipeline/feature-extraction`;
17
+ const response = await fetch(url, {
18
+ method: "POST",
19
+ headers: {
20
+ Authorization: `Bearer ${this.options.token}`,
21
+ "Content-Type": "application/json",
22
+ },
23
+ body: JSON.stringify({
24
+ inputs: texts,
25
+ options: {
26
+ wait_for_model: true,
27
+ },
28
+ }),
29
+ });
30
+ if (!response.ok) {
31
+ throw new Error(`HF embedding failed: ${response.status} ${await response.text()}`);
32
+ }
33
+ const data = await response.json();
34
+ if (!Array.isArray(data)) {
35
+ throw new Error("HF embedding returned invalid response");
36
+ }
37
+ /*
38
+ * API có thể trả:
39
+ * [vector]
40
+ * hoặc [[token vectors]]
41
+ *
42
+ * Normalize về sentence vector.
43
+ */
44
+ return data.map((item) => normalizeEmbedding(item));
45
+ }
46
+ }
47
+ function normalizeEmbedding(value) {
48
+ if (!Array.isArray(value)) {
49
+ throw new Error("Invalid embedding");
50
+ }
51
+ if (value.length > 0 &&
52
+ typeof value[0] === "number") {
53
+ return value;
54
+ }
55
+ if (value.length > 0 &&
56
+ Array.isArray(value[0])) {
57
+ const rows = value;
58
+ if (rows.length === 0) {
59
+ return [];
60
+ }
61
+ const dimensions = rows[0].length;
62
+ const output = new Array(dimensions).fill(0);
63
+ for (const row of rows) {
64
+ for (let i = 0; i < dimensions; i++) {
65
+ output[i] +=
66
+ row[i] ?? 0;
67
+ }
68
+ }
69
+ for (let i = 0; i < dimensions; i++) {
70
+ output[i] /=
71
+ rows.length;
72
+ }
73
+ return output;
74
+ }
75
+ throw new Error("Unsupported embedding shape");
76
+ }
@@ -0,0 +1,16 @@
1
+ import "dotenv/config";
2
+ import { createEmbeddingProvider, } from "./embedder.js";
3
+ async function main() {
4
+ const provider = createEmbeddingProvider();
5
+ const vector = await provider.embed("ToolNet Memory semantic search");
6
+ console.log({
7
+ ok: vector.length > 0,
8
+ provider: provider.name,
9
+ dimensions: vector.length,
10
+ sample: vector.slice(0, 5),
11
+ });
12
+ }
13
+ main().catch((error) => {
14
+ console.error(error);
15
+ process.exit(1);
16
+ });
@@ -0,0 +1,3 @@
1
+ export async function afterEdit(runtime, filePath) {
2
+ await runtime.fileWrite(filePath);
3
+ }
@@ -0,0 +1,3 @@
1
+ export async function afterTool(runtime, tool, output) {
2
+ await runtime.afterTool(tool, output);
3
+ }
@@ -0,0 +1,68 @@
1
+ import { getArchitecture } from "../code-intelligence/graph/architecture.js";
2
+ export class AutoContextBuilder {
3
+ memory;
4
+ retrieval;
5
+ graph;
6
+ constructor(memory, retrieval, graph) {
7
+ this.memory = memory;
8
+ this.retrieval = retrieval;
9
+ this.graph = graph;
10
+ }
11
+ build(projectId, query, options = {}) {
12
+ const maxRules = options.maxRules ?? 3;
13
+ const maxTodos = options.maxTodos ?? 3;
14
+ const maxDecisions = options.maxDecisions ?? 3;
15
+ const maxRelevant = options.maxRelevant ?? 5;
16
+ const maxCharacters = options.maxCharacters ?? 7000;
17
+ const rules = this.memory
18
+ .byType(projectId, "rule")
19
+ .slice(0, maxRules);
20
+ const todos = this.memory
21
+ .byType(projectId, "todo")
22
+ .slice(0, maxTodos);
23
+ const decisions = this.memory
24
+ .byType(projectId, "decision")
25
+ .slice(0, maxDecisions);
26
+ const relevant = this.retrieval.search(projectId, query, {
27
+ topK: maxRelevant,
28
+ });
29
+ const architecture = getArchitecture(this.graph, projectId);
30
+ const blocks = [];
31
+ blocks.push([
32
+ "[PROJECT]",
33
+ `files=${architecture.files}`,
34
+ `classes=${architecture.classes}`,
35
+ `functions=${architecture.functions}`,
36
+ `methods=${architecture.methods}`,
37
+ `calls=${architecture.calls}`,
38
+ ].join(" "));
39
+ for (const item of rules) {
40
+ blocks.push(`[RULE] ${item.content}`);
41
+ }
42
+ for (const item of decisions) {
43
+ blocks.push(`[DECISION] ${item.content}`);
44
+ }
45
+ for (const item of todos) {
46
+ blocks.push(`[TODO] ${item.content}`);
47
+ }
48
+ for (const item of relevant) {
49
+ const prefix = item.memory.type.toUpperCase();
50
+ const block = `[${prefix}] ${item.memory.content}`;
51
+ if (!blocks.includes(block)) {
52
+ blocks.push(block);
53
+ }
54
+ }
55
+ let output = "";
56
+ for (const block of blocks) {
57
+ const next = output.length === 0
58
+ ? block
59
+ : `${output}\n${block}`;
60
+ if (next.length >
61
+ maxCharacters) {
62
+ break;
63
+ }
64
+ output = next;
65
+ }
66
+ return output;
67
+ }
68
+ }
@@ -0,0 +1,94 @@
1
+ import { extractEditedFiles, } from "../code-intelligence/impact/edit-tool-detector.js";
2
+ const RISK_ORDER = {
3
+ LOW: 0,
4
+ MEDIUM: 1,
5
+ HIGH: 2,
6
+ CRITICAL: 3,
7
+ };
8
+ export class AutoImpactGuard {
9
+ guard;
10
+ projectId;
11
+ constructor(guard, projectId) {
12
+ this.guard = guard;
13
+ this.projectId = projectId;
14
+ }
15
+ async beforeTool(tool, input) {
16
+ const paths = extractEditedFiles(tool, input);
17
+ if (paths.length === 0) {
18
+ return {
19
+ triggered: false,
20
+ tool,
21
+ highestRisk: "LOW",
22
+ totalRiskScore: 0,
23
+ files: [],
24
+ impactedFiles: [],
25
+ suggestedTests: [],
26
+ requiresVerification: false,
27
+ context: "",
28
+ };
29
+ }
30
+ const files = [];
31
+ for (const filePath of paths) {
32
+ const result = this.guard.analyzeFile(this.projectId, filePath);
33
+ files.push({
34
+ filePath,
35
+ risk: result.risk,
36
+ riskScore: result.riskScore,
37
+ impactedFiles: result.impactedFiles,
38
+ suggestedTests: result.suggestedTests,
39
+ impactedCount: result.impacted.length,
40
+ });
41
+ }
42
+ let highestRisk = "LOW";
43
+ for (const file of files) {
44
+ if (RISK_ORDER[file.risk] >
45
+ RISK_ORDER[highestRisk]) {
46
+ highestRisk =
47
+ file.risk;
48
+ }
49
+ }
50
+ const impactedFiles = [
51
+ ...new Set(files.flatMap((file) => file.impactedFiles)),
52
+ ];
53
+ const suggestedTests = [
54
+ ...new Set(files.flatMap((file) => file.suggestedTests)),
55
+ ];
56
+ const totalRiskScore = files.reduce((total, file) => total +
57
+ file.riskScore, 0);
58
+ const requiresVerification = highestRisk ===
59
+ "HIGH" ||
60
+ highestRisk ===
61
+ "CRITICAL";
62
+ const lines = [
63
+ "[TOOLNET IMPACT GUARD]",
64
+ `Risk: ${highestRisk}`,
65
+ `Risk score: ${totalRiskScore}`,
66
+ `Files being changed: ${paths.join(", ")}`,
67
+ `Impacted files: ${impactedFiles.length}`,
68
+ ];
69
+ if (impactedFiles.length) {
70
+ lines.push("Blast radius:", ...impactedFiles
71
+ .slice(0, 20)
72
+ .map((path) => `- ${path}`));
73
+ }
74
+ if (suggestedTests.length) {
75
+ lines.push("Verify/tests:", ...suggestedTests
76
+ .slice(0, 15)
77
+ .map((path) => `- ${path}`));
78
+ }
79
+ if (requiresVerification) {
80
+ lines.push("IMPORTANT: High blast radius. Inspect affected dependencies and run relevant tests after the edit.");
81
+ }
82
+ return {
83
+ triggered: true,
84
+ tool,
85
+ highestRisk,
86
+ totalRiskScore,
87
+ files,
88
+ impactedFiles,
89
+ suggestedTests,
90
+ requiresVerification,
91
+ context: lines.join("\n"),
92
+ };
93
+ }
94
+ }
@@ -0,0 +1,27 @@
1
+ export class AutoRetrieval {
2
+ runtime;
3
+ builder;
4
+ projectId;
5
+ constructor(runtime, builder, projectId) {
6
+ this.runtime = runtime;
7
+ this.builder = builder;
8
+ this.projectId = projectId;
9
+ }
10
+ async prepare(prompt) {
11
+ await this.runtime.userPrompt(prompt);
12
+ const context = this.builder.build(this.projectId, prompt);
13
+ return {
14
+ originalPrompt: prompt,
15
+ context,
16
+ augmentedPrompt: context
17
+ ? [
18
+ "<toolnet_memory>",
19
+ context,
20
+ "</toolnet_memory>",
21
+ "",
22
+ prompt,
23
+ ].join("\n")
24
+ : prompt,
25
+ };
26
+ }
27
+ }
@@ -0,0 +1,18 @@
1
+ export async function beforeAgent(runtime, contextBuilder, projectId, prompt) {
2
+ await runtime.userPrompt(prompt);
3
+ const memoryContext = contextBuilder.build(projectId, prompt);
4
+ const augmentedPrompt = memoryContext
5
+ ? [
6
+ "<toolnet_memory>",
7
+ memoryContext,
8
+ "</toolnet_memory>",
9
+ "",
10
+ prompt,
11
+ ].join("\n")
12
+ : prompt;
13
+ return {
14
+ prompt,
15
+ memoryContext,
16
+ augmentedPrompt,
17
+ };
18
+ }
@@ -0,0 +1,3 @@
1
+ export async function beforeCompact(runtime) {
2
+ await runtime.flush();
3
+ }
@@ -0,0 +1,20 @@
1
+ export async function beforeEdit(impactGuard, projectId, filePath) {
2
+ const result = impactGuard.analyzeFile(projectId, filePath);
3
+ /*
4
+ * Không block cứng AI.
5
+ * Guard cảnh báo và yêu cầu verify.
6
+ */
7
+ return {
8
+ allowed: true,
9
+ risk: result.risk,
10
+ riskScore: result.riskScore,
11
+ impactedFiles: result.impactedFiles,
12
+ suggestedTests: result.suggestedTests,
13
+ warning: result.risk ===
14
+ "CRITICAL" ||
15
+ result.risk ===
16
+ "HIGH"
17
+ ? `High blast radius: verify ${result.impactedFiles.length} impacted files before finalizing edit.`
18
+ : undefined,
19
+ };
20
+ }
@@ -0,0 +1,11 @@
1
+ export * from "./runtime.js";
2
+ export * from "./auto-context.js";
3
+ export * from "./auto-retrieval.js";
4
+ export * from "./session-start.js";
5
+ export * from "./session-end.js";
6
+ export * from "./before-agent.js";
7
+ export * from "./after-tool.js";
8
+ export * from "./after-edit.js";
9
+ export * from "./before-compact.js";
10
+ export * from "./before-edit.js";
11
+ export * from "./auto-impact-guard.js";
@@ -0,0 +1,110 @@
1
+ import { ActivityCapture, EventDeduplicator, EventQueue, SessionCapture, } from "../capture/index.js";
2
+ import { MemoryProcessor } from "../processor/memory-processor.js";
3
+ import { deduplicateMemories } from "../memory/deduplicate.js";
4
+ export class HookRuntime {
5
+ projectId;
6
+ memory;
7
+ memoryStore;
8
+ queue = new EventQueue();
9
+ capture = new ActivityCapture(this.queue);
10
+ session = new SessionCapture(this.capture);
11
+ processor;
12
+ dedup = new EventDeduplicator();
13
+ maxEventsBeforeFlush;
14
+ constructor(options) {
15
+ this.projectId = options.projectId;
16
+ this.memory = options.memory;
17
+ this.memoryStore = options.memoryStore;
18
+ this.maxEventsBeforeFlush =
19
+ options.maxEventsBeforeFlush ?? 100;
20
+ this.processor = new MemoryProcessor(this.memory);
21
+ }
22
+ async sessionStart() {
23
+ this.session.start(this.projectId);
24
+ await this.flushIfNeeded();
25
+ }
26
+ async sessionEnd() {
27
+ this.session.end(this.projectId);
28
+ await this.flush();
29
+ }
30
+ async userPrompt(content) {
31
+ this.capture.capture(this.projectId, "user_prompt", { content });
32
+ await this.flushIfNeeded();
33
+ }
34
+ async beforeTool(tool, input) {
35
+ this.capture.capture(this.projectId, "tool_call", {
36
+ phase: "before",
37
+ tool,
38
+ input,
39
+ });
40
+ await this.flushIfNeeded();
41
+ }
42
+ async afterTool(tool, output) {
43
+ this.capture.capture(this.projectId, "tool_call", {
44
+ phase: "after",
45
+ tool,
46
+ output,
47
+ });
48
+ await this.flushIfNeeded();
49
+ }
50
+ async fileRead(filePath) {
51
+ this.capture.capture(this.projectId, "file_read", { filePath });
52
+ await this.flushIfNeeded();
53
+ }
54
+ async fileWrite(filePath) {
55
+ this.capture.capture(this.projectId, "file_write", { filePath });
56
+ await this.flushIfNeeded();
57
+ }
58
+ async command(command, exitCode) {
59
+ this.capture.capture(this.projectId, "command", {
60
+ command,
61
+ exitCode,
62
+ });
63
+ await this.flushIfNeeded();
64
+ }
65
+ async error(error) {
66
+ const message = error instanceof Error
67
+ ? error.message
68
+ : String(error);
69
+ this.capture.capture(this.projectId, "error", { message });
70
+ await this.flushIfNeeded();
71
+ }
72
+ async decision(content, metadata = {}) {
73
+ this.capture.capture(this.projectId, "decision", {
74
+ content,
75
+ ...metadata,
76
+ });
77
+ await this.flushIfNeeded();
78
+ }
79
+ async todo(content, metadata = {}) {
80
+ this.capture.capture(this.projectId, "todo", {
81
+ content,
82
+ ...metadata,
83
+ });
84
+ await this.flushIfNeeded();
85
+ }
86
+ async flushIfNeeded() {
87
+ if (this.queue.shouldFlush(this.maxEventsBeforeFlush)) {
88
+ await this.flush();
89
+ }
90
+ }
91
+ async flush() {
92
+ const events = this.queue.drain();
93
+ if (events.length === 0) {
94
+ return 0;
95
+ }
96
+ const uniqueEvents = this.dedup.filter(events);
97
+ if (uniqueEvents.length === 0) {
98
+ return 0;
99
+ }
100
+ const created = this.processor.process(uniqueEvents);
101
+ const records = deduplicateMemories(this.memory.exportProject(this.projectId));
102
+ this.memory.clearProject(this.projectId);
103
+ this.memory.importRecords(records);
104
+ await this.memoryStore.save(this.projectId, records);
105
+ return created;
106
+ }
107
+ pendingEvents() {
108
+ return this.queue.size();
109
+ }
110
+ }
@@ -0,0 +1,3 @@
1
+ export async function onSessionEnd(runtime) {
2
+ await runtime.sessionEnd();
3
+ }
@@ -0,0 +1,3 @@
1
+ export async function onSessionStart(runtime) {
2
+ await runtime.sessionStart();
3
+ }
@@ -0,0 +1,22 @@
1
+ import { createToolNetMemoryRuntime, } from "./runtime/index.js";
2
+ async function main() {
3
+ const runtime = createToolNetMemoryRuntime();
4
+ const startup = await runtime.start();
5
+ const prepared = await runtime.preparePrompt("Tiếp tục công việc hiện tại");
6
+ console.log({
7
+ started: true,
8
+ ...startup,
9
+ contextCharacters: prepared.context.length,
10
+ });
11
+ const shutdown = await runtime.stop();
12
+ console.log({
13
+ stopped: true,
14
+ memories: shutdown.memories,
15
+ codeParsed: shutdown.code.parsed,
16
+ vectorsIndexed: shutdown.vectors.indexed,
17
+ });
18
+ }
19
+ main().catch((error) => {
20
+ console.error(error);
21
+ process.exit(1);
22
+ });
@@ -0,0 +1,68 @@
1
+ import "dotenv/config";
2
+ import { loadConfig, MemoryEngine, ProjectManager, } from "../core/index.js";
3
+ import { RetrievalEngine, } from "../retrieval/retrieval-engine.js";
4
+ import { createEmbeddingProvider, } from "../embeddings/index.js";
5
+ import { CodeGraphStore, ReferenceResolver, SemanticCodeEngine, } from "../code-intelligence/index.js";
6
+ import { createStorageProvider, withStorageRetry, ProjectScopedStorageProvider, MemoryStore, PersistentCodeGraphStore, } from "../storage/index.js";
7
+ import { startMCPServer, } from "./server.js";
8
+ import { ProjectLock, } from "../production/project-lock.js";
9
+ async function main() {
10
+ const config = loadConfig();
11
+ const project = new ProjectManager()
12
+ .detect();
13
+ const rawStorage = createStorageProvider({
14
+ provider: config.storage.provider,
15
+ huggingface: config.storage.huggingface,
16
+ localRoot: config.storage.localRoot,
17
+ });
18
+ const retryStorage = withStorageRetry(rawStorage, {
19
+ attempts: Number(process.env
20
+ .TOOLNET_STORAGE_RETRIES ??
21
+ 3),
22
+ });
23
+ const storage = new ProjectScopedStorageProvider(retryStorage, project.id, project.name, project.remote ?? project.name);
24
+ const processLock = new ProjectLock(project.id);
25
+ await processLock.acquire();
26
+ const stop = () => {
27
+ void processLock
28
+ .release()
29
+ .finally(() => process.exit(0));
30
+ };
31
+ process.once("SIGINT", stop);
32
+ process.once("SIGTERM", stop);
33
+ const memory = new MemoryEngine();
34
+ const memoryStore = new MemoryStore(storage);
35
+ memory.importRecords(await memoryStore.load(project.id));
36
+ const retrieval = new RetrievalEngine(memory);
37
+ const graph = new CodeGraphStore();
38
+ const graphSnapshot = await new PersistentCodeGraphStore(storage).load(project.id);
39
+ if (graphSnapshot) {
40
+ graph.import(graphSnapshot.symbols, graphSnapshot.edges);
41
+ }
42
+ const references = new ReferenceResolver(graph);
43
+ const codeSemantic = new SemanticCodeEngine({
44
+ projectId: project.id,
45
+ rootPath: project.rootPath,
46
+ model: process.env
47
+ .HF_EMBEDDING_MODEL ??
48
+ "sentence-transformers/all-MiniLM-L6-v2",
49
+ storage,
50
+ embeddings: createEmbeddingProvider(),
51
+ graph,
52
+ });
53
+ await codeSemantic.initialize();
54
+ await startMCPServer({
55
+ project,
56
+ memory,
57
+ retrieval,
58
+ graph,
59
+ references,
60
+ codeSemantic,
61
+ memoryStore,
62
+ storage,
63
+ });
64
+ }
65
+ main().catch((error) => {
66
+ console.error(error);
67
+ process.exit(1);
68
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,3 @@
1
+ export * from "./context.js";
2
+ export * from "./server.js";
3
+ export * from "./tools/index.js";
@@ -0,0 +1,45 @@
1
+ import { McpServer, } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { StdioServerTransport, } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { memorySearch, memorySearchSchema, memoryRemember, memoryRememberSchema, memoryForget, memoryForgetSchema, findSymbol, findSymbolSchema, findCallers, findCallersSchema, searchCode, searchCodeSchema, projectContext, projectContextSchema, traceCalls, traceCallsSchema, analyzeImpact, analyzeImpactSchema, getProjectArchitecture, findDependencies, findDependenciesSchema, semanticCodeSearch, semanticCodeSearchSchema, snapshotCreate, snapshotCreateSchema, snapshotList, snapshotRestore, snapshotRestoreSchema, impactGuard, impactGuardSchema, graphDependents, graphDependentsSchema, graphPath, graphPathSchema, graphNeighborhood, graphNeighborhoodSchema, deadCode, deadCodeSchema, } from "./tools/index.js";
4
+ function jsonText(value) {
5
+ return {
6
+ content: [
7
+ {
8
+ type: "text",
9
+ text: JSON.stringify(value, null, 2),
10
+ },
11
+ ],
12
+ };
13
+ }
14
+ export function createMCPServer(ctx) {
15
+ const server = new McpServer({
16
+ name: "toolnet-memory",
17
+ version: "0.1.0",
18
+ });
19
+ server.tool("memory_search", "Search relevant long-term memory for the current project.", memorySearchSchema, async (input) => jsonText(await memorySearch(ctx, input)));
20
+ server.tool("memory_save", "Save an important memory, decision, rule, TODO or summary.", memoryRememberSchema, async (input) => jsonText(await memoryRemember(ctx, input)));
21
+ server.tool("memory_forget", "Delete a memory by id.", memoryForgetSchema, async (input) => jsonText(await memoryForget(ctx, input)));
22
+ server.tool("find_symbol", "Find code symbols by exact name.", findSymbolSchema, async (input) => jsonText(await findSymbol(ctx, input)));
23
+ server.tool("find_callers", "Find functions or methods calling a symbol.", findCallersSchema, async (input) => jsonText(await findCallers(ctx, input)));
24
+ server.tool("code_search", "Search indexed code symbols and files.", searchCodeSchema, async (input) => jsonText(await searchCode(ctx, input)));
25
+ server.tool("project_context", "Get compact project architecture, recent memory and relevant context.", projectContextSchema, async (input) => jsonText(await projectContext(ctx, input)));
26
+ server.tool("trace_calls", "Trace callers or callees through the code call graph.", traceCallsSchema, async (input) => jsonText(await traceCalls(ctx, input)));
27
+ server.tool("analyze_impact", "Analyze what code can be affected if a symbol changes.", analyzeImpactSchema, async (input) => jsonText(await analyzeImpact(ctx, input)));
28
+ server.tool("get_architecture", "Get compact architecture statistics for the indexed project.", {}, async () => jsonText(await getProjectArchitecture(ctx)));
29
+ server.tool("find_dependencies", "Find direct file dependencies and reverse dependents.", findDependenciesSchema, async (input) => jsonText(await findDependencies(ctx, input)));
30
+ server.tool("semantic_code_search", "Search source code by semantic meaning, not only exact symbol names.", semanticCodeSearchSchema, async (input) => jsonText(await semanticCodeSearch(ctx, input)));
31
+ server.tool("snapshot_create", "Create a safe versioned snapshot of project memory, vectors and graph.", snapshotCreateSchema, async (input) => jsonText(await snapshotCreate(ctx, input)));
32
+ server.tool("snapshot_list", "List available ToolNet Memory snapshots.", {}, async () => jsonText(await snapshotList(ctx)));
33
+ server.tool("snapshot_restore", "Restore a previous ToolNet Memory snapshot. A safety snapshot is created first.", snapshotRestoreSchema, async (input) => jsonText(await snapshotRestore(ctx, input)));
34
+ server.tool("impact_guard", "Analyze blast radius before or after code changes. Maps changed files/lines to symbols, follows reverse dependencies, assigns risk and suggests verification targets.", impactGuardSchema, async (input) => jsonText(await impactGuard(ctx, input)));
35
+ server.tool("graph_dependents", "Find code symbols that depend on a symbol through calls, imports, type usage, writes, inheritance or implementation relationships.", graphDependentsSchema, async (input) => jsonText(await graphDependents(ctx, input)));
36
+ server.tool("graph_path", "Find the shortest dependency path between two code symbols.", graphPathSchema, async (input) => jsonText(await graphPath(ctx, input)));
37
+ server.tool("graph_neighborhood", "Explore incoming and outgoing dependency relationships around a code symbol.", graphNeighborhoodSchema, async (input) => jsonText(await graphNeighborhood(ctx, input)));
38
+ server.tool("dead_code", "Find likely unused code. Results are candidates and must be verified before deletion.", deadCodeSchema, async (input) => jsonText(await deadCode(ctx, input)));
39
+ return server;
40
+ }
41
+ export async function startMCPServer(ctx) {
42
+ const server = createMCPServer(ctx);
43
+ const transport = new StdioServerTransport();
44
+ await server.connect(transport);
45
+ }
@@ -0,0 +1,41 @@
1
+ import { z, } from "zod";
2
+ import { ImpactAnalyzer, } from "../../code-intelligence/impact/impact-analyzer.js";
3
+ export const analyzeImpactSchema = {
4
+ symbolId: z.string().min(1),
5
+ depth: z.number()
6
+ .int()
7
+ .min(1)
8
+ .max(10)
9
+ .optional(),
10
+ };
11
+ export async function analyzeImpact(ctx, input) {
12
+ const symbol = ctx.graph.getSymbol(input.symbolId);
13
+ if (!symbol) {
14
+ return {
15
+ found: false,
16
+ impacts: [],
17
+ };
18
+ }
19
+ const analyzer = new ImpactAnalyzer(ctx.graph);
20
+ const impacts = analyzer.analyze(ctx.project.id, symbol.id, input.depth ?? 4);
21
+ return {
22
+ found: true,
23
+ target: {
24
+ id: symbol.id,
25
+ name: symbol.name,
26
+ qualifiedName: symbol.qualifiedName,
27
+ filePath: symbol.filePath,
28
+ type: symbol.type,
29
+ },
30
+ impacts: impacts.map((item) => ({
31
+ id: item.symbol.id,
32
+ name: item.symbol.name,
33
+ qualifiedName: item.symbol
34
+ .qualifiedName,
35
+ filePath: item.symbol.filePath,
36
+ type: item.symbol.type,
37
+ relation: item.relation,
38
+ depth: item.depth,
39
+ })),
40
+ };
41
+ }