atoo-studio 0.0.1 → 0.0.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 (408) hide show
  1. package/LICENSE +21 -0
  2. package/README.github.md +322 -0
  3. package/README.md +112 -0
  4. package/README.npm.md +112 -0
  5. package/bin/atoo-studio.js +90 -0
  6. package/dist/src/agents/claude-code-terminal/adapter.d.ts +42 -0
  7. package/dist/src/agents/claude-code-terminal/adapter.js +166 -0
  8. package/dist/src/agents/claude-code-terminal/index.d.ts +13 -0
  9. package/dist/src/agents/claude-code-terminal/index.js +45 -0
  10. package/dist/src/agents/claude-code-terminal/spawner.d.ts +9 -0
  11. package/dist/src/agents/claude-code-terminal/spawner.js +37 -0
  12. package/dist/src/agents/claude-code-terminal-chatro/adapter.d.ts +51 -0
  13. package/dist/src/agents/claude-code-terminal-chatro/adapter.js +301 -0
  14. package/dist/src/agents/claude-code-terminal-chatro/index.d.ts +13 -0
  15. package/dist/src/agents/claude-code-terminal-chatro/index.js +45 -0
  16. package/dist/src/agents/claude-code-terminal-chatro/jsonl-watcher.d.ts +67 -0
  17. package/dist/src/agents/claude-code-terminal-chatro/jsonl-watcher.js +431 -0
  18. package/dist/src/agents/claude-code-terminal-chatro/spawner.d.ts +9 -0
  19. package/dist/src/agents/claude-code-terminal-chatro/spawner.js +37 -0
  20. package/dist/src/agents/codex-terminal/adapter.d.ts +40 -0
  21. package/dist/src/agents/codex-terminal/adapter.js +160 -0
  22. package/dist/src/agents/codex-terminal/index.d.ts +13 -0
  23. package/dist/src/agents/codex-terminal/index.js +47 -0
  24. package/dist/src/agents/codex-terminal/spawner.d.ts +9 -0
  25. package/dist/src/agents/codex-terminal/spawner.js +56 -0
  26. package/dist/src/agents/codex-terminal-chatro/adapter.d.ts +58 -0
  27. package/dist/src/agents/codex-terminal-chatro/adapter.js +266 -0
  28. package/dist/src/agents/codex-terminal-chatro/index.d.ts +13 -0
  29. package/dist/src/agents/codex-terminal-chatro/index.js +50 -0
  30. package/dist/src/agents/codex-terminal-chatro/jsonl-watcher.d.ts +36 -0
  31. package/dist/src/agents/codex-terminal-chatro/jsonl-watcher.js +205 -0
  32. package/dist/src/agents/codex-terminal-chatro/spawner.d.ts +9 -0
  33. package/dist/src/agents/codex-terminal-chatro/spawner.js +57 -0
  34. package/dist/src/agents/lib/chain-builder.d.ts +21 -0
  35. package/dist/src/agents/lib/chain-builder.js +139 -0
  36. package/dist/src/agents/lib/claude/fs-sessions.d.ts +31 -0
  37. package/dist/src/agents/lib/claude/fs-sessions.js +329 -0
  38. package/dist/src/agents/lib/claude/jsonl-writer.d.ts +32 -0
  39. package/dist/src/agents/lib/claude/jsonl-writer.js +342 -0
  40. package/dist/src/agents/lib/claude/workspace-trust.d.ts +1 -0
  41. package/dist/src/agents/lib/claude/workspace-trust.js +29 -0
  42. package/dist/src/agents/lib/codex/fs-sessions.d.ts +34 -0
  43. package/dist/src/agents/lib/codex/fs-sessions.js +255 -0
  44. package/dist/src/agents/lib/codex/jsonl-mapper.d.ts +11 -0
  45. package/dist/src/agents/lib/codex/jsonl-mapper.js +154 -0
  46. package/dist/src/agents/lib/codex/jsonl-writer.d.ts +8 -0
  47. package/dist/src/agents/lib/codex/jsonl-writer.js +440 -0
  48. package/dist/src/agents/lib/fs-tracking.d.ts +36 -0
  49. package/dist/src/agents/lib/fs-tracking.js +109 -0
  50. package/dist/src/agents/lib/pty-activity-tracker.d.ts +37 -0
  51. package/dist/src/agents/lib/pty-activity-tracker.js +105 -0
  52. package/dist/src/agents/lib/session-id-utils.d.ts +46 -0
  53. package/dist/src/agents/lib/session-id-utils.js +147 -0
  54. package/dist/src/agents/lib/session-precreate.d.ts +17 -0
  55. package/dist/src/agents/lib/session-precreate.js +177 -0
  56. package/dist/src/agents/registry.d.ts +72 -0
  57. package/dist/src/agents/registry.js +337 -0
  58. package/dist/src/agents/types.d.ts +135 -0
  59. package/dist/src/agents/types.js +1 -0
  60. package/dist/src/auth/crypto-key.d.ts +6 -0
  61. package/dist/src/auth/crypto-key.js +45 -0
  62. package/dist/src/auth/middleware.d.ts +18 -0
  63. package/dist/src/auth/middleware.js +54 -0
  64. package/dist/src/auth/password.d.ts +2 -0
  65. package/dist/src/auth/password.js +12 -0
  66. package/dist/src/auth/session.d.ts +10 -0
  67. package/dist/src/auth/session.js +33 -0
  68. package/dist/src/auth/totp.d.ts +12 -0
  69. package/dist/src/auth/totp.js +61 -0
  70. package/dist/src/auth/webauthn.d.ts +6 -0
  71. package/dist/src/auth/webauthn.js +117 -0
  72. package/dist/src/config.d.ts +10 -0
  73. package/dist/src/config.js +16 -0
  74. package/dist/src/database/connection-manager.d.ts +25 -0
  75. package/dist/src/database/connection-manager.js +211 -0
  76. package/dist/src/database/discovery/container.d.ts +6 -0
  77. package/dist/src/database/discovery/container.js +226 -0
  78. package/dist/src/database/discovery/env-parser.d.ts +9 -0
  79. package/dist/src/database/discovery/env-parser.js +525 -0
  80. package/dist/src/database/discovery/local-files.d.ts +6 -0
  81. package/dist/src/database/discovery/local-files.js +58 -0
  82. package/dist/src/database/discovery/port-scan.d.ts +7 -0
  83. package/dist/src/database/discovery/port-scan.js +61 -0
  84. package/dist/src/database/drivers/cassandra.d.ts +12 -0
  85. package/dist/src/database/drivers/cassandra.js +91 -0
  86. package/dist/src/database/drivers/clickhouse.d.ts +11 -0
  87. package/dist/src/database/drivers/clickhouse.js +127 -0
  88. package/dist/src/database/drivers/elasticsearch.d.ts +12 -0
  89. package/dist/src/database/drivers/elasticsearch.js +169 -0
  90. package/dist/src/database/drivers/influxdb.d.ts +14 -0
  91. package/dist/src/database/drivers/influxdb.js +194 -0
  92. package/dist/src/database/drivers/memcached.d.ts +11 -0
  93. package/dist/src/database/drivers/memcached.js +117 -0
  94. package/dist/src/database/drivers/mongodb.d.ts +12 -0
  95. package/dist/src/database/drivers/mongodb.js +128 -0
  96. package/dist/src/database/drivers/mysql.d.ts +11 -0
  97. package/dist/src/database/drivers/mysql.js +112 -0
  98. package/dist/src/database/drivers/neo4j.d.ts +11 -0
  99. package/dist/src/database/drivers/neo4j.js +158 -0
  100. package/dist/src/database/drivers/postgresql.d.ts +11 -0
  101. package/dist/src/database/drivers/postgresql.js +133 -0
  102. package/dist/src/database/drivers/redis.d.ts +11 -0
  103. package/dist/src/database/drivers/redis.js +91 -0
  104. package/dist/src/database/drivers/sqlite.d.ts +10 -0
  105. package/dist/src/database/drivers/sqlite.js +100 -0
  106. package/dist/src/database/query-stream.d.ts +5 -0
  107. package/dist/src/database/query-stream.js +75 -0
  108. package/dist/src/database/types.d.ts +71 -0
  109. package/dist/src/database/types.js +1 -0
  110. package/dist/src/events/index.d.ts +3 -0
  111. package/dist/src/events/index.js +3 -0
  112. package/dist/src/events/types.d.ts +214 -0
  113. package/dist/src/events/types.js +22 -0
  114. package/dist/src/events/wire.d.ts +114 -0
  115. package/dist/src/events/wire.js +296 -0
  116. package/dist/src/fs-monitor-types.d.ts +24 -0
  117. package/dist/src/fs-monitor-types.js +1 -0
  118. package/dist/src/fs-monitor.d.ts +80 -0
  119. package/dist/src/fs-monitor.js +637 -0
  120. package/dist/src/handlers/auth.d.ts +1 -0
  121. package/dist/src/handlers/auth.js +170 -0
  122. package/dist/src/handlers/changes.d.ts +1 -0
  123. package/dist/src/handlers/changes.js +203 -0
  124. package/dist/src/handlers/containers.d.ts +12 -0
  125. package/dist/src/handlers/containers.js +379 -0
  126. package/dist/src/handlers/databases.d.ts +3 -0
  127. package/dist/src/handlers/databases.js +327 -0
  128. package/dist/src/handlers/environments.d.ts +3 -0
  129. package/dist/src/handlers/environments.js +286 -0
  130. package/dist/src/handlers/github.d.ts +1 -0
  131. package/dist/src/handlers/github.js +153 -0
  132. package/dist/src/handlers/projects.d.ts +1 -0
  133. package/dist/src/handlers/projects.js +895 -0
  134. package/dist/src/handlers/ssh.d.ts +1 -0
  135. package/dist/src/handlers/ssh.js +162 -0
  136. package/dist/src/handlers/users.d.ts +1 -0
  137. package/dist/src/handlers/users.js +195 -0
  138. package/dist/src/index.d.ts +1 -0
  139. package/dist/src/index.js +228 -0
  140. package/dist/src/mcp/config.d.ts +32 -0
  141. package/dist/src/mcp/config.js +227 -0
  142. package/dist/src/mcp/server.d.ts +1 -0
  143. package/dist/src/mcp/server.js +574 -0
  144. package/dist/src/serial/cuse-device.d.ts +19 -0
  145. package/dist/src/serial/cuse-device.js +260 -0
  146. package/dist/src/serial/manager.d.ts +63 -0
  147. package/dist/src/serial/manager.js +206 -0
  148. package/dist/src/serial/pty-pair.d.ts +16 -0
  149. package/dist/src/serial/pty-pair.js +68 -0
  150. package/dist/src/services/fs-browser.d.ts +14 -0
  151. package/dist/src/services/fs-browser.js +98 -0
  152. package/dist/src/services/git-ops.d.ts +78 -0
  153. package/dist/src/services/git-ops.js +288 -0
  154. package/dist/src/services/github-ops.d.ts +104 -0
  155. package/dist/src/services/github-ops.js +192 -0
  156. package/dist/src/services/obfuscation.d.ts +2 -0
  157. package/dist/src/services/obfuscation.js +16 -0
  158. package/dist/src/services/preview/headless-backend.d.ts +62 -0
  159. package/dist/src/services/preview/headless-backend.js +698 -0
  160. package/dist/src/services/preview/injected-scripts.d.ts +9 -0
  161. package/dist/src/services/preview/injected-scripts.js +232 -0
  162. package/dist/src/services/preview/preview-backend.d.ts +92 -0
  163. package/dist/src/services/preview/preview-backend.js +15 -0
  164. package/dist/src/services/preview/universal-setter.d.ts +7 -0
  165. package/dist/src/services/preview/universal-setter.js +46 -0
  166. package/dist/src/services/preview-manager.d.ts +50 -0
  167. package/dist/src/services/preview-manager.js +216 -0
  168. package/dist/src/services/project-watcher.d.ts +6 -0
  169. package/dist/src/services/project-watcher.js +307 -0
  170. package/dist/src/services/remote-fs-browser.d.ts +11 -0
  171. package/dist/src/services/remote-fs-browser.js +50 -0
  172. package/dist/src/services/remote-git-ops.d.ts +71 -0
  173. package/dist/src/services/remote-git-ops.js +215 -0
  174. package/dist/src/services/session-search.d.ts +56 -0
  175. package/dist/src/services/session-search.js +303 -0
  176. package/dist/src/services/ssh-manager.d.ts +44 -0
  177. package/dist/src/services/ssh-manager.js +359 -0
  178. package/dist/src/session-writer.d.ts +9 -0
  179. package/dist/src/session-writer.js +66 -0
  180. package/dist/src/spawner.d.ts +56 -0
  181. package/dist/src/spawner.js +135 -0
  182. package/dist/src/state/db.d.ts +214 -0
  183. package/dist/src/state/db.js +897 -0
  184. package/dist/src/state/store.d.ts +37 -0
  185. package/dist/src/state/store.js +108 -0
  186. package/dist/src/state/types.d.ts +13 -0
  187. package/dist/src/state/types.js +1 -0
  188. package/dist/src/web/devtools-proxy.d.ts +7 -0
  189. package/dist/src/web/devtools-proxy.js +176 -0
  190. package/dist/src/web/port-proxy.d.ts +15 -0
  191. package/dist/src/web/port-proxy.js +124 -0
  192. package/dist/src/web/preview-ws.d.ts +5 -0
  193. package/dist/src/web/preview-ws.js +207 -0
  194. package/dist/src/web/server.d.ts +6 -0
  195. package/dist/src/web/server.js +1694 -0
  196. package/dist/src/ws/agent-ws.d.ts +5 -0
  197. package/dist/src/ws/agent-ws.js +93 -0
  198. package/frontend/dist/assets/_basePickBy-B-LibQ4-.js +1 -0
  199. package/frontend/dist/assets/_baseUniq-CprifHap.js +1 -0
  200. package/frontend/dist/assets/_createAssigner-ByDUqGii.js +1 -0
  201. package/frontend/dist/assets/abap-DuT-3z4x.js +1 -0
  202. package/frontend/dist/assets/addon-fit-CxQet2ja.js +1 -0
  203. package/frontend/dist/assets/addon-web-links-D_jRkPIl.js +1 -0
  204. package/frontend/dist/assets/apex-B-em86xX.js +1 -0
  205. package/frontend/dist/assets/api-SUPuHhSY.js +2 -0
  206. package/frontend/dist/assets/arc-Z0_eVteO.js +1 -0
  207. package/frontend/dist/assets/architecture-PBZL5I3N-hvVXGhqd.js +1 -0
  208. package/frontend/dist/assets/architectureDiagram-2XIMDMQ5-DiHPxX4j.js +36 -0
  209. package/frontend/dist/assets/array-CwG8vNfn.js +1 -0
  210. package/frontend/dist/assets/auth-store-R7eW5SVu.js +1 -0
  211. package/frontend/dist/assets/azcli-Bg9wQloi.js +1 -0
  212. package/frontend/dist/assets/bat-BM46z99L.js +1 -0
  213. package/frontend/dist/assets/bicep-DcBsJUfh.js +2 -0
  214. package/frontend/dist/assets/blockDiagram-WCTKOSBZ-C40u_hLo.js +132 -0
  215. package/frontend/dist/assets/c4Diagram-IC4MRINW-Ct7LjWFQ.js +10 -0
  216. package/frontend/dist/assets/cameligo-zw7JTtim.js +1 -0
  217. package/frontend/dist/assets/channel-ClCsE6HN.js +1 -0
  218. package/frontend/dist/assets/chunk-4BX2VUAB-zZ6P90VO.js +1 -0
  219. package/frontend/dist/assets/chunk-55IACEB6-DXllTDQl.js +1 -0
  220. package/frontend/dist/assets/chunk-7E7YKBS2-7zRaOLjj.js +1 -0
  221. package/frontend/dist/assets/chunk-7R4GIKGN-Csst1274.js +80 -0
  222. package/frontend/dist/assets/chunk-C72U2L5F-_JbQPbLN.js +1 -0
  223. package/frontend/dist/assets/chunk-CFjPhJqf.js +1 -0
  224. package/frontend/dist/assets/chunk-EGIJ26TM-B--aFyPw.js +1 -0
  225. package/frontend/dist/assets/chunk-FMBD7UC4-DVR34RNb.js +15 -0
  226. package/frontend/dist/assets/chunk-GEFDOKGD-CnmN6cC8.js +2 -0
  227. package/frontend/dist/assets/chunk-JSJVCQXG-CWxHBzeJ.js +1 -0
  228. package/frontend/dist/assets/chunk-KX2RTZJC-DkRk56s7.js +1 -0
  229. package/frontend/dist/assets/chunk-KYZI473N-DCCsG2dK.js +53 -0
  230. package/frontend/dist/assets/chunk-L3YUKLVL-C-DkZTMr.js +1 -0
  231. package/frontend/dist/assets/chunk-MX3YWQON-OUdzv5sZ.js +1 -0
  232. package/frontend/dist/assets/chunk-NQ4KR5QH-Bpu9FsM7.js +220 -0
  233. package/frontend/dist/assets/chunk-O4XLMI2P-BMLK6_ib.js +7 -0
  234. package/frontend/dist/assets/chunk-OZEHJAEY-CNNiJtG0.js +1 -0
  235. package/frontend/dist/assets/chunk-PQ6SQG4A-evVHD3KM.js +1 -0
  236. package/frontend/dist/assets/chunk-PU5JKC2W-DPFTYuvl.js +70 -0
  237. package/frontend/dist/assets/chunk-QZHKN3VN-JRdddPvu.js +1 -0
  238. package/frontend/dist/assets/chunk-R5LLSJPH-CHQzVVOV.js +1 -0
  239. package/frontend/dist/assets/chunk-WL4C6EOR-BNFU6IIi.js +189 -0
  240. package/frontend/dist/assets/chunk-XIRO2GV7-98T93G85.js +1 -0
  241. package/frontend/dist/assets/chunk-XZSTWKYB-BcW3cyNp.js +94 -0
  242. package/frontend/dist/assets/chunk-YBOYWFTD-BgKO1qAJ.js +1 -0
  243. package/frontend/dist/assets/classDiagram-VBA2DB6C-DikXzgcD.js +1 -0
  244. package/frontend/dist/assets/classDiagram-v2-RAHNMMFH-D7E3tQUK.js +1 -0
  245. package/frontend/dist/assets/clojure-FspFoNNQ.js +1 -0
  246. package/frontend/dist/assets/clone-mOXuZa7C.js +1 -0
  247. package/frontend/dist/assets/codicon-ngg6Pgfi.ttf +0 -0
  248. package/frontend/dist/assets/coffee-13n8Bk2W.js +1 -0
  249. package/frontend/dist/assets/cose-bilkent-S5V4N54A-zUOWQqLe.js +1 -0
  250. package/frontend/dist/assets/cpp-BVm2xGEs.js +1 -0
  251. package/frontend/dist/assets/csharp-D2kAWmUm.js +1 -0
  252. package/frontend/dist/assets/csp-Ezvgpf0e.js +1 -0
  253. package/frontend/dist/assets/css-CYxRwcFy.js +3 -0
  254. package/frontend/dist/assets/css.worker-Cd5h-ZOL.js +89 -0
  255. package/frontend/dist/assets/cssMode-CrXej49V.js +1 -0
  256. package/frontend/dist/assets/cypher-jg3SGErc.js +1 -0
  257. package/frontend/dist/assets/cytoscape.esm-kyyvzxNV.js +321 -0
  258. package/frontend/dist/assets/dagre-DH4bgZO7.js +1 -0
  259. package/frontend/dist/assets/dagre-KLK3FWXG-DNSqDkwT.js +4 -0
  260. package/frontend/dist/assets/dart-179jqhK4.js +1 -0
  261. package/frontend/dist/assets/defaultLocale-Dda4OpKy.js +1 -0
  262. package/frontend/dist/assets/diagram-E7M64L7V-RqPNT5Vs.js +24 -0
  263. package/frontend/dist/assets/diagram-IFDJBPK2-B-5NRyaE.js +43 -0
  264. package/frontend/dist/assets/diagram-P4PSJMXO-BrP69Hk0.js +24 -0
  265. package/frontend/dist/assets/dist-CU_Nb1G5.js +1 -0
  266. package/frontend/dist/assets/dockerfile-CIAtSGxS.js +1 -0
  267. package/frontend/dist/assets/ecl-CGVKfDxD.js +1 -0
  268. package/frontend/dist/assets/editor-Br_kD0ds.css +1 -0
  269. package/frontend/dist/assets/editor.api2-YXkDn0Gm.js +872 -0
  270. package/frontend/dist/assets/editor.main-fBaXZjJ0.js +6 -0
  271. package/frontend/dist/assets/elixir-BZ-6w0y3.js +1 -0
  272. package/frontend/dist/assets/erDiagram-INFDFZHY-BYiB9NYg.js +70 -0
  273. package/frontend/dist/assets/flow9-CVuOjTMv.js +1 -0
  274. package/frontend/dist/assets/flowDiagram-PKNHOUZH-Cwq47rsR.js +162 -0
  275. package/frontend/dist/assets/freemarker2-DM-pztJU.js +3 -0
  276. package/frontend/dist/assets/fsharp-q0pGJYr6.js +1 -0
  277. package/frontend/dist/assets/ganttDiagram-A5KZAMGK-Dnx3szD9.js +292 -0
  278. package/frontend/dist/assets/gitGraph-HDMCJU4V-COlTQ7bA.js +1 -0
  279. package/frontend/dist/assets/gitGraphDiagram-K3NZZRJ6-BaUxboNc.js +65 -0
  280. package/frontend/dist/assets/go-dzSPfdEO.js +1 -0
  281. package/frontend/dist/assets/graphlib-kEFlkt3U.js +1 -0
  282. package/frontend/dist/assets/graphql-CG4OUoEV.js +1 -0
  283. package/frontend/dist/assets/handlebars-BbK53Vec.js +1 -0
  284. package/frontend/dist/assets/hcl-Cy14JPk3.js +1 -0
  285. package/frontend/dist/assets/html-DYtTQNOG.js +1 -0
  286. package/frontend/dist/assets/html.worker-BjVEKLoU.js +502 -0
  287. package/frontend/dist/assets/htmlMode-C6GTouth.js +1 -0
  288. package/frontend/dist/assets/index-DMLxes_u.js +157 -0
  289. package/frontend/dist/assets/index-DmzeqkB1.css +1 -0
  290. package/frontend/dist/assets/info-3K5VOQVL-DBtHyA4C.js +1 -0
  291. package/frontend/dist/assets/infoDiagram-LFFYTUFH-yBXLgMPI.js +2 -0
  292. package/frontend/dist/assets/ini-Pbg8HGVD.js +1 -0
  293. package/frontend/dist/assets/init-D6KNwrax.js +1 -0
  294. package/frontend/dist/assets/ishikawaDiagram-PHBUUO56-Bld4two_.js +70 -0
  295. package/frontend/dist/assets/java-BmVu6Qrl.js +1 -0
  296. package/frontend/dist/assets/javascript-PbfQEdcJ.js +1 -0
  297. package/frontend/dist/assets/journeyDiagram-4ABVD52K-4HyMd4R2.js +139 -0
  298. package/frontend/dist/assets/json.worker-DqU5Wxnl.js +58 -0
  299. package/frontend/dist/assets/jsonMode-CASsGppE.js +7 -0
  300. package/frontend/dist/assets/julia-3cGnieBq.js +1 -0
  301. package/frontend/dist/assets/kanban-definition-K7BYSVSG-DpgsZmpG.js +89 -0
  302. package/frontend/dist/assets/katex-CEw3x5bf.js +261 -0
  303. package/frontend/dist/assets/kotlin-BuWkVcfV.js +1 -0
  304. package/frontend/dist/assets/less-CJ_VPy2C.js +2 -0
  305. package/frontend/dist/assets/lexon-BygAuZPu.js +1 -0
  306. package/frontend/dist/assets/line-CA_wh_TY.js +1 -0
  307. package/frontend/dist/assets/linear-BAcLW45z.js +1 -0
  308. package/frontend/dist/assets/liquid-kz84dle6.js +1 -0
  309. package/frontend/dist/assets/lspLanguageFeatures-C7hAHFn1.js +4 -0
  310. package/frontend/dist/assets/lua-C8Xs3dCx.js +1 -0
  311. package/frontend/dist/assets/m3-DTJeKBk4.js +1 -0
  312. package/frontend/dist/assets/markdown-QCgx8JqZ.js +1 -0
  313. package/frontend/dist/assets/math-D0YcMJAn.js +1 -0
  314. package/frontend/dist/assets/mdx-yRw0ap-E.js +1 -0
  315. package/frontend/dist/assets/mermaid-parser.core-DAeTodBQ.js +4 -0
  316. package/frontend/dist/assets/mindmap-definition-YRQLILUH-CoNlFyVl.js +68 -0
  317. package/frontend/dist/assets/mips-DopWaYgE.js +1 -0
  318. package/frontend/dist/assets/monaco.contribution-DeY0Qei-.js +2 -0
  319. package/frontend/dist/assets/msdax-BDis4ARV.js +1 -0
  320. package/frontend/dist/assets/mysql-BV6MLsOI.js +1 -0
  321. package/frontend/dist/assets/objective-c-B1UuzKs6.js +1 -0
  322. package/frontend/dist/assets/ordinal-jM7S0YHN.js +1 -0
  323. package/frontend/dist/assets/packet-RMMSAZCW-FF6-Tmai.js +1 -0
  324. package/frontend/dist/assets/pascal-BkvESCrc.js +1 -0
  325. package/frontend/dist/assets/pascaligo-lTy0kZYr.js +1 -0
  326. package/frontend/dist/assets/path-DNPd7Py7.js +1 -0
  327. package/frontend/dist/assets/perl-CrtUPXLV.js +1 -0
  328. package/frontend/dist/assets/pgsql-B9IbNWx2.js +1 -0
  329. package/frontend/dist/assets/php-CXvQBY2p.js +1 -0
  330. package/frontend/dist/assets/pie-UPGHQEXC-CFvXY2o-.js +1 -0
  331. package/frontend/dist/assets/pieDiagram-SKSYHLDU-CM_hbCcn.js +30 -0
  332. package/frontend/dist/assets/pla-DxBxuqWu.js +1 -0
  333. package/frontend/dist/assets/postiats-OkEuT5YF.js +1 -0
  334. package/frontend/dist/assets/powerquery-CMx5Tq4K.js +1 -0
  335. package/frontend/dist/assets/powershell-CstRxrEc.js +1 -0
  336. package/frontend/dist/assets/preload-helper-D4M6sveU.js +1 -0
  337. package/frontend/dist/assets/protobuf-Bx0Z-uRj.js +2 -0
  338. package/frontend/dist/assets/pug--W8vanWl.js +1 -0
  339. package/frontend/dist/assets/python-DA0rnlw3.js +1 -0
  340. package/frontend/dist/assets/qsharp-CRtr0YbN.js +1 -0
  341. package/frontend/dist/assets/quadrantDiagram-337W2JSQ-B3n3IUhC.js +7 -0
  342. package/frontend/dist/assets/r-C6E1d6iv.js +1 -0
  343. package/frontend/dist/assets/radar-KQ55EAFF-MPZu7SdX.js +1 -0
  344. package/frontend/dist/assets/razor-yd73uata.js +1 -0
  345. package/frontend/dist/assets/redis-Dx13voP3.js +1 -0
  346. package/frontend/dist/assets/redshift-D66HwlyV.js +1 -0
  347. package/frontend/dist/assets/requirementDiagram-Z7DCOOCP-CorP7L7F.js +73 -0
  348. package/frontend/dist/assets/restructuredtext-DQT2NKJ2.js +1 -0
  349. package/frontend/dist/assets/rough.esm-DxAX5Vpo.js +1 -0
  350. package/frontend/dist/assets/ruby-iFXI8hwH.js +1 -0
  351. package/frontend/dist/assets/rust-CSKiei34.js +1 -0
  352. package/frontend/dist/assets/sankeyDiagram-WA2Y5GQK-RDx6Bd-B.js +10 -0
  353. package/frontend/dist/assets/sb-Bo3ttdP2.js +1 -0
  354. package/frontend/dist/assets/scala-BC1D-Nxp.js +1 -0
  355. package/frontend/dist/assets/scheme-Z4OAo4Lv.js +1 -0
  356. package/frontend/dist/assets/scss-BvrdPs6B.js +3 -0
  357. package/frontend/dist/assets/sequenceDiagram-2WXFIKYE-JMqJSFq6.js +145 -0
  358. package/frontend/dist/assets/shell-Bh_aCyF-.js +1 -0
  359. package/frontend/dist/assets/solidity-CWHj6tSe.js +1 -0
  360. package/frontend/dist/assets/sophia-raoNtKtm.js +1 -0
  361. package/frontend/dist/assets/sparql-XzmoGnue.js +1 -0
  362. package/frontend/dist/assets/sql-BD0i9Gvg.js +1 -0
  363. package/frontend/dist/assets/src-Bn-kKzs7.js +1 -0
  364. package/frontend/dist/assets/st-DtVKyms6.js +1 -0
  365. package/frontend/dist/assets/stateDiagram-RAJIS63D-CgFfENdy.js +1 -0
  366. package/frontend/dist/assets/stateDiagram-v2-FVOUBMTO-C4Hh2P-U.js +1 -0
  367. package/frontend/dist/assets/swift--UZs77wT.js +1 -0
  368. package/frontend/dist/assets/systemverilog-CDnBSWUd.js +1 -0
  369. package/frontend/dist/assets/tcl-DdCEuTHZ.js +1 -0
  370. package/frontend/dist/assets/timeline-definition-YZTLITO2-BnatPBR5.js +61 -0
  371. package/frontend/dist/assets/treemap-KZPCXAKY-qb1Pl9la.js +1 -0
  372. package/frontend/dist/assets/ts.worker-DyPAEIuH.js +67719 -0
  373. package/frontend/dist/assets/tsMode-iuvyEpyO.js +11 -0
  374. package/frontend/dist/assets/twig-SSL-Altf.js +1 -0
  375. package/frontend/dist/assets/typescript-17918Hud.js +1 -0
  376. package/frontend/dist/assets/typespec-BT7S0ETg.js +1 -0
  377. package/frontend/dist/assets/vb-CrIgucua.js +1 -0
  378. package/frontend/dist/assets/vennDiagram-LZ73GAT5-DygS4Zzd.js +34 -0
  379. package/frontend/dist/assets/wgsl-BeKc3oEp.js +298 -0
  380. package/frontend/dist/assets/workers-DTfwKVoM.js +1 -0
  381. package/frontend/dist/assets/xml-CBMr_Wbw.js +1 -0
  382. package/frontend/dist/assets/xterm-BrP-ENHg.css +1 -0
  383. package/frontend/dist/assets/xterm-CBX2m0YM.js +36 -0
  384. package/frontend/dist/assets/xychartDiagram-JWTSCODW-D6wY1Jwd.js +7 -0
  385. package/frontend/dist/assets/yaml-CTjCH7Bv.js +1 -0
  386. package/frontend/dist/fonts/inter-300.ttf +0 -0
  387. package/frontend/dist/fonts/inter-400.ttf +0 -0
  388. package/frontend/dist/fonts/inter-500.ttf +0 -0
  389. package/frontend/dist/fonts/inter-600.ttf +0 -0
  390. package/frontend/dist/fonts/inter-700.ttf +0 -0
  391. package/frontend/dist/index.html +49 -0
  392. package/frontend/dist/logo_192x192.png +0 -0
  393. package/frontend/dist/logo_32x32.png +0 -0
  394. package/frontend/dist/logo_512x512.png +0 -0
  395. package/frontend/dist/logo_64x64.png +0 -0
  396. package/frontend/dist/logobg_192x192.png +0 -0
  397. package/frontend/dist/logobg_512x512.png +0 -0
  398. package/frontend/dist/logobg_64x64.png +0 -0
  399. package/frontend/dist/manifest.json +25 -0
  400. package/frontend/dist/sw.js +22 -0
  401. package/package.json +74 -7
  402. package/preload/Makefile +12 -0
  403. package/preload/atoo-studio-preload.c +647 -0
  404. package/preload/atoo-studio-preload.so +0 -0
  405. package/setup-cuse.sh +260 -0
  406. package/setup.sh +81 -0
  407. package/src/serial/native/binding.gyp +10 -0
  408. package/src/serial/native/pty_pair.c +222 -0
@@ -0,0 +1,637 @@
1
+ import net from 'net';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import os from 'os';
5
+ import crypto from 'crypto';
6
+ import readline from 'readline';
7
+ import { v4 as uuidv4 } from 'uuid';
8
+ const ATOO_DIR = path.join(os.homedir(), '.atoo-studio');
9
+ const SOCKET_PATH = path.join(ATOO_DIR, 'preload.sock');
10
+ const OBJECTS_DIR = path.join(ATOO_DIR, 'objects');
11
+ /** Map a preload op to a FileChange operation. */
12
+ function mapOperation(op, fileExisted) {
13
+ switch (op) {
14
+ case 'write':
15
+ return fileExisted ? 'modify' : 'create';
16
+ case 'rename':
17
+ return 'rename';
18
+ case 'delete':
19
+ return 'delete';
20
+ case 'truncate':
21
+ return 'modify';
22
+ }
23
+ }
24
+ /** Detect if a buffer is likely binary (contains null bytes). */
25
+ function isBinaryBuffer(buf) {
26
+ for (let i = 0; i < Math.min(buf.length, 8192); i++) {
27
+ if (buf[i] === 0)
28
+ return true;
29
+ }
30
+ return false;
31
+ }
32
+ /** Paths to exclude from inotify watching. */
33
+ function shouldExcludeInotify(filePath) {
34
+ const base = path.basename(filePath);
35
+ // Skip hidden dirs/files (except specific ones), node_modules, etc.
36
+ if (base === 'node_modules')
37
+ return true;
38
+ if (base === '.git')
39
+ return true;
40
+ if (base === '.atoo-studio')
41
+ return true;
42
+ if (filePath.includes('/node_modules/'))
43
+ return true;
44
+ if (filePath.includes('/.git/'))
45
+ return true;
46
+ if (filePath.includes('/.atoo-studio/'))
47
+ return true;
48
+ return false;
49
+ }
50
+ /** Store a buffer in the content-addressed object store. Returns the hash. */
51
+ function storeObject(buf) {
52
+ const hash = crypto.createHash('sha256').update(buf).digest('hex');
53
+ const objectPath = path.join(OBJECTS_DIR, hash);
54
+ if (!fs.existsSync(objectPath)) {
55
+ fs.writeFileSync(objectPath, buf);
56
+ }
57
+ return hash;
58
+ }
59
+ export class FsMonitor {
60
+ server = null;
61
+ clients = new Set();
62
+ listening = false;
63
+ changes = new Map(); // sessionId → changes
64
+ changeListeners = [];
65
+ /** Mapping from preload tracking UUID → real session ID */
66
+ sessionMap = new Map();
67
+ /** Active inotify watchers per session */
68
+ inotifySessions = new Map();
69
+ /** Track paths already reported by preload (to dedup with inotify) */
70
+ preloadReportedPaths = new Map(); // sessionId → Set<path>
71
+ /** Start the Unix socket server for preload library connections. */
72
+ async connect() {
73
+ return new Promise((resolve, reject) => {
74
+ // Ensure directories exist
75
+ fs.mkdirSync(ATOO_DIR, { recursive: true });
76
+ fs.mkdirSync(OBJECTS_DIR, { recursive: true });
77
+ // Remove stale socket
78
+ try {
79
+ fs.unlinkSync(SOCKET_PATH);
80
+ }
81
+ catch { }
82
+ const server = net.createServer((client) => {
83
+ this.clients.add(client);
84
+ const rl = readline.createInterface({ input: client });
85
+ rl.on('line', (line) => {
86
+ this.handlePreloadEvent(line);
87
+ });
88
+ client.on('error', () => {
89
+ this.clients.delete(client);
90
+ });
91
+ client.on('close', () => {
92
+ this.clients.delete(client);
93
+ });
94
+ });
95
+ server.on('error', (err) => {
96
+ console.error(`[fs-monitor] Socket server error: ${err.message}`);
97
+ reject(err);
98
+ });
99
+ server.listen(SOCKET_PATH, () => {
100
+ this.listening = true;
101
+ console.log(`[fs-monitor] Preload socket listening on ${SOCKET_PATH}`);
102
+ resolve();
103
+ });
104
+ this.server = server;
105
+ });
106
+ }
107
+ /** Register a listener for real-time change events. */
108
+ onChangeEvent(listener) {
109
+ this.changeListeners.push(listener);
110
+ }
111
+ /** Remove a change event listener. */
112
+ offChangeEvent(listener) {
113
+ const idx = this.changeListeners.indexOf(listener);
114
+ if (idx >= 0)
115
+ this.changeListeners.splice(idx, 1);
116
+ }
117
+ /** Handle a JSON line from a preload library instance. */
118
+ handlePreloadEvent(line) {
119
+ const trimmed = line.trim();
120
+ if (!trimmed)
121
+ return;
122
+ let event;
123
+ try {
124
+ event = JSON.parse(trimmed);
125
+ }
126
+ catch {
127
+ console.warn('[fs-monitor] Invalid JSON from preload:', trimmed.substring(0, 100));
128
+ return;
129
+ }
130
+ // Remap tracking UUID to real session ID
131
+ const realSessionId = this.sessionMap.get(event.session_id) || event.session_id;
132
+ // Mark this path as reported by preload (for inotify dedup)
133
+ if (!this.preloadReportedPaths.has(realSessionId)) {
134
+ this.preloadReportedPaths.set(realSessionId, new Set());
135
+ }
136
+ this.preloadReportedPaths.get(realSessionId).add(event.path);
137
+ // Process snapshot: hash and move to object store
138
+ let beforeHash = null;
139
+ let fileSize = 0;
140
+ let binary = false;
141
+ if (event.snapshot) {
142
+ try {
143
+ const snapBuf = fs.readFileSync(event.snapshot);
144
+ fileSize = snapBuf.length;
145
+ binary = isBinaryBuffer(snapBuf);
146
+ const hash = crypto.createHash('sha256').update(snapBuf).digest('hex');
147
+ const objectPath = path.join(OBJECTS_DIR, hash);
148
+ // Move snapshot to object store (content-addressed, skip if exists)
149
+ if (!fs.existsSync(objectPath)) {
150
+ fs.renameSync(event.snapshot, objectPath);
151
+ }
152
+ else {
153
+ try {
154
+ fs.unlinkSync(event.snapshot);
155
+ }
156
+ catch { }
157
+ }
158
+ beforeHash = hash;
159
+ }
160
+ catch (err) {
161
+ console.warn(`[fs-monitor] Failed to process snapshot ${event.snapshot}: ${err.message}`);
162
+ }
163
+ }
164
+ const operation = mapOperation(event.op, event.file_existed);
165
+ this.recordChange({
166
+ sessionId: realSessionId,
167
+ timestamp: event.ts,
168
+ operation,
169
+ filePath: event.path,
170
+ oldPath: event.old_path,
171
+ beforeHash,
172
+ fileSize,
173
+ isBinary: binary,
174
+ });
175
+ }
176
+ /** Handle an inotify event from fs.watch. */
177
+ handleInotifyEvent(sessionId, baseDir, _eventType, filename) {
178
+ if (!filename)
179
+ return;
180
+ const filePath = path.resolve(baseDir, filename);
181
+ // Skip excluded paths
182
+ if (shouldExcludeInotify(filePath))
183
+ return;
184
+ // Skip if already reported by preload recently
185
+ const preloadPaths = this.preloadReportedPaths.get(sessionId);
186
+ if (preloadPaths?.has(filePath))
187
+ return;
188
+ const inoSession = this.inotifySessions.get(sessionId);
189
+ if (!inoSession)
190
+ return;
191
+ this.processInotifyChange(sessionId, filePath, inoSession);
192
+ }
193
+ /** Process a debounced inotify change. */
194
+ processInotifyChange(sessionId, filePath, inoSession) {
195
+ // Re-check preload dedup after debounce
196
+ const preloadPaths = this.preloadReportedPaths.get(sessionId);
197
+ if (preloadPaths?.has(filePath))
198
+ return;
199
+ const fileExists = fs.existsSync(filePath);
200
+ const initialHash = inoSession.initialHashes.get(filePath);
201
+ let operation;
202
+ let beforeHash = initialHash || null;
203
+ let fileSize = 0;
204
+ let binary = false;
205
+ if (!fileExists) {
206
+ if (!initialHash) {
207
+ // File never existed at session start and is now gone — transient, skip
208
+ return;
209
+ }
210
+ operation = 'delete';
211
+ }
212
+ else {
213
+ try {
214
+ const stat = fs.statSync(filePath);
215
+ if (!stat.isFile())
216
+ return; // Skip directories
217
+ fileSize = stat.size;
218
+ }
219
+ catch {
220
+ return;
221
+ }
222
+ if (initialHash) {
223
+ // File existed before — check if actually changed
224
+ try {
225
+ const buf = fs.readFileSync(filePath);
226
+ const currentHash = crypto.createHash('sha256').update(buf).digest('hex');
227
+ if (currentHash === initialHash)
228
+ return; // No actual change
229
+ binary = isBinaryBuffer(buf);
230
+ fileSize = buf.length;
231
+ }
232
+ catch {
233
+ return;
234
+ }
235
+ operation = 'modify';
236
+ }
237
+ else {
238
+ // File didn't exist at session start — it's a create
239
+ operation = 'create';
240
+ try {
241
+ const buf = fs.readFileSync(filePath);
242
+ binary = isBinaryBuffer(buf);
243
+ fileSize = buf.length;
244
+ }
245
+ catch { }
246
+ }
247
+ }
248
+ // Update initial hash for subsequent changes
249
+ if (fileExists) {
250
+ try {
251
+ const buf = fs.readFileSync(filePath);
252
+ const newHash = storeObject(buf);
253
+ inoSession.initialHashes.set(filePath, newHash);
254
+ }
255
+ catch { }
256
+ }
257
+ else {
258
+ inoSession.initialHashes.delete(filePath);
259
+ }
260
+ this.recordChange({
261
+ sessionId,
262
+ timestamp: Date.now() / 1000,
263
+ operation,
264
+ filePath,
265
+ beforeHash,
266
+ fileSize,
267
+ isBinary: binary,
268
+ });
269
+ }
270
+ /** Record a FileChange and notify listeners. */
271
+ recordChange(opts) {
272
+ const change = {
273
+ changeId: uuidv4(),
274
+ sessionId: opts.sessionId,
275
+ timestamp: opts.timestamp,
276
+ pid: 0,
277
+ operation: opts.operation,
278
+ path: opts.filePath,
279
+ oldPath: opts.oldPath,
280
+ beforeHash: opts.beforeHash,
281
+ afterHash: null, // lazy — materialized on demand
282
+ fileSize: opts.fileSize,
283
+ isBinary: opts.isBinary,
284
+ };
285
+ if (!this.changes.has(opts.sessionId)) {
286
+ this.changes.set(opts.sessionId, []);
287
+ }
288
+ this.changes.get(opts.sessionId).push(change);
289
+ // Notify listeners
290
+ for (const listener of this.changeListeners) {
291
+ try {
292
+ listener(change);
293
+ }
294
+ catch (err) {
295
+ console.error('[fs-monitor] Listener error:', err);
296
+ }
297
+ }
298
+ }
299
+ /**
300
+ * Start watching a session's working directory.
301
+ * Combines preload session mapping + inotify watching.
302
+ */
303
+ watchPid(sessionId, _pid, baseDir) {
304
+ console.log(`[fs-monitor] watchPid: session=${sessionId}, dir=${baseDir}`);
305
+ if (!this.changes.has(sessionId)) {
306
+ this.changes.set(sessionId, []);
307
+ }
308
+ // Start inotify watcher for the working directory
309
+ this.startInotifyWatch(sessionId, baseDir);
310
+ }
311
+ /** Start an inotify (fs.watch) watcher for a session's working directory. */
312
+ startInotifyWatch(sessionId, baseDir) {
313
+ // Don't double-watch
314
+ if (this.inotifySessions.has(sessionId))
315
+ return;
316
+ try {
317
+ // Snapshot initial file hashes for before-state tracking
318
+ const initialHashes = new Map();
319
+ this.snapshotDirectory(baseDir, initialHashes);
320
+ console.log(`[fs-monitor] Snapshotted ${initialHashes.size} files in ${baseDir}`);
321
+ const watcher = fs.watch(baseDir, { recursive: true }, (eventType, filename) => {
322
+ this.handleInotifyEvent(sessionId, baseDir, eventType, filename);
323
+ });
324
+ watcher.on('error', (err) => {
325
+ console.warn(`[fs-monitor] Inotify watcher error for ${sessionId}: ${err.message}`);
326
+ });
327
+ const inoSession = {
328
+ sessionId,
329
+ baseDir,
330
+ watcher,
331
+ initialHashes,
332
+ };
333
+ this.inotifySessions.set(sessionId, inoSession);
334
+ console.log(`[fs-monitor] Inotify watching ${baseDir} for session ${sessionId}`);
335
+ }
336
+ catch (err) {
337
+ console.warn(`[fs-monitor] Failed to start inotify for ${baseDir}: ${err.message}`);
338
+ }
339
+ }
340
+ /** Recursively snapshot file hashes in a directory. */
341
+ snapshotDirectory(dir, hashes, depth = 0) {
342
+ if (depth > 10)
343
+ return; // Limit recursion depth
344
+ if (shouldExcludeInotify(dir))
345
+ return;
346
+ try {
347
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
348
+ for (const entry of entries) {
349
+ const fullPath = path.join(dir, entry.name);
350
+ if (shouldExcludeInotify(fullPath))
351
+ continue;
352
+ if (entry.isDirectory()) {
353
+ this.snapshotDirectory(fullPath, hashes, depth + 1);
354
+ }
355
+ else if (entry.isFile()) {
356
+ try {
357
+ const buf = fs.readFileSync(fullPath);
358
+ const hash = storeObject(buf);
359
+ hashes.set(fullPath, hash);
360
+ }
361
+ catch {
362
+ // Skip unreadable files
363
+ }
364
+ }
365
+ }
366
+ }
367
+ catch {
368
+ // Skip unreadable directories
369
+ }
370
+ }
371
+ /** Register the mapping from a preload tracking UUID to the real session ID. */
372
+ registerSessionMapping(preloadSessionId, realSessionId) {
373
+ this.sessionMap.set(preloadSessionId, realSessionId);
374
+ // Remap any changes already received with the tracking UUID
375
+ const pending = this.changes.get(preloadSessionId);
376
+ if (pending && pending.length > 0) {
377
+ const existing = this.changes.get(realSessionId) || [];
378
+ for (const c of pending) {
379
+ c.sessionId = realSessionId;
380
+ existing.push(c);
381
+ }
382
+ this.changes.set(realSessionId, existing);
383
+ this.changes.delete(preloadSessionId);
384
+ }
385
+ // Also remap preload reported paths
386
+ const preloadPaths = this.preloadReportedPaths.get(preloadSessionId);
387
+ if (preloadPaths) {
388
+ const existing = this.preloadReportedPaths.get(realSessionId) || new Set();
389
+ for (const p of preloadPaths)
390
+ existing.add(p);
391
+ this.preloadReportedPaths.set(realSessionId, existing);
392
+ this.preloadReportedPaths.delete(preloadSessionId);
393
+ }
394
+ }
395
+ /** Stop watching a session. */
396
+ unwatchPid(sessionId) {
397
+ const inoSession = this.inotifySessions.get(sessionId);
398
+ if (inoSession) {
399
+ inoSession.watcher.close();
400
+ this.inotifySessions.delete(sessionId);
401
+ }
402
+ }
403
+ /** Get all changes for a session. */
404
+ getChanges(sessionId) {
405
+ return this.changes.get(sessionId) || [];
406
+ }
407
+ /** Get changes for a session within a time range. */
408
+ getChangesInRange(sessionId, from, to) {
409
+ const all = this.getChanges(sessionId);
410
+ if (from === undefined && to === undefined)
411
+ return all;
412
+ return all.filter(c => {
413
+ if (from !== undefined && c.timestamp < from)
414
+ return false;
415
+ if (to !== undefined && c.timestamp > to)
416
+ return false;
417
+ return true;
418
+ });
419
+ }
420
+ /** Get the change count for a session. */
421
+ getChangeCount(sessionId) {
422
+ return this.changes.get(sessionId)?.length || 0;
423
+ }
424
+ /** Read file content by hash from the object store. Returns base64-encoded content. */
425
+ async getFileContent(hash) {
426
+ const objectPath = path.join(OBJECTS_DIR, hash);
427
+ try {
428
+ const buf = fs.readFileSync(objectPath);
429
+ return buf.toString('base64');
430
+ }
431
+ catch {
432
+ return null;
433
+ }
434
+ }
435
+ /**
436
+ * Materialize the after_hash for a change by reading the file's current content.
437
+ * Returns the hash, or null if the file doesn't exist.
438
+ */
439
+ async materializeAfterHash(change) {
440
+ if (change.afterHash !== null)
441
+ return change.afterHash;
442
+ if (change.operation === 'delete')
443
+ return null;
444
+ try {
445
+ const buf = fs.readFileSync(change.path);
446
+ const hash = storeObject(buf);
447
+ // Cache on the change record
448
+ change.afterHash = hash;
449
+ change.fileSize = Math.max(change.fileSize, buf.length);
450
+ change.isBinary = change.isBinary || isBinaryBuffer(buf);
451
+ return hash;
452
+ }
453
+ catch {
454
+ // File may have been deleted since the change
455
+ return null;
456
+ }
457
+ }
458
+ /** Revert a single change by restoring the file to its before state. */
459
+ async revertChange(change) {
460
+ try {
461
+ switch (change.operation) {
462
+ case 'modify': {
463
+ if (!change.beforeHash) {
464
+ return { success: false, message: 'No before snapshot available' };
465
+ }
466
+ const content = await this.getFileContent(change.beforeHash);
467
+ if (!content) {
468
+ return { success: false, message: 'Failed to read before content from object store' };
469
+ }
470
+ const buf = Buffer.from(content, 'base64');
471
+ fs.writeFileSync(change.path, buf);
472
+ return { success: true };
473
+ }
474
+ case 'create': {
475
+ // Undo creation by deleting the file
476
+ if (fs.existsSync(change.path)) {
477
+ fs.unlinkSync(change.path);
478
+ }
479
+ return { success: true };
480
+ }
481
+ case 'delete': {
482
+ if (!change.beforeHash) {
483
+ return { success: false, message: 'No before snapshot available for deleted file' };
484
+ }
485
+ const content = await this.getFileContent(change.beforeHash);
486
+ if (!content) {
487
+ return { success: false, message: 'Failed to read before content from object store' };
488
+ }
489
+ const buf = Buffer.from(content, 'base64');
490
+ // Ensure parent directory exists
491
+ const dir = path.dirname(change.path);
492
+ fs.mkdirSync(dir, { recursive: true });
493
+ fs.writeFileSync(change.path, buf);
494
+ return { success: true };
495
+ }
496
+ case 'rename': {
497
+ if (change.oldPath) {
498
+ fs.renameSync(change.path, change.oldPath);
499
+ }
500
+ return { success: true };
501
+ }
502
+ default:
503
+ return { success: false, message: `Unknown operation: ${change.operation}` };
504
+ }
505
+ }
506
+ catch (err) {
507
+ return { success: false, message: err.message };
508
+ }
509
+ }
510
+ /** Revert all changes for a session in reverse chronological order. */
511
+ async revertAll(sessionId) {
512
+ const changes = this.getChanges(sessionId);
513
+ if (changes.length === 0) {
514
+ return { success: true, reverted: 0, failed: 0 };
515
+ }
516
+ // Process in reverse order
517
+ const reversed = [...changes].reverse();
518
+ let reverted = 0;
519
+ let failed = 0;
520
+ for (const change of reversed) {
521
+ const result = await this.revertChange(change);
522
+ if (result.success) {
523
+ reverted++;
524
+ }
525
+ else {
526
+ failed++;
527
+ console.warn(`[fs-monitor] Failed to revert ${change.changeId}: ${result.message}`);
528
+ }
529
+ }
530
+ return { success: failed === 0, reverted, failed };
531
+ }
532
+ /** Find a specific change by ID across all sessions. */
533
+ findChange(changeId) {
534
+ for (const changes of this.changes.values()) {
535
+ const found = changes.find(c => c.changeId === changeId);
536
+ if (found)
537
+ return found;
538
+ }
539
+ return undefined;
540
+ }
541
+ /**
542
+ * Third fallback: notify that a tool call modified a file.
543
+ * Called when a Write/Edit tool_result arrives. Checks if the change
544
+ * was already captured by preload or inotify; if not, records it.
545
+ */
546
+ notifyToolChange(sessionId, filePath, toolName) {
547
+ const absPath = path.resolve(filePath);
548
+ // Dedup: check if this path was already captured recently (within 3s)
549
+ const existing = this.changes.get(sessionId);
550
+ if (existing) {
551
+ const now = Date.now() / 1000;
552
+ const alreadyCaptured = existing.some(c => c.path === absPath && (now - c.timestamp) < 3);
553
+ if (alreadyCaptured) {
554
+ console.log(`[fs-monitor] Tool change for ${absPath} already captured, skipping`);
555
+ return;
556
+ }
557
+ }
558
+ // Also check preload reported paths
559
+ const preloadPaths = this.preloadReportedPaths.get(sessionId);
560
+ if (preloadPaths?.has(absPath)) {
561
+ console.log(`[fs-monitor] Tool change for ${absPath} already reported by preload, skipping`);
562
+ return;
563
+ }
564
+ // Determine before hash from inotify session snapshot
565
+ const inoSession = this.inotifySessions.get(sessionId);
566
+ let beforeHash = null;
567
+ if (inoSession) {
568
+ beforeHash = inoSession.initialHashes.get(absPath) || null;
569
+ }
570
+ // Determine operation
571
+ let operation;
572
+ if (toolName === 'Write') {
573
+ operation = beforeHash ? 'modify' : 'create';
574
+ }
575
+ else if (toolName === 'Edit') {
576
+ operation = 'modify';
577
+ }
578
+ else {
579
+ return;
580
+ }
581
+ // Read current file state
582
+ let fileSize = 0;
583
+ let binary = false;
584
+ const fileExists = fs.existsSync(absPath);
585
+ if (fileExists) {
586
+ try {
587
+ const buf = fs.readFileSync(absPath);
588
+ fileSize = buf.length;
589
+ binary = isBinaryBuffer(buf);
590
+ // Update inotify initial hash for future change detection
591
+ if (inoSession) {
592
+ const hash = storeObject(buf);
593
+ inoSession.initialHashes.set(absPath, hash);
594
+ }
595
+ }
596
+ catch { }
597
+ }
598
+ console.log(`[fs-monitor] Tool change: ${toolName} → ${operation} ${absPath}`);
599
+ this.recordChange({
600
+ sessionId,
601
+ timestamp: Date.now() / 1000,
602
+ operation,
603
+ filePath: absPath,
604
+ beforeHash,
605
+ fileSize,
606
+ isBinary: binary,
607
+ });
608
+ }
609
+ /** Whether the monitor is available (socket server listening). */
610
+ isAvailable() {
611
+ return this.listening;
612
+ }
613
+ /** Close the socket server, inotify watchers, and all client connections. */
614
+ disconnect() {
615
+ // Close inotify watchers
616
+ for (const [, inoSession] of this.inotifySessions) {
617
+ inoSession.watcher.close();
618
+ }
619
+ this.inotifySessions.clear();
620
+ // Close preload socket clients
621
+ for (const client of this.clients) {
622
+ client.destroy();
623
+ }
624
+ this.clients.clear();
625
+ if (this.server) {
626
+ this.server.close();
627
+ this.server = null;
628
+ }
629
+ this.listening = false;
630
+ // Clean up socket file
631
+ try {
632
+ fs.unlinkSync(SOCKET_PATH);
633
+ }
634
+ catch { }
635
+ }
636
+ }
637
+ export const fsMonitor = new FsMonitor();
@@ -0,0 +1 @@
1
+ export declare const authRouter: import("express-serve-static-core").Router;