toolnet-memory 0.2.0 → 0.2.2

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 (341) hide show
  1. package/README.md +443 -70
  2. package/bin/toolnet-memory +66 -53
  3. package/bundle/agy.js +88 -0
  4. package/bundle/codex.js +92 -0
  5. package/bundle/context-runtime.js +56 -0
  6. package/bundle/context.js +62 -0
  7. package/bundle/doctor.js +3 -0
  8. package/bundle/full-index.js +8 -0
  9. package/bundle/learner.js +8 -0
  10. package/bundle/mcp.js +7 -0
  11. package/bundle/opencode.js +314 -0
  12. package/bundle/project-manual.js +54 -0
  13. package/bundle/setup.js +31 -0
  14. package/bundle/snapshot.js +4 -0
  15. package/bundle/work-continuity.js +12 -0
  16. package/package.json +11 -5
  17. package/dist/packages/cli/commands.js +0 -1
  18. package/dist/packages/cli/index.js +0 -1
  19. package/dist/packages/sdk/client.js +0 -78
  20. package/dist/packages/sdk/index.js +0 -1
  21. package/dist/packages/sdk/types.js +0 -1
  22. package/dist/src/api/index.js +0 -1
  23. package/dist/src/api/routes/health.js +0 -1
  24. package/dist/src/api/routes/index.js +0 -1
  25. package/dist/src/api/routes/memory.js +0 -1
  26. package/dist/src/api/routes/projects.js +0 -1
  27. package/dist/src/api/routes/search.js +0 -1
  28. package/dist/src/api/server.js +0 -1
  29. package/dist/src/capture/activity-capture.js +0 -21
  30. package/dist/src/capture/command-capture.js +0 -12
  31. package/dist/src/capture/error-capture.js +0 -14
  32. package/dist/src/capture/event-deduplicator.js +0 -28
  33. package/dist/src/capture/event-queue.js +0 -20
  34. package/dist/src/capture/file-capture.js +0 -23
  35. package/dist/src/capture/index.js +0 -8
  36. package/dist/src/capture/session-capture.js +0 -18
  37. package/dist/src/capture/tool-capture.js +0 -13
  38. package/dist/src/code-intelligence/analysis/analysis-engine.js +0 -26
  39. package/dist/src/code-intelligence/analysis/dead-code-analyzer.js +0 -127
  40. package/dist/src/code-intelligence/analysis/dependency-analyzer.js +0 -66
  41. package/dist/src/code-intelligence/analysis/index.js +0 -4
  42. package/dist/src/code-intelligence/analysis/types.js +0 -1
  43. package/dist/src/code-intelligence/architecture/architecture-engine.js +0 -48
  44. package/dist/src/code-intelligence/architecture/clusters.js +0 -322
  45. package/dist/src/code-intelligence/architecture/entry-points.js +0 -150
  46. package/dist/src/code-intelligence/architecture/hotspots.js +0 -136
  47. package/dist/src/code-intelligence/architecture/index.js +0 -6
  48. package/dist/src/code-intelligence/architecture/layers.js +0 -197
  49. package/dist/src/code-intelligence/architecture/types.js +0 -1
  50. package/dist/src/code-intelligence/chunks/index.js +0 -2
  51. package/dist/src/code-intelligence/chunks/smart-chunker.js +0 -125
  52. package/dist/src/code-intelligence/chunks/types.js +0 -1
  53. package/dist/src/code-intelligence/git/git-diff.js +0 -109
  54. package/dist/src/code-intelligence/git/index.js +0 -1
  55. package/dist/src/code-intelligence/graph/architecture.js +0 -26
  56. package/dist/src/code-intelligence/graph/graph-builder.js +0 -213
  57. package/dist/src/code-intelligence/graph/graph-store.js +0 -57
  58. package/dist/src/code-intelligence/graph/index.js +0 -1
  59. package/dist/src/code-intelligence/graph/relationships.js +0 -1
  60. package/dist/src/code-intelligence/graph/trace.js +0 -65
  61. package/dist/src/code-intelligence/impact/blast-radius.js +0 -160
  62. package/dist/src/code-intelligence/impact/change-mapper.js +0 -69
  63. package/dist/src/code-intelligence/impact/edit-tool-detector.js +0 -92
  64. package/dist/src/code-intelligence/impact/impact-analyzer.js +0 -60
  65. package/dist/src/code-intelligence/impact/impact-guard.js +0 -33
  66. package/dist/src/code-intelligence/impact/index.js +0 -5
  67. package/dist/src/code-intelligence/incremental/file-hash.js +0 -8
  68. package/dist/src/code-intelligence/incremental/incremental-indexer.js +0 -106
  69. package/dist/src/code-intelligence/incremental/manifest-builder.js +0 -19
  70. package/dist/src/code-intelligence/incremental/manifest.js +0 -31
  71. package/dist/src/code-intelligence/index.js +0 -23
  72. package/dist/src/code-intelligence/indexer/file-watcher.js +0 -1
  73. package/dist/src/code-intelligence/indexer/incremental-indexer.js +0 -1
  74. package/dist/src/code-intelligence/indexer/index.js +0 -1
  75. package/dist/src/code-intelligence/indexer/repository-indexer.js +0 -31
  76. package/dist/src/code-intelligence/indexer/repository-scanner.js +0 -50
  77. package/dist/src/code-intelligence/parsers/index.js +0 -1
  78. package/dist/src/code-intelligence/parsers/tree-sitter/index.js +0 -1
  79. package/dist/src/code-intelligence/parsers/tree-sitter/languages.js +0 -1
  80. package/dist/src/code-intelligence/parsers/tree-sitter/parser.js +0 -1
  81. package/dist/src/code-intelligence/parsers/typescript-parser.js +0 -190
  82. package/dist/src/code-intelligence/query/graph-query-engine.js +0 -275
  83. package/dist/src/code-intelligence/query/index.js +0 -2
  84. package/dist/src/code-intelligence/query/types.js +0 -1
  85. package/dist/src/code-intelligence/resolution/index.js +0 -2
  86. package/dist/src/code-intelligence/resolution/types.js +0 -1
  87. package/dist/src/code-intelligence/resolution/typescript-resolver.js +0 -316
  88. package/dist/src/code-intelligence/rich/index.js +0 -1
  89. package/dist/src/code-intelligence/rich/rich-graph-enricher.js +0 -463
  90. package/dist/src/code-intelligence/semantic/index.js +0 -2
  91. package/dist/src/code-intelligence/semantic/semantic-code-engine.js +0 -213
  92. package/dist/src/code-intelligence/semantic/source-priority.js +0 -22
  93. package/dist/src/code-intelligence/symbols/index.js +0 -1
  94. package/dist/src/code-intelligence/symbols/reference-resolver.js +0 -21
  95. package/dist/src/code-intelligence/symbols/symbol-extractor.js +0 -1
  96. package/dist/src/code-intelligence/test-analysis.js +0 -72
  97. package/dist/src/code-intelligence/test-architecture.js +0 -67
  98. package/dist/src/code-intelligence/test-impact.js +0 -47
  99. package/dist/src/code-intelligence/test-incremental.js +0 -24
  100. package/dist/src/code-intelligence/test-index.js +0 -39
  101. package/dist/src/code-intelligence/test-resolution.js +0 -54
  102. package/dist/src/code-intelligence/test-rich-graph.js +0 -48
  103. package/dist/src/code-intelligence/test-semantic.js +0 -57
  104. package/dist/src/code-intelligence/test-visualization.js +0 -36
  105. package/dist/src/code-intelligence/types.js +0 -1
  106. package/dist/src/code-intelligence/visualization/index.js +0 -2
  107. package/dist/src/code-intelligence/visualization/types.js +0 -1
  108. package/dist/src/code-intelligence/visualization/visualization-builder.js +0 -104
  109. package/dist/src/core/config.js +0 -66
  110. package/dist/src/core/global-env.js +0 -70
  111. package/dist/src/core/importance.js +0 -30
  112. package/dist/src/core/index.js +0 -5
  113. package/dist/src/core/memory-engine.js +0 -183
  114. package/dist/src/core/project-manager.js +0 -243
  115. package/dist/src/core/types.js +0 -1
  116. package/dist/src/embeddings/batch-embedder.js +0 -1
  117. package/dist/src/embeddings/cache.js +0 -1
  118. package/dist/src/embeddings/embedder.js +0 -51
  119. package/dist/src/embeddings/index.js +0 -4
  120. package/dist/src/embeddings/local.js +0 -37
  121. package/dist/src/embeddings/provider.js +0 -1
  122. package/dist/src/embeddings/remote.js +0 -76
  123. package/dist/src/embeddings/test-connection.js +0 -16
  124. package/dist/src/hooks/after-edit.js +0 -3
  125. package/dist/src/hooks/after-tool.js +0 -3
  126. package/dist/src/hooks/auto-context.js +0 -68
  127. package/dist/src/hooks/auto-impact-guard.js +0 -94
  128. package/dist/src/hooks/auto-retrieval.js +0 -27
  129. package/dist/src/hooks/before-agent.js +0 -18
  130. package/dist/src/hooks/before-compact.js +0 -3
  131. package/dist/src/hooks/before-edit.js +0 -20
  132. package/dist/src/hooks/index.js +0 -11
  133. package/dist/src/hooks/runtime.js +0 -110
  134. package/dist/src/hooks/session-end.js +0 -3
  135. package/dist/src/hooks/session-start.js +0 -3
  136. package/dist/src/index.js +0 -22
  137. package/dist/src/mcp/bootstrap.js +0 -68
  138. package/dist/src/mcp/context.js +0 -1
  139. package/dist/src/mcp/index.js +0 -3
  140. package/dist/src/mcp/server.js +0 -45
  141. package/dist/src/mcp/tools/analyze-impact.js +0 -41
  142. package/dist/src/mcp/tools/dead-code.js +0 -55
  143. package/dist/src/mcp/tools/find-callers.js +0 -24
  144. package/dist/src/mcp/tools/find-dependencies.js +0 -57
  145. package/dist/src/mcp/tools/find-symbol.js +0 -7
  146. package/dist/src/mcp/tools/get-architecture.js +0 -11
  147. package/dist/src/mcp/tools/graph-dependents.js +0 -24
  148. package/dist/src/mcp/tools/graph-neighborhood.js +0 -58
  149. package/dist/src/mcp/tools/graph-path.js +0 -43
  150. package/dist/src/mcp/tools/graph-query-utils.js +0 -32
  151. package/dist/src/mcp/tools/impact-guard.js +0 -34
  152. package/dist/src/mcp/tools/index-repository.js +0 -1
  153. package/dist/src/mcp/tools/index.js +0 -20
  154. package/dist/src/mcp/tools/memory-decisions.js +0 -1
  155. package/dist/src/mcp/tools/memory-forget.js +0 -14
  156. package/dist/src/mcp/tools/memory-recent.js +0 -1
  157. package/dist/src/mcp/tools/memory-remember.js +0 -33
  158. package/dist/src/mcp/tools/memory-rules.js +0 -1
  159. package/dist/src/mcp/tools/memory-search.js +0 -18
  160. package/dist/src/mcp/tools/memory-todos.js +0 -1
  161. package/dist/src/mcp/tools/project-context.js +0 -25
  162. package/dist/src/mcp/tools/search-code.js +0 -21
  163. package/dist/src/mcp/tools/semantic-code-search.js +0 -33
  164. package/dist/src/mcp/tools/snapshot-create.js +0 -13
  165. package/dist/src/mcp/tools/snapshot-list.js +0 -7
  166. package/dist/src/mcp/tools/snapshot-restore.js +0 -13
  167. package/dist/src/mcp/tools/trace-calls.js +0 -37
  168. package/dist/src/memory/activity.js +0 -5
  169. package/dist/src/memory/conflict-detector.js +0 -105
  170. package/dist/src/memory/consolidator.js +0 -104
  171. package/dist/src/memory/decay.js +0 -59
  172. package/dist/src/memory/decisions.js +0 -3
  173. package/dist/src/memory/deduplicate.js +0 -25
  174. package/dist/src/memory/index.js +0 -11
  175. package/dist/src/memory/maintenance.js +0 -16
  176. package/dist/src/memory/remember.js +0 -3
  177. package/dist/src/memory/rules.js +0 -3
  178. package/dist/src/memory/search.js +0 -3
  179. package/dist/src/memory/summaries.js +0 -1
  180. package/dist/src/memory/todos.js +0 -3
  181. package/dist/src/processor/decision-extractor.js +0 -13
  182. package/dist/src/processor/importance-scorer.js +0 -22
  183. package/dist/src/processor/index.js +0 -7
  184. package/dist/src/processor/memory-extractor.js +0 -59
  185. package/dist/src/processor/memory-processor.js +0 -105
  186. package/dist/src/processor/rule-extractor.js +0 -13
  187. package/dist/src/processor/summarizer.js +0 -71
  188. package/dist/src/processor/todo-extractor.js +0 -12
  189. package/dist/src/production/config-check.js +0 -34
  190. package/dist/src/production/doctor.js +0 -58
  191. package/dist/src/production/full-index.js +0 -114
  192. package/dist/src/production/health.js +0 -58
  193. package/dist/src/production/index-pipeline.js +0 -151
  194. package/dist/src/production/index.js +0 -4
  195. package/dist/src/production/project-lock.js +0 -95
  196. package/dist/src/production/project-status.js +0 -16
  197. package/dist/src/production/recovery.js +0 -15
  198. package/dist/src/production/snapshot-cli.js +0 -58
  199. package/dist/src/project-manual/cli.js +0 -77
  200. package/dist/src/project-manual/index.js +0 -2
  201. package/dist/src/project-manual/manager.js +0 -147
  202. package/dist/src/project-manual/types.js +0 -1
  203. package/dist/src/retrieval/bm25/index.js +0 -1
  204. package/dist/src/retrieval/bm25/search.js +0 -1
  205. package/dist/src/retrieval/bm25.js +0 -30
  206. package/dist/src/retrieval/context-budget.js +0 -1
  207. package/dist/src/retrieval/context-builder.js +0 -22
  208. package/dist/src/retrieval/graph/index.js +0 -1
  209. package/dist/src/retrieval/graph/search.js +0 -1
  210. package/dist/src/retrieval/hybrid/hybrid-search.js +0 -1
  211. package/dist/src/retrieval/hybrid/index.js +0 -1
  212. package/dist/src/retrieval/hybrid-search.js +0 -68
  213. package/dist/src/retrieval/importance.js +0 -16
  214. package/dist/src/retrieval/index.js +0 -12
  215. package/dist/src/retrieval/query-analyzer.js +0 -32
  216. package/dist/src/retrieval/query-classifier.js +0 -1
  217. package/dist/src/retrieval/query-expansion.js +0 -1
  218. package/dist/src/retrieval/recency.js +0 -12
  219. package/dist/src/retrieval/reranker/index.js +0 -1
  220. package/dist/src/retrieval/reranker/reranker.js +0 -1
  221. package/dist/src/retrieval/retrieval-engine.js +0 -17
  222. package/dist/src/retrieval/tokenizer.js +0 -9
  223. package/dist/src/retrieval/type-priority.js +0 -10
  224. package/dist/src/retrieval/types.js +0 -1
  225. package/dist/src/retrieval/vector/index.js +0 -4
  226. package/dist/src/retrieval/vector/metadata-filter.js +0 -1
  227. package/dist/src/retrieval/vector/persistence.js +0 -67
  228. package/dist/src/retrieval/vector/search.js +0 -12
  229. package/dist/src/retrieval/vector/test-persistence.js +0 -36
  230. package/dist/src/retrieval/vector/upsert.js +0 -40
  231. package/dist/src/retrieval/vector/vector-store.js +0 -89
  232. package/dist/src/retrieval/vector-hybrid-engine.js +0 -91
  233. package/dist/src/runtime/bootstrap.js +0 -28
  234. package/dist/src/runtime/graceful.js +0 -17
  235. package/dist/src/runtime/index.js +0 -3
  236. package/dist/src/runtime/toolnet-memory-runtime.js +0 -156
  237. package/dist/src/security/encryption.js +0 -1
  238. package/dist/src/security/file-filter.js +0 -30
  239. package/dist/src/security/index.js +0 -3
  240. package/dist/src/security/sanitizer.js +0 -49
  241. package/dist/src/security/secret-scanner.js +0 -56
  242. package/dist/src/session/agy/adapter.js +0 -159
  243. package/dist/src/session/agy/cli.js +0 -87
  244. package/dist/src/session/agy/hook-installer.js +0 -62
  245. package/dist/src/session/agy/hook.js +0 -167
  246. package/dist/src/session/agy/index.js +0 -5
  247. package/dist/src/session/agy/project-resolver.js +0 -27
  248. package/dist/src/session/agy/recovery.js +0 -112
  249. package/dist/src/session/agy/transcript.js +0 -191
  250. package/dist/src/session/codex/adapter.js +0 -138
  251. package/dist/src/session/codex/cli.js +0 -236
  252. package/dist/src/session/codex/context-hook-installer.js +0 -70
  253. package/dist/src/session/codex/context-hook.js +0 -69
  254. package/dist/src/session/codex/discovery.js +0 -138
  255. package/dist/src/session/codex/index.js +0 -6
  256. package/dist/src/session/codex/notify-installer.js +0 -135
  257. package/dist/src/session/codex/project-resolver.js +0 -25
  258. package/dist/src/session/codex/recovery.js +0 -27
  259. package/dist/src/session/codex/rollout.js +0 -186
  260. package/dist/src/session/core.js +0 -239
  261. package/dist/src/session/identity.js +0 -57
  262. package/dist/src/session/index.js +0 -9
  263. package/dist/src/session/learner/cli.js +0 -62
  264. package/dist/src/session/learner/extractor.js +0 -461
  265. package/dist/src/session/learner/index.js +0 -4
  266. package/dist/src/session/learner/journal.js +0 -159
  267. package/dist/src/session/learner/learner.js +0 -124
  268. package/dist/src/session/learner/types.js +0 -1
  269. package/dist/src/session/opencode/adapter.js +0 -553
  270. package/dist/src/session/opencode/cli.js +0 -121
  271. package/dist/src/session/opencode/index.js +0 -2
  272. package/dist/src/session/opencode/plugin-installer.js +0 -230
  273. package/dist/src/session/store.js +0 -242
  274. package/dist/src/session/types.js +0 -1
  275. package/dist/src/session/utils.js +0 -47
  276. package/dist/src/session/wal.js +0 -303
  277. package/dist/src/snapshot/index.js +0 -2
  278. package/dist/src/snapshot/manager.js +0 -130
  279. package/dist/src/snapshot/test-snapshot.js +0 -28
  280. package/dist/src/snapshot/types.js +0 -1
  281. package/dist/src/storage/architecture-store.js +0 -37
  282. package/dist/src/storage/cleanup-health.js +0 -20
  283. package/dist/src/storage/code-analysis-store.js +0 -35
  284. package/dist/src/storage/code-chunk-store.js +0 -25
  285. package/dist/src/storage/code-graph-store.js +0 -24
  286. package/dist/src/storage/code-manifest-store.js +0 -24
  287. package/dist/src/storage/code-vector-store.js +0 -25
  288. package/dist/src/storage/github/client.js +0 -1
  289. package/dist/src/storage/github/index.js +0 -1
  290. package/dist/src/storage/google-drive/client.js +0 -1
  291. package/dist/src/storage/google-drive/index.js +0 -1
  292. package/dist/src/storage/huggingface/client.js +0 -116
  293. package/dist/src/storage/huggingface/index.js +0 -1
  294. package/dist/src/storage/index.js +0 -16
  295. package/dist/src/storage/list-bucket-raw.js +0 -14
  296. package/dist/src/storage/list-bucket-tree.js +0 -38
  297. package/dist/src/storage/local/client.js +0 -99
  298. package/dist/src/storage/local/index.js +0 -1
  299. package/dist/src/storage/memory-store.js +0 -30
  300. package/dist/src/storage/project/cleanup-layout-v1.js +0 -72
  301. package/dist/src/storage/project/folder.js +0 -15
  302. package/dist/src/storage/project/index.js +0 -3
  303. package/dist/src/storage/project/layout.js +0 -74
  304. package/dist/src/storage/project/migrate-layout-v2.js +0 -101
  305. package/dist/src/storage/project/migrate.js +0 -73
  306. package/dist/src/storage/project/scoped-provider.js +0 -165
  307. package/dist/src/storage/provider.js +0 -26
  308. package/dist/src/storage/retrying-provider.js +0 -23
  309. package/dist/src/storage/test-connection.js +0 -32
  310. package/dist/src/storage/type-resolution-store.js +0 -26
  311. package/dist/src/storage/types.js +0 -1
  312. package/dist/src/storage/vector-store.js +0 -30
  313. package/dist/src/storage/visualization-store.js +0 -25
  314. package/dist/src/sync/compressor.js +0 -1
  315. package/dist/src/sync/conflict-resolver.js +0 -1
  316. package/dist/src/sync/downloader.js +0 -1
  317. package/dist/src/sync/index.js +0 -1
  318. package/dist/src/sync/sync-engine.js +0 -1
  319. package/dist/src/sync/upload-queue.js +0 -1
  320. package/dist/src/utils/retry.js +0 -29
  321. package/dist/src/visualization/server.js +0 -270
  322. package/dist/src/work-continuity/brief-cache.js +0 -107
  323. package/dist/src/work-continuity/brief.js +0 -349
  324. package/dist/src/work-continuity/cli.js +0 -96
  325. package/dist/src/work-continuity/context-cli.js +0 -106
  326. package/dist/src/work-continuity/context-runtime-cli.js +0 -88
  327. package/dist/src/work-continuity/extractor.js +0 -339
  328. package/dist/src/work-continuity/handoff.js +0 -185
  329. package/dist/src/work-continuity/index.js +0 -14
  330. package/dist/src/work-continuity/injection.js +0 -84
  331. package/dist/src/work-continuity/journal.js +0 -49
  332. package/dist/src/work-continuity/learner.js +0 -127
  333. package/dist/src/work-continuity/reducer.js +0 -316
  334. package/dist/src/work-continuity/semantic-extractor.js +0 -360
  335. package/dist/src/work-continuity/semantic-journal.js +0 -55
  336. package/dist/src/work-continuity/semantic-learner.js +0 -125
  337. package/dist/src/work-continuity/semantic-reducer.js +0 -268
  338. package/dist/src/work-continuity/semantic-types.js +0 -1
  339. package/dist/src/work-continuity/types.js +0 -1
  340. package/dist/visualization/public/index.html +0 -2896
  341. package/dist/visualization/public/vendor/3d-force-graph.min.js +0 -5
@@ -0,0 +1,12 @@
1
+ import{existsSync as ne,readFileSync as ie}from"node:fs";import{homedir as ae}from"node:os";import{join as ce}from"node:path";function pe(r){let e=r.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
2
+ `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function de(){let r=process.env.TOOLNET_GLOBAL_ENV??ce(ae(),".config","toolnet-memory",".env");if(!ne(r))return;let e=ie(r,"utf8");for(let t of e.split(/\r?\n/)){let o=t.trim();if(!o||o.startsWith("#"))continue;o.startsWith("export ")&&(o=o.slice(7));let s=o.indexOf("=");if(s<=0)continue;let i=o.slice(0,s).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(i)&&process.env[i]===void 0&&(process.env[i]=pe(o.slice(s+1)))}}de();function j(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function y(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function z(){return{memory:{autoCapture:j(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:j(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:j(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:j(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:y(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:y(process.env.MEMORY_RERANK_TOP,10),finalContext:y(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:y(process.env.MEMORY_TOKEN_BUDGET,2e3)},storage:{provider:process.env.MEMORY_STORAGE_PROVIDER??"huggingface",huggingface:{namespace:process.env.HF_NAMESPACE,bucket:process.env.HF_BUCKET,accessKeyId:process.env.HF_S3_ACCESS_KEY_ID,secretAccessKey:process.env.HF_S3_SECRET_ACCESS_KEY},localRoot:process.env.MEMORY_LOCAL_STORAGE_PATH},cache:{maxMb:y(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as ue}from"node:crypto";import{existsSync as V,mkdirSync as me,readFileSync as le,renameSync as ge,writeFileSync as fe}from"node:fs";import{basename as ye,dirname as k,join as R,parse as W,resolve as v}from"node:path";var K=".toolnet",he="project.json";function Se(r){return ue("sha256").update(r).digest("hex").slice(0,16)}function T(r){return R(r,K,he)}function je(r){return V(T(r))}function ke(r){let e=v(r),t=W(e).root;for(;;){if(je(e))return e;if(e===t)break;let o=k(e);if(o===e)break;e=o}return null}function ve(r){let e=v(r),t=W(e).root,o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(o.some(i=>V(R(e,i))))return e;if(e===t)break;let s=k(e);if(s===e)break;e=s}return v(r)}function xe(r){let e;try{e=JSON.parse(le(r,"utf8"))}catch(s){throw new Error(`Invalid ToolNet project manifest: ${r}: ${s instanceof Error?s.message:String(s)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${r}`);let t=e;if(typeof t.id!="string"||!t.id.trim())throw new Error(`ToolNet project manifest is missing id: ${r}`);if(typeof t.name!="string"||!t.name.trim())throw new Error(`ToolNet project manifest is missing name: ${r}`);let o=new Date().toISOString();return{version:1,id:t.id,name:t.name,remote:typeof t.remote=="string"&&t.remote.trim()?t.remote:t.name,rootPath:typeof t.rootPath=="string"?t.rootPath:k(k(r)),createdAt:typeof t.createdAt=="string"?t.createdAt:o,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:o,graphVersion:typeof t.graphVersion=="number"?t.graphVersion:0,memoryVersion:typeof t.memoryVersion=="number"?t.memoryVersion:0,metadata:t.metadata&&typeof t.metadata=="object"?t.metadata:void 0}}function D(r,e){let t=R(r,K);me(t,{recursive:!0});let o=T(r),s=`${o}.tmp-${process.pid}`;fe(s,JSON.stringify(e,null,2)+`
3
+ `,{encoding:"utf8",mode:384}),ge(s,o)}function L(r,e){return{id:r.id,name:r.name,remote:r.remote,rootPath:e,createdAt:r.createdAt,updatedAt:r.updatedAt,graphVersion:r.graphVersion,memoryVersion:r.memoryVersion,metadata:r.metadata}}var x=class{detect(e=process.cwd()){let t=v(e),o=ke(t);if(o){let d=T(o),p=xe(d);return p.rootPath!==o&&(p.rootPath=o,p.updatedAt=new Date().toISOString(),D(o,p)),L(p,o)}let s=ve(t),i=new Date().toISOString(),a=ye(s),c={version:1,id:Se(s),name:a,remote:a,rootPath:s,createdAt:i,updatedAt:i,graphVersion:0,memoryVersion:0};return D(s,c),L(c,s)}};import{homedir as De}from"node:os";import{join as Le}from"node:path";import{DeleteObjectCommand as we,GetObjectCommand as be,HeadObjectCommand as Pe,ListObjectsV2Command as Ae,PutObjectCommand as Re,S3Client as Te}from"@aws-sdk/client-s3";import{getSignedUrl as Me}from"@aws-sdk/s3-request-presigner";var w=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new Te({region:"us-east-1",endpoint:`https://s3.hf.co/${e.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,o="application/octet-stream"){let s=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Re({Bucket:this.bucket,Key:e,Body:s,ContentType:o}))}async get(e){let t=await Me(this.client,new be({Bucket:this.bucket,Key:e}),{expiresIn:60}),o=await fetch(t,{redirect:"follow"});if(o.status===404)return null;if(!o.ok)throw new Error(`HF download failed: ${o.status} ${o.statusText}`);return new Uint8Array(await o.arrayBuffer())}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new Pe({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new we({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],o;do{let s=await this.client.send(new Ae({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:o}));for(let i of s.Contents??[])i.Key&&t.push({key:i.Key,size:i.Size,updatedAt:i.LastModified?.toISOString()});o=s.IsTruncated?s.NextContinuationToken:void 0}while(o);return t}};import{access as J,mkdir as Ie,readFile as Oe,readdir as Ee,rm as Ce,stat as B,writeFile as _e}from"node:fs/promises";import{dirname as Ne,join as $e,relative as F,resolve as ze}from"node:path";var h=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return ze(this.root,t)}async put(e,t){let o=this.path(e);await Ie(Ne(o),{recursive:!0}),await _e(o,t)}async get(e){try{return await Oe(this.path(e))}catch(t){if(typeof t=="object"&&t!==null&&"code"in t&&t.code==="ENOENT")return null;throw t}}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await J(this.path(e)),!0}catch{return!1}}async delete(e){await Ce(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),o=[];try{await J(t)}catch{return o}let s=async a=>{let c=await Ee(a,{withFileTypes:!0});for(let d of c){let p=$e(a,d.name);if(d.isDirectory()){await s(p);continue}let f=await B(p);o.push({key:F(this.root,p),size:f.size,updatedAt:f.mtime.toISOString()})}},i=await B(t);return i.isDirectory()?await s(t):o.push({key:F(this.root,t),size:i.size,updatedAt:i.mtime.toISOString()}),o}};function H(r){let e=r.localRoot??Le(De(),".toolnet-memory","storage");if(r.provider==="huggingface"){let t=r.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new w({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):(console.warn("[storage] Hugging Face credentials missing. Using local fallback."),new h(e))}return new h(e)}function Ve(r){return new Promise(e=>setTimeout(e,r))}async function G(r,e={}){let t=Math.max(1,e.attempts??3),o=e.baseDelayMs??150,s=e.maxDelayMs??2e3,i;for(let a=1;a<=t;a++)try{return await r()}catch(c){if(i=c,a>=t)break;let d=Math.min(s,o*2**(a-1)),p=Math.floor(Math.random()*Math.max(1,d*.2));await Ve(d+p)}throw i}var We=new Set(["put","get","getText","delete","list"]);function U(r,e={}){return new Proxy(r,{get(t,o){let s=Reflect.get(t,o,t);return typeof s!="function"?s:We.has(o)?(...i)=>G(()=>Promise.resolve(s.apply(t,i)),e):s.bind(t)}})}function Y(r){let e=r.trim().replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,"").slice(0,100);if(!e||e==="."||e==="..")throw new Error("Invalid project storage folder");return e}function Z(r){let e=r.replace(/^\/+/,"");if(e.startsWith("memories/"))return"memory/records/"+e.slice(9);if(e.startsWith("vectors/"))return"memory/vectors/"+e.slice(8);if(e.startsWith("graph/"))return"code/graph/"+e.slice(6);let t=e.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(t)return`${t[1]}memory/records/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),t)return`${t[1]}memory/vectors/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),t)return`${t[1]}code/graph/${t[2]}`;let o=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(o)return`${o[1]}memory/records/${o[2]}`;if(o=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),o)return`${o[1]}memory/vectors/${o[2]}`;if(o=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),o)return`${o[1]}code/graph/${o[2]}`;let s=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return s?`${s[1]}memory/records/${s[2]}`:(s=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),s?`${s[1]}memory/vectors/${s[2]}`:(s=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),s?`${s[1]}code/graph/${s[2]}`:e))}var b=class{constructor(e,t,o,s){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=o,this.folder=Y(s??o),this.sourcePrefix=`projects/${t}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let e=`${this.targetPrefix}/project.json`,t=new Date().toISOString(),o=t,s=await this.provider.getText(e);if(s){let a;try{a=JSON.parse(s)}catch(c){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${c instanceof Error?c.message:String(c)}`)}if(typeof a.id=="string"&&a.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${a.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof a.createdAt=="string"&&(o=a.createdAt)}let i={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:o,updatedAt:t};await this.provider.put(e,JSON.stringify(i,null,2)+`
4
+ `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=Z(e),e===this.sourcePrefix)return this.targetPrefix;if(e.startsWith(`${this.sourcePrefix}/`))return this.targetPrefix+e.slice(this.sourcePrefix.length);if(e===this.targetPrefix||e.startsWith(`${this.targetPrefix}/`))return e;if(e.startsWith("projects/"))throw new Error(["Cross-project storage access denied.",`Current project: ${this.targetPrefix}`,`Requested key: ${e}`].join(" "));return e}async put(e,t,o){return await this.ensureRegistered(),this.provider.put(this.key(e),t,o)}async get(e){return await this.ensureRegistered(),this.provider.get(this.key(e))}async getText(e){return await this.ensureRegistered(),this.provider.getText(this.key(e))}async delete(e){return await this.ensureRegistered(),this.provider.delete(this.key(e))}async exists(e){return await this.ensureRegistered(),this.provider.exists(this.key(e))}async list(e){return await this.ensureRegistered(),this.provider.list(this.key(e))}};import{join as q}from"node:path";import{mkdirSync as Ge}from"node:fs";import{createHash as Ke}from"node:crypto";import{dirname as Je}from"node:path";import{mkdirSync as Be,readFileSync as Lr,renameSync as Fe,writeFileSync as He}from"node:fs";function X(r){return Ke("sha256").update(r).digest("hex")}function Q(r,e){Be(Je(r),{recursive:!0});let t=`${r}.${process.pid}.tmp`;He(t,JSON.stringify(e,null,2)+`
5
+ `,{encoding:"utf8",mode:384}),Fe(t,r)}function Ue(r){return r.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function g(r,e=20){let t=[],o=new Set;for(let s of r.slice().reverse()){let i=Ue(s);if(!(!i||o.has(i))&&(o.add(i),t.push(s),t.length>=e))break}return t.reverse()}function Ye(r){return r.kind==="phase"?/^Phase\s+\d+$/iu.test(r.text):r.kind==="task"?/^(?:TODO|Task|Việc)\s+\d+$/iu.test(r.text):!1}function ee(r,e){let t=e.status??r?.status??"pending",o=t;r&&(r.status==="completed"&&t!=="completed"?o="completed":t==="pending"&&(r.status==="in_progress"||r.status==="blocked")&&(o=r.status));let s=r&&Ye(e)?r.title:e.text;return{id:r?.id??X(e.key).slice(0,24),title:s,status:o,order:e.order??r?.order,confidence:Math.max(e.confidence,r?.confidence??0),updatedAt:e.occurredAt,updatedBy:{agent:e.agent,nativeSessionId:e.nativeSessionId,eventId:e.eventId}}}async function Ze(r,e){let t=`projects/${r.id}/work/observations/`,o=await e.list(t),s=[];for(let i of o.filter(a=>a.key.endsWith(".json")).sort((a,c)=>a.key.localeCompare(c.key))){let a=await e.getText(i.key);if(a)try{let c=JSON.parse(a);c.version===1&&Array.isArray(c.observations)&&s.push(c)}catch{}}return s}async function te(r,e){let o=(await Ze(r,e)).flatMap(n=>n.observations).sort((n,l)=>{let N=n.occurredAt.localeCompare(l.occurredAt);if(N!==0)return N;let $=n.sequence-l.sequence;return $!==0?$:n.id.localeCompare(l.id)}),s=new Map,i=new Map,a,c,d,p=[],f=[],I=[],O=[],E=[],C=[];for(let n of o)switch(n.kind){case"goal":a=n.text;break;case"plan":c=n.text;break;case"phase":s.set(n.key,ee(s.get(n.key),n));break;case"task":i.set(n.key,ee(i.get(n.key),n));break;case"decision":p.push(n.text);break;case"blocker":f.push(n.text);break;case"warning":I.push(n.text);break;case"next_action":O.push(n.text);break;case"file":E.push(n.text);break;case"test":C.push(n.text);break;case"session":d={agent:n.agent,nativeSessionId:n.nativeSessionId,sessionKey:n.sessionKey,updatedAt:n.occurredAt};break}let m=Array.from(s.values()).sort((n,l)=>(n.order??Number.MAX_SAFE_INTEGER)-(l.order??Number.MAX_SAFE_INTEGER)),u=Array.from(i.values()).sort((n,l)=>(n.order??Number.MAX_SAFE_INTEGER)-(l.order??Number.MAX_SAFE_INTEGER)),P=m.find(n=>n.status==="in_progress")??m.find(n=>n.status==="blocked")??m.find(n=>n.status==="pending"),S=u.find(n=>n.status==="in_progress")??u.find(n=>n.status==="blocked")??u.find(n=>n.status==="pending"),oe=g([...O,...S?[S.title]:[],...!S&&P?[P.title]:[],...u.filter(n=>n.status==="pending").slice(0,5).map(n=>n.title)],8),se=g([...f,...m.filter(n=>n.status==="blocked").map(n=>n.title),...u.filter(n=>n.status==="blocked").map(n=>n.title)],20),A={version:1,projectId:r.id,projectName:r.name,goal:a,plan:c,phases:m,tasks:u,decisions:g(p,20),blockers:se,warnings:g(I,20),nextActions:oe,filesTouched:g(E,30),tests:g(C,20),currentPhase:P,currentTask:S,progress:{phasesTotal:m.length,phasesCompleted:m.filter(n=>n.status==="completed").length,tasksTotal:u.length,tasksCompleted:u.filter(n=>n.status==="completed").length,blocked:m.filter(n=>n.status==="blocked").length+u.filter(n=>n.status==="blocked").length},lastSession:d,updatedAt:o.length?o[o.length-1].occurredAt:new Date().toISOString()},_=q(r.rootPath,".toolnet","work");return Ge(_,{recursive:!0}),Q(q(_,"current.json"),A),await e.put(`projects/${r.id}/work/current.json`,JSON.stringify(A,null,2)+`
6
+ `,"application/json"),A}async function M(r,e){let t=await e.getText(`projects/${r.id}/work/current.json`);if(!t)return null;try{return JSON.parse(t)}catch{return null}}function Xe(r,e){let t=r.indexOf(e);return t>=0?r[t+1]:void 0}function Qe(r){let e=z(),t=U(H({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3});return new b(t,r.id,r.name,r.remote??r.name)}function re(r){console.log(),console.log(`Project: ${r.projectName}`),r.goal&&console.log(`Goal: ${r.goal}`),r.currentPhase&&console.log(`Current phase: ${r.currentPhase.title} [${r.currentPhase.status}]`),r.currentTask&&console.log(`Current task: ${r.currentTask.title} [${r.currentTask.status}]`),console.log(`Phases: ${r.progress.phasesCompleted}/${r.progress.phasesTotal}`),console.log(`Tasks: ${r.progress.tasksCompleted}/${r.progress.tasksTotal}`),r.nextActions.length&&(console.log(),console.log("Next actions:"),r.nextActions.forEach((e,t)=>console.log(`${t+1}. ${e}`))),r.blockers.length&&(console.log(),console.log("Blockers:"),r.blockers.forEach(e=>console.log(`- ${e}`))),r.lastSession&&(console.log(),console.log(`Last session: ${r.lastSession.agent} / ${r.lastSession.nativeSessionId}`))}async function qe(){let[r="help",...e]=process.argv.slice(2),t=new x().detect(Xe(e,"--project")??process.cwd()),o=Qe(t);if(r==="reconcile"){let s=await te(t,o);re(s);return}if(r==="status"){let s=await M(t,o);if(!s){console.log("No active work state yet.");return}re(s);return}if(r==="json"){let s=await M(t,o);console.log(JSON.stringify(s,null,2));return}console.log(`Work Continuity
7
+
8
+ Commands:
9
+ status [--project PATH]
10
+ json [--project PATH]
11
+ reconcile [--project PATH]
12
+ `)}qe().catch(r=>{console.error(r instanceof Error?r.message:r),process.exit(1)});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toolnet-memory",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "dev": "tsx src/index.ts",
@@ -41,7 +41,9 @@
41
41
  "work-continuity:test": "vitest run tests/work-continuity/work-continuity.test.ts",
42
42
  "work-handoff:test": "vitest run tests/work-continuity/handoff-brief.test.ts",
43
43
  "semantic-work:test": "vitest run tests/work-continuity/semantic-context.test.ts",
44
- "context-injection:test": "vitest run tests/work-continuity/context-injection.test.ts"
44
+ "context-injection:test": "vitest run tests/work-continuity/context-injection.test.ts",
45
+ "build:bundle": "npm run build && node scripts/build-bundle.mjs",
46
+ "build:release": "npm run build:prod && node scripts/build-bundle.mjs"
45
47
  },
46
48
  "dependencies": {
47
49
  "@aws-sdk/client-s3": "^3.1102.0",
@@ -53,6 +55,7 @@
53
55
  "devDependencies": {
54
56
  "@types/node": "^24.0.0",
55
57
  "3d-force-graph": "^1.80.0",
58
+ "esbuild": "^0.28.1",
56
59
  "tsx": "^4.20.0",
57
60
  "typescript": "^5.9.0",
58
61
  "vitest": "^3.2.0"
@@ -61,9 +64,12 @@
61
64
  "toolnet-memory": "bin/toolnet-memory"
62
65
  },
63
66
  "files": [
64
- "dist",
65
- "bin",
67
+ "bundle",
68
+ "bin/toolnet-memory",
66
69
  "README.md",
67
70
  ".env.example"
68
- ]
71
+ ],
72
+ "publishConfig": {
73
+ "access": "public"
74
+ }
69
75
  }
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1,78 +0,0 @@
1
- export class ToolNetMemoryClient {
2
- runtime;
3
- autoRetrieval;
4
- autoImpactGuard;
5
- constructor(runtime, autoRetrieval, autoImpactGuard) {
6
- this.runtime = runtime;
7
- this.autoRetrieval = autoRetrieval;
8
- this.autoImpactGuard = autoImpactGuard;
9
- }
10
- sessionStart() {
11
- return this.runtime
12
- .sessionStart();
13
- }
14
- sessionEnd() {
15
- return this.runtime
16
- .sessionEnd();
17
- }
18
- prompt(content) {
19
- return this.runtime
20
- .userPrompt(content);
21
- }
22
- preparePrompt(content) {
23
- if (!this.autoRetrieval) {
24
- return Promise.resolve({
25
- originalPrompt: content,
26
- context: "",
27
- augmentedPrompt: content,
28
- });
29
- }
30
- return this.autoRetrieval
31
- .prepare(content);
32
- }
33
- /*
34
- * Đây là hook ToolNet Agent cần gọi
35
- * TRƯỚC tool executor.
36
- */
37
- async beforeTool(tool, input) {
38
- const impact = this.autoImpactGuard
39
- ? await this.autoImpactGuard
40
- .beforeTool(tool, input)
41
- : null;
42
- await this.runtime
43
- .beforeTool(tool, input);
44
- return impact;
45
- }
46
- afterTool(tool, output) {
47
- return this.runtime
48
- .afterTool(tool, output);
49
- }
50
- fileRead(filePath) {
51
- return this.runtime
52
- .fileRead(filePath);
53
- }
54
- fileWrite(filePath) {
55
- return this.runtime
56
- .fileWrite(filePath);
57
- }
58
- command(command, exitCode) {
59
- return this.runtime
60
- .command(command, exitCode);
61
- }
62
- error(error) {
63
- return this.runtime
64
- .error(error);
65
- }
66
- decision(content) {
67
- return this.runtime
68
- .decision(content);
69
- }
70
- todo(content) {
71
- return this.runtime
72
- .todo(content);
73
- }
74
- flush() {
75
- return this.runtime
76
- .flush();
77
- }
78
- }
@@ -1 +0,0 @@
1
- export * from "./client.js";
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1,21 +0,0 @@
1
- import { randomUUID, } from "node:crypto";
2
- import { Sanitizer } from "../security/sanitizer.js";
3
- export class ActivityCapture {
4
- queue;
5
- sanitizer = new Sanitizer();
6
- constructor(queue) {
7
- this.queue = queue;
8
- }
9
- capture(projectId, type, data = {}) {
10
- const event = {
11
- id: randomUUID(),
12
- projectId,
13
- type,
14
- timestamp: new Date().toISOString(),
15
- data: this.sanitizer
16
- .sanitizeValue(data),
17
- };
18
- this.queue.push(event);
19
- return event;
20
- }
21
- }
@@ -1,12 +0,0 @@
1
- export class CommandCapture {
2
- capture;
3
- constructor(capture) {
4
- this.capture = capture;
5
- }
6
- record(projectId, command, exitCode) {
7
- return this.capture.capture(projectId, "command", {
8
- command,
9
- exitCode,
10
- });
11
- }
12
- }
@@ -1,14 +0,0 @@
1
- export class ErrorCapture {
2
- capture;
3
- constructor(capture) {
4
- this.capture = capture;
5
- }
6
- record(projectId, error) {
7
- const message = error instanceof Error
8
- ? error.message
9
- : String(error);
10
- return this.capture.capture(projectId, "error", {
11
- message,
12
- });
13
- }
14
- }
@@ -1,28 +0,0 @@
1
- import { createHash } from "node:crypto";
2
- export class EventDeduplicator {
3
- seen = new Set();
4
- fingerprint(event) {
5
- return createHash("sha256")
6
- .update(JSON.stringify({
7
- projectId: event.projectId,
8
- type: event.type,
9
- data: event.data,
10
- }))
11
- .digest("hex");
12
- }
13
- filter(events) {
14
- const result = [];
15
- for (const event of events) {
16
- const hash = this.fingerprint(event);
17
- if (this.seen.has(hash)) {
18
- continue;
19
- }
20
- this.seen.add(hash);
21
- result.push(event);
22
- }
23
- return result;
24
- }
25
- clear() {
26
- this.seen.clear();
27
- }
28
- }
@@ -1,20 +0,0 @@
1
- export class EventQueue {
2
- events = [];
3
- push(event) {
4
- this.events.push(event);
5
- }
6
- drain() {
7
- const items = [...this.events];
8
- this.events.length = 0;
9
- return items;
10
- }
11
- list() {
12
- return [...this.events];
13
- }
14
- size() {
15
- return this.events.length;
16
- }
17
- shouldFlush(maxEvents) {
18
- return this.events.length >= maxEvents;
19
- }
20
- }
@@ -1,23 +0,0 @@
1
- import { isSensitiveFile, } from "../security/file-filter.js";
2
- export class FileCapture {
3
- capture;
4
- constructor(capture) {
5
- this.capture = capture;
6
- }
7
- read(projectId, filePath) {
8
- if (isSensitiveFile(filePath)) {
9
- return null;
10
- }
11
- return this.capture.capture(projectId, "file_read", {
12
- filePath,
13
- });
14
- }
15
- write(projectId, filePath) {
16
- if (isSensitiveFile(filePath)) {
17
- return null;
18
- }
19
- return this.capture.capture(projectId, "file_write", {
20
- filePath,
21
- });
22
- }
23
- }
@@ -1,8 +0,0 @@
1
- export * from "./event-queue.js";
2
- export * from "./event-deduplicator.js";
3
- export * from "./activity-capture.js";
4
- export * from "./session-capture.js";
5
- export * from "./tool-capture.js";
6
- export * from "./file-capture.js";
7
- export * from "./command-capture.js";
8
- export * from "./error-capture.js";
@@ -1,18 +0,0 @@
1
- import { randomUUID, } from "node:crypto";
2
- export class SessionCapture {
3
- capture;
4
- sessionId = randomUUID();
5
- constructor(capture) {
6
- this.capture = capture;
7
- }
8
- start(projectId) {
9
- return this.capture.capture(projectId, "session_start", {
10
- sessionId: this.sessionId,
11
- });
12
- }
13
- end(projectId) {
14
- return this.capture.capture(projectId, "session_end", {
15
- sessionId: this.sessionId,
16
- });
17
- }
18
- }
@@ -1,13 +0,0 @@
1
- export class ToolCapture {
2
- capture;
3
- constructor(capture) {
4
- this.capture = capture;
5
- }
6
- record(projectId, tool, input, output) {
7
- return this.capture.capture(projectId, "tool_call", {
8
- tool,
9
- input,
10
- output,
11
- });
12
- }
13
- }
@@ -1,26 +0,0 @@
1
- import { DeadCodeAnalyzer, } from "./dead-code-analyzer.js";
2
- import { DependencyAnalyzer, } from "./dependency-analyzer.js";
3
- export class CodeAnalysisEngine {
4
- graph;
5
- constructor(graph) {
6
- this.graph = graph;
7
- }
8
- analyze(projectId) {
9
- const deadCode = new DeadCodeAnalyzer(this.graph).analyze(projectId);
10
- const dependencies = new DependencyAnalyzer(this.graph).analyze(projectId);
11
- return {
12
- version: 1,
13
- projectId,
14
- updatedAt: new Date()
15
- .toISOString(),
16
- summary: {
17
- deadCodeCandidates: deadCode.length,
18
- highConfidenceDeadCode: deadCode.filter((item) => item.confidence ===
19
- "high").length,
20
- files: dependencies.length,
21
- },
22
- deadCode,
23
- dependencies,
24
- };
25
- }
26
- }
@@ -1,127 +0,0 @@
1
- import { EntryPointDetector, } from "../architecture/entry-points.js";
2
- const USAGE_EDGES = new Set([
3
- "CALLS",
4
- "CALL_REFERENCE",
5
- "IMPORTS",
6
- "USES_TYPE",
7
- "WRITES",
8
- "INHERITS",
9
- "IMPLEMENTS",
10
- "ROUTE",
11
- "TESTS",
12
- ]);
13
- function normalize(value) {
14
- return value
15
- .replaceAll("\\", "/")
16
- .toLowerCase();
17
- }
18
- function isTestFile(filePath) {
19
- const path = normalize(filePath);
20
- return (path.startsWith("tests/") ||
21
- path.includes("/tests/") ||
22
- path.includes("__tests__") ||
23
- /\.(test|spec)\.[^.]+$/
24
- .test(path));
25
- }
26
- function looksPublicApi(symbol) {
27
- const path = normalize(symbol.filePath);
28
- return (path.startsWith("bin/") ||
29
- /(^|\/)index\.[^.]+$/
30
- .test(path) ||
31
- /(^|\/)(main|server|cli)\.[^.]+$/
32
- .test(path));
33
- }
34
- export class DeadCodeAnalyzer {
35
- graph;
36
- constructor(graph) {
37
- this.graph = graph;
38
- }
39
- analyze(projectId) {
40
- const symbols = this.graph.allSymbols(projectId);
41
- const edges = this.graph.allEdges(projectId);
42
- const entrySymbols = new Set(new EntryPointDetector(this.graph)
43
- .detect(projectId)
44
- .map((entry) => entry.symbolId));
45
- const candidates = [];
46
- for (const symbol of symbols) {
47
- if (![
48
- "function",
49
- "method",
50
- "class",
51
- "interface",
52
- "property",
53
- ].includes(symbol.type)) {
54
- continue;
55
- }
56
- if (isTestFile(symbol.filePath) ||
57
- entrySymbols.has(symbol.id) ||
58
- looksPublicApi(symbol)) {
59
- continue;
60
- }
61
- const incoming = edges.filter((edge) => edge.to ===
62
- symbol.id &&
63
- USAGE_EDGES.has(edge.type));
64
- if (incoming.length >
65
- 0) {
66
- continue;
67
- }
68
- const outgoing = edges.filter((edge) => edge.from ===
69
- symbol.id &&
70
- USAGE_EDGES.has(edge.type));
71
- const reasons = [
72
- "no incoming usage edge",
73
- ];
74
- let score = 50;
75
- if (symbol.type ===
76
- "function" ||
77
- symbol.type ===
78
- "method") {
79
- score +=
80
- 20;
81
- reasons.push("callable symbol");
82
- }
83
- if (symbol.type ===
84
- "property") {
85
- score -=
86
- 15;
87
- }
88
- if (outgoing.length ===
89
- 0) {
90
- score +=
91
- 10;
92
- reasons.push("no outgoing dependency");
93
- }
94
- const path = normalize(symbol.filePath);
95
- if (path.includes("/internal/")) {
96
- score +=
97
- 10;
98
- reasons.push("internal implementation");
99
- }
100
- if (symbol.name
101
- .startsWith("_")) {
102
- score +=
103
- 5;
104
- }
105
- const confidence = score >= 75
106
- ? "high"
107
- : score >= 55
108
- ? "medium"
109
- : "low";
110
- candidates.push({
111
- symbolId: symbol.id,
112
- name: symbol.name,
113
- qualifiedName: symbol.qualifiedName,
114
- type: symbol.type,
115
- filePath: symbol.filePath,
116
- startLine: symbol.startLine,
117
- confidence,
118
- score,
119
- reasons,
120
- });
121
- }
122
- return candidates.sort((a, b) => b.score -
123
- a.score ||
124
- a.filePath.localeCompare(b.filePath) ||
125
- a.name.localeCompare(b.name));
126
- }
127
- }
@@ -1,66 +0,0 @@
1
- const EDGE_TYPES = new Set([
2
- "CALLS",
3
- "CALL_REFERENCE",
4
- "IMPORTS",
5
- "USES_TYPE",
6
- "WRITES",
7
- "INHERITS",
8
- "IMPLEMENTS",
9
- "ROUTE",
10
- ]);
11
- export class DependencyAnalyzer {
12
- graph;
13
- constructor(graph) {
14
- this.graph = graph;
15
- }
16
- analyze(projectId) {
17
- const symbols = this.graph.allSymbols(projectId);
18
- const edges = this.graph
19
- .allEdges(projectId)
20
- .filter((edge) => EDGE_TYPES.has(edge.type));
21
- const symbolById = new Map(symbols.map((symbol) => [
22
- symbol.id,
23
- symbol,
24
- ]));
25
- const files = [
26
- ...new Set(symbols.map((symbol) => symbol.filePath)),
27
- ].sort();
28
- return files.map((filePath) => {
29
- const dependencies = new Set();
30
- const dependents = new Set();
31
- let outgoingEdges = 0;
32
- let incomingEdges = 0;
33
- for (const edge of edges) {
34
- const from = symbolById.get(edge.from);
35
- const to = symbolById.get(edge.to);
36
- if (!from ||
37
- !to ||
38
- from.filePath ===
39
- to.filePath) {
40
- continue;
41
- }
42
- if (from.filePath ===
43
- filePath) {
44
- dependencies.add(to.filePath);
45
- outgoingEdges++;
46
- }
47
- if (to.filePath ===
48
- filePath) {
49
- dependents.add(from.filePath);
50
- incomingEdges++;
51
- }
52
- }
53
- return {
54
- filePath,
55
- dependencies: [
56
- ...dependencies,
57
- ].sort(),
58
- dependents: [
59
- ...dependents,
60
- ].sort(),
61
- outgoingEdges,
62
- incomingEdges,
63
- };
64
- });
65
- }
66
- }
@@ -1,4 +0,0 @@
1
- export * from "./types.js";
2
- export * from "./dead-code-analyzer.js";
3
- export * from "./dependency-analyzer.js";
4
- export * from "./analysis-engine.js";
@@ -1 +0,0 @@
1
- export {};
@@ -1,48 +0,0 @@
1
- import { ClusterDetector, } from "./clusters.js";
2
- import { EntryPointDetector, } from "./entry-points.js";
3
- import { HotspotAnalyzer, } from "./hotspots.js";
4
- import { LayerDetector, } from "./layers.js";
5
- export class ArchitectureEngine {
6
- graph;
7
- entryPoints;
8
- hotspots;
9
- layers;
10
- clusters;
11
- constructor(graph) {
12
- this.graph = graph;
13
- this.entryPoints =
14
- new EntryPointDetector(graph);
15
- this.hotspots =
16
- new HotspotAnalyzer(graph);
17
- this.layers =
18
- new LayerDetector(graph);
19
- this.clusters =
20
- new ClusterDetector(graph);
21
- }
22
- analyze(projectId) {
23
- const entryPoints = this.entryPoints.detect(projectId);
24
- const hotspots = this.hotspots.analyze(projectId);
25
- const layers = this.layers.detect(projectId);
26
- const clusters = this.clusters.detect(projectId);
27
- const files = new Set(this.graph
28
- .allSymbols(projectId)
29
- .map((symbol) => symbol.filePath));
30
- return {
31
- version: 1,
32
- projectId,
33
- updatedAt: new Date()
34
- .toISOString(),
35
- summary: {
36
- files: files.size,
37
- entryPoints: entryPoints.length,
38
- hotspots: hotspots.length,
39
- layers: layers.length,
40
- clusters: clusters.length,
41
- },
42
- entryPoints,
43
- hotspots,
44
- layers,
45
- clusters,
46
- };
47
- }
48
- }