toolnet-memory 0.2.1 → 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 (342) hide show
  1. package/README.md +55 -28
  2. package/bin/toolnet-memory +55 -55
  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 +9 -6
  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/setup.js +0 -219
  199. package/dist/src/production/snapshot-cli.js +0 -58
  200. package/dist/src/project-manual/cli.js +0 -77
  201. package/dist/src/project-manual/index.js +0 -2
  202. package/dist/src/project-manual/manager.js +0 -147
  203. package/dist/src/project-manual/types.js +0 -1
  204. package/dist/src/retrieval/bm25/index.js +0 -1
  205. package/dist/src/retrieval/bm25/search.js +0 -1
  206. package/dist/src/retrieval/bm25.js +0 -30
  207. package/dist/src/retrieval/context-budget.js +0 -1
  208. package/dist/src/retrieval/context-builder.js +0 -22
  209. package/dist/src/retrieval/graph/index.js +0 -1
  210. package/dist/src/retrieval/graph/search.js +0 -1
  211. package/dist/src/retrieval/hybrid/hybrid-search.js +0 -1
  212. package/dist/src/retrieval/hybrid/index.js +0 -1
  213. package/dist/src/retrieval/hybrid-search.js +0 -68
  214. package/dist/src/retrieval/importance.js +0 -16
  215. package/dist/src/retrieval/index.js +0 -12
  216. package/dist/src/retrieval/query-analyzer.js +0 -32
  217. package/dist/src/retrieval/query-classifier.js +0 -1
  218. package/dist/src/retrieval/query-expansion.js +0 -1
  219. package/dist/src/retrieval/recency.js +0 -12
  220. package/dist/src/retrieval/reranker/index.js +0 -1
  221. package/dist/src/retrieval/reranker/reranker.js +0 -1
  222. package/dist/src/retrieval/retrieval-engine.js +0 -17
  223. package/dist/src/retrieval/tokenizer.js +0 -9
  224. package/dist/src/retrieval/type-priority.js +0 -10
  225. package/dist/src/retrieval/types.js +0 -1
  226. package/dist/src/retrieval/vector/index.js +0 -4
  227. package/dist/src/retrieval/vector/metadata-filter.js +0 -1
  228. package/dist/src/retrieval/vector/persistence.js +0 -67
  229. package/dist/src/retrieval/vector/search.js +0 -12
  230. package/dist/src/retrieval/vector/test-persistence.js +0 -36
  231. package/dist/src/retrieval/vector/upsert.js +0 -40
  232. package/dist/src/retrieval/vector/vector-store.js +0 -89
  233. package/dist/src/retrieval/vector-hybrid-engine.js +0 -91
  234. package/dist/src/runtime/bootstrap.js +0 -28
  235. package/dist/src/runtime/graceful.js +0 -17
  236. package/dist/src/runtime/index.js +0 -3
  237. package/dist/src/runtime/toolnet-memory-runtime.js +0 -156
  238. package/dist/src/security/encryption.js +0 -1
  239. package/dist/src/security/file-filter.js +0 -30
  240. package/dist/src/security/index.js +0 -3
  241. package/dist/src/security/sanitizer.js +0 -49
  242. package/dist/src/security/secret-scanner.js +0 -56
  243. package/dist/src/session/agy/adapter.js +0 -159
  244. package/dist/src/session/agy/cli.js +0 -87
  245. package/dist/src/session/agy/hook-installer.js +0 -62
  246. package/dist/src/session/agy/hook.js +0 -167
  247. package/dist/src/session/agy/index.js +0 -5
  248. package/dist/src/session/agy/project-resolver.js +0 -27
  249. package/dist/src/session/agy/recovery.js +0 -112
  250. package/dist/src/session/agy/transcript.js +0 -191
  251. package/dist/src/session/codex/adapter.js +0 -138
  252. package/dist/src/session/codex/cli.js +0 -236
  253. package/dist/src/session/codex/context-hook-installer.js +0 -70
  254. package/dist/src/session/codex/context-hook.js +0 -69
  255. package/dist/src/session/codex/discovery.js +0 -138
  256. package/dist/src/session/codex/index.js +0 -6
  257. package/dist/src/session/codex/notify-installer.js +0 -135
  258. package/dist/src/session/codex/project-resolver.js +0 -25
  259. package/dist/src/session/codex/recovery.js +0 -27
  260. package/dist/src/session/codex/rollout.js +0 -186
  261. package/dist/src/session/core.js +0 -239
  262. package/dist/src/session/identity.js +0 -57
  263. package/dist/src/session/index.js +0 -9
  264. package/dist/src/session/learner/cli.js +0 -62
  265. package/dist/src/session/learner/extractor.js +0 -461
  266. package/dist/src/session/learner/index.js +0 -4
  267. package/dist/src/session/learner/journal.js +0 -159
  268. package/dist/src/session/learner/learner.js +0 -124
  269. package/dist/src/session/learner/types.js +0 -1
  270. package/dist/src/session/opencode/adapter.js +0 -553
  271. package/dist/src/session/opencode/cli.js +0 -121
  272. package/dist/src/session/opencode/index.js +0 -2
  273. package/dist/src/session/opencode/plugin-installer.js +0 -230
  274. package/dist/src/session/store.js +0 -242
  275. package/dist/src/session/types.js +0 -1
  276. package/dist/src/session/utils.js +0 -47
  277. package/dist/src/session/wal.js +0 -303
  278. package/dist/src/snapshot/index.js +0 -2
  279. package/dist/src/snapshot/manager.js +0 -130
  280. package/dist/src/snapshot/test-snapshot.js +0 -28
  281. package/dist/src/snapshot/types.js +0 -1
  282. package/dist/src/storage/architecture-store.js +0 -37
  283. package/dist/src/storage/cleanup-health.js +0 -20
  284. package/dist/src/storage/code-analysis-store.js +0 -35
  285. package/dist/src/storage/code-chunk-store.js +0 -25
  286. package/dist/src/storage/code-graph-store.js +0 -24
  287. package/dist/src/storage/code-manifest-store.js +0 -24
  288. package/dist/src/storage/code-vector-store.js +0 -25
  289. package/dist/src/storage/github/client.js +0 -1
  290. package/dist/src/storage/github/index.js +0 -1
  291. package/dist/src/storage/google-drive/client.js +0 -1
  292. package/dist/src/storage/google-drive/index.js +0 -1
  293. package/dist/src/storage/huggingface/client.js +0 -116
  294. package/dist/src/storage/huggingface/index.js +0 -1
  295. package/dist/src/storage/index.js +0 -16
  296. package/dist/src/storage/list-bucket-raw.js +0 -14
  297. package/dist/src/storage/list-bucket-tree.js +0 -38
  298. package/dist/src/storage/local/client.js +0 -99
  299. package/dist/src/storage/local/index.js +0 -1
  300. package/dist/src/storage/memory-store.js +0 -30
  301. package/dist/src/storage/project/cleanup-layout-v1.js +0 -72
  302. package/dist/src/storage/project/folder.js +0 -15
  303. package/dist/src/storage/project/index.js +0 -3
  304. package/dist/src/storage/project/layout.js +0 -74
  305. package/dist/src/storage/project/migrate-layout-v2.js +0 -101
  306. package/dist/src/storage/project/migrate.js +0 -73
  307. package/dist/src/storage/project/scoped-provider.js +0 -165
  308. package/dist/src/storage/provider.js +0 -26
  309. package/dist/src/storage/retrying-provider.js +0 -23
  310. package/dist/src/storage/test-connection.js +0 -32
  311. package/dist/src/storage/type-resolution-store.js +0 -26
  312. package/dist/src/storage/types.js +0 -1
  313. package/dist/src/storage/vector-store.js +0 -30
  314. package/dist/src/storage/visualization-store.js +0 -25
  315. package/dist/src/sync/compressor.js +0 -1
  316. package/dist/src/sync/conflict-resolver.js +0 -1
  317. package/dist/src/sync/downloader.js +0 -1
  318. package/dist/src/sync/index.js +0 -1
  319. package/dist/src/sync/sync-engine.js +0 -1
  320. package/dist/src/sync/upload-queue.js +0 -1
  321. package/dist/src/utils/retry.js +0 -29
  322. package/dist/src/visualization/server.js +0 -270
  323. package/dist/src/work-continuity/brief-cache.js +0 -107
  324. package/dist/src/work-continuity/brief.js +0 -349
  325. package/dist/src/work-continuity/cli.js +0 -96
  326. package/dist/src/work-continuity/context-cli.js +0 -106
  327. package/dist/src/work-continuity/context-runtime-cli.js +0 -88
  328. package/dist/src/work-continuity/extractor.js +0 -339
  329. package/dist/src/work-continuity/handoff.js +0 -185
  330. package/dist/src/work-continuity/index.js +0 -14
  331. package/dist/src/work-continuity/injection.js +0 -84
  332. package/dist/src/work-continuity/journal.js +0 -49
  333. package/dist/src/work-continuity/learner.js +0 -127
  334. package/dist/src/work-continuity/reducer.js +0 -316
  335. package/dist/src/work-continuity/semantic-extractor.js +0 -360
  336. package/dist/src/work-continuity/semantic-journal.js +0 -55
  337. package/dist/src/work-continuity/semantic-learner.js +0 -125
  338. package/dist/src/work-continuity/semantic-reducer.js +0 -268
  339. package/dist/src/work-continuity/semantic-types.js +0 -1
  340. package/dist/src/work-continuity/types.js +0 -1
  341. package/dist/visualization/public/index.html +0 -2896
  342. package/dist/visualization/public/vendor/3d-force-graph.min.js +0 -5
@@ -0,0 +1,92 @@
1
+ import{existsSync as Ps,readFileSync as Os}from"node:fs";import{spawn as Es}from"node:child_process";import{homedir as Cs}from"node:os";import{join as Ms}from"node:path";import{existsSync as Ft,readFileSync as Wt}from"node:fs";import{homedir as zt}from"node:os";import{join as Bt}from"node:path";function Kt(t){let e=t.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 Dt(){let t=process.env.TOOLNET_GLOBAL_ENV??Bt(zt(),".config","toolnet-memory",".env");if(!Ft(t))return;let e=Wt(t,"utf8");for(let n of e.split(/\r?\n/)){let r=n.trim();if(!r||r.startsWith("#"))continue;r.startsWith("export ")&&(r=r.slice(7));let s=r.indexOf("=");if(s<=0)continue;let o=r.slice(0,s).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(o)&&process.env[o]===void 0&&(process.env[o]=Kt(r.slice(s+1)))}}Dt();function J(t,e){return t===void 0?e:["1","true","yes","on"].includes(t.toLowerCase())}function W(t,e){if(!t)return e;let n=Number(t);return Number.isFinite(n)?n:e}function Me(){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:W(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:W(process.env.MEMORY_RERANK_TOP,10),finalContext:W(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:W(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:W(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as Jt}from"node:crypto";import{existsSync as Ne,mkdirSync as qt,readFileSync as Vt,renameSync as Ht,writeFileSync as Ut}from"node:fs";import{basename as Yt,dirname as q,join as me,parse as Te,resolve as V}from"node:path";var _e=".toolnet",Gt="project.json";function Xt(t){return Jt("sha256").update(t).digest("hex").slice(0,16)}function ge(t){return me(t,_e,Gt)}function Qt(t){return Ne(ge(t))}function Zt(t){let e=V(t),n=Te(e).root;for(;;){if(Qt(e))return e;if(e===n)break;let r=q(e);if(r===e)break;e=r}return null}function en(t){let e=V(t),n=Te(e).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(o=>Ne(me(e,o))))return e;if(e===n)break;let s=q(e);if(s===e)break;e=s}return V(t)}function tn(t){let e;try{e=JSON.parse(Vt(t,"utf8"))}catch(s){throw new Error(`Invalid ToolNet project manifest: ${t}: ${s instanceof Error?s.message:String(s)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${t}`);let n=e;if(typeof n.id!="string"||!n.id.trim())throw new Error(`ToolNet project manifest is missing id: ${t}`);if(typeof n.name!="string"||!n.name.trim())throw new Error(`ToolNet project manifest is missing name: ${t}`);let r=new Date().toISOString();return{version:1,id:n.id,name:n.name,remote:typeof n.remote=="string"&&n.remote.trim()?n.remote:n.name,rootPath:typeof n.rootPath=="string"?n.rootPath:q(q(t)),createdAt:typeof n.createdAt=="string"?n.createdAt:r,updatedAt:typeof n.updatedAt=="string"?n.updatedAt:r,graphVersion:typeof n.graphVersion=="number"?n.graphVersion:0,memoryVersion:typeof n.memoryVersion=="number"?n.memoryVersion:0,metadata:n.metadata&&typeof n.metadata=="object"?n.metadata:void 0}}function Ae(t,e){let n=me(t,_e);qt(n,{recursive:!0});let r=ge(t),s=`${r}.tmp-${process.pid}`;Ut(s,JSON.stringify(e,null,2)+`
3
+ `,{encoding:"utf8",mode:384}),Ht(s,r)}function Re(t,e){return{id:t.id,name:t.name,remote:t.remote,rootPath:e,createdAt:t.createdAt,updatedAt:t.updatedAt,graphVersion:t.graphVersion,memoryVersion:t.memoryVersion,metadata:t.metadata}}var T=class{detect(e=process.cwd()){let n=V(e),r=Zt(n);if(r){let c=ge(r),a=tn(c);return a.rootPath!==r&&(a.rootPath=r,a.updatedAt=new Date().toISOString(),Ae(r,a)),Re(a,r)}let s=en(n),o=new Date().toISOString(),i=Yt(s),u={version:1,id:Xt(s),name:i,remote:i,rootPath:s,createdAt:o,updatedAt:o,graphVersion:0,memoryVersion:0};return Ae(s,u),Re(u,s)}};var nn=[{type:"openai_key",regex:/\bsk-[A-Za-z0-9_\-]{20,}\b/g},{type:"huggingface_token",regex:/\bhf_[A-Za-z0-9]{20,}\b/g},{type:"hf_s3_access_key",regex:/\bHFAK[A-Za-z0-9]{8,}\b/g},{type:"bearer_token",regex:/\bBearer\s+[A-Za-z0-9._\-]{16,}\b/gi},{type:"jwt",regex:/\beyJ[A-Za-z0-9_\-]{8,}\.[A-Za-z0-9_\-]{8,}\.[A-Za-z0-9_\-]{8,}\b/g},{type:"private_key",regex:/-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/g},{type:"password_assignment",regex:/\b(password|passwd|pwd)\s*[:=]\s*["']?[^"'\s]{6,}["']?/gi},{type:"secret_assignment",regex:/\b(secret|api[_-]?key|access[_-]?token|refresh[_-]?token)\s*[:=]\s*["']?[^"'\s]{8,}["']?/gi},{type:"cookie",regex:/\b(cookie|set-cookie)\s*[:=]\s*[^;\n]{8,}/gi}],H=class{scan(e){let n=[];for(let r of nn){let s=new RegExp(r.regex.source,r.regex.flags);for(let o of e.matchAll(s))n.push({type:r.type,value:o[0]})}return n}hasSecrets(e){return this.scan(e).length>0}};var z=class{scanner=new H;sanitize(e){let n=e,r=this.scanner.scan(e),s=new Set;for(let o of r)s.add(o.type),n=n.split(o.value).join(`[REDACTED:${o.type}]`);return{text:n,redacted:r.length,secretTypes:[...s]}}sanitizeValue(e){if(typeof e=="string")return this.sanitize(e).text;if(Array.isArray(e))return e.map(n=>this.sanitizeValue(n));if(e&&typeof e=="object"){let n={};for(let[r,s]of Object.entries(e)){let o=r.toLowerCase();o.includes("password")||o.includes("secret")||o.includes("token")||o.includes("cookie")||o.includes("authorization")?n[r]="[REDACTED]":n[r]=this.sanitizeValue(s)}return n}return e}};import{homedir as vn}from"node:os";import{join as wn}from"node:path";import{DeleteObjectCommand as rn,GetObjectCommand as sn,HeadObjectCommand as on,ListObjectsV2Command as an,PutObjectCommand as cn,S3Client as un}from"@aws-sdk/client-s3";import{getSignedUrl as ln}from"@aws-sdk/s3-request-presigner";var U=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new un({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,n,r="application/octet-stream"){let s=typeof n=="string"?Buffer.from(n,"utf8"):n;await this.client.send(new cn({Bucket:this.bucket,Key:e,Body:s,ContentType:r}))}async get(e){let n=await ln(this.client,new sn({Bucket:this.bucket,Key:e}),{expiresIn:60}),r=await fetch(n,{redirect:"follow"});if(r.status===404)return null;if(!r.ok)throw new Error(`HF download failed: ${r.status} ${r.statusText}`);return new Uint8Array(await r.arrayBuffer())}async getText(e){let n=await this.get(e);return n?Buffer.from(n).toString("utf8"):null}async exists(e){try{return await this.client.send(new on({Bucket:this.bucket,Key:e})),!0}catch(n){if(typeof n=="object"&&n!==null&&"$metadata"in n&&n.$metadata?.httpStatusCode===404)return!1;throw n}}async delete(e){await this.client.send(new rn({Bucket:this.bucket,Key:e}))}async list(e=""){let n=[],r;do{let s=await this.client.send(new an({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let o of s.Contents??[])o.Key&&n.push({key:o.Key,size:o.Size,updatedAt:o.LastModified?.toISOString()});r=s.IsTruncated?s.NextContinuationToken:void 0}while(r);return n}};import{access as $e,mkdir as dn,readFile as pn,readdir as fn,rm as mn,stat as Le,writeFile as gn}from"node:fs/promises";import{dirname as hn,join as yn,relative as Fe,resolve as Sn}from"node:path";var B=class{constructor(e){this.root=e}root;name="local";path(e){let n=e.replace(/^\/+/,"");return Sn(this.root,n)}async put(e,n){let r=this.path(e);await dn(hn(r),{recursive:!0}),await gn(r,n)}async get(e){try{return await pn(this.path(e))}catch(n){if(typeof n=="object"&&n!==null&&"code"in n&&n.code==="ENOENT")return null;throw n}}async getText(e){let n=await this.get(e);return n?Buffer.from(n).toString("utf8"):null}async exists(e){try{return await $e(this.path(e)),!0}catch{return!1}}async delete(e){await mn(this.path(e),{force:!0})}async list(e=""){let n=this.path(e),r=[];try{await $e(n)}catch{return r}let s=async i=>{let u=await fn(i,{withFileTypes:!0});for(let c of u){let a=yn(i,c.name);if(c.isDirectory()){await s(a);continue}let m=await Le(a);r.push({key:Fe(this.root,a),size:m.size,updatedAt:m.mtime.toISOString()})}},o=await Le(n);return o.isDirectory()?await s(n):r.push({key:Fe(this.root,n),size:o.size,updatedAt:o.mtime.toISOString()}),r}};function We(t){let e=t.localRoot??wn(vn(),".toolnet-memory","storage");if(t.provider==="huggingface"){let n=t.huggingface;return n?.namespace&&n.bucket&&n.accessKeyId&&n.secretAccessKey?new U({namespace:n.namespace,bucket:n.bucket,accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey}):(console.warn("[storage] Hugging Face credentials missing. Using local fallback."),new B(e))}return new B(e)}function jn(t){return new Promise(e=>setTimeout(e,t))}async function ze(t,e={}){let n=Math.max(1,e.attempts??3),r=e.baseDelayMs??150,s=e.maxDelayMs??2e3,o;for(let i=1;i<=n;i++)try{return await t()}catch(u){if(o=u,i>=n)break;let c=Math.min(s,r*2**(i-1)),a=Math.floor(Math.random()*Math.max(1,c*.2));await jn(c+a)}throw o}var xn=new Set(["put","get","getText","delete","list"]);function Be(t,e={}){return new Proxy(t,{get(n,r){let s=Reflect.get(n,r,n);return typeof s!="function"?s:xn.has(r)?(...o)=>ze(()=>Promise.resolve(s.apply(n,o)),e):s.bind(n)}})}function Ke(t){let e=t.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 De(t){let e=t.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 n=e.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(n)return`${n[1]}memory/records/${n[2]}`;if(n=e.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),n)return`${n[1]}memory/vectors/${n[2]}`;if(n=e.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),n)return`${n[1]}code/graph/${n[2]}`;let r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(r)return`${r[1]}memory/records/${r[2]}`;if(r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),r)return`${r[1]}memory/vectors/${r[2]}`;if(r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),r)return`${r[1]}code/graph/${r[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 Y=class{constructor(e,n,r,s){this.provider=e;this.name=e.name,this.projectId=n,this.projectName=r,this.folder=Ke(s??r),this.sourcePrefix=`projects/${n}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let e=`${this.targetPrefix}/project.json`,n=new Date().toISOString(),r=n,s=await this.provider.getText(e);if(s){let i;try{i=JSON.parse(s)}catch(u){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${u instanceof Error?u.message:String(u)}`)}if(typeof i.id=="string"&&i.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${i.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof i.createdAt=="string"&&(r=i.createdAt)}let o={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:r,updatedAt:n};await this.provider.put(e,JSON.stringify(o,null,2)+`
4
+ `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=De(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,n,r){return await this.ensureRegistered(),this.provider.put(this.key(e),n,r)}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 Cn}from"node:path";import{createHash as bn}from"node:crypto";import{dirname as kn}from"node:path";import{mkdirSync as In,readFileSync as Pn,renameSync as On,writeFileSync as En}from"node:fs";function v(t){return bn("sha256").update(t).digest("hex")}function he(t){if(Array.isArray(t))return t.map(he);if(t&&typeof t=="object"){let e=t,n={};for(let r of Object.keys(e).sort())n[r]=he(e[r]);return n}return t}function Je(t){return JSON.stringify(he(t))}function qe(t){try{return JSON.parse(Pn(t,"utf8"))}catch{return null}}function k(t,e){In(kn(t),{recursive:!0});let n=`${t}.${process.pid}.tmp`;En(n,JSON.stringify(e,null,2)+`
5
+ `,{encoding:"utf8",mode:384}),On(n,t)}function Ve(t,e){let n=t.trim(),r=n.replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,""),s=v(n).slice(0,12);if(!r||r==="."||r==="..")return`${e}--${s}`;let o=r.slice(0,100);return o===n&&n.length<=100?o:`${o.slice(0,85)}--${s}`}function He(t,e,n){let r=e.trim(),s=n.trim();if(!r)throw new Error("Session agent is required");if(!s)throw new Error("Native session ID is required");let o=Ve(r.toLowerCase(),"agent"),i=Ve(s,"session");return{projectId:t.id,projectName:t.name,projectRoot:t.rootPath,agent:r,nativeSessionId:s,sessionKey:`${r}:${s}`,remotePrefix:["projects",t.id,"sessions",o,i].join("/"),localDirectory:Cn(t.rootPath,".toolnet","sessions",o,i)}}function Ue(t){return String(t).padStart(12,"0")}var G=class{constructor(e,n=100,r=512*1024){this.storage=e;this.maxEventsPerChunk=n;this.maxChunkBytes=r;if(n<1)throw new Error("maxEventsPerChunk must be positive");if(r<1024)throw new Error("maxChunkBytes is too small")}storage;maxEventsPerChunk;maxChunkBytes;async getJson(e){let n=await this.storage.getText(e);return n?JSON.parse(n):null}async putJson(e,n){await this.storage.put(e,JSON.stringify(n,null,2)+`
6
+ `,"application/json")}async scan(e){let n=`${e.remotePrefix}/events/`,r=await this.storage.list(n),s=[],o=0;for(let i of r){let u=i.key.match(/\/events\/(\d+)-(\d+)-[a-f0-9]+\.jsonl$/);if(!u)continue;let c=Number(u[1]),a=Number(u[2]);!Number.isFinite(c)||!Number.isFinite(a)||(s.push({key:i.key,start:c,end:a}),o=Math.max(o,a))}return s.sort((i,u)=>i.start-u.start),{chunks:s,maxSequence:o}}split(e){let n=[],r=[],s=0;for(let o of e){let i=Buffer.byteLength(JSON.stringify(o)+`
7
+ `,"utf8");r.length>0&&(r.length>=this.maxEventsPerChunk||s+i>this.maxChunkBytes)&&(n.push(r),r=[],s=0),r.push(o),s+=i}return r.length>0&&n.push(r),n}async loadManifest(e){return this.getJson(`${e.remotePrefix}/session.json`)}async loadCursor(e){return this.getJson(`${e.remotePrefix}/cursor.json`)}async recover(e){let n=await this.scan(e);return{maxSequence:n.maxSequence,chunkCount:n.chunks.length}}async append(e,n,r,s={}){let o=await this.loadManifest(e),i=await this.scan(e),u=n.filter(g=>g.sequence>i.maxSequence),c=0;for(let g of this.split(u)){let S=g[0],b=g[g.length-1],A=g.map(R=>JSON.stringify(R)).join(`
8
+ `)+`
9
+ `,N=v(A).slice(0,16),E=[e.remotePrefix,"events",`${Ue(S.sequence)}-${Ue(b.sequence)}-${N}.jsonl`].join("/");await this.storage.exists(E)||await this.storage.put(E,A,"application/x-ndjson"),c+=g.length}let a=await this.scan(e),m=n[n.length-1],l=o?.status??"active";m?.type==="session_end"||m?.type==="session_idle"?l="idle":m?.type==="error"?l="error":n.length>0&&(l="active");let p=new Date().toISOString(),d=n[0],y={version:1,projectId:e.projectId,projectName:e.projectName,agent:e.agent,nativeSessionId:e.nativeSessionId,sessionKey:e.sessionKey,status:l,createdAt:o?.createdAt??d?.timestamp??p,updatedAt:m?.timestamp??p,firstEventAt:o?.firstEventAt??d?.timestamp,lastEventAt:m?.timestamp??o?.lastEventAt,eventCount:a.maxSequence,chunkCount:a.chunks.length,metadata:{...o?.metadata,...s.metadata}};(s.title??o?.title)&&(y.title=s.title??o?.title);let h={version:1,projectId:e.projectId,agent:e.agent,nativeSessionId:e.nativeSessionId,lastLocalSequence:n.length>0?n[n.length-1].sequence:a.maxSequence,lastRemoteSequence:a.maxSequence,sourceCursors:r,updatedAt:p};return await this.putJson(`${e.remotePrefix}/cursor.json`,h),await this.putJson(`${e.remotePrefix}/session.json`,y),{uploadedEvents:c,lastRemoteSequence:a.maxSequence,eventCount:y.eventCount,chunkCount:y.chunkCount,status:l}}};import{closeSync as ye,existsSync as Mn,fsyncSync as An,mkdirSync as Rn,openSync as Se,readSync as Nn,rmSync as Ye,statSync as Ge,writeSync as Tn}from"node:fs";import{join as ve}from"node:path";var _n=12e4,$n=80,Ln=2e3;function Fn(t){Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,t)}var X=class{constructor(e){this.identity=e;Rn(e.localDirectory,{recursive:!0}),this.eventsFile=ve(e.localDirectory,"events.jsonl"),this.stateFile=ve(e.localDirectory,"state.json"),this.lockFile=ve(e.localDirectory,"journal.lock")}identity;eventsFile;stateFile;lockFile;initialState(){let e=new Date().toISOString();return{version:1,projectId:this.identity.projectId,agent:this.identity.agent,nativeSessionId:this.identity.nativeSessionId,status:"idle",createdAt:e,updatedAt:e,lastSequence:0,lastRemoteSequence:0,remoteByteOffset:0,sourceCursors:{},recentEventIds:[]}}loadStateUnsafe(){return qe(this.stateFile)??this.initialState()}loadState(){return this.withLock(()=>this.loadStateUnsafe())}saveStateUnsafe(e){k(this.stateFile,e)}acquireLock(){for(let e=0;e<$n;e+=1)try{return Se(this.lockFile,"wx",384)}catch(n){if(n.code!=="EEXIST")throw n;try{if(Date.now()-Ge(this.lockFile).mtimeMs>_n){Ye(this.lockFile,{force:!0});continue}}catch{}Fn(25)}throw new Error(`Session journal is locked: ${this.lockFile}`)}withLock(e){let n=this.acquireLock();try{return e()}finally{ye(n),Ye(this.lockFile,{force:!0})}}append(e){return e.length===0?[]:this.withLock(()=>{let n=this.loadStateUnsafe(),r=new Set(n.recentEventIds),s=n.lastSequence,o=[];for(let l of e){let p=l.timestamp??new Date().toISOString(),d=l.data??{},y=l.provenance?.rawDigest??v(Je(d)),h=l.sourceEventId?[this.identity.projectId,this.identity.agent,this.identity.nativeSessionId,l.sourceEventId].join("|"):[this.identity.projectId,this.identity.agent,this.identity.nativeSessionId,s+1,l.type,p,y].join("|"),g=v(h).slice(0,32);if(r.has(g))continue;s+=1;let S={version:1,id:g,sequence:s,projectId:this.identity.projectId,agent:this.identity.agent,nativeSessionId:this.identity.nativeSessionId,type:l.type,timestamp:p,data:d,provenance:{...l.provenance,rawDigest:y}};l.role!==void 0&&(S.role=l.role),l.sourceEventId!==void 0&&(S.sourceEventId=l.sourceEventId),l.sourceSequence!==void 0&&(S.sourceSequence=l.sourceSequence),o.push(S),r.add(g)}if(o.length===0)return[];let i=o.map(l=>JSON.stringify(l)).join(`
10
+ `)+`
11
+ `,u=Se(this.eventsFile,"a",384);try{Tn(u,i,null,"utf8"),An(u)}finally{ye(u)}let c=o[o.length-1],a="active";c.type==="session_end"||c.type==="session_idle"?a="idle":c.type==="error"&&(a="error");let m=Array.from(r).slice(-Ln);return this.saveStateUnsafe({...n,status:a,updatedAt:c.timestamp,lastSequence:c.sequence,recentEventIds:m}),o})}readPending(){return this.withLock(()=>{let e=this.loadStateUnsafe();if(!Mn(this.eventsFile))return{events:[],startOffset:e.remoteByteOffset,endOffset:e.remoteByteOffset};let n=Ge(this.eventsFile).size,r=Math.min(e.remoteByteOffset,n);if(n<=r)return{events:[],startOffset:r,endOffset:n};let s=n-r,o=Buffer.alloc(s),i=Se(this.eventsFile,"r");try{Nn(i,o,0,s,r)}finally{ye(i)}return{events:o.toString("utf8").split(`
12
+ `).filter(Boolean).map(a=>JSON.parse(a)),startOffset:r,endOffset:n}})}markRemote(e,n){this.withLock(()=>{let r=this.loadStateUnsafe();this.saveStateUnsafe({...r,lastRemoteSequence:Math.max(r.lastRemoteSequence,e),remoteByteOffset:Math.max(r.remoteByteOffset,n),updatedAt:new Date().toISOString()})})}setSourceCursor(e,n){this.withLock(()=>{let r=this.loadStateUnsafe();this.saveStateUnsafe({...r,sourceCursors:{...r.sourceCursors,[e]:String(n)},updatedAt:new Date().toISOString()})})}};import{closeSync as er,existsSync as tr,openSync as nr,readSync as rr,statSync as sr}from"node:fs";function Xe(t,e){let n=e.toLowerCase();return n.includes("kh\xF4ng \u0111\u01B0\u1EE3c")||n.includes("tuy\u1EC7t \u0111\u1ED1i")||n.includes("must not")||n.includes("never ")?"critical":t==="rule"||t==="decision"?"high":t==="todo"||n.includes("error")||n.includes("failed")||n.includes("exception")?"normal":"temporary"}var tt=[/không được/iu,/tuyệt đối/iu,/bắt buộc/iu,/đừng\s+/iu,/must not/iu,/do not/iu,/don't/iu,/\bnever\b/iu],Wn=[/từ giờ/iu,/về sau/iu,/mỗi lần/iu,/luôn luôn/iu,/\bluôn\b/iu,/quy tắc/iu,/workflow/iu,/\balways\b/iu,/\brequired\b/iu,/\bmust\b/iu,/from now on/iu],zn=[/\bchốt\b/iu,/quyết định/iu,/sẽ dùng/iu,/chọn .+ thay/iu,/đổi sang/iu,/chuyển sang/iu,/\bdecided\b/iu,/\bchosen\b/iu,/we will use/iu,/use .+ instead/iu,/switch(?:ed)? to/iu],Bn=[/\btodo\b/iu,/cần làm/iu,/cần thêm/iu,/cần sửa/iu,/cần kiểm tra/iu,/tiếp theo/iu,/bước tiếp theo/iu,/còn phải/iu,/còn cần/iu,/next step/iu,/\bneed to\b/iu,/\bremaining\b/iu,/follow[- ]?up/iu],Kn=[/đã sửa/iu,/đã fix/iu,/đã khắc phục/iu,/đã xử lý/iu,/hoàn tất/iu,/hoàn thành/iu,/\bfixed\b/iu,/\bresolved\b/iu,/\bimplemented\b/iu,/\bcompleted\b/iu,/\bpasses?\b/iu],Qe=[/kiến trúc/iu,/pipeline/iu,/adapter/iu,/schema/iu,/runtime/iu,/namespace/iu,/storage/iu,/lưu trữ/iu,/workflow/iu,/session core/iu,/memory engine/iu,/retrieval/iu],Dn=[/\bdùng\b/iu,/\btách\b/iu,/\bthay\b/iu,/\bchuyển\b/iu,/\blưu\b/iu,/\bmap\b/iu,/\buse\b/iu,/\bsplit\b/iu,/\bstore\b/iu,/\breplace\b/iu,/\bmove\b/iu],Jn=[/đường dẫn/iu,/\bpath\b/iu,/\bport\b/iu,/\bendpoint\b/iu,/\bdomain\b/iu,/\bbucket\b/iu,/\brepository\b/iu,/\brepo\b/iu,/\bbranch\b/iu,/\/[A-Za-z0-9._/-]{4,}/u],qn=[/\blà\b/iu,/\bở\b/iu,/\bdùng\b/iu,/\bnằm\b/iu,/\bis\b/iu,/\buse\b/iu,/located/iu,/runs on/iu],Ze=new Set(["content","text","message","prompt","summary","description","reason","title","last_assistant_message","lastAssistantMessage","input_messages","inputMessages"]),Vn=new Set(["payload","data","content","message","messages","parts","summary"]);function I(t,e){return e.some(n=>n.test(t))}function nt(t){return t.normalize("NFKC").replace(/\r/g,"").replace(/^[\s>*#\-•]+/u,"").replace(/\s+/g," ").trim()}function Hn(t){return nt(t).toLowerCase().replace(/[^\p{L}\p{N}:/._-]+/gu," ").replace(/\s+/g," ").trim()}function Un(t){return!(t.length<12||t.length>1e3||(t.match(new RegExp("\\p{L}","gu"))??[]).length<6||/^(?:https?:\/\/\S+|[A-Za-z0-9+/=]{80,})$/u.test(t))}function we(t,e,n,r=0){if(!(r>6)){if(typeof t=="string"){(!e||Ze.has(e))&&n.push(t);return}if(Array.isArray(t)){for(let s of t.slice(0,50))we(s,e,n,r+1);return}if(!(!t||typeof t!="object"))for(let[s,o]of Object.entries(t))(Ze.has(s)||Vn.has(s))&&we(o,s,n,r+1)}}function Yn(t){let e=[];we(t.data,void 0,e);let n=[],r=new Set;for(let s of e)for(let o of s.split(/\n+|(?<=[.!?])\s+/u)){let i=nt(o);if(Un(i)&&!r.has(i)&&(r.add(i),n.push(i),n.length>=50))return n}return n}function et(t){return(t.role??(typeof t.data.role=="string"?t.data.role:"")).toLowerCase()}function Gn(t,e,n){if(n.type==="decision")return{kind:"decision",confidence:1};if(n.type==="todo")return{kind:"todo",confidence:1};let r=e==="user"||n.type==="user_prompt",s=e==="assistant"||n.type==="assistant_message";return r&&I(t,tt)?{kind:"rule",confidence:.98}:r&&I(t,Wn)?{kind:"rule",confidence:.92}:I(t,zn)?{kind:I(t,Qe)?"architecture":"decision",confidence:r?.93:.86}:r&&I(t,Bn)?{kind:"todo",confidence:.87}:I(t,Qe)&&I(t,Dn)?{kind:"architecture",confidence:r?.88:.82}:s&&I(t,Kn)?{kind:"fix",confidence:.8}:r&&I(t,Jn)&&I(t,qn)?{kind:"context",confidence:.79}:null}function Xn(t){switch(t){case"rule":return"rule";case"decision":case"architecture":return"decision";case"todo":return"todo";case"fix":case"context":return"code"}}function Qn(t,e,n){return t==="rule"&&I(n,tt)?"critical":t==="architecture"||t==="decision"||t==="rule"?"high":t==="fix"||t==="context"?"normal":Xe(e,n)}function rt(t,e){let n=[],r=new Set,s=new Map;for(let o of e){let i=typeof o.data.messageId=="string"?o.data.messageId:void 0,u=et(o);i&&u&&s.set(i,u)}for(let o of e){let i=et(o),u=typeof o.data.messageId=="string"?o.data.messageId:void 0;!i&&u&&(i=s.get(u)??"");for(let c of Yn(o)){let a=Gn(c,i,o);if(!a||a.confidence<.75)continue;let m=Xn(a.kind),l=Hn(c),p=v([t.projectId,a.kind,l].join("|"));if(r.has(p))continue;r.add(p);let d=o.provenance.sourcePath?[o.provenance.sourcePath]:[],y=o.sourceEventId?[o.sourceEventId]:[];n.push({version:1,fingerprint:p,projectId:t.projectId,agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,kind:a.kind,type:m,content:c,confidence:a.confidence,importance:Qn(a.kind,m,c),tags:[m],provenance:{agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,eventIds:[o.id],sourceEventIds:y,sourcePaths:d,firstSequence:o.sequence,lastSequence:o.sequence},createdAt:o.timestamp})}}return n}function st(t){return String(t).padStart(12,"0")}function Zn(t){return t.remotePrefix.replace("/sessions/","/memory/learned/")}var Q=class{constructor(e){this.storage=e}storage;async write(e,n,r){if(r.length===0||n.length===0)return null;let s=Math.min(...n.map(m=>m.sequence)),o=Math.max(...n.map(m=>m.sequence)),i={version:1,projectId:e.projectId,agent:e.agent,nativeSessionId:e.nativeSessionId,sessionKey:e.sessionKey,createdAt:new Date().toISOString(),firstSequence:s,lastSequence:o,candidateCount:r.length,candidates:r},u=JSON.stringify(i,null,2)+`
13
+ `,c=v(r.map(m=>m.fingerprint).sort().join("|")).slice(0,16),a=[Zn(e),"batches",`${st(s)}-${st(o)}-${c}.json`].join("/");return await this.storage.exists(a)||await this.storage.put(a,u,"application/json"),a}};function or(t,e){if(!tr(t))return{events:[],nextOffset:e};let n=sr(t).size,r=Number.isFinite(e)?Math.max(0,e):0;if(r>n&&(r=0),r===n)return{events:[],nextOffset:n};let s=n-r,o=Buffer.alloc(s),i=nr(t,"r");try{rr(i,o,0,s,r)}finally{er(i)}let u=o.toString("utf8"),c=u.lastIndexOf(`
14
+ `);if(c<0)return{events:[],nextOffset:r};let a=u.slice(0,c+1);return{events:a.split(`
15
+ `).filter(Boolean).flatMap(l=>{try{return[JSON.parse(l)]}catch{return[]}}),nextOffset:r+Buffer.byteLength(a,"utf8")}}var Z=class{constructor(e){this.options=e;this.journal=new Q(e.storage)}options;journal;async learnNew(){let e=this.options.wal.loadState(),n=Number(e.sourceCursors["memory.learner.offset"]??0),r=Number.isFinite(n)?n:0,s=or(this.options.wal.eventsFile,r);if(s.events.length===0)return{scannedEvents:0,candidates:0,journalWritten:!1,nextOffset:s.nextOffset};let o=rt(this.options.identity,s.events),i=!1;return o.length>0&&(i=!!await this.journal.write(this.options.identity,s.events,o)),this.options.wal.setSourceCursor("memory.learner.offset",s.nextOffset),{scannedEvents:s.events.length,candidates:o.length,journalWritten:i,nextOffset:s.nextOffset}}};import{closeSync as pr,existsSync as fr,openSync as mr,readSync as gr,statSync as hr}from"node:fs";var ir=new Set(["content","text","message","prompt","summary","description","title","reason","last_assistant_message","lastAssistantMessage"]);function $(t){return t.normalize("NFKC").replace(/\s+/g," ").replace(/^[\s>*#•-]+/u,"").trim()}function it(t){return $(t).toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function _(t,e,n=0){if(!(n>6)){if(typeof t=="string"){e.push(t);return}if(Array.isArray(t)){for(let r of t.slice(0,50))_(r,e,n+1);return}if(!(!t||typeof t!="object"))for(let[r,s]of Object.entries(t))(ir.has(r)||["data","payload","parts","messages"].includes(r))&&_(s,e,n+1)}}function ee(t){return/\b(cancelled|canceled)\b|đã hủy|bỏ qua/iu.test(t)?"cancelled":/\b(blocked|blocker)\b|đang vướng|bị vướng|đang kẹt|chưa thể/iu.test(t)?"blocked":/\b(completed|complete|done|finished|passed)\b|hoàn thành|hoàn tất|đã xong|đã làm xong|\bxong\b/iu.test(t)?"completed":/\bin[\s_-]*progress\b|working on|đang làm|đang thực hiện|đang xử lý|đang triển khai/iu.test(t)?"in_progress":"pending"}function ot(t){let e=$(t);return/^(?:đang\s+làm|đang\s+thực\s+hiện|đang\s+xử\s+lý|đang\s+triển\s+khai|hoàn\s+thành|hoàn\s+tất|đã\s+xong|đã\s+làm\s+xong|xong|pending|in[\s_-]*progress|completed|complete|done|finished|blocked|cancelled|canceled)[.!]*$/iu.test(e)}function j(t,e,n,r,s={}){let o=$(r),i=s.key??it(o);return{version:1,id:v([t.projectId,n,i,e.id,o,s.status??"",s.order??""].join("|")).slice(0,32),projectId:t.projectId,kind:n,key:i,text:o,status:s.status,order:s.order,confidence:s.confidence??.85,occurredAt:e.timestamp,sequence:e.sequence,agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,eventId:e.id,sourceEventId:e.sourceEventId}}function ar(t,e,n){let r=$(n);if(r.length<5||r.length>1200)return[];let s=[],o=/^(?:next|next action|next step|tiếp theo|bước tiếp theo|cần làm tiếp)\b/iu.test(r),i=r.match(/^(?:mục tiêu|goal|objective)\s*(?::|-)\s*(.+)$/iu);i?.[1]&&s.push(j(t,e,"goal",i[1],{confidence:.97}));let u=r.match(/^(?:kế hoạch|plan)\s*(?::|-)\s*(.+)$/iu);u?.[1]&&s.push(j(t,e,"plan",u[1],{confidence:.95}));let c=/\b(?:phase|giai đoạn|giai doan|stage)\s*(\d+)\s*(?:[:\-–—]\s*)?([^.;\n]{0,220})/giu,a;for(;!o&&(a=c.exec(r));){let p=Number(a[1]),d=$(a[2]??""),y=d&&!ot(d)?`Phase ${p} - ${d}`:`Phase ${p}`;s.push(j(t,e,"phase",y,{key:`phase:${p}`,order:p,status:ee(r),confidence:.93}))}let m=n.match(/^\s*[-*]\s*\[([ xX])\]\s*(.+)$/u);m?.[2]&&s.push(j(t,e,"task",m[2],{status:m[1].trim()?"completed":ee(m[2]),confidence:.96}));let l=r.match(/^(?:todo|task|việc)\s*(\d+)?(?:\s*[:.\-–—]\s*|\s+)(.+)$/iu);if(l?.[2]){let p=l[1]?Number(l[1]):void 0,d=$(l[2]),y=ot(d);s.push(j(t,e,"task",y&&p!==void 0?`TODO ${p}`:d,{key:p!==void 0?`task:${p}`:it(d),order:p,status:ee(r),confidence:.93}))}if(/^(?:next|next action|next step|tiếp theo|bước tiếp theo|cần làm tiếp)\b/iu.test(r)){let p=r.replace(/^(?:next|next action|next step|tiếp theo|bước tiếp theo|cần làm tiếp)\s*(?::|-)?\s*/iu,"");p&&s.push(j(t,e,"next_action",p,{confidence:.9}))}return/\b(blocker|blocked)\b|đang vướng|bị vướng|đang kẹt/iu.test(r)&&s.push(j(t,e,"blocker",r,{confidence:.9})),/\b(chú ý|lưu ý|warning|attention|cẩn thận)\b/iu.test(r)&&s.push(j(t,e,"warning",r,{confidence:.88})),/\b(chốt|quyết định|decided|decision)\b/iu.test(r)&&s.push(j(t,e,"decision",r,{confidence:.9})),s}function at(t,e){if(e.length===0)return[];let n=[],r=new Set;function s(i){r.has(i.id)||(r.add(i.id),n.push(i))}for(let i of e){if(i.type==="decision"){let c=[];_(i.data,c);for(let a of c)s(j(t,i,"decision",a,{confidence:1}))}if(i.type==="todo"){let c=[];_(i.data,c);for(let a of c)s(j(t,i,"task",a,{status:ee(a),confidence:1}))}if(["file_write","file_edit"].includes(i.type))for(let c of["filePath","path","file"]){let a=i.data[c];typeof a=="string"&&a&&s(j(t,i,"file",a,{confidence:1}))}if(i.type==="test"){let c=[];_(i.data,c);for(let a of c)s(j(t,i,"test",a,{confidence:1}))}let u=[];_(i.data,u);for(let c of u)for(let a of c.split(/\n+/u))for(let m of ar(t,i,a))s(m)}let o=e[e.length-1];return s(j(t,o,"session",`${t.agent}:${t.nativeSessionId}`,{key:t.sessionKey,confidence:1})),n}function ct(t){return String(t).padStart(12,"0")}var te=class{constructor(e){this.storage=e}storage;async write(e,n){if(n.length===0)return null;let r=Math.min(...n.map(a=>a.sequence)),s=Math.max(...n.map(a=>a.sequence)),o={version:1,projectId:e.projectId,agent:e.agent,nativeSessionId:e.nativeSessionId,sessionKey:e.sessionKey,createdAt:new Date().toISOString(),firstSequence:r,lastSequence:s,observations:n},i=JSON.stringify(o,null,2)+`
16
+ `,u=v(n.map(a=>a.id).sort().join("|")).slice(0,16),c=[`projects/${e.projectId}`,"work","observations",e.agent,e.nativeSessionId,`${ct(r)}-${ct(s)}-${u}.json`].join("/");return await this.storage.exists(c)||await this.storage.put(c,i,"application/json"),c}};import{join as ut}from"node:path";import{mkdirSync as cr}from"node:fs";function ur(t){return t.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function L(t,e=20){let n=[],r=new Set;for(let s of t.slice().reverse()){let o=ur(s);if(!(!o||r.has(o))&&(r.add(o),n.push(s),n.length>=e))break}return n.reverse()}function lr(t){return t.kind==="phase"?/^Phase\s+\d+$/iu.test(t.text):t.kind==="task"?/^(?:TODO|Task|Việc)\s+\d+$/iu.test(t.text):!1}function lt(t,e){let n=e.status??t?.status??"pending",r=n;t&&(t.status==="completed"&&n!=="completed"?r="completed":n==="pending"&&(t.status==="in_progress"||t.status==="blocked")&&(r=t.status));let s=t&&lr(e)?t.title:e.text;return{id:t?.id??v(e.key).slice(0,24),title:s,status:r,order:e.order??t?.order,confidence:Math.max(e.confidence,t?.confidence??0),updatedAt:e.occurredAt,updatedBy:{agent:e.agent,nativeSessionId:e.nativeSessionId,eventId:e.eventId}}}async function dr(t,e){let n=`projects/${t.id}/work/observations/`,r=await e.list(n),s=[];for(let o of r.filter(i=>i.key.endsWith(".json")).sort((i,u)=>i.key.localeCompare(u.key))){let i=await e.getText(o.key);if(i)try{let u=JSON.parse(i);u.version===1&&Array.isArray(u.observations)&&s.push(u)}catch{}}return s}async function ne(t,e){let r=(await dr(t,e)).flatMap(f=>f.observations).sort((f,x)=>{let Ee=f.occurredAt.localeCompare(x.occurredAt);if(Ee!==0)return Ee;let Ce=f.sequence-x.sequence;return Ce!==0?Ce:f.id.localeCompare(x.id)}),s=new Map,o=new Map,i,u,c,a=[],m=[],l=[],p=[],d=[],y=[];for(let f of r)switch(f.kind){case"goal":i=f.text;break;case"plan":u=f.text;break;case"phase":s.set(f.key,lt(s.get(f.key),f));break;case"task":o.set(f.key,lt(o.get(f.key),f));break;case"decision":a.push(f.text);break;case"blocker":m.push(f.text);break;case"warning":l.push(f.text);break;case"next_action":p.push(f.text);break;case"file":d.push(f.text);break;case"test":y.push(f.text);break;case"session":c={agent:f.agent,nativeSessionId:f.nativeSessionId,sessionKey:f.sessionKey,updatedAt:f.occurredAt};break}let h=Array.from(s.values()).sort((f,x)=>(f.order??Number.MAX_SAFE_INTEGER)-(x.order??Number.MAX_SAFE_INTEGER)),g=Array.from(o.values()).sort((f,x)=>(f.order??Number.MAX_SAFE_INTEGER)-(x.order??Number.MAX_SAFE_INTEGER)),S=h.find(f=>f.status==="in_progress")??h.find(f=>f.status==="blocked")??h.find(f=>f.status==="pending"),b=g.find(f=>f.status==="in_progress")??g.find(f=>f.status==="blocked")??g.find(f=>f.status==="pending"),A=L([...p,...b?[b.title]:[],...!b&&S?[S.title]:[],...g.filter(f=>f.status==="pending").slice(0,5).map(f=>f.title)],8),N=L([...m,...h.filter(f=>f.status==="blocked").map(f=>f.title),...g.filter(f=>f.status==="blocked").map(f=>f.title)],20),E={version:1,projectId:t.id,projectName:t.name,goal:i,plan:u,phases:h,tasks:g,decisions:L(a,20),blockers:N,warnings:L(l,20),nextActions:A,filesTouched:L(d,30),tests:L(y,20),currentPhase:S,currentTask:b,progress:{phasesTotal:h.length,phasesCompleted:h.filter(f=>f.status==="completed").length,tasksTotal:g.length,tasksCompleted:g.filter(f=>f.status==="completed").length,blocked:h.filter(f=>f.status==="blocked").length+g.filter(f=>f.status==="blocked").length},lastSession:c,updatedAt:r.length?r[r.length-1].occurredAt:new Date().toISOString()},R=ut(t.rootPath,".toolnet","work");return cr(R,{recursive:!0}),k(ut(R,"current.json"),E),await e.put(`projects/${t.id}/work/current.json`,JSON.stringify(E,null,2)+`
17
+ `,"application/json"),E}async function re(t,e){let n=await e.getText(`projects/${t.id}/work/current.json`);if(!n)return null;try{return JSON.parse(n)}catch{return null}}function yr(t,e){if(!fr(t))return{events:[],nextOffset:e};let n=hr(t).size,r=Number.isFinite(e)?Math.max(0,e):0;if(r>n&&(r=0),r===n)return{events:[],nextOffset:n};let s=n-r,o=Buffer.alloc(s),i=mr(t,"r");try{gr(i,o,0,s,r)}finally{pr(i)}let u=o.toString("utf8"),c=u.lastIndexOf(`
18
+ `);if(c<0)return{events:[],nextOffset:r};let a=u.slice(0,c+1);return{events:a.split(`
19
+ `).filter(Boolean).flatMap(l=>{try{return[JSON.parse(l)]}catch{return[]}}),nextOffset:r+Buffer.byteLength(a,"utf8")}}var se=class{constructor(e){this.options=e;this.journal=new te(e.storage)}options;journal;async learnNew(){let e=this.options.wal.loadState(),n=Number(e.sourceCursors["work.continuity.offset"]??0),r=yr(this.options.wal.eventsFile,Number.isFinite(n)?n:0);if(r.events.length===0)return{scannedEvents:0,observations:0,journalWritten:!1,reconciled:!1,nextOffset:r.nextOffset};let s=at(this.options.identity,r.events),o=!1,i=!1;return s.length>0&&(o=!!await this.journal.write(this.options.identity,s),o&&(await ne(this.options.project,this.options.storage),i=!0)),this.options.wal.setSourceCursor("work.continuity.offset",r.nextOffset),{scannedEvents:r.events.length,observations:s.length,journalWritten:o,reconciled:i,nextOffset:r.nextOffset}}};import{closeSync as Pr,existsSync as Or,openSync as Er,readSync as Cr,statSync as Mr}from"node:fs";var Sr=new Set(["content","text","message","prompt","summary","description","title","reason","last_assistant_message","lastAssistantMessage"]);function F(t){return t.normalize("NFKC").replace(/\s+/g," ").replace(/^[\s>*#•-]+/u,"").trim()}function je(t,e,n=0){if(!(n>6)){if(typeof t=="string"){e.push(t);return}if(Array.isArray(t)){for(let r of t.slice(0,50))je(r,e,n+1);return}if(!(!t||typeof t!="object"))for(let[r,s]of Object.entries(t))(Sr.has(r)||["data","payload","parts","messages"].includes(r))&&je(s,e,n+1)}}function P(t,e,n,r,s,o=.95){let i=F(r);return{version:1,id:v([t.projectId,n,s.type,s.key??"",i.toLowerCase(),e.id].join("|")).slice(0,32),projectId:t.projectId,kind:n,value:i,scope:s.type,scopeKey:s.key,scopeOrder:s.order,confidence:o,evidence:{agent:t.agent,nativeSessionId:t.nativeSessionId,sessionKey:t.sessionKey,eventId:e.id,sourceEventId:e.sourceEventId,sequence:e.sequence,occurredAt:e.timestamp}}}function O(t,e){let n=t.toLowerCase();for(let r of e){let s=r.toLowerCase();if(n.startsWith(`${s}:`)||n.startsWith(`${s} -`)||n.startsWith(`${s} \u2014`))return F(t.slice(r.length+1))}return null}function vr(t){let e=t.trimStart();return e.startsWith("- ")||e.startsWith("* ")||/^\d+[.)]\s+/u.test(e)}function wr(t){return F(t.trim().replace(/^[-*]\s+/u,"").replace(/^\d+[.)]\s+/u,""))}function dt(t,e){let n=[],r=new Set;function s(o){!o.value||o.value.length<3||r.has(o.id)||(r.add(o.id),n.push(o))}for(let o of e){let i=[];je(o.data,i);for(let u of i){let c={type:"project"},a=null;for(let m of u.split(/\r?\n/u)){let l=F(m);if(!l){a=null;continue}let p=l.match(/^(?:phase|giai đoạn|giai doan|stage)\s*(\d+)\s*(?:[:\-–—]\s*)?(.*)$/iu);if(p){let x=Number(p[1]);c={type:"phase",key:`phase:${x}`,order:x,title:F(p[2]??"")},a=null;continue}let d=l.match(/^(?:todo|task|việc)\s*(\d+)\s*(?:[:\-–—]\s*)?(.*)$/iu);if(d){let x=Number(d[1]);c={type:"task",key:`task:${x}`,order:x,title:F(d[2]??"")},a=null;continue}let y=O(l,["mission","s\u1EE9 m\u1EC7nh","m\u1EE5c ti\xEAu t\u1ED5ng th\u1EC3","m\u1EE5c ti\xEAu project","project goal"]);if(y){s(P(t,o,"mission",y,{type:"project"},.99)),a=null;continue}let h=O(l,["current objective","active objective","m\u1EE5c ti\xEAu hi\u1EC7n t\u1EA1i","objective","m\u1EE5c ti\xEAu","m\u1EE5c \u0111\xEDch"]);if(h){s(P(t,o,c.type==="phase"?"phase_objective":"objective",h,c,.98)),a=null;continue}let g=O(l,["why","why this","why this phase","reason","rationale","v\xEC sao","l\xFD do","t\u1EA1i sao","\xFD ngh\u0129a"]);if(g){s(P(t,o,c.type==="phase"?"phase_why":"why",g,c,.98)),a=null;continue}let S=O(l,["desired outcome","final outcome","k\u1EBFt qu\u1EA3 cu\u1ED1i","k\u1EBFt qu\u1EA3 mong mu\u1ED1n","m\u1EE5c ti\xEAu cu\u1ED1i"]);if(S){s(P(t,o,"desired_outcome",S,{type:"project"},.98)),a=null;continue}let b=O(l,["plan rationale","approach rationale","why this approach","t\u1EA1i sao ch\u1ECDn h\u01B0\u1EDBng n\xE0y","l\xFD do ch\u1ECDn h\u01B0\u1EDBng n\xE0y","l\xFD do ch\u1ECDn ki\u1EBFn tr\xFAc"]);if(b){s(P(t,o,"plan_rationale",b,{type:"project"},.98)),a=null;continue}let A=O(l,["deliverable","output","k\u1EBFt qu\u1EA3 c\u1EA7n \u0111\u1EA1t","ph\u1EA3i t\u1EA1o ra","\u0111\u1EA7u ra"]);if(A){s(P(t,o,"phase_deliverable",A,c,.97)),a=null;continue}let N=O(l,["acceptance criteria","definition of done","done khi","ho\xE0n th\xE0nh khi","ti\xEAu ch\xED ho\xE0n th\xE0nh"]);if(N){s(P(t,o,"acceptance_criterion",N,c,.98)),a="acceptance_criterion";continue}let E=O(l,["depends on","dependency","dependencies","ph\u1EE5 thu\u1ED9c","c\u1EA7n c\xF3 tr\u01B0\u1EDBc"]);if(E){s(P(t,o,"dependency",E,c,.97)),a="dependency";continue}let R=O(l,["open question","open questions","c\xE2u h\u1ECFi m\u1EDF","ch\u01B0a quy\u1EBFt \u0111\u1ECBnh","ch\u01B0a r\xF5"]);if(R){s(P(t,o,"open_question",R,c,.95)),a="open_question";continue}let f=O(l,["constraint","constraints","r\xE0ng bu\u1ED9c","gi\u1EDBi h\u1EA1n"]);if(f){s(P(t,o,"constraint",f,c,.97)),a="constraint";continue}if(/^(?:acceptance criteria|definition of done|done khi|tiêu chí hoàn thành)\s*:?\s*$/iu.test(l)){a="acceptance_criterion";continue}if(/^(?:dependencies|dependency|phụ thuộc)\s*:?\s*$/iu.test(l)){a="dependency";continue}if(/^(?:open questions|open question|câu hỏi mở)\s*:?\s*$/iu.test(l)){a="open_question";continue}if(/^(?:constraints|constraint|ràng buộc)\s*:?\s*$/iu.test(l)){a="constraint";continue}if(a&&vr(m)){s(P(t,o,a,wr(m),c,.96));continue}a=null}}}return n}function pt(t){return String(t).padStart(12,"0")}var oe=class{constructor(e){this.storage=e}storage;async write(e,n){if(n.length===0)return null;let r=Math.min(...n.map(c=>c.evidence.sequence)),s=Math.max(...n.map(c=>c.evidence.sequence)),o={version:1,projectId:e.projectId,agent:e.agent,nativeSessionId:e.nativeSessionId,sessionKey:e.sessionKey,firstSequence:r,lastSequence:s,createdAt:new Date().toISOString(),observations:n},i=v(n.map(c=>c.id).sort().join("|")).slice(0,16),u=[`projects/${e.projectId}`,"work","semantic","observations",e.agent,e.nativeSessionId,`${pt(r)}-${pt(s)}-${i}.json`].join("/");return await this.storage.exists(u)||await this.storage.put(u,JSON.stringify(o,null,2)+`
20
+ `,"application/json"),u}};import{mkdirSync as jr}from"node:fs";import{join as ft}from"node:path";function xr(t){return{value:t.value,confidence:t.confidence,evidence:t.evidence}}function br(t,e){if(!e)return!0;let n=t.evidence.occurredAt.localeCompare(e.evidence.occurredAt);return n!==0?n>0:t.evidence.sessionKey===e.evidence.sessionKey?t.evidence.sequence>=e.evidence.sequence:t.confidence>=e.confidence}function C(t,e){return br(e,t)?e:t}function M(t,e=30){let n=new Set,r=[];for(let s of t){let o=s.value.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim();!o||n.has(o)||(n.add(o),r.push(s))}return r.slice(-e)}async function kr(t,e){let n=`projects/${t.id}/work/semantic/observations/`,r=await e.list(n),s=[];for(let o of r.filter(i=>i.key.endsWith(".json")).sort((i,u)=>i.key.localeCompare(u.key))){let i=await e.getText(o.key);if(i)try{let u=JSON.parse(i);u.version===1&&Array.isArray(u.observations)&&s.push(u)}catch{}}return s}function Ir(t){return{key:t.scopeKey??`phase:${t.scopeOrder??0}`,order:t.scopeOrder??0,acceptanceCriteria:[],dependencies:[],openQuestions:[],constraints:[],notes:[]}}async function mt(t,e){let r=(await kr(t,e)).flatMap(h=>h.observations).sort((h,g)=>{let S=h.evidence.occurredAt.localeCompare(g.evidence.occurredAt);return S!==0?S:h.evidence.sessionKey===g.evidence.sessionKey?h.evidence.sequence-g.evidence.sequence:h.id.localeCompare(g.id)}),s,o,i,u,c,a=new Map,m=[],l=[],p=[];for(let h of r){let g=xr(h);if(h.scope==="phase"&&h.scopeKey){let S=a.get(h.scopeKey)??Ir(h);switch(h.kind){case"phase_objective":S.objective=C(S.objective,g);break;case"phase_why":S.why=C(S.why,g);break;case"phase_deliverable":S.deliverable=C(S.deliverable,g);break;case"acceptance_criterion":S.acceptanceCriteria.push(g);break;case"dependency":S.dependencies.push(g);break;case"open_question":S.openQuestions.push(g);break;case"constraint":S.constraints.push(g);break;case"note":S.notes.push(g);break}a.set(S.key,S);continue}switch(h.kind){case"mission":s=C(s,g);break;case"objective":o=C(o,g);break;case"why":i=C(i,g);break;case"desired_outcome":u=C(u,g);break;case"plan_rationale":c=C(c,g);break;case"open_question":m.push(g);break;case"constraint":l.push(g);break;case"note":p.push(g);break}}for(let h of a.values())h.acceptanceCriteria=M(h.acceptanceCriteria,20),h.dependencies=M(h.dependencies,15),h.openQuestions=M(h.openQuestions,15),h.constraints=M(h.constraints,15),h.notes=M(h.notes,20);let d={version:1,projectId:t.id,projectName:t.name,mission:s,activeObjective:o,why:i,desiredOutcome:u,planRationale:c,phases:Array.from(a.values()).sort((h,g)=>h.order-g.order),openQuestions:M(m,20),constraints:M(l,20),notes:M(p,20),updatedAt:r.length?r[r.length-1].evidence.occurredAt:new Date().toISOString()},y=ft(t.rootPath,".toolnet","work");return jr(y,{recursive:!0}),k(ft(y,"semantic-current.json"),d),await e.put(`projects/${t.id}/work/semantic/current.json`,JSON.stringify(d,null,2)+`
21
+ `,"application/json"),d}async function gt(t,e){let n=await e.getText(`projects/${t.id}/work/semantic/current.json`);if(!n)return null;try{return JSON.parse(n)}catch{return null}}function Ar(t,e){if(!Or(t))return{events:[],nextOffset:e};let n=Mr(t).size,r=Number.isFinite(e)?Math.max(0,e):0;if(r>n&&(r=0),r===n)return{events:[],nextOffset:n};let s=Buffer.alloc(n-r),o=Er(t,"r");try{Cr(o,s,0,s.length,r)}finally{Pr(o)}let i=s.toString("utf8"),u=i.lastIndexOf(`
22
+ `);if(u<0)return{events:[],nextOffset:r};let c=i.slice(0,u+1);return{events:c.split(`
23
+ `).filter(Boolean).flatMap(a=>{try{return[JSON.parse(a)]}catch{return[]}}),nextOffset:r+Buffer.byteLength(c,"utf8")}}var ie=class{constructor(e){this.options=e;this.journal=new oe(e.storage)}options;journal;async learnNew(){let e=this.options.wal.loadState(),n=Number(e.sourceCursors["work.semantic.offset"]??0),r=Ar(this.options.wal.eventsFile,Number.isFinite(n)?n:0);if(r.events.length===0)return{scannedEvents:0,observations:0,journalWritten:!1,reconciled:!1,nextOffset:r.nextOffset};let s=dt(this.options.identity,r.events),o=!1,i=!1;return s.length>0&&(o=!!await this.journal.write(this.options.identity,s),o&&(await mt(this.options.project,this.options.storage),i=!0)),this.options.wal.setSourceCursor("work.semantic.offset",r.nextOffset),{scannedEvents:r.events.length,observations:s.length,journalWritten:o,reconciled:i,nextOffset:r.nextOffset}}};import{mkdirSync as Br}from"node:fs";import{join as xe}from"node:path";import{existsSync as St,mkdirSync as Rr,readFileSync as Nr,statSync as ht,writeFileSync as Tr}from"node:fs";import{dirname as _r,join as $r}from"node:path";var yt=64*1024,Lr=`# ToolNet Project Operating Manual
24
+
25
+ This file contains persistent instructions for AI agents working on this project.
26
+
27
+ ## Critical Rules
28
+
29
+ <!--
30
+ Examples:
31
+
32
+ - [enforce] Never edit production files directly.
33
+ - [enforce] Edit source only in /path/to/source.
34
+ - [enforce] Deploy only with ./deploy.sh --apply
35
+ -->
36
+
37
+ ## Workflow
38
+
39
+ <!--
40
+ Describe the correct working process.
41
+ -->
42
+
43
+ ## Architecture
44
+
45
+ <!--
46
+ Important architecture conventions.
47
+ -->
48
+
49
+ ## Verification
50
+
51
+ <!--
52
+ Tests / QA required after changes.
53
+ -->
54
+
55
+ ## Known Gotchas
56
+
57
+ <!--
58
+ Things an AI agent should always remember.
59
+ -->
60
+
61
+ ## Preferences
62
+
63
+ <!--
64
+ - [advisory] Prefer small focused files.
65
+ -->
66
+ `;function ae(t){return $r(t.rootPath,".toolnet","PROJECT.md")}function Fr(t){return t.normalize("NFKC").replace(/\s+/g," ").trim()}function Wr(t){let e=[],n=new Set,r=/^\s*[-*]\s+\[(enforce|advisory)\]\s+(.+?)\s*$/gimu,s;for(;s=r.exec(t);){let o=s[1].toLowerCase(),i=Fr(s[2]);if(!i)continue;let u=`${o}:${i.toLowerCase()}`;n.has(u)||(n.add(u),e.push({id:v(u).slice(0,24),mode:o,text:i,source:"manual"}))}return e}function zr(t){let e=ae(t);return St(e)||(Rr(_r(e),{recursive:!0}),Tr(e,Lr,{encoding:"utf8",mode:384})),e}function ce(t,e=!1){let n=e?zr(t):ae(t);if(!St(n))return null;if(ht(n).size>yt)throw new Error(`PROJECT.md exceeds ${yt} bytes`);let s=Nr(n,"utf8");return{path:n,content:s,digest:v(s),rules:Wr(s),bytes:Buffer.byteLength(s,"utf8"),updatedAt:new Date(ht(n).mtimeMs).toISOString()}}function Kr(t){return{goal:t.goal,plan:t.plan,phases:t.phases.map(e=>({id:e.id,title:e.title,status:e.status,order:e.order})),tasks:t.tasks.map(e=>({id:e.id,title:e.title,status:e.status,order:e.order})),decisions:t.decisions,blockers:t.blockers,warnings:t.warnings,nextActions:t.nextActions,filesTouched:t.filesTouched,tests:t.tests}}function Dr(t){return t.phases.some(e=>e.status==="pending"||e.status==="in_progress"||e.status==="blocked")||t.tasks.some(e=>e.status==="pending"||e.status==="in_progress"||e.status==="blocked")||t.nextActions.length>0||t.blockers.length>0}var ue=class{constructor(e){this.options=e}options;async capture(e,n){let r=await re(this.options.project,this.options.storage);if(r||(r=await ne(this.options.project,this.options.storage)),!Dr(r))return null;let s=ce(this.options.project,!1),o=s?s.rules.filter(p=>p.mode==="enforce").map(p=>p.text):[],i=v(JSON.stringify(Kr(r))),u=v([this.options.project.id,this.options.identity.sessionKey,i].join("|")).slice(0,24),c=new Date().toISOString(),a={version:1,id:u,projectId:this.options.project.id,projectName:this.options.project.name,createdAt:c,reason:e,sourceSession:{agent:this.options.identity.agent,nativeSessionId:this.options.identity.nativeSessionId,sessionKey:this.options.identity.sessionKey,sequence:n},goal:r.goal,plan:r.plan,progress:r.progress,currentPhase:r.currentPhase,currentTask:r.currentTask,incompletePhases:r.phases.filter(p=>p.status!=="completed"&&p.status!=="cancelled"),incompleteTasks:r.tasks.filter(p=>p.status!=="completed"&&p.status!=="cancelled"),nextActions:r.nextActions.slice(0,10),blockers:r.blockers.slice(0,10),decisions:r.decisions.slice(-10),warnings:r.warnings.slice(-10),attention:[...o,...r.warnings].slice(0,20),filesTouched:r.filesTouched.slice(-20),tests:r.tests.slice(-15),stateDigest:i},m=`projects/${this.options.project.id}/work/handoffs/${u}.json`;await this.options.storage.exists(m)||await this.options.storage.put(m,JSON.stringify(a,null,2)+`
67
+ `,"application/json"),await this.options.storage.put(`projects/${this.options.project.id}/work/handoff-latest.json`,JSON.stringify(a,null,2)+`
68
+ `,"application/json");let l=xe(this.options.project.rootPath,".toolnet","work","handoffs");return Br(l,{recursive:!0}),k(xe(l,`${u}.json`),a),k(xe(this.options.project.rootPath,".toolnet","work","handoff-latest.json"),a),a}};async function vt(t,e){let n=await e.getText(`projects/${t.id}/work/handoff-latest.json`);if(!n)return null;try{return JSON.parse(n)}catch{return null}}var le=class{identity;wal;remote;sanitizer=new z;learner;continuity;semantic;handoff;title;metadata;constructor(e){this.identity=He(e.project,e.agent,e.nativeSessionId),this.title=e.title,this.metadata=this.sanitizer.sanitizeValue(e.metadata??{}),this.wal=new X(this.identity),this.remote=new G(e.storage,e.maxEventsPerChunk??100,e.maxChunkBytes??512*1024),this.learner=new Z({project:e.project,storage:e.storage,identity:this.identity,wal:this.wal}),this.continuity=new se({project:e.project,storage:e.storage,identity:this.identity,wal:this.wal}),this.semantic=new ie({project:e.project,storage:e.storage,identity:this.identity,wal:this.wal}),this.handoff=new ue({project:e.project,storage:e.storage,identity:this.identity})}sanitizeEvent(e){let n=e.provenance?{...e.provenance,metadata:this.sanitizer.sanitizeValue(e.provenance.metadata)}:void 0;return{...e,data:this.sanitizer.sanitizeValue(e.data??{}),provenance:n}}start(e={}){let n=this.wal.loadState();return this.record({type:n.lastSequence===0?"session_start":"session_resume",data:e,provenance:{source:this.identity.agent}})}record(e){return this.wal.append([this.sanitizeEvent(e)])[0]}recordMany(e){return this.wal.append(e.map(n=>this.sanitizeEvent(n)))}setSourceCursor(e,n){this.wal.setSourceCursor(e,n)}async flush(){let e=this.wal.readPending(),n=this.wal.loadState(),r=await this.remote.append(this.identity,e.events,n.sourceCursors,{title:this.title,metadata:this.metadata});if(e.events.length>0){let s=e.events[e.events.length-1];this.wal.markRemote(s.sequence,e.endOffset)}if(process.env.TOOLNET_SESSION_LEARNING!=="0")try{await this.learner.learnNew()}catch{}if(process.env.TOOLNET_WORK_CONTINUITY!=="0")try{await this.continuity.learnNew()}catch{}if(process.env.TOOLNET_SEMANTIC_CONTINUITY!=="0")try{await this.semantic.learnNew()}catch{}if(process.env.TOOLNET_SMART_HANDOFF!=="0"&&e.events.length>0)try{let s=e.events[e.events.length-1],o=["session_idle","session_end","session_compact"].includes(s.type)?s.type:"checkpoint";await this.handoff.capture(o,s.sequence)}catch{}return r}async idle(e={}){return this.record({type:"session_idle",data:e,provenance:{source:this.identity.agent}}),this.flush()}async end(e={}){return this.record({type:"session_end",data:e,provenance:{source:this.identity.agent}}),this.flush()}status(){return this.wal.loadState()}recoverRemote(){return this.remote.recover(this.identity)}};import{existsSync as Jr,readFileSync as qr,readdirSync as Vr,statSync as wt}from"node:fs";import{homedir as Hr}from"node:os";import{join as de,resolve as jt}from"node:path";function xt(t){return t&&typeof t=="object"&&!Array.isArray(t)?t:{}}function Ur(){return process.env.CODEX_HOME??de(Hr(),".codex")}function K(t){let e="";try{e=qr(t,"utf8").slice(0,128*1024)}catch{return{raw:{}}}for(let n of e.split(`
69
+ `))if(n)try{let r=xt(JSON.parse(n));if(r.type!=="session_meta")continue;let s=xt(r.payload),o=[s.id,s.thread_id,s.threadId,s.session_id,s.sessionId].find(u=>typeof u=="string"),i=typeof s.cwd=="string"?s.cwd:void 0;return{threadId:o,cwd:i,raw:s}}catch{}return{raw:{}}}function be(t,e){if(!Jr(t))return;let n;try{n=Vr(t,{withFileTypes:!0})}catch{return}for(let r of n){let s=de(t,r.name);if(r.isDirectory()){be(s,e);continue}r.isFile()&&r.name.endsWith(".jsonl")&&e.push(s)}}function ke(){let t=Ur(),e=[];return be(de(t,"sessions"),e),be(de(t,"archived_sessions"),e),e.sort((n,r)=>{try{return wt(r).mtimeMs-wt(n).mtimeMs}catch{return 0}})}function Ie(t){let e=ke(),n=e.find(r=>r.includes(t));if(n)return n;for(let r of e)if(K(r).threadId===t)return r;return null}function pe(t,e){let n=jt(t),r=jt(e);return r===n||r.startsWith(n+"/")||n.startsWith(r+"/")}import{closeSync as Yr,existsSync as Gr,openSync as Xr,readSync as Qr,statSync as Zr}from"node:fs";function bt(t){return t&&typeof t=="object"&&!Array.isArray(t)?t:{}}function es(t){let e=t.timestamp;if(typeof e=="string"){let n=new Date(e);if(!Number.isNaN(n.getTime()))return n.toISOString()}return new Date().toISOString()}function ts(t){let e=typeof t.type=="string"?t.type.toLowerCase():"",n=bt(t.payload),r=typeof n.type=="string"?n.type.toLowerCase():"",s=typeof n.role=="string"?n.role.toLowerCase():void 0;return e==="session_meta"?{type:"custom"}:s==="user"||r==="user_message"?{type:"user_prompt",role:"user"}:s==="assistant"||r==="agent_message"||r==="assistant_message"?{type:"assistant_message",role:"assistant"}:r.includes("function_call")||r.includes("tool_call")||r.includes("exec_command_begin")||r.includes("exec_command_start")?{type:"tool_call"}:r.includes("function_call_output")||r.includes("tool_result")||r.includes("exec_command_end")||r.includes("exec_command_complete")?{type:"tool_result"}:r.includes("error")?{type:"error"}:e.includes("compacted")||r.includes("compacted")?{type:"session_compact"}:{type:"custom",role:s}}function kt(t,e=0){if(!Gr(t))return{events:[],nextOffset:e,reset:!1};let n=Zr(t).size,r=e>n,s=r?0:e;if(s>=n)return{events:[],nextOffset:n,reset:r};let o=n-s,i=Buffer.alloc(o),u=Xr(t,"r");try{Qr(u,i,0,o,s)}finally{Yr(u)}let c=i.toString("utf8"),a=c.lastIndexOf(`
70
+ `);if(a<0)return{events:[],nextOffset:s,reset:r};let m=c.slice(0,a+1),l=0,p=[];for(let d of m.split(`
71
+ `)){if(!d)continue;let y=Buffer.byteLength(d+`
72
+ `,"utf8"),h=s+l;l+=y;let g;try{g=JSON.parse(d)}catch{continue}let S=bt(g),b=ts(S);p.push({type:b.type,timestamp:es(S),role:b.role,sourceEventId:`rollout:${h}`,sourceSequence:h,data:S,provenance:{source:"codex-rollout",sourcePath:t,sourceOffset:h}})}return{events:p,nextOffset:s+Buffer.byteLength(m,"utf8"),reset:r}}async function D(t){let e=t.threadId.trim();if(!e)throw new Error("Codex thread ID is required");let n=K(t.rolloutPath),r=t.cwd??n.cwd;if(r&&!pe(t.project.rootPath,r))throw new Error(`Codex thread does not belong to project: ${r}`);if(n.threadId&&n.threadId!==e)throw new Error(`Codex rollout thread mismatch: expected ${e}, got ${n.threadId}`);let s=new le({project:t.project,storage:t.storage,agent:"codex",nativeSessionId:e,metadata:{source:"codex-rollout",rolloutPath:t.rolloutPath,cwd:r,client:t.client}}),o=s.status(),i=o.sourceCursors["codex.rollout.path"],u=Number(o.sourceCursors["codex.rollout.offset"]??0);i&&i!==t.rolloutPath&&(u=0),(!Number.isFinite(u)||u<0)&&(u=0);let c=kt(t.rolloutPath,u),a=[];o.lastSequence===0&&a.push({type:"session_start",sourceEventId:`codex:${e}:start`,data:{threadId:e,cwd:r,rolloutPath:t.rolloutPath,sessionMeta:n.raw},provenance:{source:"codex-rollout",sourcePath:t.rolloutPath}}),i&&i!==t.rolloutPath&&a.push({type:"custom",sourceEventId:`codex:${e}:rollout-rotation:${t.rolloutPath}`,data:{event:"rollout_rotation",previousPath:i,rolloutPath:t.rolloutPath},provenance:{source:"codex-rollout"}}),c.reset&&a.push({type:"custom",sourceEventId:`codex:${e}:rollout-reset:${c.nextOffset}`,data:{event:"rollout_reset"},provenance:{source:"codex-rollout",sourcePath:t.rolloutPath}}),a.push(...c.events),t.idle&&t.turnId&&a.push({type:"session_idle",sourceEventId:`codex:${e}:turn:${t.turnId}:idle`,data:{turnId:t.turnId,client:t.client},provenance:{source:"codex-notify"}});let m=s.recordMany(a);s.setSourceCursor("codex.rollout.path",t.rolloutPath),s.setSourceCursor("codex.rollout.offset",c.nextOffset),t.turnId&&s.setSourceCursor("codex.last.turn",t.turnId);let l=await s.flush();return{threadId:e,imported:m.length,rolloutEvents:c.events.length,eventCount:l.eventCount,chunkCount:l.chunkCount,status:l.status,rolloutOffset:c.nextOffset,reset:c.reset}}import{existsSync as ns}from"node:fs";import{dirname as rs,join as ss,parse as os,resolve as is}from"node:path";function It(t){let e=is(t),n=os(e).root;for(;;){if(ns(ss(e,".toolnet","project.json")))return new T().detect(e);if(e===n)break;let r=rs(e);if(r===e)break;e=r}return null}async function Pt(t,e,n=100){let r=[];for(let s of ke()){let o=K(s);if(!(!o.threadId||!o.cwd)&&pe(t.rootPath,o.cwd)&&(r.push(await D({project:t,storage:e,threadId:o.threadId,rolloutPath:s,cwd:o.cwd})),r.length>=n))break}return r}import{existsSync as as,mkdirSync as Ot,readFileSync as cs,writeFileSync as Et}from"node:fs";import{homedir as Ct}from"node:os";import{dirname as Mt,join as Pe}from"node:path";function us(t){let e=[],n=/"((?:\\.|[^"\\])*)"|'([^']*)'/g,r;for(;r=n.exec(t);){let s=r[1]??r[2]??"";try{e.push(r[1]!==void 0?JSON.parse(`"${s}"`):s)}catch{e.push(s)}}return e}function At(t={}){let e=t.configFile??Pe(process.env.CODEX_HOME??Pe(Ct(),".codex"),"config.toml"),n=t.previousFile??Pe(Ct(),".config","toolnet-memory","codex-notify-previous.json");Ot(Mt(e),{recursive:!0}),Ot(Mt(n),{recursive:!0});let r=as(e)?cs(e,"utf8"):"",s=t.binary??"toolnet-memory",o=`notify = [${JSON.stringify(s)}, "session:codex-notify"]`,i=r.split(`
73
+ `),u=i.findIndex(p=>/^\s*\[/.test(p));u<0&&(u=i.length);let c=-1,a=-1;for(let p=0;p<u;p+=1)if(/^\s*notify\s*=/.test(i[p])){if(c=p,a=p,i[p].includes("[")&&!i[p].includes("]"))for(;a+1<u&&(a+=1,!i[a].includes("]")););break}let m=[];if(c>=0){let p=i.slice(c,a+1).join(`
74
+ `);m=us(p),i.splice(c,a-c+1,o)}else u=i.findIndex(p=>/^\s*\[/.test(p)),u<0&&(u=i.length),i.splice(u,0,o);let l=m.length>=2&&m[m.length-1]==="session:codex-notify";return m.length>0&&!l&&Et(n,JSON.stringify(m,null,2)+`
75
+ `,{encoding:"utf8",mode:384}),r=i.join(`
76
+ `),r.endsWith(`
77
+ `)||(r+=`
78
+ `),Et(e,r,{encoding:"utf8",mode:384}),{configFile:e,previousFile:n,preservedPrevious:m.length>0&&!l}}import{existsSync as ls,mkdirSync as ds,readFileSync as ps,writeFileSync as fs}from"node:fs";import{homedir as ms}from"node:os";import{dirname as gs,join as Rt}from"node:path";function hs(t){return`'${t.replace(/'/g,"'\\''")}'`}function Nt(t={}){let e=t.hooksFile??Rt(process.env.CODEX_HOME??Rt(ms(),".codex"),"hooks.json");ds(gs(e),{recursive:!0});let n={};if(ls(e))try{n=JSON.parse(ps(e,"utf8"))}catch(u){throw new Error(`Invalid existing Codex hooks.json: ${u instanceof Error?u.message:String(u)}`)}let r=n.hooks&&typeof n.hooks=="object"&&!Array.isArray(n.hooks)?n.hooks:{};n.hooks=r;let o=(Array.isArray(r.SessionStart)?r.SessionStart:[]).filter(u=>{try{return!JSON.stringify(u).includes("session:codex-context")}catch{return!0}}),i=t.binary??"toolnet-memory";return o.push({matcher:"startup|resume|clear|compact",hooks:[{type:"command",command:`${hs(i)} session:codex-context`,timeout:15,additionalContextLimit:1e3,statusMessage:"Loading ToolNet project continuity"}]}),r.SessionStart=o,fs(e,JSON.stringify(n,null,2)+`
79
+ `,{encoding:"utf8",mode:384}),e}import{existsSync as mc,mkdirSync as ws,readFileSync as gc,writeFileSync as js}from"node:fs";import{dirname as xs,join as _t}from"node:path";function Oe(t){if(!t)return 0;let e=Array.from(t).length,n=t.trim().split(/\s+/u).filter(Boolean).length;return Math.ceil(Math.max(e/3.5,n*1.3))}function w(t,e){let n=t.replace(/\s+/g," ").trim();return n.length<=e?n:n.slice(0,Math.max(0,e-1)).trimEnd()+"\u2026"}function ys(t){let e=[],n=!1;for(let r of t.split(/\r?\n/u)){let s=r.trim();if(s.includes("<!--")&&(n=!0),n){s.includes("-->")&&(n=!1);continue}let o=s.toLowerCase();if(!(!s||s.startsWith("#")||s==="```"||o.startsWith("- [enforce]")||o.startsWith("* [enforce]")||o.startsWith("- [advisory]")||o.startsWith("* [advisory]"))&&(s=s.replace(/^[-*]\s+/u,""),s&&e.push(w(s,280)),e.length>=16))break}return e}function Ss(t){let e=[],n=[];for(let r of t.split(/\\r?\\n/u)){let s=r.trim(),o=s.toLowerCase(),u=["- [enforce]","* [enforce]","- [advisory]","* [advisory]"].find(a=>o.startsWith(a));if(!u)continue;let c=s.slice(u.length).trim();c&&(u.includes("enforce")?e.push(c):n.push(c))}return{enforce:e,advisory:n}}function vs(t,e){let n=[];for(let r of t){let s=[...n,r].join(`
80
+ `);if(Oe(s)<=e){n.push(r);continue}let o=Oe(n.join(`
81
+ `)),i=Math.max(0,e-o);if(i>=16){let u=Math.floor(i*3.2),c=w(r,u);c&&n.push(c)}break}return n.join(`
82
+ `).trim()}async function Tt(t){let e=Math.max(256,Math.min(2e3,t.maxTokens??1e3)),n=ce(t.project,!1),r=n?.content??"";r||(r=await t.storage.getText(`projects/${t.project.id}/project/manual.md`)??"");let s=Ss(r),o=n?n.rules.filter(d=>d.mode==="enforce").map(d=>d.text):s.enforce,i=n?n.rules.filter(d=>d.mode==="advisory").map(d=>d.text):s.advisory,u=r?ys(r):[],c=await re(t.project,t.storage),a=await gt(t.project,t.storage),m=await vt(t.project,t.storage),l=[];if(l.push("[TOOLNET PROJECT CONTEXT]"),l.push(`Project: ${t.project.name}`),l.push("Continue existing project state. Do not restart completed work unless evidence shows it is necessary."),r&&l.push(`Full operating manual: ${ae(t.project)}`),o.length){l.push("","PROJECT RULES \u2014 MUST FOLLOW");for(let d of o.slice(0,24))l.push(`- [ENFORCE] ${w(d,240)}`)}if(i.length){l.push("","PROJECT PREFERENCES");for(let d of i.slice(0,10))l.push(`- ${w(d,220)}`)}if(a&&(a.mission&&l.push("","MISSION",w(a.mission.value,420)),a.activeObjective&&l.push("","CURRENT OBJECTIVE",w(a.activeObjective.value,420)),a.why&&l.push("","WHY THIS WORK MATTERS",w(a.why.value,420)),a.desiredOutcome&&l.push("","DESIRED OUTCOME",w(a.desiredOutcome.value,420)),a.planRationale&&l.push("","WHY THIS APPROACH",w(a.planRationale.value,420))),c){if(l.push("","ACTIVE WORK"),c.goal&&l.push(`Goal: ${w(c.goal,320)}`),c.plan&&l.push(`Plan: ${w(c.plan,320)}`),l.push(`Progress: phases ${c.progress.phasesCompleted}/${c.progress.phasesTotal}; tasks ${c.progress.tasksCompleted}/${c.progress.tasksTotal}; blocked ${c.progress.blocked}`),c.currentPhase&&l.push(`Current phase: ${c.currentPhase.title} [${c.currentPhase.status}]`),c.currentPhase&&a){let d=a.phases.find(y=>y.order===c.currentPhase?.order);d&&(d.objective&&l.push(`Phase objective: ${w(d.objective.value,340)}`),d.why?l.push(`Why this phase: ${w(d.why.value,340)}`):l.push("Why this phase: not explicitly recorded. Inspect existing implementation before assuming intent."),d.deliverable&&l.push(`Deliverable: ${w(d.deliverable.value,340)}`),d.dependencies.length&&l.push(`Depends on: ${d.dependencies.slice(0,4).map(y=>w(y.value,180)).join("; ")}`),d.acceptanceCriteria.length&&(l.push("","DEFINITION OF DONE"),d.acceptanceCriteria.slice(0,6).forEach(y=>{l.push(`- ${w(y.value,260)}`)})),d.openQuestions.length&&(l.push("","OPEN QUESTIONS FOR CURRENT PHASE"),d.openQuestions.slice(0,4).forEach(y=>{l.push(`- ${w(y.value,260)}`)})))}c.currentTask&&l.push(`Current task: ${c.currentTask.title} [${c.currentTask.status}]`),c.nextActions.length&&(l.push("","NEXT ACTIONS"),c.nextActions.slice(0,6).forEach((d,y)=>{l.push(`${y+1}. ${w(d,260)}`)})),c.blockers.length&&(l.push("","BLOCKERS"),c.blockers.slice(0,5).forEach(d=>{l.push(`- ${w(d,260)}`)})),c.warnings.length&&(l.push("","ATTENTION"),c.warnings.slice(-5).forEach(d=>{l.push(`- ${w(d,260)}`)})),c.decisions.length&&(l.push("","RECENT DECISIONS"),c.decisions.slice(-5).forEach(d=>{l.push(`- ${w(d,260)}`)})),c.lastSession&&l.push("",`Last work session: ${c.lastSession.agent} / ${c.lastSession.nativeSessionId}`)}if(a&&a.openQuestions.length&&(l.push("","UNRESOLVED QUESTIONS"),a.openQuestions.slice(0,5).forEach(d=>{l.push(`- ${w(d.value,260)}`)})),m&&l.push(`Latest handoff: ${m.reason} / ${m.sourceSession.agent}`),u.length){l.push("","OPERATING NOTES");for(let d of u)l.push(`- ${d}`)}l.push("","Before changing anything: verify the current repository state and continue from the active phase/task above.");let p=vs(l,e);return{version:1,projectId:t.project.id,projectName:t.project.name,text:p,estimatedTokens:Oe(p),maxTokens:e,hasManual:!!r,hasWorkState:!!c,hasHandoff:!!m,generatedAt:new Date().toISOString()}}function bs(t){return _t(t.rootPath,".toolnet","context","startup.md")}function ks(t){return _t(t.rootPath,".toolnet","context","startup.json")}function Is(t,e){let n=bs(t);ws(xs(n),{recursive:!0}),js(n,e.text.endsWith(`
83
+ `)?e.text:e.text+`
84
+ `,{encoding:"utf8",mode:384}),k(ks(t),e)}async function $t(t,e,n=900){let r=await Tt({project:t,storage:e,maxTokens:n}),s={version:1,projectId:t.id,projectName:t.name,text:r.text,digest:v(r.text),estimatedTokens:r.estimatedTokens,generatedAt:new Date().toISOString()};return Is(t,s),await e.put(`projects/${t.id}/context/startup.md`,s.text+`
85
+ `,"text/markdown"),await e.put(`projects/${t.id}/context/startup.json`,JSON.stringify(s,null,2)+`
86
+ `,"application/json"),s}function fe(t,e){let n=t.indexOf(e);return n>=0?t[n+1]:void 0}function Lt(t){let e=Me(),n=Be(We({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3});return new Y(n,t.id,t.name,t.remote??t.name)}async function As(t){for(let e=0;e<10;e+=1){let n=Ie(t);if(n)return n;await new Promise(r=>setTimeout(r,150))}return null}function Rs(t){let e=Ms(Cs(),".config","toolnet-memory","codex-notify-previous.json");if(Ps(e))try{let n=JSON.parse(Os(e,"utf8"));if(!Array.isArray(n)||n.length===0||!n.every(s=>typeof s=="string"))return;Es(n[0],[...n.slice(1),t],{detached:!0,stdio:"ignore"}).unref()}catch{}}async function Ns(t){let e;try{e=JSON.parse(t)}catch{return}if(e.type!=="agent-turn-complete")return;let r=typeof e["thread-id"]=="string"?e["thread-id"]:"",s=typeof e["turn-id"]=="string"?e["turn-id"]:"",o=typeof e.cwd=="string"?e.cwd:"",i=typeof e.client=="string"?e.client:void 0;if(!r||!o)return;let u=It(o);if(!u)return;let c=await As(r);if(!c)return;let a=Lt(u);await D({project:u,storage:a,threadId:r,rolloutPath:c,cwd:o,turnId:s,client:i,idle:!0});try{await $t(u,a,900)}catch{}}async function Ts(){let[t="help",...e]=process.argv.slice(2);if(t==="install-notify"){let o=fe(e,"--bin"),i=At({binary:o}),u=Nt({binary:o});console.log(`\u2705 Codex notify installed: ${i.configFile}`),i.preservedPrevious&&console.log(`\u2705 Previous notify preserved: ${i.previousFile}`),console.log(`\u2705 Codex SessionStart context hook: ${u}`);return}if(t==="notify"){let o=e[e.length-1]??"";try{await Ns(o)}finally{Rs(o)}return}let n=fe(e,"--project")??process.cwd(),r=new T().detect(n),s=Lt(r);if(t==="sync"){let o=e[0];if(!o)throw new Error("Usage: sync <thread-id>");let i=fe(e,"--rollout")??Ie(o);if(!i)throw new Error(`Codex rollout not found for ${o}`);let u=await D({project:r,storage:s,threadId:o,rolloutPath:i,idle:e.includes("--idle")});console.log(JSON.stringify(u,null,2));return}if(t==="recover"){let o=Number(fe(e,"--limit")??100),i=await Pt(r,s,Number.isFinite(o)?o:100);console.log(JSON.stringify({project:r.name,sessions:i.length,imported:i.reduce((u,c)=>u+c.imported,0)},null,2));return}console.log(`Codex Session Adapter
87
+
88
+ Commands:
89
+ install-notify
90
+ sync <thread-id> [--project PATH]
91
+ recover [--project PATH] [--limit N]
92
+ `)}Ts().catch(t=>{process.argv[2]==="notify"&&process.exit(0),console.error(t instanceof Error?t.message:t),process.exit(1)});
@@ -0,0 +1,56 @@
1
+ import{existsSync as ut}from"node:fs";import{dirname as lt,join as dt,resolve as mt}from"node:path";import{existsSync as se,readFileSync as ne}from"node:fs";import{homedir as ie}from"node:os";import{join as ae}from"node:path";function ce(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 pe(){let r=process.env.TOOLNET_GLOBAL_ENV??ae(ie(),".config","toolnet-memory",".env");if(!se(r))return;let e=ne(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]=ce(o.slice(s+1)))}}pe();function j(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function h(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function C(){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:h(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:h(process.env.MEMORY_RERANK_TOP,10),finalContext:h(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:h(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:h(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as ue}from"node:crypto";import{existsSync as _,mkdirSync as le,readFileSync as de,renameSync as me,writeFileSync as fe}from"node:fs";import{basename as ge,dirname as v,join as A,parse as W,resolve as k}from"node:path";var D=".toolnet",he="project.json";function ye(r){return ue("sha256").update(r).digest("hex").slice(0,16)}function T(r){return A(r,D,he)}function Se(r){return _(T(r))}function je(r){let e=k(r),t=W(e).root;for(;;){if(Se(e))return e;if(e===t)break;let o=v(e);if(o===e)break;e=o}return null}function ve(r){let e=k(r),t=W(e).root,o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(o.some(i=>_(A(e,i))))return e;if(e===t)break;let s=v(e);if(s===e)break;e=s}return k(r)}function ke(r){let e;try{e=JSON.parse(de(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:v(v(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 N(r,e){let t=A(r,D);le(t,{recursive:!0});let o=T(r),s=`${o}.tmp-${process.pid}`;fe(s,JSON.stringify(e,null,2)+`
3
+ `,{encoding:"utf8",mode:384}),me(s,o)}function $(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 w=class{detect(e=process.cwd()){let t=k(e),o=je(t);if(o){let n=T(o),u=ke(n);return u.rootPath!==o&&(u.rootPath=o,u.updatedAt=new Date().toISOString(),N(o,u)),$(u,o)}let s=ve(t),i=new Date().toISOString(),p=ge(s),l={version:1,id:ye(s),name:p,remote:p,rootPath:s,createdAt:i,updatedAt:i,graphVersion:0,memoryVersion:0};return N(s,l),$(l,s)}};import{homedir as We}from"node:os";import{join as De}from"node:path";import{DeleteObjectCommand as we,GetObjectCommand as xe,HeadObjectCommand as be,ListObjectsV2Command as Pe,PutObjectCommand as Ae,S3Client as Te}from"@aws-sdk/client-s3";import{getSignedUrl as Re}from"@aws-sdk/s3-request-presigner";var x=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 Ae({Bucket:this.bucket,Key:e,Body:s,ContentType:o}))}async get(e){let t=await Re(this.client,new xe({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 be({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 Pe({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 L,mkdir as Me,readFile as Oe,readdir as Ee,rm as Ie,stat as V,writeFile as Ce}from"node:fs/promises";import{dirname as Ne,join as $e,relative as B,resolve as _e}from"node:path";var y=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return _e(this.root,t)}async put(e,t){let o=this.path(e);await Me(Ne(o),{recursive:!0}),await Ce(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 L(this.path(e)),!0}catch{return!1}}async delete(e){await Ie(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),o=[];try{await L(t)}catch{return o}let s=async p=>{let l=await Ee(p,{withFileTypes:!0});for(let n of l){let u=$e(p,n.name);if(n.isDirectory()){await s(u);continue}let g=await V(u);o.push({key:B(this.root,u),size:g.size,updatedAt:g.mtime.toISOString()})}},i=await V(t);return i.isDirectory()?await s(t):o.push({key:B(this.root,t),size:i.size,updatedAt:i.mtime.toISOString()}),o}};function K(r){let e=r.localRoot??De(We(),".toolnet-memory","storage");if(r.provider==="huggingface"){let t=r.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new x({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):(console.warn("[storage] Hugging Face credentials missing. Using local fallback."),new y(e))}return new y(e)}function Le(r){return new Promise(e=>setTimeout(e,r))}async function J(r,e={}){let t=Math.max(1,e.attempts??3),o=e.baseDelayMs??150,s=e.maxDelayMs??2e3,i;for(let p=1;p<=t;p++)try{return await r()}catch(l){if(i=l,p>=t)break;let n=Math.min(s,o*2**(p-1)),u=Math.floor(Math.random()*Math.max(1,n*.2));await Le(n+u)}throw i}var Ve=new Set(["put","get","getText","delete","list"]);function F(r,e={}){return new Proxy(r,{get(t,o){let s=Reflect.get(t,o,t);return typeof s!="function"?s:Ve.has(o)?(...i)=>J(()=>Promise.resolve(s.apply(t,i)),e):s.bind(t)}})}function z(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 H(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=z(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 p;try{p=JSON.parse(s)}catch(l){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${l instanceof Error?l.message:String(l)}`)}if(typeof p.id=="string"&&p.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${p.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof p.createdAt=="string"&&(o=p.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=H(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{existsSync as st,mkdirSync as nt,readFileSync as it,writeFileSync as at}from"node:fs";import{dirname as ct,join as X}from"node:path";import{createHash as Be}from"node:crypto";import{dirname as Ke}from"node:path";import{mkdirSync as Je,readFileSync as ro,renameSync as Fe,writeFileSync as ze}from"node:fs";function f(r){return Be("sha256").update(r).digest("hex")}function S(r,e){Je(Ke(r),{recursive:!0});let t=`${r}.${process.pid}.tmp`;ze(t,JSON.stringify(e,null,2)+`
5
+ `,{encoding:"utf8",mode:384}),Fe(t,r)}import{existsSync as Y,mkdirSync as He,readFileSync as Ue,statSync as U,writeFileSync as Ge}from"node:fs";import{dirname as Ye,join as Qe}from"node:path";var G=64*1024,qe=`# ToolNet Project Operating Manual
6
+
7
+ This file contains persistent instructions for AI agents working on this project.
8
+
9
+ ## Critical Rules
10
+
11
+ <!--
12
+ Examples:
13
+
14
+ - [enforce] Never edit production files directly.
15
+ - [enforce] Edit source only in /path/to/source.
16
+ - [enforce] Deploy only with ./deploy.sh --apply
17
+ -->
18
+
19
+ ## Workflow
20
+
21
+ <!--
22
+ Describe the correct working process.
23
+ -->
24
+
25
+ ## Architecture
26
+
27
+ <!--
28
+ Important architecture conventions.
29
+ -->
30
+
31
+ ## Verification
32
+
33
+ <!--
34
+ Tests / QA required after changes.
35
+ -->
36
+
37
+ ## Known Gotchas
38
+
39
+ <!--
40
+ Things an AI agent should always remember.
41
+ -->
42
+
43
+ ## Preferences
44
+
45
+ <!--
46
+ - [advisory] Prefer small focused files.
47
+ -->
48
+ `;function P(r){return Qe(r.rootPath,".toolnet","PROJECT.md")}function Ze(r){return r.normalize("NFKC").replace(/\s+/g," ").trim()}function Xe(r){let e=[],t=new Set,o=/^\s*[-*]\s+\[(enforce|advisory)\]\s+(.+?)\s*$/gimu,s;for(;s=o.exec(r);){let i=s[1].toLowerCase(),p=Ze(s[2]);if(!p)continue;let l=`${i}:${p.toLowerCase()}`;t.has(l)||(t.add(l),e.push({id:f(l).slice(0,24),mode:i,text:p,source:"manual"}))}return e}function et(r){let e=P(r);return Y(e)||(He(Ye(e),{recursive:!0}),Ge(e,qe,{encoding:"utf8",mode:384})),e}function R(r,e=!1){let t=e?et(r):P(r);if(!Y(t))return null;if(U(t).size>G)throw new Error(`PROJECT.md exceeds ${G} bytes`);let s=Ue(t,"utf8");return{path:t,content:s,digest:f(s),rules:Xe(s),bytes:Buffer.byteLength(s,"utf8"),updatedAt:new Date(U(t).mtimeMs).toISOString()}}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}}async function Q(r,e){let t=await e.getText(`projects/${r.id}/work/handoff-latest.json`);if(!t)return null;try{return JSON.parse(t)}catch{return null}}async function q(r,e){let t=await e.getText(`projects/${r.id}/work/semantic/current.json`);if(!t)return null;try{return JSON.parse(t)}catch{return null}}function O(r){if(!r)return 0;let e=Array.from(r).length,t=r.trim().split(/\s+/u).filter(Boolean).length;return Math.ceil(Math.max(e/3.5,t*1.3))}function d(r,e){let t=r.replace(/\s+/g," ").trim();return t.length<=e?t:t.slice(0,Math.max(0,e-1)).trimEnd()+"\u2026"}function tt(r){let e=[],t=!1;for(let o of r.split(/\r?\n/u)){let s=o.trim();if(s.includes("<!--")&&(t=!0),t){s.includes("-->")&&(t=!1);continue}let i=s.toLowerCase();if(!(!s||s.startsWith("#")||s==="```"||i.startsWith("- [enforce]")||i.startsWith("* [enforce]")||i.startsWith("- [advisory]")||i.startsWith("* [advisory]"))&&(s=s.replace(/^[-*]\s+/u,""),s&&e.push(d(s,280)),e.length>=16))break}return e}function rt(r){let e=[],t=[];for(let o of r.split(/\\r?\\n/u)){let s=o.trim(),i=s.toLowerCase(),l=["- [enforce]","* [enforce]","- [advisory]","* [advisory]"].find(u=>i.startsWith(u));if(!l)continue;let n=s.slice(l.length).trim();n&&(l.includes("enforce")?e.push(n):t.push(n))}return{enforce:e,advisory:t}}function ot(r,e){let t=[];for(let o of r){let s=[...t,o].join(`
49
+ `);if(O(s)<=e){t.push(o);continue}let i=O(t.join(`
50
+ `)),p=Math.max(0,e-i);if(p>=16){let l=Math.floor(p*3.2),n=d(o,l);n&&t.push(n)}break}return t.join(`
51
+ `).trim()}async function Z(r){let e=Math.max(256,Math.min(2e3,r.maxTokens??1e3)),t=R(r.project,!1),o=t?.content??"";o||(o=await r.storage.getText(`projects/${r.project.id}/project/manual.md`)??"");let s=rt(o),i=t?t.rules.filter(c=>c.mode==="enforce").map(c=>c.text):s.enforce,p=t?t.rules.filter(c=>c.mode==="advisory").map(c=>c.text):s.advisory,l=o?tt(o):[],n=await M(r.project,r.storage),u=await q(r.project,r.storage),g=await Q(r.project,r.storage),a=[];if(a.push("[TOOLNET PROJECT CONTEXT]"),a.push(`Project: ${r.project.name}`),a.push("Continue existing project state. Do not restart completed work unless evidence shows it is necessary."),o&&a.push(`Full operating manual: ${P(r.project)}`),i.length){a.push("","PROJECT RULES \u2014 MUST FOLLOW");for(let c of i.slice(0,24))a.push(`- [ENFORCE] ${d(c,240)}`)}if(p.length){a.push("","PROJECT PREFERENCES");for(let c of p.slice(0,10))a.push(`- ${d(c,220)}`)}if(u&&(u.mission&&a.push("","MISSION",d(u.mission.value,420)),u.activeObjective&&a.push("","CURRENT OBJECTIVE",d(u.activeObjective.value,420)),u.why&&a.push("","WHY THIS WORK MATTERS",d(u.why.value,420)),u.desiredOutcome&&a.push("","DESIRED OUTCOME",d(u.desiredOutcome.value,420)),u.planRationale&&a.push("","WHY THIS APPROACH",d(u.planRationale.value,420))),n){if(a.push("","ACTIVE WORK"),n.goal&&a.push(`Goal: ${d(n.goal,320)}`),n.plan&&a.push(`Plan: ${d(n.plan,320)}`),a.push(`Progress: phases ${n.progress.phasesCompleted}/${n.progress.phasesTotal}; tasks ${n.progress.tasksCompleted}/${n.progress.tasksTotal}; blocked ${n.progress.blocked}`),n.currentPhase&&a.push(`Current phase: ${n.currentPhase.title} [${n.currentPhase.status}]`),n.currentPhase&&u){let c=u.phases.find(m=>m.order===n.currentPhase?.order);c&&(c.objective&&a.push(`Phase objective: ${d(c.objective.value,340)}`),c.why?a.push(`Why this phase: ${d(c.why.value,340)}`):a.push("Why this phase: not explicitly recorded. Inspect existing implementation before assuming intent."),c.deliverable&&a.push(`Deliverable: ${d(c.deliverable.value,340)}`),c.dependencies.length&&a.push(`Depends on: ${c.dependencies.slice(0,4).map(m=>d(m.value,180)).join("; ")}`),c.acceptanceCriteria.length&&(a.push("","DEFINITION OF DONE"),c.acceptanceCriteria.slice(0,6).forEach(m=>{a.push(`- ${d(m.value,260)}`)})),c.openQuestions.length&&(a.push("","OPEN QUESTIONS FOR CURRENT PHASE"),c.openQuestions.slice(0,4).forEach(m=>{a.push(`- ${d(m.value,260)}`)})))}n.currentTask&&a.push(`Current task: ${n.currentTask.title} [${n.currentTask.status}]`),n.nextActions.length&&(a.push("","NEXT ACTIONS"),n.nextActions.slice(0,6).forEach((c,m)=>{a.push(`${m+1}. ${d(c,260)}`)})),n.blockers.length&&(a.push("","BLOCKERS"),n.blockers.slice(0,5).forEach(c=>{a.push(`- ${d(c,260)}`)})),n.warnings.length&&(a.push("","ATTENTION"),n.warnings.slice(-5).forEach(c=>{a.push(`- ${d(c,260)}`)})),n.decisions.length&&(a.push("","RECENT DECISIONS"),n.decisions.slice(-5).forEach(c=>{a.push(`- ${d(c,260)}`)})),n.lastSession&&a.push("",`Last work session: ${n.lastSession.agent} / ${n.lastSession.nativeSessionId}`)}if(u&&u.openQuestions.length&&(a.push("","UNRESOLVED QUESTIONS"),u.openQuestions.slice(0,5).forEach(c=>{a.push(`- ${d(c.value,260)}`)})),g&&a.push(`Latest handoff: ${g.reason} / ${g.sourceSession.agent}`),l.length){a.push("","OPERATING NOTES");for(let c of l)a.push(`- ${c}`)}a.push("","Before changing anything: verify the current repository state and continue from the active phase/task above.");let I=ot(a,e);return{version:1,projectId:r.project.id,projectName:r.project.name,text:I,estimatedTokens:O(I),maxTokens:e,hasManual:!!o,hasWorkState:!!n,hasHandoff:!!g,generatedAt:new Date().toISOString()}}function ee(r){return X(r.rootPath,".toolnet","context","startup.md")}function pt(r){return X(r.rootPath,".toolnet","context","startup.json")}function te(r,e){let t=ee(r);nt(ct(t),{recursive:!0}),at(t,e.text.endsWith(`
52
+ `)?e.text:e.text+`
53
+ `,{encoding:"utf8",mode:384}),S(pt(r),e)}async function E(r,e,t=900){let o=await Z({project:r,storage:e,maxTokens:t}),s={version:1,projectId:r.id,projectName:r.name,text:o.text,digest:f(o.text),estimatedTokens:o.estimatedTokens,generatedAt:new Date().toISOString()};return te(r,s),await e.put(`projects/${r.id}/context/startup.md`,s.text+`
54
+ `,"text/markdown"),await e.put(`projects/${r.id}/context/startup.json`,JSON.stringify(s,null,2)+`
55
+ `,"application/json"),s}async function re(r,e,t=900){try{let s=await e.getText(`projects/${r.id}/context/startup.md`);if(s&&s.trim()){let i=s.trim(),p={version:1,projectId:r.id,projectName:r.name,text:i,digest:f(i),estimatedTokens:Math.ceil(i.length/3.5),generatedAt:new Date().toISOString()};return te(r,p),p}}catch{}let o=ee(r);if(st(o))try{let s=it(o,"utf8").trim();if(s)return{version:1,projectId:r.id,projectName:r.name,text:s,digest:f(s),estimatedTokens:Math.ceil(s.length/3.5),generatedAt:new Date().toISOString()}}catch{}try{return await E(r,e,t)}catch{return null}}function oe(r,e){let t=r.indexOf(e);return t>=0?r[t+1]:void 0}function ft(r){let e=mt(r);for(;;){if(ut(dt(e,".toolnet","project.json")))return e;let t=lt(e);if(t===e)return null;e=t}}function gt(r){let e=C(),t=F(K({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:2});return new b(t,r.id,r.name,r.remote??r.name)}async function ht(){let[r="print",...e]=process.argv.slice(2),t=oe(e,"--project")??process.cwd(),o=ft(t);if(!o)return;let s=new w().detect(o),i=gt(s),p=Number(oe(e,"--tokens")??900);if(r==="refresh"){let n=await E(s,i,Number.isFinite(p)?p:900);console.log(n.text);return}let l=await re(s,i,Number.isFinite(p)?p:900);if(l){if(r==="sync"){console.log(l.digest);return}process.stdout.write(l.text+`
56
+ `)}}ht().catch(()=>{process.exitCode=0});
@@ -0,0 +1,62 @@
1
+ import{existsSync as je,readFileSync as ve}from"node:fs";import{homedir as ke}from"node:os";import{join as we}from"node:path";function xe(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 be(){let r=process.env.TOOLNET_GLOBAL_ENV??we(ke(),".config","toolnet-memory",".env");if(!je(r))return;let e=ve(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 n=o.slice(0,s).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(n)&&process.env[n]===void 0&&(process.env[n]=xe(o.slice(s+1)))}}be();function T(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function x(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function G(){return{memory:{autoCapture:T(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:T(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:T(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:T(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:x(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:x(process.env.MEMORY_RERANK_TOP,10),finalContext:x(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:x(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:x(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as Pe}from"node:crypto";import{existsSync as q,mkdirSync as Ae,readFileSync as Te,renameSync as Re,writeFileSync as Oe}from"node:fs";import{basename as Me,dirname as R,join as V,parse as Z,resolve as O}from"node:path";var X=".toolnet",Ee="project.json";function Ie(r){return Pe("sha256").update(r).digest("hex").slice(0,16)}function K(r){return V(r,X,Ee)}function Ce(r){return q(K(r))}function Ne(r){let e=O(r),t=Z(e).root;for(;;){if(Ce(e))return e;if(e===t)break;let o=R(e);if(o===e)break;e=o}return null}function $e(r){let e=O(r),t=Z(e).root,o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(o.some(n=>q(V(e,n))))return e;if(e===t)break;let s=R(e);if(s===e)break;e=s}return O(r)}function _e(r){let e;try{e=JSON.parse(Te(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:R(R(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 Y(r,e){let t=V(r,X);Ae(t,{recursive:!0});let o=K(r),s=`${o}.tmp-${process.pid}`;Oe(s,JSON.stringify(e,null,2)+`
3
+ `,{encoding:"utf8",mode:384}),Re(s,o)}function Q(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 M=class{detect(e=process.cwd()){let t=O(e),o=Ne(t);if(o){let a=K(o),l=_e(a);return l.rootPath!==o&&(l.rootPath=o,l.updatedAt=new Date().toISOString(),Y(o,l)),Q(l,o)}let s=$e(t),n=new Date().toISOString(),p=Me(s),d={version:1,id:Ie(s),name:p,remote:p,rootPath:s,createdAt:n,updatedAt:n,graphVersion:0,memoryVersion:0};return Y(s,d),Q(d,s)}};import{homedir as Ze}from"node:os";import{join as Xe}from"node:path";import{DeleteObjectCommand as We,GetObjectCommand as De,HeadObjectCommand as Le,ListObjectsV2Command as Ve,PutObjectCommand as Ke,S3Client as Je}from"@aws-sdk/client-s3";import{getSignedUrl as ze}from"@aws-sdk/s3-request-presigner";var E=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new Je({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 Ke({Bucket:this.bucket,Key:e,Body:s,ContentType:o}))}async get(e){let t=await ze(this.client,new De({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 Le({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 Ve({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:o}));for(let n of s.Contents??[])n.Key&&t.push({key:n.Key,size:n.Size,updatedAt:n.LastModified?.toISOString()});o=s.IsTruncated?s.NextContinuationToken:void 0}while(o);return t}};import{access as ee,mkdir as Be,readFile as Fe,readdir as He,rm as Ue,stat as te,writeFile as Ge}from"node:fs/promises";import{dirname as Ye,join as Qe,relative as re,resolve as qe}from"node:path";var b=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return qe(this.root,t)}async put(e,t){let o=this.path(e);await Be(Ye(o),{recursive:!0}),await Ge(o,t)}async get(e){try{return await Fe(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 ee(this.path(e)),!0}catch{return!1}}async delete(e){await Ue(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),o=[];try{await ee(t)}catch{return o}let s=async p=>{let d=await He(p,{withFileTypes:!0});for(let a of d){let l=Qe(p,a.name);if(a.isDirectory()){await s(l);continue}let g=await te(l);o.push({key:re(this.root,l),size:g.size,updatedAt:g.mtime.toISOString()})}},n=await te(t);return n.isDirectory()?await s(t):o.push({key:re(this.root,t),size:n.size,updatedAt:n.mtime.toISOString()}),o}};function oe(r){let e=r.localRoot??Xe(Ze(),".toolnet-memory","storage");if(r.provider==="huggingface"){let t=r.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new E({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):(console.warn("[storage] Hugging Face credentials missing. Using local fallback."),new b(e))}return new b(e)}function et(r){return new Promise(e=>setTimeout(e,r))}async function se(r,e={}){let t=Math.max(1,e.attempts??3),o=e.baseDelayMs??150,s=e.maxDelayMs??2e3,n;for(let p=1;p<=t;p++)try{return await r()}catch(d){if(n=d,p>=t)break;let a=Math.min(s,o*2**(p-1)),l=Math.floor(Math.random()*Math.max(1,a*.2));await et(a+l)}throw n}var tt=new Set(["put","get","getText","delete","list"]);function ne(r,e={}){return new Proxy(r,{get(t,o){let s=Reflect.get(t,o,t);return typeof s!="function"?s:tt.has(o)?(...n)=>se(()=>Promise.resolve(s.apply(t,n)),e):s.bind(t)}})}function ie(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 ae(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 I=class{constructor(e,t,o,s){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=o,this.folder=ie(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 p;try{p=JSON.parse(s)}catch(d){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${d instanceof Error?d.message:String(d)}`)}if(typeof p.id=="string"&&p.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${p.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof p.createdAt=="string"&&(o=p.createdAt)}let n={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:o,updatedAt:t};await this.provider.put(e,JSON.stringify(n,null,2)+`
4
+ `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=ae(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 at}from"node:path";import{createHash as rt}from"node:crypto";import{dirname as ot}from"node:path";import{mkdirSync as st,readFileSync as go,renameSync as nt,writeFileSync as it}from"node:fs";function y(r){return rt("sha256").update(r).digest("hex")}function k(r,e){st(ot(r),{recursive:!0});let t=`${r}.${process.pid}.tmp`;it(t,JSON.stringify(e,null,2)+`
5
+ `,{encoding:"utf8",mode:384}),nt(t,r)}function ce(r,e){let t=r.trim(),o=t.replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,""),s=y(t).slice(0,12);if(!o||o==="."||o==="..")return`${e}--${s}`;let n=o.slice(0,100);return n===t&&t.length<=100?n:`${n.slice(0,85)}--${s}`}function pe(r,e,t){let o=e.trim(),s=t.trim();if(!o)throw new Error("Session agent is required");if(!s)throw new Error("Native session ID is required");let n=ce(o.toLowerCase(),"agent"),p=ce(s,"session");return{projectId:r.id,projectName:r.name,projectRoot:r.rootPath,agent:o,nativeSessionId:s,sessionKey:`${o}:${s}`,remotePrefix:["projects",r.id,"sessions",n,p].join("/"),localDirectory:at(r.rootPath,".toolnet","sessions",n,p)}}import{existsSync as de,mkdirSync as ct,readFileSync as pt,statSync as ue,writeFileSync as ut}from"node:fs";import{dirname as lt,join as dt}from"node:path";var le=64*1024,mt=`# ToolNet Project Operating Manual
6
+
7
+ This file contains persistent instructions for AI agents working on this project.
8
+
9
+ ## Critical Rules
10
+
11
+ <!--
12
+ Examples:
13
+
14
+ - [enforce] Never edit production files directly.
15
+ - [enforce] Edit source only in /path/to/source.
16
+ - [enforce] Deploy only with ./deploy.sh --apply
17
+ -->
18
+
19
+ ## Workflow
20
+
21
+ <!--
22
+ Describe the correct working process.
23
+ -->
24
+
25
+ ## Architecture
26
+
27
+ <!--
28
+ Important architecture conventions.
29
+ -->
30
+
31
+ ## Verification
32
+
33
+ <!--
34
+ Tests / QA required after changes.
35
+ -->
36
+
37
+ ## Known Gotchas
38
+
39
+ <!--
40
+ Things an AI agent should always remember.
41
+ -->
42
+
43
+ ## Preferences
44
+
45
+ <!--
46
+ - [advisory] Prefer small focused files.
47
+ -->
48
+ `;function C(r){return dt(r.rootPath,".toolnet","PROJECT.md")}function ft(r){return r.normalize("NFKC").replace(/\s+/g," ").trim()}function gt(r){let e=[],t=new Set,o=/^\s*[-*]\s+\[(enforce|advisory)\]\s+(.+?)\s*$/gimu,s;for(;s=o.exec(r);){let n=s[1].toLowerCase(),p=ft(s[2]);if(!p)continue;let d=`${n}:${p.toLowerCase()}`;t.has(d)||(t.add(d),e.push({id:y(d).slice(0,24),mode:n,text:p,source:"manual"}))}return e}function ht(r){let e=C(r);return de(e)||(ct(lt(e),{recursive:!0}),ut(e,mt,{encoding:"utf8",mode:384})),e}function N(r,e=!1){let t=e?ht(r):C(r);if(!de(t))return null;if(ue(t).size>le)throw new Error(`PROJECT.md exceeds ${le} bytes`);let s=pt(t,"utf8");return{path:t,content:s,digest:y(s),rules:gt(s),bytes:Buffer.byteLength(s,"utf8"),updatedAt:new Date(ue(t).mtimeMs).toISOString()}}import{mkdirSync as kt}from"node:fs";import{join as J}from"node:path";import{join as me}from"node:path";import{mkdirSync as yt}from"node:fs";function St(r){return r.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function w(r,e=20){let t=[],o=new Set;for(let s of r.slice().reverse()){let n=St(s);if(!(!n||o.has(n))&&(o.add(n),t.push(s),t.length>=e))break}return t.reverse()}function jt(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 fe(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&&jt(e)?r.title:e.text;return{id:r?.id??y(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 vt(r,e){let t=`projects/${r.id}/work/observations/`,o=await e.list(t),s=[];for(let n of o.filter(p=>p.key.endsWith(".json")).sort((p,d)=>p.key.localeCompare(d.key))){let p=await e.getText(n.key);if(p)try{let d=JSON.parse(p);d.version===1&&Array.isArray(d.observations)&&s.push(d)}catch{}}return s}async function ge(r,e){let o=(await vt(r,e)).flatMap(i=>i.observations).sort((i,v)=>{let H=i.occurredAt.localeCompare(v.occurredAt);if(H!==0)return H;let U=i.sequence-v.sequence;return U!==0?U:i.id.localeCompare(v.id)}),s=new Map,n=new Map,p,d,a,l=[],g=[],c=[],f=[],u=[],h=[];for(let i of o)switch(i.kind){case"goal":p=i.text;break;case"plan":d=i.text;break;case"phase":s.set(i.key,fe(s.get(i.key),i));break;case"task":n.set(i.key,fe(n.get(i.key),i));break;case"decision":l.push(i.text);break;case"blocker":g.push(i.text);break;case"warning":c.push(i.text);break;case"next_action":f.push(i.text);break;case"file":u.push(i.text);break;case"test":h.push(i.text);break;case"session":a={agent:i.agent,nativeSessionId:i.nativeSessionId,sessionKey:i.sessionKey,updatedAt:i.occurredAt};break}let j=Array.from(s.values()).sort((i,v)=>(i.order??Number.MAX_SAFE_INTEGER)-(v.order??Number.MAX_SAFE_INTEGER)),S=Array.from(n.values()).sort((i,v)=>(i.order??Number.MAX_SAFE_INTEGER)-(v.order??Number.MAX_SAFE_INTEGER)),D=j.find(i=>i.status==="in_progress")??j.find(i=>i.status==="blocked")??j.find(i=>i.status==="pending"),A=S.find(i=>i.status==="in_progress")??S.find(i=>i.status==="blocked")??S.find(i=>i.status==="pending"),ye=w([...f,...A?[A.title]:[],...!A&&D?[D.title]:[],...S.filter(i=>i.status==="pending").slice(0,5).map(i=>i.title)],8),Se=w([...g,...j.filter(i=>i.status==="blocked").map(i=>i.title),...S.filter(i=>i.status==="blocked").map(i=>i.title)],20),L={version:1,projectId:r.id,projectName:r.name,goal:p,plan:d,phases:j,tasks:S,decisions:w(l,20),blockers:Se,warnings:w(c,20),nextActions:ye,filesTouched:w(u,30),tests:w(h,20),currentPhase:D,currentTask:A,progress:{phasesTotal:j.length,phasesCompleted:j.filter(i=>i.status==="completed").length,tasksTotal:S.length,tasksCompleted:S.filter(i=>i.status==="completed").length,blocked:j.filter(i=>i.status==="blocked").length+S.filter(i=>i.status==="blocked").length},lastSession:a,updatedAt:o.length?o[o.length-1].occurredAt:new Date().toISOString()},F=me(r.rootPath,".toolnet","work");return yt(F,{recursive:!0}),k(me(F,"current.json"),L),await e.put(`projects/${r.id}/work/current.json`,JSON.stringify(L,null,2)+`
49
+ `,"application/json"),L}async function $(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 wt(r){return{goal:r.goal,plan:r.plan,phases:r.phases.map(e=>({id:e.id,title:e.title,status:e.status,order:e.order})),tasks:r.tasks.map(e=>({id:e.id,title:e.title,status:e.status,order:e.order})),decisions:r.decisions,blockers:r.blockers,warnings:r.warnings,nextActions:r.nextActions,filesTouched:r.filesTouched,tests:r.tests}}function xt(r){return r.phases.some(e=>e.status==="pending"||e.status==="in_progress"||e.status==="blocked")||r.tasks.some(e=>e.status==="pending"||e.status==="in_progress"||e.status==="blocked")||r.nextActions.length>0||r.blockers.length>0}var _=class{constructor(e){this.options=e}options;async capture(e,t){let o=await $(this.options.project,this.options.storage);if(o||(o=await ge(this.options.project,this.options.storage)),!xt(o))return null;let s=N(this.options.project,!1),n=s?s.rules.filter(f=>f.mode==="enforce").map(f=>f.text):[],p=y(JSON.stringify(wt(o))),d=y([this.options.project.id,this.options.identity.sessionKey,p].join("|")).slice(0,24),a=new Date().toISOString(),l={version:1,id:d,projectId:this.options.project.id,projectName:this.options.project.name,createdAt:a,reason:e,sourceSession:{agent:this.options.identity.agent,nativeSessionId:this.options.identity.nativeSessionId,sessionKey:this.options.identity.sessionKey,sequence:t},goal:o.goal,plan:o.plan,progress:o.progress,currentPhase:o.currentPhase,currentTask:o.currentTask,incompletePhases:o.phases.filter(f=>f.status!=="completed"&&f.status!=="cancelled"),incompleteTasks:o.tasks.filter(f=>f.status!=="completed"&&f.status!=="cancelled"),nextActions:o.nextActions.slice(0,10),blockers:o.blockers.slice(0,10),decisions:o.decisions.slice(-10),warnings:o.warnings.slice(-10),attention:[...n,...o.warnings].slice(0,20),filesTouched:o.filesTouched.slice(-20),tests:o.tests.slice(-15),stateDigest:p},g=`projects/${this.options.project.id}/work/handoffs/${d}.json`;await this.options.storage.exists(g)||await this.options.storage.put(g,JSON.stringify(l,null,2)+`
50
+ `,"application/json"),await this.options.storage.put(`projects/${this.options.project.id}/work/handoff-latest.json`,JSON.stringify(l,null,2)+`
51
+ `,"application/json");let c=J(this.options.project.rootPath,".toolnet","work","handoffs");return kt(c,{recursive:!0}),k(J(c,`${d}.json`),l),k(J(this.options.project.rootPath,".toolnet","work","handoff-latest.json"),l),l}};async function W(r,e){let t=await e.getText(`projects/${r.id}/work/handoff-latest.json`);if(!t)return null;try{return JSON.parse(t)}catch{return null}}async function he(r,e){let t=await e.getText(`projects/${r.id}/work/semantic/current.json`);if(!t)return null;try{return JSON.parse(t)}catch{return null}}function z(r){if(!r)return 0;let e=Array.from(r).length,t=r.trim().split(/\s+/u).filter(Boolean).length;return Math.ceil(Math.max(e/3.5,t*1.3))}function m(r,e){let t=r.replace(/\s+/g," ").trim();return t.length<=e?t:t.slice(0,Math.max(0,e-1)).trimEnd()+"\u2026"}function bt(r){let e=[],t=!1;for(let o of r.split(/\r?\n/u)){let s=o.trim();if(s.includes("<!--")&&(t=!0),t){s.includes("-->")&&(t=!1);continue}let n=s.toLowerCase();if(!(!s||s.startsWith("#")||s==="```"||n.startsWith("- [enforce]")||n.startsWith("* [enforce]")||n.startsWith("- [advisory]")||n.startsWith("* [advisory]"))&&(s=s.replace(/^[-*]\s+/u,""),s&&e.push(m(s,280)),e.length>=16))break}return e}function Pt(r){let e=[],t=[];for(let o of r.split(/\\r?\\n/u)){let s=o.trim(),n=s.toLowerCase(),d=["- [enforce]","* [enforce]","- [advisory]","* [advisory]"].find(l=>n.startsWith(l));if(!d)continue;let a=s.slice(d.length).trim();a&&(d.includes("enforce")?e.push(a):t.push(a))}return{enforce:e,advisory:t}}function At(r,e){let t=[];for(let o of r){let s=[...t,o].join(`
52
+ `);if(z(s)<=e){t.push(o);continue}let n=z(t.join(`
53
+ `)),p=Math.max(0,e-n);if(p>=16){let d=Math.floor(p*3.2),a=m(o,d);a&&t.push(a)}break}return t.join(`
54
+ `).trim()}async function B(r){let e=Math.max(256,Math.min(2e3,r.maxTokens??1e3)),t=N(r.project,!1),o=t?.content??"";o||(o=await r.storage.getText(`projects/${r.project.id}/project/manual.md`)??"");let s=Pt(o),n=t?t.rules.filter(u=>u.mode==="enforce").map(u=>u.text):s.enforce,p=t?t.rules.filter(u=>u.mode==="advisory").map(u=>u.text):s.advisory,d=o?bt(o):[],a=await $(r.project,r.storage),l=await he(r.project,r.storage),g=await W(r.project,r.storage),c=[];if(c.push("[TOOLNET PROJECT CONTEXT]"),c.push(`Project: ${r.project.name}`),c.push("Continue existing project state. Do not restart completed work unless evidence shows it is necessary."),o&&c.push(`Full operating manual: ${C(r.project)}`),n.length){c.push("","PROJECT RULES \u2014 MUST FOLLOW");for(let u of n.slice(0,24))c.push(`- [ENFORCE] ${m(u,240)}`)}if(p.length){c.push("","PROJECT PREFERENCES");for(let u of p.slice(0,10))c.push(`- ${m(u,220)}`)}if(l&&(l.mission&&c.push("","MISSION",m(l.mission.value,420)),l.activeObjective&&c.push("","CURRENT OBJECTIVE",m(l.activeObjective.value,420)),l.why&&c.push("","WHY THIS WORK MATTERS",m(l.why.value,420)),l.desiredOutcome&&c.push("","DESIRED OUTCOME",m(l.desiredOutcome.value,420)),l.planRationale&&c.push("","WHY THIS APPROACH",m(l.planRationale.value,420))),a){if(c.push("","ACTIVE WORK"),a.goal&&c.push(`Goal: ${m(a.goal,320)}`),a.plan&&c.push(`Plan: ${m(a.plan,320)}`),c.push(`Progress: phases ${a.progress.phasesCompleted}/${a.progress.phasesTotal}; tasks ${a.progress.tasksCompleted}/${a.progress.tasksTotal}; blocked ${a.progress.blocked}`),a.currentPhase&&c.push(`Current phase: ${a.currentPhase.title} [${a.currentPhase.status}]`),a.currentPhase&&l){let u=l.phases.find(h=>h.order===a.currentPhase?.order);u&&(u.objective&&c.push(`Phase objective: ${m(u.objective.value,340)}`),u.why?c.push(`Why this phase: ${m(u.why.value,340)}`):c.push("Why this phase: not explicitly recorded. Inspect existing implementation before assuming intent."),u.deliverable&&c.push(`Deliverable: ${m(u.deliverable.value,340)}`),u.dependencies.length&&c.push(`Depends on: ${u.dependencies.slice(0,4).map(h=>m(h.value,180)).join("; ")}`),u.acceptanceCriteria.length&&(c.push("","DEFINITION OF DONE"),u.acceptanceCriteria.slice(0,6).forEach(h=>{c.push(`- ${m(h.value,260)}`)})),u.openQuestions.length&&(c.push("","OPEN QUESTIONS FOR CURRENT PHASE"),u.openQuestions.slice(0,4).forEach(h=>{c.push(`- ${m(h.value,260)}`)})))}a.currentTask&&c.push(`Current task: ${a.currentTask.title} [${a.currentTask.status}]`),a.nextActions.length&&(c.push("","NEXT ACTIONS"),a.nextActions.slice(0,6).forEach((u,h)=>{c.push(`${h+1}. ${m(u,260)}`)})),a.blockers.length&&(c.push("","BLOCKERS"),a.blockers.slice(0,5).forEach(u=>{c.push(`- ${m(u,260)}`)})),a.warnings.length&&(c.push("","ATTENTION"),a.warnings.slice(-5).forEach(u=>{c.push(`- ${m(u,260)}`)})),a.decisions.length&&(c.push("","RECENT DECISIONS"),a.decisions.slice(-5).forEach(u=>{c.push(`- ${m(u,260)}`)})),a.lastSession&&c.push("",`Last work session: ${a.lastSession.agent} / ${a.lastSession.nativeSessionId}`)}if(l&&l.openQuestions.length&&(c.push("","UNRESOLVED QUESTIONS"),l.openQuestions.slice(0,5).forEach(u=>{c.push(`- ${m(u.value,260)}`)})),g&&c.push(`Latest handoff: ${g.reason} / ${g.sourceSession.agent}`),d.length){c.push("","OPERATING NOTES");for(let u of d)c.push(`- ${u}`)}c.push("","Before changing anything: verify the current repository state and continue from the active phase/task above.");let f=At(c,e);return{version:1,projectId:r.project.id,projectName:r.project.name,text:f,estimatedTokens:z(f),maxTokens:e,hasManual:!!o,hasWorkState:!!a,hasHandoff:!!g,generatedAt:new Date().toISOString()}}function P(r,e){let t=r.indexOf(e);return t>=0?r[t+1]:void 0}function Tt(r){let e=G(),t=ne(oe({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3});return new I(t,r.id,r.name,r.remote??r.name)}async function Rt(){let[r="help",...e]=process.argv.slice(2),t=new M().detect(P(e,"--project")??process.cwd()),o=Tt(t);if(r==="brief"){let s=Number(P(e,"--tokens")??1e3),n=await B({project:t,storage:o,maxTokens:Number.isFinite(s)?s:1e3});process.stdout.write(n.text+`
55
+ `);return}if(r==="brief-json"){let s=await B({project:t,storage:o,maxTokens:Number(P(e,"--tokens")??1e3)});console.log(JSON.stringify(s,null,2));return}if(r==="handoff-latest"){let s=await W(t,o);console.log(JSON.stringify(s,null,2));return}if(r==="handoff-create"){let s=P(e,"--agent")??"manual";if(s==="manual")throw new Error("--agent must be opencode, agy, or codex");let n=P(e,"--session");if(!n)throw new Error("--session is required");let p=pe(t,s,n),a=await new _({project:t,storage:o,identity:p}).capture("manual",0);console.log(JSON.stringify(a,null,2));return}console.log(`Work Context
56
+
57
+ Commands:
58
+ brief [--project PATH] [--tokens N]
59
+ brief-json [--project PATH] [--tokens N]
60
+ handoff-latest [--project PATH]
61
+ handoff-create --agent <opencode|agy|codex> --session <id>
62
+ `)}Rt().catch(r=>{console.error(r instanceof Error?r.message:r),process.exit(1)});
@@ -0,0 +1,3 @@
1
+ import"dotenv/config";import{existsSync as U,readFileSync as Y}from"node:fs";import{homedir as G}from"node:os";import{join as W}from"node:path";function Z(o){let e=o.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 Q(){let o=process.env.TOOLNET_GLOBAL_ENV??W(G(),".config","toolnet-memory",".env");if(!U(o))return;let e=Y(o,"utf8");for(let t of e.split(/\r?\n/)){let r=t.trim();if(!r||r.startsWith("#"))continue;r.startsWith("export ")&&(r=r.slice(7));let s=r.indexOf("=");if(s<=0)continue;let n=r.slice(0,s).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(n)&&process.env[n]===void 0&&(process.env[n]=Z(r.slice(s+1)))}}Q();function u(o,e){return o===void 0?e:["1","true","yes","on"].includes(o.toLowerCase())}function d(o,e){if(!o)return e;let t=Number(o);return Number.isFinite(t)?t:e}function O(){return{memory:{autoCapture:u(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:u(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:u(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:u(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:d(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:d(process.env.MEMORY_RERANK_TOP,10),finalContext:d(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:d(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:d(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as X}from"node:crypto";import{existsSync as $,mkdirSync as q,readFileSync as ee,renameSync as te,writeFileSync as re}from"node:fs";import{basename as oe,dirname as l,join as R,parse as N,resolve as f}from"node:path";var D=".toolnet",se="project.json";function ne(o){return X("sha256").update(o).digest("hex").slice(0,16)}function M(o){return R(o,D,se)}function ie(o){return $(M(o))}function ae(o){let e=f(o),t=N(e).root;for(;;){if(ie(e))return e;if(e===t)break;let r=l(e);if(r===e)break;e=r}return null}function ce(o){let e=f(o),t=N(e).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(n=>$(R(e,n))))return e;if(e===t)break;let s=l(e);if(s===e)break;e=s}return f(o)}function pe(o){let e;try{e=JSON.parse(ee(o,"utf8"))}catch(s){throw new Error(`Invalid ToolNet project manifest: ${o}: ${s instanceof Error?s.message:String(s)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${o}`);let t=e;if(typeof t.id!="string"||!t.id.trim())throw new Error(`ToolNet project manifest is missing id: ${o}`);if(typeof t.name!="string"||!t.name.trim())throw new Error(`ToolNet project manifest is missing name: ${o}`);let r=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:l(l(o)),createdAt:typeof t.createdAt=="string"?t.createdAt:r,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:r,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 _(o,e){let t=R(o,D);q(t,{recursive:!0});let r=M(o),s=`${r}.tmp-${process.pid}`;re(s,JSON.stringify(e,null,2)+`
3
+ `,{encoding:"utf8",mode:384}),te(s,r)}function I(o,e){return{id:o.id,name:o.name,remote:o.remote,rootPath:e,createdAt:o.createdAt,updatedAt:o.updatedAt,graphVersion:o.graphVersion,memoryVersion:o.memoryVersion,metadata:o.metadata}}var h=class{detect(e=process.cwd()){let t=f(e),r=ae(t);if(r){let p=M(r),c=pe(p);return c.rootPath!==r&&(c.rootPath=r,c.updatedAt=new Date().toISOString(),_(r,c)),I(c,r)}let s=ce(t),n=new Date().toISOString(),i=oe(s),a={version:1,id:ne(s),name:i,remote:i,rootPath:s,createdAt:n,updatedAt:n,graphVersion:0,memoryVersion:0};return _(s,a),I(a,s)}};import{homedir as ke}from"node:os";import{join as Ee}from"node:path";import{DeleteObjectCommand as me,GetObjectCommand as de,HeadObjectCommand as ge,ListObjectsV2Command as ue,PutObjectCommand as le,S3Client as fe}from"@aws-sdk/client-s3";import{getSignedUrl as he}from"@aws-sdk/s3-request-presigner";var y=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new fe({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,r="application/octet-stream"){let s=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new le({Bucket:this.bucket,Key:e,Body:s,ContentType:r}))}async get(e){let t=await he(this.client,new de({Bucket:this.bucket,Key:e}),{expiresIn:60}),r=await fetch(t,{redirect:"follow"});if(r.status===404)return null;if(!r.ok)throw new Error(`HF download failed: ${r.status} ${r.statusText}`);return new Uint8Array(await r.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 ge({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 me({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let s=await this.client.send(new ue({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let n of s.Contents??[])n.Key&&t.push({key:n.Key,size:n.Size,updatedAt:n.LastModified?.toISOString()});r=s.IsTruncated?s.NextContinuationToken:void 0}while(r);return t}};import{access as z,mkdir as ye,readFile as ve,readdir as we,rm as je,stat as V,writeFile as Se}from"node:fs/promises";import{dirname as be,join as xe,relative as K,resolve as Pe}from"node:path";var g=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return Pe(this.root,t)}async put(e,t){let r=this.path(e);await ye(be(r),{recursive:!0}),await Se(r,t)}async get(e){try{return await ve(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 z(this.path(e)),!0}catch{return!1}}async delete(e){await je(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),r=[];try{await z(t)}catch{return r}let s=async i=>{let a=await we(i,{withFileTypes:!0});for(let p of a){let c=xe(i,p.name);if(p.isDirectory()){await s(c);continue}let m=await V(c);r.push({key:K(this.root,c),size:m.size,updatedAt:m.mtime.toISOString()})}},n=await V(t);return n.isDirectory()?await s(t):r.push({key:K(this.root,t),size:n.size,updatedAt:n.mtime.toISOString()}),r}};function L(o){let e=o.localRoot??Ee(ke(),".toolnet-memory","storage");if(o.provider==="huggingface"){let t=o.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new y({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):(console.warn("[storage] Hugging Face credentials missing. Using local fallback."),new g(e))}return new g(e)}var v=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"memories","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));if(!t)return[];let r=JSON.parse(t);if(!Array.isArray(r))throw new Error("Invalid memory snapshot");return r}async save(e,t){let r=JSON.stringify(t,null,2);await this.storage.put(this.key(e),r,"application/json")}};var w=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"vectors","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));if(!t)return null;let r=JSON.parse(t);if(r.version!==1||r.projectId!==e||!Array.isArray(r.records))throw new Error("Invalid vector snapshot");return r}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var j=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"graph","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var S=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"code","chunks","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var b=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"code","vectors","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};function Ae(o){return new Promise(e=>setTimeout(e,o))}async function F(o,e={}){let t=Math.max(1,e.attempts??3),r=e.baseDelayMs??150,s=e.maxDelayMs??2e3,n;for(let i=1;i<=t;i++)try{return await o()}catch(a){if(n=a,i>=t)break;let p=Math.min(s,r*2**(i-1)),c=Math.floor(Math.random()*Math.max(1,p*.2));await Ae(p+c)}throw n}var Re=new Set(["put","get","getText","delete","list"]);function B(o,e={}){return new Proxy(o,{get(t,r){let s=Reflect.get(t,r,t);return typeof s!="function"?s:Re.has(r)?(...n)=>F(()=>Promise.resolve(s.apply(t,n)),e):s.bind(t)}})}var x=class{constructor(e){this.options=e}options;name="huggingface";dimensions=384;async embed(e){let[t]=await this.embedMany([e]);return t}async embedMany(e){if(e.length===0)return[];let t=`https://router.huggingface.co/hf-inference/models/${this.options.model}/pipeline/feature-extraction`,r=await fetch(t,{method:"POST",headers:{Authorization:`Bearer ${this.options.token}`,"Content-Type":"application/json"},body:JSON.stringify({inputs:e,options:{wait_for_model:!0}})});if(!r.ok)throw new Error(`HF embedding failed: ${r.status} ${await r.text()}`);let s=await r.json();if(!Array.isArray(s))throw new Error("HF embedding returned invalid response");return s.map(n=>Me(n))}};function Me(o){if(!Array.isArray(o))throw new Error("Invalid embedding");if(o.length>0&&typeof o[0]=="number")return o;if(o.length>0&&Array.isArray(o[0])){let e=o;if(e.length===0)return[];let t=e[0].length,r=new Array(t).fill(0);for(let s of e)for(let n=0;n<t;n++)r[n]+=s[n]??0;for(let s=0;s<t;s++)r[s]/=e.length;return r}throw new Error("Unsupported embedding shape")}import{createHash as Te}from"node:crypto";var P=class{name="hash-fallback";dimensions=128;async embed(e){let t=new Array(this.dimensions).fill(0),r=e.toLowerCase().split(/\s+/).filter(Boolean);for(let s of r){let i=Te("sha256").update(s).digest().readUInt32BE(0)%this.dimensions;t[i]+=1}return Ce(t)}async embedMany(e){return Promise.all(e.map(t=>this.embed(t)))}};function Ce(o){let e=Math.sqrt(o.reduce((t,r)=>t+r*r,0));return e===0?o:o.map(t=>t/e)}var T=class{constructor(e,t=new P){this.primary=e;this.fallback=t}primary;fallback;name="resilient";async embed(e){if(this.primary)try{return await this.primary.embed(e)}catch(t){console.warn("[embedding] primary failed, fallback enabled:",t instanceof Error?t.message:t)}return this.fallback.embed(e)}async embedMany(e){if(this.primary)try{return await this.primary.embedMany(e)}catch(t){console.warn("[embedding] primary failed, fallback enabled:",t instanceof Error?t.message:t)}return this.fallback.embedMany(e)}};function H(){let o=process.env.HF_TOKEN,e=process.env.HF_EMBEDDING_MODEL??"sentence-transformers/all-MiniLM-L6-v2",t=o?new x({token:o,model:e}):null;return new T(t)}var Oe=["memories/current.json","vectors/current.json","graph/current.json","graph/manifest.json","graph/resolution/current.json","code/chunks/current.json","code/vectors/current.json","code/architecture/current.json","code/architecture/entry-points.json","code/architecture/hotspots.json","code/architecture/layers.json","code/architecture/clusters.json","code/analysis/current.json","code/analysis/dead-code.json","code/analysis/dependencies.json","code/visualization/graph.json"],k=class{constructor(e){this.storage=e}storage;projectPrefix(e){return`projects/${e}`}snapshotPrefix(e,t){return[this.projectPrefix(e),"snapshots",t].join("/")}async create(e,t="automatic",r){let s=new Date().toISOString(),n=s.replace(/[:.]/g,"-"),i=this.projectPrefix(e),a=this.snapshotPrefix(e,n),p=[];for(let m of Oe){let A=`${i}/${m}`,C=await this.storage.get(A);C&&(await this.storage.put(`${a}/${m}`,C,"application/json"),p.push(m))}if(p.length===0)return null;let c={version:1,id:n,projectId:e,createdAt:s,reason:t,objects:p,metadata:r};return await this.storage.put(`${a}/snapshot.json`,JSON.stringify(c,null,2),"application/json"),c}async list(e){let t=[this.projectPrefix(e),"snapshots"].join("/"),s=(await this.storage.list(t)).filter(i=>i.key.endsWith("/snapshot.json")),n=[];for(let i of s){let a=await this.storage.getText(i.key);if(a)try{n.push(JSON.parse(a))}catch{}}return n.sort((i,a)=>a.createdAt.localeCompare(i.createdAt))}async restore(e,t){let r=this.snapshotPrefix(e,t),s=await this.storage.getText(`${r}/snapshot.json`);if(!s)throw new Error(`Snapshot not found: ${t}`);let n=JSON.parse(s);if(n.projectId!==e)throw new Error("Snapshot project mismatch");let i=this.projectPrefix(e),a=[];for(let p of n.objects){let c=await this.storage.get(`${r}/${p}`);c&&(await this.storage.put(`${i}/${p}`,c,"application/json"),a.push(p))}return{restored:a}}async remove(e,t){let r=this.snapshotPrefix(e,t),s=await this.storage.list(r);for(let n of s)await this.storage.delete(n.key);return s.length}async prune(e,t=10){let s=(await this.list(e)).slice(t),n=0;for(let i of s)await this.remove(e,i.id),n++;return n}};function J(){let o=[],e=[];if((process.env.MEMORY_STORAGE_PROVIDER??"local")==="huggingface"){let s=["HF_NAMESPACE","HF_BUCKET","HF_S3_ACCESS_KEY_ID","HF_S3_SECRET_ACCESS_KEY"];for(let n of s)process.env[n]||o.push(`Missing ${n}`);process.env.HF_TOKEN||e.push("HF_TOKEN missing: semantic embedding will use fallback")}return process.env.HF_EMBEDDING_MODEL||e.push("HF_EMBEDDING_MODEL not set; default model will be used"),{ok:o.length===0,errors:o,warnings:e}}import{randomUUID as _e}from"node:crypto";var E=class{constructor(e,t){this.storage=e;this.embeddings=t}storage;embeddings;async run(){let e=`_health/production-${_e()}.txt`,t=`toolnet-memory:${Date.now()}`,r=!1;try{await this.storage.put(e,t,"text/plain"),r=await this.storage.getText(e)===t}finally{try{await this.storage.delete(e)}catch{}}let s=null;if(this.embeddings)try{let n=await this.embeddings.embed("ToolNet Memory production health check");s={ok:n.length>0,dimensions:n.length,mode:n.length===384?"huggingface":"fallback-or-custom"}}catch{s={ok:!1,dimensions:0,mode:"failed"}}return{ok:r&&(s===null||s.ok),storage:{ok:r,provider:this.storage.name},embedding:s}}};async function Ie(){let o=J();o.ok||(console.log({ok:!1,config:o}),process.exit(1));let e=O(),t=new h().detect(),r=B(L({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3}),s=H(),n=await new E(r,s).run(),i=await new v(r).load(t.id),a=await new j(r).load(t.id),p=await new w(r).load(t.id),c=await new S(r).load(t.id),m=await new b(r).load(t.id),A=await new k(r).list(t.id);console.log({ok:n.ok,project:t.name,storage:n.storage,embedding:n.embedding,memory:i.length,graphSymbols:a?.symbols.length??0,graphEdges:a?.edges.length??0,memoryVectors:p?.records.length??0,codeChunks:c?.chunks.length??0,codeVectors:m?.records.length??0,snapshots:A.length,warnings:o.warnings}),n.ok||process.exit(1)}Ie().catch(o=>{console.error(o instanceof Error?o.message:o),process.exit(1)});