toolnet-memory 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (329) hide show
  1. package/.env.example +28 -0
  2. package/README.md +147 -0
  3. package/bin/toolnet-memory +415 -0
  4. package/dist/packages/cli/commands.js +1 -0
  5. package/dist/packages/cli/index.js +1 -0
  6. package/dist/packages/sdk/client.js +78 -0
  7. package/dist/packages/sdk/index.js +1 -0
  8. package/dist/packages/sdk/types.js +1 -0
  9. package/dist/src/api/index.js +1 -0
  10. package/dist/src/api/routes/health.js +1 -0
  11. package/dist/src/api/routes/index.js +1 -0
  12. package/dist/src/api/routes/memory.js +1 -0
  13. package/dist/src/api/routes/projects.js +1 -0
  14. package/dist/src/api/routes/search.js +1 -0
  15. package/dist/src/api/server.js +1 -0
  16. package/dist/src/capture/activity-capture.js +21 -0
  17. package/dist/src/capture/command-capture.js +12 -0
  18. package/dist/src/capture/error-capture.js +14 -0
  19. package/dist/src/capture/event-deduplicator.js +28 -0
  20. package/dist/src/capture/event-queue.js +20 -0
  21. package/dist/src/capture/file-capture.js +23 -0
  22. package/dist/src/capture/index.js +8 -0
  23. package/dist/src/capture/session-capture.js +18 -0
  24. package/dist/src/capture/tool-capture.js +13 -0
  25. package/dist/src/code-intelligence/analysis/analysis-engine.js +26 -0
  26. package/dist/src/code-intelligence/analysis/dead-code-analyzer.js +127 -0
  27. package/dist/src/code-intelligence/analysis/dependency-analyzer.js +66 -0
  28. package/dist/src/code-intelligence/analysis/index.js +4 -0
  29. package/dist/src/code-intelligence/analysis/types.js +1 -0
  30. package/dist/src/code-intelligence/architecture/architecture-engine.js +48 -0
  31. package/dist/src/code-intelligence/architecture/clusters.js +322 -0
  32. package/dist/src/code-intelligence/architecture/entry-points.js +150 -0
  33. package/dist/src/code-intelligence/architecture/hotspots.js +136 -0
  34. package/dist/src/code-intelligence/architecture/index.js +6 -0
  35. package/dist/src/code-intelligence/architecture/layers.js +197 -0
  36. package/dist/src/code-intelligence/architecture/types.js +1 -0
  37. package/dist/src/code-intelligence/chunks/index.js +2 -0
  38. package/dist/src/code-intelligence/chunks/smart-chunker.js +125 -0
  39. package/dist/src/code-intelligence/chunks/types.js +1 -0
  40. package/dist/src/code-intelligence/git/git-diff.js +109 -0
  41. package/dist/src/code-intelligence/git/index.js +1 -0
  42. package/dist/src/code-intelligence/graph/architecture.js +26 -0
  43. package/dist/src/code-intelligence/graph/graph-builder.js +213 -0
  44. package/dist/src/code-intelligence/graph/graph-store.js +57 -0
  45. package/dist/src/code-intelligence/graph/index.js +1 -0
  46. package/dist/src/code-intelligence/graph/relationships.js +1 -0
  47. package/dist/src/code-intelligence/graph/trace.js +65 -0
  48. package/dist/src/code-intelligence/impact/blast-radius.js +160 -0
  49. package/dist/src/code-intelligence/impact/change-mapper.js +69 -0
  50. package/dist/src/code-intelligence/impact/edit-tool-detector.js +92 -0
  51. package/dist/src/code-intelligence/impact/impact-analyzer.js +60 -0
  52. package/dist/src/code-intelligence/impact/impact-guard.js +33 -0
  53. package/dist/src/code-intelligence/impact/index.js +5 -0
  54. package/dist/src/code-intelligence/incremental/file-hash.js +8 -0
  55. package/dist/src/code-intelligence/incremental/incremental-indexer.js +106 -0
  56. package/dist/src/code-intelligence/incremental/manifest-builder.js +19 -0
  57. package/dist/src/code-intelligence/incremental/manifest.js +31 -0
  58. package/dist/src/code-intelligence/index.js +23 -0
  59. package/dist/src/code-intelligence/indexer/file-watcher.js +1 -0
  60. package/dist/src/code-intelligence/indexer/incremental-indexer.js +1 -0
  61. package/dist/src/code-intelligence/indexer/index.js +1 -0
  62. package/dist/src/code-intelligence/indexer/repository-indexer.js +31 -0
  63. package/dist/src/code-intelligence/indexer/repository-scanner.js +50 -0
  64. package/dist/src/code-intelligence/parsers/index.js +1 -0
  65. package/dist/src/code-intelligence/parsers/tree-sitter/index.js +1 -0
  66. package/dist/src/code-intelligence/parsers/tree-sitter/languages.js +1 -0
  67. package/dist/src/code-intelligence/parsers/tree-sitter/parser.js +1 -0
  68. package/dist/src/code-intelligence/parsers/typescript-parser.js +190 -0
  69. package/dist/src/code-intelligence/query/graph-query-engine.js +275 -0
  70. package/dist/src/code-intelligence/query/index.js +2 -0
  71. package/dist/src/code-intelligence/query/types.js +1 -0
  72. package/dist/src/code-intelligence/resolution/index.js +2 -0
  73. package/dist/src/code-intelligence/resolution/types.js +1 -0
  74. package/dist/src/code-intelligence/resolution/typescript-resolver.js +316 -0
  75. package/dist/src/code-intelligence/rich/index.js +1 -0
  76. package/dist/src/code-intelligence/rich/rich-graph-enricher.js +463 -0
  77. package/dist/src/code-intelligence/semantic/index.js +2 -0
  78. package/dist/src/code-intelligence/semantic/semantic-code-engine.js +213 -0
  79. package/dist/src/code-intelligence/semantic/source-priority.js +22 -0
  80. package/dist/src/code-intelligence/symbols/index.js +1 -0
  81. package/dist/src/code-intelligence/symbols/reference-resolver.js +21 -0
  82. package/dist/src/code-intelligence/symbols/symbol-extractor.js +1 -0
  83. package/dist/src/code-intelligence/test-analysis.js +72 -0
  84. package/dist/src/code-intelligence/test-architecture.js +67 -0
  85. package/dist/src/code-intelligence/test-impact.js +47 -0
  86. package/dist/src/code-intelligence/test-incremental.js +24 -0
  87. package/dist/src/code-intelligence/test-index.js +39 -0
  88. package/dist/src/code-intelligence/test-resolution.js +54 -0
  89. package/dist/src/code-intelligence/test-rich-graph.js +48 -0
  90. package/dist/src/code-intelligence/test-semantic.js +57 -0
  91. package/dist/src/code-intelligence/test-visualization.js +36 -0
  92. package/dist/src/code-intelligence/types.js +1 -0
  93. package/dist/src/code-intelligence/visualization/index.js +2 -0
  94. package/dist/src/code-intelligence/visualization/types.js +1 -0
  95. package/dist/src/code-intelligence/visualization/visualization-builder.js +104 -0
  96. package/dist/src/core/config.js +66 -0
  97. package/dist/src/core/global-env.js +70 -0
  98. package/dist/src/core/importance.js +30 -0
  99. package/dist/src/core/index.js +5 -0
  100. package/dist/src/core/memory-engine.js +183 -0
  101. package/dist/src/core/project-manager.js +243 -0
  102. package/dist/src/core/types.js +1 -0
  103. package/dist/src/embeddings/batch-embedder.js +1 -0
  104. package/dist/src/embeddings/cache.js +1 -0
  105. package/dist/src/embeddings/embedder.js +51 -0
  106. package/dist/src/embeddings/index.js +4 -0
  107. package/dist/src/embeddings/local.js +37 -0
  108. package/dist/src/embeddings/provider.js +1 -0
  109. package/dist/src/embeddings/remote.js +76 -0
  110. package/dist/src/embeddings/test-connection.js +16 -0
  111. package/dist/src/hooks/after-edit.js +3 -0
  112. package/dist/src/hooks/after-tool.js +3 -0
  113. package/dist/src/hooks/auto-context.js +68 -0
  114. package/dist/src/hooks/auto-impact-guard.js +94 -0
  115. package/dist/src/hooks/auto-retrieval.js +27 -0
  116. package/dist/src/hooks/before-agent.js +18 -0
  117. package/dist/src/hooks/before-compact.js +3 -0
  118. package/dist/src/hooks/before-edit.js +20 -0
  119. package/dist/src/hooks/index.js +11 -0
  120. package/dist/src/hooks/runtime.js +110 -0
  121. package/dist/src/hooks/session-end.js +3 -0
  122. package/dist/src/hooks/session-start.js +3 -0
  123. package/dist/src/index.js +22 -0
  124. package/dist/src/mcp/bootstrap.js +68 -0
  125. package/dist/src/mcp/context.js +1 -0
  126. package/dist/src/mcp/index.js +3 -0
  127. package/dist/src/mcp/server.js +45 -0
  128. package/dist/src/mcp/tools/analyze-impact.js +41 -0
  129. package/dist/src/mcp/tools/dead-code.js +55 -0
  130. package/dist/src/mcp/tools/find-callers.js +24 -0
  131. package/dist/src/mcp/tools/find-dependencies.js +57 -0
  132. package/dist/src/mcp/tools/find-symbol.js +7 -0
  133. package/dist/src/mcp/tools/get-architecture.js +11 -0
  134. package/dist/src/mcp/tools/graph-dependents.js +24 -0
  135. package/dist/src/mcp/tools/graph-neighborhood.js +58 -0
  136. package/dist/src/mcp/tools/graph-path.js +43 -0
  137. package/dist/src/mcp/tools/graph-query-utils.js +32 -0
  138. package/dist/src/mcp/tools/impact-guard.js +34 -0
  139. package/dist/src/mcp/tools/index-repository.js +1 -0
  140. package/dist/src/mcp/tools/index.js +20 -0
  141. package/dist/src/mcp/tools/memory-decisions.js +1 -0
  142. package/dist/src/mcp/tools/memory-forget.js +14 -0
  143. package/dist/src/mcp/tools/memory-recent.js +1 -0
  144. package/dist/src/mcp/tools/memory-remember.js +33 -0
  145. package/dist/src/mcp/tools/memory-rules.js +1 -0
  146. package/dist/src/mcp/tools/memory-search.js +18 -0
  147. package/dist/src/mcp/tools/memory-todos.js +1 -0
  148. package/dist/src/mcp/tools/project-context.js +25 -0
  149. package/dist/src/mcp/tools/search-code.js +21 -0
  150. package/dist/src/mcp/tools/semantic-code-search.js +33 -0
  151. package/dist/src/mcp/tools/snapshot-create.js +13 -0
  152. package/dist/src/mcp/tools/snapshot-list.js +7 -0
  153. package/dist/src/mcp/tools/snapshot-restore.js +13 -0
  154. package/dist/src/mcp/tools/trace-calls.js +37 -0
  155. package/dist/src/memory/activity.js +5 -0
  156. package/dist/src/memory/conflict-detector.js +105 -0
  157. package/dist/src/memory/consolidator.js +104 -0
  158. package/dist/src/memory/decay.js +59 -0
  159. package/dist/src/memory/decisions.js +3 -0
  160. package/dist/src/memory/deduplicate.js +25 -0
  161. package/dist/src/memory/index.js +11 -0
  162. package/dist/src/memory/maintenance.js +16 -0
  163. package/dist/src/memory/remember.js +3 -0
  164. package/dist/src/memory/rules.js +3 -0
  165. package/dist/src/memory/search.js +3 -0
  166. package/dist/src/memory/summaries.js +1 -0
  167. package/dist/src/memory/todos.js +3 -0
  168. package/dist/src/processor/decision-extractor.js +13 -0
  169. package/dist/src/processor/importance-scorer.js +22 -0
  170. package/dist/src/processor/index.js +7 -0
  171. package/dist/src/processor/memory-extractor.js +59 -0
  172. package/dist/src/processor/memory-processor.js +105 -0
  173. package/dist/src/processor/rule-extractor.js +13 -0
  174. package/dist/src/processor/summarizer.js +71 -0
  175. package/dist/src/processor/todo-extractor.js +12 -0
  176. package/dist/src/production/config-check.js +34 -0
  177. package/dist/src/production/doctor.js +58 -0
  178. package/dist/src/production/full-index.js +114 -0
  179. package/dist/src/production/health.js +58 -0
  180. package/dist/src/production/index-pipeline.js +151 -0
  181. package/dist/src/production/index.js +4 -0
  182. package/dist/src/production/project-lock.js +95 -0
  183. package/dist/src/production/project-status.js +16 -0
  184. package/dist/src/production/recovery.js +15 -0
  185. package/dist/src/production/snapshot-cli.js +58 -0
  186. package/dist/src/project-manual/cli.js +77 -0
  187. package/dist/src/project-manual/index.js +2 -0
  188. package/dist/src/project-manual/manager.js +147 -0
  189. package/dist/src/project-manual/types.js +1 -0
  190. package/dist/src/retrieval/bm25/index.js +1 -0
  191. package/dist/src/retrieval/bm25/search.js +1 -0
  192. package/dist/src/retrieval/bm25.js +30 -0
  193. package/dist/src/retrieval/context-budget.js +1 -0
  194. package/dist/src/retrieval/context-builder.js +22 -0
  195. package/dist/src/retrieval/graph/index.js +1 -0
  196. package/dist/src/retrieval/graph/search.js +1 -0
  197. package/dist/src/retrieval/hybrid/hybrid-search.js +1 -0
  198. package/dist/src/retrieval/hybrid/index.js +1 -0
  199. package/dist/src/retrieval/hybrid-search.js +68 -0
  200. package/dist/src/retrieval/importance.js +16 -0
  201. package/dist/src/retrieval/index.js +12 -0
  202. package/dist/src/retrieval/query-analyzer.js +32 -0
  203. package/dist/src/retrieval/query-classifier.js +1 -0
  204. package/dist/src/retrieval/query-expansion.js +1 -0
  205. package/dist/src/retrieval/recency.js +12 -0
  206. package/dist/src/retrieval/reranker/index.js +1 -0
  207. package/dist/src/retrieval/reranker/reranker.js +1 -0
  208. package/dist/src/retrieval/retrieval-engine.js +17 -0
  209. package/dist/src/retrieval/tokenizer.js +9 -0
  210. package/dist/src/retrieval/type-priority.js +10 -0
  211. package/dist/src/retrieval/types.js +1 -0
  212. package/dist/src/retrieval/vector/index.js +4 -0
  213. package/dist/src/retrieval/vector/metadata-filter.js +1 -0
  214. package/dist/src/retrieval/vector/persistence.js +67 -0
  215. package/dist/src/retrieval/vector/search.js +12 -0
  216. package/dist/src/retrieval/vector/test-persistence.js +36 -0
  217. package/dist/src/retrieval/vector/upsert.js +40 -0
  218. package/dist/src/retrieval/vector/vector-store.js +89 -0
  219. package/dist/src/retrieval/vector-hybrid-engine.js +91 -0
  220. package/dist/src/runtime/bootstrap.js +28 -0
  221. package/dist/src/runtime/graceful.js +17 -0
  222. package/dist/src/runtime/index.js +3 -0
  223. package/dist/src/runtime/toolnet-memory-runtime.js +156 -0
  224. package/dist/src/security/encryption.js +1 -0
  225. package/dist/src/security/file-filter.js +30 -0
  226. package/dist/src/security/index.js +3 -0
  227. package/dist/src/security/sanitizer.js +49 -0
  228. package/dist/src/security/secret-scanner.js +56 -0
  229. package/dist/src/session/agy/adapter.js +159 -0
  230. package/dist/src/session/agy/cli.js +87 -0
  231. package/dist/src/session/agy/hook-installer.js +62 -0
  232. package/dist/src/session/agy/hook.js +167 -0
  233. package/dist/src/session/agy/index.js +5 -0
  234. package/dist/src/session/agy/project-resolver.js +27 -0
  235. package/dist/src/session/agy/recovery.js +112 -0
  236. package/dist/src/session/agy/transcript.js +191 -0
  237. package/dist/src/session/codex/adapter.js +138 -0
  238. package/dist/src/session/codex/cli.js +236 -0
  239. package/dist/src/session/codex/context-hook-installer.js +70 -0
  240. package/dist/src/session/codex/context-hook.js +69 -0
  241. package/dist/src/session/codex/discovery.js +138 -0
  242. package/dist/src/session/codex/index.js +6 -0
  243. package/dist/src/session/codex/notify-installer.js +135 -0
  244. package/dist/src/session/codex/project-resolver.js +25 -0
  245. package/dist/src/session/codex/recovery.js +27 -0
  246. package/dist/src/session/codex/rollout.js +186 -0
  247. package/dist/src/session/core.js +239 -0
  248. package/dist/src/session/identity.js +57 -0
  249. package/dist/src/session/index.js +9 -0
  250. package/dist/src/session/learner/cli.js +62 -0
  251. package/dist/src/session/learner/extractor.js +461 -0
  252. package/dist/src/session/learner/index.js +4 -0
  253. package/dist/src/session/learner/journal.js +159 -0
  254. package/dist/src/session/learner/learner.js +124 -0
  255. package/dist/src/session/learner/types.js +1 -0
  256. package/dist/src/session/opencode/adapter.js +553 -0
  257. package/dist/src/session/opencode/cli.js +121 -0
  258. package/dist/src/session/opencode/index.js +2 -0
  259. package/dist/src/session/opencode/plugin-installer.js +230 -0
  260. package/dist/src/session/store.js +242 -0
  261. package/dist/src/session/types.js +1 -0
  262. package/dist/src/session/utils.js +47 -0
  263. package/dist/src/session/wal.js +303 -0
  264. package/dist/src/snapshot/index.js +2 -0
  265. package/dist/src/snapshot/manager.js +130 -0
  266. package/dist/src/snapshot/test-snapshot.js +28 -0
  267. package/dist/src/snapshot/types.js +1 -0
  268. package/dist/src/storage/architecture-store.js +37 -0
  269. package/dist/src/storage/cleanup-health.js +20 -0
  270. package/dist/src/storage/code-analysis-store.js +35 -0
  271. package/dist/src/storage/code-chunk-store.js +25 -0
  272. package/dist/src/storage/code-graph-store.js +24 -0
  273. package/dist/src/storage/code-manifest-store.js +24 -0
  274. package/dist/src/storage/code-vector-store.js +25 -0
  275. package/dist/src/storage/github/client.js +1 -0
  276. package/dist/src/storage/github/index.js +1 -0
  277. package/dist/src/storage/google-drive/client.js +1 -0
  278. package/dist/src/storage/google-drive/index.js +1 -0
  279. package/dist/src/storage/huggingface/client.js +116 -0
  280. package/dist/src/storage/huggingface/index.js +1 -0
  281. package/dist/src/storage/index.js +16 -0
  282. package/dist/src/storage/list-bucket-raw.js +14 -0
  283. package/dist/src/storage/list-bucket-tree.js +38 -0
  284. package/dist/src/storage/local/client.js +99 -0
  285. package/dist/src/storage/local/index.js +1 -0
  286. package/dist/src/storage/memory-store.js +30 -0
  287. package/dist/src/storage/project/cleanup-layout-v1.js +72 -0
  288. package/dist/src/storage/project/folder.js +15 -0
  289. package/dist/src/storage/project/index.js +3 -0
  290. package/dist/src/storage/project/layout.js +74 -0
  291. package/dist/src/storage/project/migrate-layout-v2.js +101 -0
  292. package/dist/src/storage/project/migrate.js +73 -0
  293. package/dist/src/storage/project/scoped-provider.js +165 -0
  294. package/dist/src/storage/provider.js +26 -0
  295. package/dist/src/storage/retrying-provider.js +23 -0
  296. package/dist/src/storage/test-connection.js +32 -0
  297. package/dist/src/storage/type-resolution-store.js +26 -0
  298. package/dist/src/storage/types.js +1 -0
  299. package/dist/src/storage/vector-store.js +30 -0
  300. package/dist/src/storage/visualization-store.js +25 -0
  301. package/dist/src/sync/compressor.js +1 -0
  302. package/dist/src/sync/conflict-resolver.js +1 -0
  303. package/dist/src/sync/downloader.js +1 -0
  304. package/dist/src/sync/index.js +1 -0
  305. package/dist/src/sync/sync-engine.js +1 -0
  306. package/dist/src/sync/upload-queue.js +1 -0
  307. package/dist/src/utils/retry.js +29 -0
  308. package/dist/src/visualization/server.js +270 -0
  309. package/dist/src/work-continuity/brief-cache.js +107 -0
  310. package/dist/src/work-continuity/brief.js +349 -0
  311. package/dist/src/work-continuity/cli.js +96 -0
  312. package/dist/src/work-continuity/context-cli.js +106 -0
  313. package/dist/src/work-continuity/context-runtime-cli.js +88 -0
  314. package/dist/src/work-continuity/extractor.js +339 -0
  315. package/dist/src/work-continuity/handoff.js +185 -0
  316. package/dist/src/work-continuity/index.js +14 -0
  317. package/dist/src/work-continuity/injection.js +84 -0
  318. package/dist/src/work-continuity/journal.js +49 -0
  319. package/dist/src/work-continuity/learner.js +127 -0
  320. package/dist/src/work-continuity/reducer.js +316 -0
  321. package/dist/src/work-continuity/semantic-extractor.js +360 -0
  322. package/dist/src/work-continuity/semantic-journal.js +55 -0
  323. package/dist/src/work-continuity/semantic-learner.js +125 -0
  324. package/dist/src/work-continuity/semantic-reducer.js +268 -0
  325. package/dist/src/work-continuity/semantic-types.js +1 -0
  326. package/dist/src/work-continuity/types.js +1 -0
  327. package/dist/visualization/public/index.html +2896 -0
  328. package/dist/visualization/public/vendor/3d-force-graph.min.js +5 -0
  329. package/package.json +69 -0
@@ -0,0 +1,87 @@
1
+ import { loadConfig, ProjectManager, } from "../../core/index.js";
2
+ import { createStorageProvider, ProjectScopedStorageProvider, withStorageRetry, } from "../../storage/index.js";
3
+ import { syncAgySession, } from "./adapter.js";
4
+ import { installAgyHooks, } from "./hook-installer.js";
5
+ import { recoverAgyProject, } from "./recovery.js";
6
+ function after(args, flag) {
7
+ const index = args.indexOf(flag);
8
+ return index >= 0
9
+ ? args[index + 1]
10
+ : undefined;
11
+ }
12
+ function storageFor(project) {
13
+ const config = loadConfig();
14
+ const raw = withStorageRetry(createStorageProvider({
15
+ provider: config.storage.provider,
16
+ huggingface: config.storage
17
+ .huggingface,
18
+ localRoot: config.storage
19
+ .localRoot,
20
+ }), {
21
+ attempts: 3,
22
+ });
23
+ return new ProjectScopedStorageProvider(raw, project.id, project.name, project.remote ??
24
+ project.name);
25
+ }
26
+ async function main() {
27
+ const [command = "help", ...args] = process.argv.slice(2);
28
+ if (command ===
29
+ "install-hooks") {
30
+ const file = installAgyHooks({
31
+ binary: after(args, "--bin"),
32
+ });
33
+ console.log(`✅ Agy hooks installed: ${file}`);
34
+ return;
35
+ }
36
+ const projectPath = after(args, "--project") ??
37
+ process.cwd();
38
+ const project = new ProjectManager()
39
+ .detect(projectPath);
40
+ const storage = storageFor(project);
41
+ if (command ===
42
+ "sync") {
43
+ const conversationId = args[0];
44
+ const transcriptPath = after(args, "--transcript");
45
+ if (!conversationId ||
46
+ !transcriptPath) {
47
+ throw new Error("Usage: sync <conversation-id> --transcript <path>");
48
+ }
49
+ const result = await syncAgySession({
50
+ project,
51
+ storage,
52
+ conversationId,
53
+ transcriptPath,
54
+ phase: "recover",
55
+ });
56
+ console.log(JSON.stringify(result, null, 2));
57
+ return;
58
+ }
59
+ if (command ===
60
+ "recover") {
61
+ const limit = Number(after(args, "--limit") ??
62
+ 100);
63
+ const results = await recoverAgyProject(project, storage, Number.isFinite(limit)
64
+ ? limit
65
+ : 100);
66
+ console.log(JSON.stringify({
67
+ project: project.name,
68
+ sessions: results.length,
69
+ imported: results.reduce((total, item) => total +
70
+ item.imported, 0),
71
+ }, null, 2));
72
+ return;
73
+ }
74
+ console.log(`Agy Session Adapter
75
+
76
+ Commands:
77
+ install-hooks
78
+ sync <conversation-id> --transcript <path>
79
+ recover [--project PATH] [--limit N]
80
+ `);
81
+ }
82
+ main().catch(error => {
83
+ console.error(error instanceof Error
84
+ ? error.message
85
+ : error);
86
+ process.exit(1);
87
+ });
@@ -0,0 +1,62 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, } from "node:fs";
2
+ import { homedir, } from "node:os";
3
+ import { dirname, join, } from "node:path";
4
+ function quote(value) {
5
+ return `'${value.replace(/'/g, `'\\''`)}'`;
6
+ }
7
+ export function installAgyHooks(options = {}) {
8
+ const hooksFile = options.hooksFile ??
9
+ join(homedir(), ".gemini", "config", "hooks.json");
10
+ mkdirSync(dirname(hooksFile), {
11
+ recursive: true,
12
+ });
13
+ let root = {};
14
+ if (existsSync(hooksFile)) {
15
+ try {
16
+ root =
17
+ JSON.parse(readFileSync(hooksFile, "utf8"));
18
+ }
19
+ catch (error) {
20
+ throw new Error(`Invalid existing Agy hooks.json: ${error instanceof Error
21
+ ? error.message
22
+ : String(error)}`);
23
+ }
24
+ }
25
+ const binary = options.binary ??
26
+ "toolnet-memory";
27
+ const command = `${quote(binary)} session:agy-hook`;
28
+ /*
29
+ * Official Antigravity hook schema.
30
+ * Stop = sync when one execution becomes idle.
31
+ * It is intentionally NOT treated as permanent SessionEnd.
32
+ */
33
+ root["toolnet-memory"] = {
34
+ enabled: true,
35
+ PreInvocation: [
36
+ {
37
+ type: "command",
38
+ command: `${command} pre`,
39
+ timeout: 15,
40
+ },
41
+ ],
42
+ PostInvocation: [
43
+ {
44
+ type: "command",
45
+ command: `${command} post`,
46
+ timeout: 15,
47
+ },
48
+ ],
49
+ Stop: [
50
+ {
51
+ type: "command",
52
+ command: `${command} stop`,
53
+ timeout: 30,
54
+ },
55
+ ],
56
+ };
57
+ writeFileSync(hooksFile, JSON.stringify(root, null, 2) + "\n", {
58
+ encoding: "utf8",
59
+ mode: 0o600,
60
+ });
61
+ return hooksFile;
62
+ }
@@ -0,0 +1,167 @@
1
+ import { loadConfig, } from "../../core/index.js";
2
+ import { createStorageProvider, ProjectScopedStorageProvider, withStorageRetry, } from "../../storage/index.js";
3
+ import { buildAgyPreInvocationOutput, refreshStartupBriefCache, } from "../../work-continuity/index.js";
4
+ import { findToolNetProject, } from "./project-resolver.js";
5
+ import { syncAgySession, } from "./adapter.js";
6
+ async function readStdin() {
7
+ let content = "";
8
+ for await (const chunk of process.stdin) {
9
+ content +=
10
+ chunk.toString();
11
+ }
12
+ if (!content.trim()) {
13
+ return {};
14
+ }
15
+ try {
16
+ return JSON.parse(content);
17
+ }
18
+ catch {
19
+ return {};
20
+ }
21
+ }
22
+ function strings(value) {
23
+ if (!Array.isArray(value)) {
24
+ return [];
25
+ }
26
+ return value.filter(item => typeof item ===
27
+ "string");
28
+ }
29
+ async function main() {
30
+ const phase = (process.argv[2] ??
31
+ "post");
32
+ const input = await readStdin();
33
+ const conversationId = typeof input
34
+ .conversationId ===
35
+ "string"
36
+ ? input
37
+ .conversationId
38
+ : "";
39
+ const transcriptPath = typeof input
40
+ .transcriptPath ===
41
+ "string"
42
+ ? input
43
+ .transcriptPath
44
+ : "";
45
+ const workspacePaths = strings(input.workspacePaths);
46
+ const project = findToolNetProject(workspacePaths);
47
+ let hookOutput = {};
48
+ if (project &&
49
+ conversationId) {
50
+ try {
51
+ const config = loadConfig();
52
+ const raw = withStorageRetry(createStorageProvider({
53
+ provider: config.storage
54
+ .provider,
55
+ huggingface: config.storage
56
+ .huggingface,
57
+ localRoot: config.storage
58
+ .localRoot,
59
+ }), {
60
+ attempts: 2,
61
+ });
62
+ const storage = new ProjectScopedStorageProvider(raw, project.id, project.name, project.remote ??
63
+ project.name);
64
+ /*
65
+ * Session capture remains independent from context
66
+ * injection. One failure cannot break the other.
67
+ */
68
+ if (transcriptPath) {
69
+ try {
70
+ await syncAgySession({
71
+ project,
72
+ storage,
73
+ conversationId,
74
+ transcriptPath,
75
+ workspacePaths,
76
+ artifactDirectoryPath: typeof input
77
+ .artifactDirectoryPath ===
78
+ "string"
79
+ ? input
80
+ .artifactDirectoryPath
81
+ : undefined,
82
+ modelName: typeof input
83
+ .modelName ===
84
+ "string"
85
+ ? input
86
+ .modelName
87
+ : undefined,
88
+ phase,
89
+ fullyIdle: input.fullyIdle ===
90
+ true,
91
+ terminationReason: typeof input
92
+ .terminationReason ===
93
+ "string"
94
+ ? input
95
+ .terminationReason
96
+ : undefined,
97
+ error: typeof input.error ===
98
+ "string" &&
99
+ input.error
100
+ ? input.error
101
+ : undefined,
102
+ });
103
+ }
104
+ catch {
105
+ // Capture failure must not block Agy.
106
+ }
107
+ }
108
+ if (phase ===
109
+ "pre") {
110
+ try {
111
+ hookOutput =
112
+ await buildAgyPreInvocationOutput({
113
+ project,
114
+ storage,
115
+ conversationId,
116
+ invocationNum: typeof input
117
+ .invocationNum ===
118
+ "number"
119
+ ? input
120
+ .invocationNum
121
+ : undefined,
122
+ });
123
+ }
124
+ catch {
125
+ hookOutput =
126
+ {};
127
+ }
128
+ }
129
+ /*
130
+ * End of one Agy execution:
131
+ * publish the newest compact Startup Brief so another
132
+ * agent/VPS can resume immediately.
133
+ */
134
+ if (phase ===
135
+ "stop") {
136
+ try {
137
+ await refreshStartupBriefCache(project, storage, 900);
138
+ }
139
+ catch {
140
+ // Optional derived cache.
141
+ }
142
+ }
143
+ }
144
+ catch {
145
+ // ToolNet must never break Agy.
146
+ }
147
+ }
148
+ if (phase ===
149
+ "stop") {
150
+ process.stdout.write(JSON.stringify({
151
+ decision: "stop",
152
+ }));
153
+ return;
154
+ }
155
+ process.stdout.write(JSON.stringify(hookOutput));
156
+ }
157
+ main().catch(() => {
158
+ if (process.argv[2] ===
159
+ "stop") {
160
+ process.stdout.write('{"decision":"stop"}');
161
+ }
162
+ else {
163
+ process.stdout.write("{}");
164
+ }
165
+ process.exitCode =
166
+ 0;
167
+ });
@@ -0,0 +1,5 @@
1
+ export * from "./transcript.js";
2
+ export * from "./adapter.js";
3
+ export * from "./project-resolver.js";
4
+ export * from "./hook-installer.js";
5
+ export * from "./recovery.js";
@@ -0,0 +1,27 @@
1
+ import { existsSync, } from "node:fs";
2
+ import { dirname, join, parse, resolve, } from "node:path";
3
+ import { ProjectManager, } from "../../core/index.js";
4
+ export function findToolNetProject(workspacePaths) {
5
+ for (const workspace of workspacePaths) {
6
+ let current = resolve(workspace);
7
+ const root = parse(current).root;
8
+ while (true) {
9
+ if (existsSync(join(current, ".toolnet", "project.json"))) {
10
+ return new ProjectManager()
11
+ .detect(current);
12
+ }
13
+ if (current ===
14
+ root) {
15
+ break;
16
+ }
17
+ const parent = dirname(current);
18
+ if (parent ===
19
+ current) {
20
+ break;
21
+ }
22
+ current =
23
+ parent;
24
+ }
25
+ }
26
+ return null;
27
+ }
@@ -0,0 +1,112 @@
1
+ import { existsSync, } from "node:fs";
2
+ import { homedir, } from "node:os";
3
+ import { join, resolve, } from "node:path";
4
+ import { DatabaseSync, } from "node:sqlite";
5
+ import { defaultAgyTranscript, syncAgySession, } from "./adapter.js";
6
+ function uriToPath(value) {
7
+ if (value.startsWith("file://")) {
8
+ try {
9
+ return decodeURIComponent(new URL(value).pathname);
10
+ }
11
+ catch {
12
+ return value;
13
+ }
14
+ }
15
+ return value;
16
+ }
17
+ function workspaceList(value) {
18
+ if (typeof value !==
19
+ "string" ||
20
+ !value) {
21
+ return [];
22
+ }
23
+ try {
24
+ const parsed = JSON.parse(value);
25
+ if (Array.isArray(parsed)) {
26
+ return parsed
27
+ .filter(item => typeof item ===
28
+ "string")
29
+ .map(uriToPath);
30
+ }
31
+ }
32
+ catch {
33
+ // continue
34
+ }
35
+ return [
36
+ uriToPath(value),
37
+ ];
38
+ }
39
+ function belongs(project, workspaces) {
40
+ const root = resolve(project.rootPath);
41
+ return workspaces.some(workspace => {
42
+ const path = resolve(workspace);
43
+ return (path === root ||
44
+ path.startsWith(root +
45
+ "/") ||
46
+ root.startsWith(path +
47
+ "/"));
48
+ });
49
+ }
50
+ export async function recoverAgyProject(project, storage, limit = 100) {
51
+ const summaryDb = process.env
52
+ .AGY_SUMMARY_DB ??
53
+ join(homedir(), ".gemini", "antigravity-cli", "conversation_summaries.db");
54
+ if (!existsSync(summaryDb)) {
55
+ throw new Error(`Agy summary database not found: ${summaryDb}`);
56
+ }
57
+ const db = new DatabaseSync(summaryDb, {
58
+ readOnly: true,
59
+ });
60
+ db.exec("PRAGMA query_only = ON");
61
+ const rows = db.prepare(`
62
+ SELECT
63
+ conversation_id,
64
+ title,
65
+ workspace_uris,
66
+ agent_name,
67
+ last_user_input_time
68
+ FROM conversation_summaries
69
+ ORDER BY
70
+ last_user_input_time DESC
71
+ `).all();
72
+ db.close();
73
+ const results = [];
74
+ for (const row of rows) {
75
+ const id = typeof row
76
+ .conversation_id ===
77
+ "string"
78
+ ? row
79
+ .conversation_id
80
+ : "";
81
+ if (!id) {
82
+ continue;
83
+ }
84
+ const workspaces = workspaceList(row.workspace_uris);
85
+ if (!belongs(project, workspaces)) {
86
+ continue;
87
+ }
88
+ const transcriptPath = defaultAgyTranscript(id);
89
+ if (!existsSync(transcriptPath)) {
90
+ continue;
91
+ }
92
+ results.push(await syncAgySession({
93
+ project,
94
+ storage,
95
+ conversationId: id,
96
+ transcriptPath,
97
+ workspacePaths: workspaces,
98
+ modelName: typeof row
99
+ .agent_name ===
100
+ "string"
101
+ ? row
102
+ .agent_name
103
+ : undefined,
104
+ phase: "recover",
105
+ }));
106
+ if (results.length >=
107
+ limit) {
108
+ break;
109
+ }
110
+ }
111
+ return results;
112
+ }
@@ -0,0 +1,191 @@
1
+ import { existsSync, openSync, closeSync, readSync, statSync, } from "node:fs";
2
+ function classify(value) {
3
+ const role = typeof value.role ===
4
+ "string"
5
+ ? value.role
6
+ : "";
7
+ const type = typeof value.type ===
8
+ "string"
9
+ ? value.type
10
+ .toLowerCase()
11
+ : "";
12
+ if (role === "user" ||
13
+ type.includes("user")) {
14
+ return "user_prompt";
15
+ }
16
+ if (role ===
17
+ "assistant" ||
18
+ type.includes("assistant") ||
19
+ type.includes("model")) {
20
+ return "assistant_message";
21
+ }
22
+ if (type.includes("tool") ||
23
+ "toolCall" in
24
+ value ||
25
+ "tool_call" in
26
+ value) {
27
+ return "tool_call";
28
+ }
29
+ if (type.includes("error")) {
30
+ return "error";
31
+ }
32
+ return "message";
33
+ }
34
+ function timestampOf(value) {
35
+ const candidates = [
36
+ value.timestamp,
37
+ value.createdAt,
38
+ value.time,
39
+ value.created_at,
40
+ ];
41
+ for (const candidate of candidates) {
42
+ if (typeof candidate ===
43
+ "string") {
44
+ const date = new Date(candidate);
45
+ if (!Number.isNaN(date.getTime())) {
46
+ return date.toISOString();
47
+ }
48
+ }
49
+ if (typeof candidate ===
50
+ "number") {
51
+ let time = candidate;
52
+ if (time <
53
+ 100_000_000_000) {
54
+ time *= 1000;
55
+ }
56
+ const date = new Date(time);
57
+ if (!Number.isNaN(date.getTime())) {
58
+ return date.toISOString();
59
+ }
60
+ }
61
+ }
62
+ return new Date()
63
+ .toISOString();
64
+ }
65
+ export function readAgyTranscript(transcriptPath, cursor = {
66
+ offset: 0,
67
+ }) {
68
+ if (!existsSync(transcriptPath)) {
69
+ return {
70
+ events: [],
71
+ nextOffset: cursor.offset,
72
+ reset: false,
73
+ };
74
+ }
75
+ const size = statSync(transcriptPath).size;
76
+ /*
77
+ * Transcript was truncated/rewritten.
78
+ * Start a new source epoch.
79
+ */
80
+ const reset = cursor.offset >
81
+ size;
82
+ const start = reset
83
+ ? 0
84
+ : cursor.offset;
85
+ if (start === size) {
86
+ return {
87
+ events: [],
88
+ nextOffset: size,
89
+ reset,
90
+ };
91
+ }
92
+ const length = size -
93
+ start;
94
+ const buffer = Buffer.alloc(length);
95
+ const fd = openSync(transcriptPath, "r");
96
+ try {
97
+ readSync(fd, buffer, 0, length, start);
98
+ }
99
+ finally {
100
+ closeSync(fd);
101
+ }
102
+ const text = buffer.toString("utf8");
103
+ /*
104
+ * Do not consume an incomplete final line while Agy
105
+ * is still appending to transcript.jsonl.
106
+ */
107
+ const lastNewline = text.lastIndexOf("\n");
108
+ if (lastNewline <
109
+ 0) {
110
+ return {
111
+ events: [],
112
+ nextOffset: start,
113
+ reset,
114
+ };
115
+ }
116
+ const complete = text.slice(0, lastNewline +
117
+ 1);
118
+ const consumedBytes = Buffer.byteLength(complete, "utf8");
119
+ const events = [];
120
+ let relativeOffset = 0;
121
+ for (const rawLine of complete
122
+ .split("\n")) {
123
+ if (!rawLine) {
124
+ continue;
125
+ }
126
+ const lineBytes = Buffer.byteLength(rawLine +
127
+ "\n", "utf8");
128
+ const absoluteOffset = start +
129
+ relativeOffset;
130
+ relativeOffset +=
131
+ lineBytes;
132
+ let parsed;
133
+ try {
134
+ parsed =
135
+ JSON.parse(rawLine);
136
+ }
137
+ catch {
138
+ /*
139
+ * Preserve malformed but readable trajectory lines.
140
+ */
141
+ events.push({
142
+ type: "custom",
143
+ sourceEventId: `transcript:${absoluteOffset}`,
144
+ sourceSequence: absoluteOffset,
145
+ data: {
146
+ format: "raw-line",
147
+ content: rawLine,
148
+ },
149
+ provenance: {
150
+ source: "agy-transcript",
151
+ sourcePath: transcriptPath,
152
+ sourceOffset: absoluteOffset,
153
+ },
154
+ });
155
+ continue;
156
+ }
157
+ const data = parsed &&
158
+ typeof parsed ===
159
+ "object" &&
160
+ !Array.isArray(parsed)
161
+ ? parsed
162
+ : {
163
+ value: parsed,
164
+ };
165
+ events.push({
166
+ type: classify(data),
167
+ timestamp: timestampOf(data),
168
+ role: typeof data.role ===
169
+ "string"
170
+ ? data.role
171
+ : undefined,
172
+ /*
173
+ * Offset + original payload gives stable provenance.
174
+ */
175
+ sourceEventId: `transcript:${absoluteOffset}`,
176
+ sourceSequence: absoluteOffset,
177
+ data,
178
+ provenance: {
179
+ source: "agy-transcript",
180
+ sourcePath: transcriptPath,
181
+ sourceOffset: absoluteOffset,
182
+ },
183
+ });
184
+ }
185
+ return {
186
+ events,
187
+ nextOffset: start +
188
+ consumedBytes,
189
+ reset,
190
+ };
191
+ }