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,260 @@
1
+ import { spawn, execFileSync } from 'child_process';
2
+ import path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import fs from 'fs';
5
+ import os from 'os';
6
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
7
+ // Frame protocol: [type:1][len:2 BE][payload:len]
8
+ function encodeFrame(type, payload) {
9
+ const header = Buffer.alloc(3);
10
+ header[0] = type;
11
+ header[1] = (payload.length >> 8) & 0xFF;
12
+ header[2] = payload.length & 0xFF;
13
+ return Buffer.concat([header, payload]);
14
+ }
15
+ let deviceCounter = 0;
16
+ export function isCuseAvailable() {
17
+ if (process.platform !== 'linux')
18
+ return false;
19
+ // Check if /dev/cuse exists (kernel module loaded)
20
+ if (!fs.existsSync('/dev/cuse'))
21
+ return false;
22
+ // Check if /dev/cuse is actually accessible by the current user
23
+ try {
24
+ fs.accessSync('/dev/cuse', fs.constants.R_OK | fs.constants.W_OK);
25
+ }
26
+ catch {
27
+ console.log('[serial] /dev/cuse exists but is not accessible (check permissions: chmod 0666 /dev/cuse)');
28
+ return false;
29
+ }
30
+ // Unprivileged LXC containers can open /dev/cuse but can't create device nodes
31
+ try {
32
+ const uidMap = fs.readFileSync('/proc/self/uid_map', 'utf8').trim();
33
+ // In unprivileged containers, uid 0 maps to a high host uid (e.g., 100000)
34
+ // In privileged or bare-metal, uid 0 maps to 0
35
+ const match = uidMap.match(/^\s*0\s+(\d+)/);
36
+ if (match && parseInt(match[1], 10) > 0)
37
+ return false;
38
+ }
39
+ catch { }
40
+ // Check if the binary exists and has the required capability or suid bit
41
+ const bin = findCuseBinarySync();
42
+ if (!bin)
43
+ return false;
44
+ try {
45
+ const stat = fs.statSync(bin);
46
+ const hasSuid = (stat.mode & 0o4000) !== 0;
47
+ if (!hasSuid) {
48
+ // No suid — check for CAP_SYS_ADMIN via getcap
49
+ const caps = execFileSync('getcap', [bin], { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] });
50
+ if (!caps.includes('cap_sys_admin')) {
51
+ console.log(`[serial] cuse_serial binary lacks CAP_SYS_ADMIN and suid bit. Run: sudo setcap cap_sys_admin+ep ${bin}`);
52
+ return false;
53
+ }
54
+ }
55
+ }
56
+ catch { }
57
+ return true;
58
+ }
59
+ function findCuseBinarySync() {
60
+ // Preferred: installed by setup-cuse.sh to ~/.atoo-studio/bin/ (survives node-gyp rebuilds)
61
+ const installedPath = path.join(os.homedir(), '.atoo-studio', 'bin', 'cuse_serial');
62
+ if (fs.existsSync(installedPath))
63
+ return installedPath;
64
+ // Check /usr/local/bin
65
+ if (fs.existsSync('/usr/local/bin/cuse-serial'))
66
+ return '/usr/local/bin/cuse-serial';
67
+ // Fallback: node-gyp build dir (may lack capabilities after rebuild)
68
+ const localPath = path.join(__dirname, 'native', 'build', 'Release', 'cuse_serial');
69
+ if (fs.existsSync(localPath))
70
+ return localPath;
71
+ const distPath = path.join(__dirname, '..', '..', '..', 'src', 'serial', 'native', 'build', 'Release', 'cuse_serial');
72
+ if (fs.existsSync(distPath))
73
+ return distPath;
74
+ return null;
75
+ }
76
+ export function createCuseDevice() {
77
+ return new Promise((resolve, reject) => {
78
+ const bin = findCuseBinarySync();
79
+ if (!bin) {
80
+ reject(new Error('CUSE serial binary not found'));
81
+ return;
82
+ }
83
+ const devName = `ttyVS${deviceCounter++}`;
84
+ const child = spawn(bin, ['--name=' + devName, '-f'], {
85
+ stdio: ['pipe', 'pipe', 'pipe'],
86
+ });
87
+ let closed = false;
88
+ let resolved = false;
89
+ let devicePath = '';
90
+ const readBuffer = [];
91
+ let lastModemBits = { dtr: false, rts: false };
92
+ // Frame parser state for child's stdout
93
+ let parseState = 'header';
94
+ let frameType = 0;
95
+ let frameLen = 0;
96
+ let frameBuf = Buffer.alloc(0);
97
+ let headerBuf = Buffer.alloc(0);
98
+ function processFrame(type, payload) {
99
+ switch (type) {
100
+ case 0x00: // Serial data from tool
101
+ readBuffer.push(Buffer.from(payload));
102
+ break;
103
+ case 0x01: // Modem signals changed
104
+ if (payload.length >= 1) {
105
+ lastModemBits = {
106
+ dtr: (payload[0] & 0x01) !== 0,
107
+ rts: (payload[0] & 0x02) !== 0,
108
+ };
109
+ // Fire callback immediately for low-latency signal forwarding
110
+ device.onModemBitsChanged?.({ ...lastModemBits });
111
+ }
112
+ break;
113
+ case 0x02: // Device ready
114
+ devicePath = payload.toString('utf8');
115
+ break;
116
+ case 0x03: // Error
117
+ const msg = payload.toString('utf8');
118
+ if (!devicePath) {
119
+ reject(new Error(`CUSE: ${msg}`));
120
+ }
121
+ else {
122
+ console.error(`[cuse] Error: ${msg}`);
123
+ }
124
+ break;
125
+ }
126
+ }
127
+ function parseStdout(chunk) {
128
+ let offset = 0;
129
+ while (offset < chunk.length) {
130
+ if (parseState === 'header') {
131
+ const needed = 3 - headerBuf.length;
132
+ const available = chunk.length - offset;
133
+ const take = Math.min(needed, available);
134
+ headerBuf = Buffer.concat([headerBuf, chunk.subarray(offset, offset + take)]);
135
+ offset += take;
136
+ if (headerBuf.length === 3) {
137
+ frameType = headerBuf[0];
138
+ frameLen = (headerBuf[1] << 8) | headerBuf[2];
139
+ headerBuf = Buffer.alloc(0);
140
+ if (frameLen === 0) {
141
+ processFrame(frameType, Buffer.alloc(0));
142
+ }
143
+ else {
144
+ frameBuf = Buffer.alloc(0);
145
+ parseState = 'payload';
146
+ }
147
+ }
148
+ }
149
+ else {
150
+ const needed = frameLen - frameBuf.length;
151
+ const available = chunk.length - offset;
152
+ const take = Math.min(needed, available);
153
+ frameBuf = Buffer.concat([frameBuf, chunk.subarray(offset, offset + take)]);
154
+ offset += take;
155
+ if (frameBuf.length === frameLen) {
156
+ processFrame(frameType, frameBuf);
157
+ parseState = 'header';
158
+ }
159
+ }
160
+ }
161
+ }
162
+ child.stdout.on('data', (chunk) => {
163
+ parseStdout(chunk);
164
+ if (devicePath && !resolved) {
165
+ // Verify the device node actually exists (may fail in LXC due to cgroup restrictions)
166
+ let retries = 0;
167
+ const verifyInterval = setInterval(() => {
168
+ retries++;
169
+ if (fs.existsSync(devicePath)) {
170
+ clearInterval(verifyInterval);
171
+ resolved = true;
172
+ clearTimeout(timeout);
173
+ resolve(device);
174
+ }
175
+ else if (retries >= 10) {
176
+ clearInterval(verifyInterval);
177
+ resolved = true;
178
+ clearTimeout(timeout);
179
+ child.kill('SIGTERM');
180
+ reject(new Error(`CUSE device ${devicePath} was not created (blocked by container cgroup?)`));
181
+ }
182
+ }, 100);
183
+ }
184
+ });
185
+ child.stderr.on('data', (chunk) => {
186
+ const msg = chunk.toString().trim();
187
+ if (msg)
188
+ console.error(`[cuse] ${msg}`);
189
+ });
190
+ child.on('error', (err) => {
191
+ if (!devicePath)
192
+ reject(err);
193
+ });
194
+ child.on('exit', (code) => {
195
+ closed = true;
196
+ if (!devicePath) {
197
+ reject(new Error(`CUSE helper exited with code ${code}`));
198
+ }
199
+ });
200
+ // Wait up to 5s for device ready
201
+ const timeout = setTimeout(() => {
202
+ if (!devicePath) {
203
+ child.kill();
204
+ reject(new Error('CUSE device creation timed out'));
205
+ }
206
+ }, 5000);
207
+ const device = {
208
+ get devicePath() { return devicePath; },
209
+ get closed() { return closed; },
210
+ controlSignalsSupported: true,
211
+ write(data) {
212
+ if (closed)
213
+ return -1;
214
+ try {
215
+ const frame = encodeFrame(0x00, data);
216
+ child.stdin.write(frame);
217
+ return data.length;
218
+ }
219
+ catch {
220
+ return -1;
221
+ }
222
+ },
223
+ read() {
224
+ if (closed)
225
+ return null;
226
+ if (readBuffer.length === 0)
227
+ return null;
228
+ const chunk = readBuffer.shift();
229
+ return chunk;
230
+ },
231
+ getModemBits() {
232
+ return { ...lastModemBits };
233
+ },
234
+ onModemBitsChanged: null,
235
+ setModemBits(_dtr, _rts) {
236
+ // Not needed for CUSE — modem bits are set by the tool's ioctls,
237
+ // which the CUSE helper handles directly
238
+ },
239
+ close() {
240
+ if (!closed) {
241
+ closed = true;
242
+ clearTimeout(timeout);
243
+ try {
244
+ child.stdin.end();
245
+ }
246
+ catch { }
247
+ try {
248
+ child.kill('SIGTERM');
249
+ }
250
+ catch { }
251
+ // Give it a moment to clean up, then force kill
252
+ setTimeout(() => { try {
253
+ child.kill('SIGKILL');
254
+ }
255
+ catch { } }, 1000);
256
+ }
257
+ },
258
+ };
259
+ });
260
+ }
@@ -0,0 +1,63 @@
1
+ import { WebSocket } from 'ws';
2
+ import { PtyPair } from './pty-pair.js';
3
+ import { CuseDevice } from './cuse-device.js';
4
+ export type SerialDevice = PtyPair | CuseDevice;
5
+ export interface SerialRequestParams {
6
+ baudRate: number;
7
+ dataBits: number;
8
+ stopBits: number;
9
+ parity: string;
10
+ description?: string;
11
+ }
12
+ export interface SerialRequest {
13
+ requestId: string;
14
+ params: SerialRequestParams;
15
+ device: SerialDevice;
16
+ devicePath: string;
17
+ controlSignalsSupported: boolean;
18
+ status: 'pending' | 'connected' | 'closed';
19
+ browserWs: WebSocket | null;
20
+ resolveReady: ((result: {
21
+ devicePath: string;
22
+ controlSignalsSupported: boolean;
23
+ usbVendorId: number | null;
24
+ usbProductId: number | null;
25
+ }) => void) | null;
26
+ rejectReady: ((err: Error) => void) | null;
27
+ modemPollInterval: NodeJS.Timeout | null;
28
+ readPollInterval: NodeJS.Timeout | null;
29
+ lastModemBits: {
30
+ dtr: boolean;
31
+ rts: boolean;
32
+ };
33
+ }
34
+ declare class SerialManager {
35
+ private requests;
36
+ private cuseAvailable;
37
+ private ptyAvailable;
38
+ private checkCuseAvailable;
39
+ private checkPtyAvailable;
40
+ isAvailable(): boolean;
41
+ createRequest(requestId: string, params: SerialRequestParams): Promise<{
42
+ devicePath: string;
43
+ controlSignalsSupported: boolean;
44
+ readyPromise: Promise<{
45
+ devicePath: string;
46
+ controlSignalsSupported: boolean;
47
+ }>;
48
+ }>;
49
+ getRequest(requestId: string): SerialRequest | undefined;
50
+ connectBrowser(requestId: string, ws: WebSocket): boolean;
51
+ handleBrowserData(requestId: string, data: Buffer): void;
52
+ handleBrowserControl(requestId: string, msg: any): void;
53
+ rejectRequest(requestId: string, err: Error): void;
54
+ closeRequest(requestId: string): void;
55
+ getActiveRequests(): Array<{
56
+ requestId: string;
57
+ devicePath: string;
58
+ status: string;
59
+ controlSignalsSupported: boolean;
60
+ }>;
61
+ }
62
+ export declare const serialManager: SerialManager;
63
+ export {};
@@ -0,0 +1,206 @@
1
+ import { WebSocket } from 'ws';
2
+ import { createPtyPair, isPtyAvailable } from './pty-pair.js';
3
+ import { createCuseDevice, isCuseAvailable } from './cuse-device.js';
4
+ import { store } from '../state/store.js';
5
+ class SerialManager {
6
+ requests = new Map();
7
+ cuseAvailable = null;
8
+ ptyAvailable = null;
9
+ checkCuseAvailable() {
10
+ if (this.cuseAvailable === null) {
11
+ this.cuseAvailable = isCuseAvailable();
12
+ if (this.cuseAvailable) {
13
+ console.log('[serial] CUSE available — using virtual serial device with control signal support');
14
+ }
15
+ else {
16
+ console.log('[serial] CUSE not available — falling back to PTY (no control signal support)');
17
+ }
18
+ }
19
+ return this.cuseAvailable;
20
+ }
21
+ checkPtyAvailable() {
22
+ if (this.ptyAvailable === null) {
23
+ this.ptyAvailable = isPtyAvailable();
24
+ if (!this.ptyAvailable) {
25
+ console.log('[serial] PTY native module not available — serial passthrough disabled');
26
+ }
27
+ }
28
+ return this.ptyAvailable;
29
+ }
30
+ isAvailable() {
31
+ return this.checkCuseAvailable() || this.checkPtyAvailable();
32
+ }
33
+ async createRequest(requestId, params) {
34
+ let device;
35
+ let devicePath;
36
+ let controlSignalsSupported;
37
+ if (this.checkCuseAvailable()) {
38
+ try {
39
+ const cuse = await createCuseDevice();
40
+ device = cuse;
41
+ devicePath = cuse.devicePath;
42
+ controlSignalsSupported = true;
43
+ console.log(`[serial] Created CUSE device: ${devicePath}`);
44
+ }
45
+ catch (err) {
46
+ console.log(`[serial] CUSE failed (${err.message}), falling back to PTY`);
47
+ this.cuseAvailable = false;
48
+ if (!this.checkPtyAvailable()) {
49
+ throw new Error('Serial passthrough not available: native PTY module not built. Run npm run build:serial on Linux.');
50
+ }
51
+ const pty = createPtyPair();
52
+ device = pty;
53
+ devicePath = pty.slavePath;
54
+ controlSignalsSupported = false;
55
+ console.log(`[serial] Created PTY pair: master=${pty.masterFd}, slave=${pty.slavePath}`);
56
+ }
57
+ }
58
+ else if (this.checkPtyAvailable()) {
59
+ const pty = createPtyPair();
60
+ device = pty;
61
+ devicePath = pty.slavePath;
62
+ controlSignalsSupported = false;
63
+ console.log(`[serial] Created PTY pair: master=${pty.masterFd}, slave=${pty.slavePath}`);
64
+ }
65
+ else {
66
+ throw new Error('Serial passthrough not available on this platform. Requires Linux with pty_pair native module built.');
67
+ }
68
+ let resolveReady = null;
69
+ let rejectReady = null;
70
+ const readyPromise = new Promise((resolve, reject) => {
71
+ resolveReady = resolve;
72
+ rejectReady = reject;
73
+ });
74
+ const request = {
75
+ requestId,
76
+ params,
77
+ device,
78
+ devicePath,
79
+ controlSignalsSupported,
80
+ status: 'pending',
81
+ browserWs: null,
82
+ resolveReady,
83
+ rejectReady,
84
+ modemPollInterval: null,
85
+ readPollInterval: null,
86
+ lastModemBits: { dtr: false, rts: false },
87
+ };
88
+ this.requests.set(requestId, request);
89
+ return { devicePath, controlSignalsSupported, readyPromise };
90
+ }
91
+ getRequest(requestId) {
92
+ return this.requests.get(requestId);
93
+ }
94
+ connectBrowser(requestId, ws) {
95
+ const req = this.requests.get(requestId);
96
+ if (!req || req.status !== 'pending')
97
+ return false;
98
+ req.browserWs = ws;
99
+ req.status = 'connected';
100
+ // Start piping device reads → browser (poll every 5ms for low latency)
101
+ req.readPollInterval = setInterval(() => {
102
+ if (req.device.closed || ws.readyState !== WebSocket.OPEN) {
103
+ this.closeRequest(requestId);
104
+ return;
105
+ }
106
+ const data = req.device.read();
107
+ if (data) {
108
+ ws.send(data);
109
+ }
110
+ }, 5);
111
+ // Forward modem signal changes to browser
112
+ if ('onModemBitsChanged' in req.device) {
113
+ // CUSE device: event-driven, immediate forwarding for precise reset timing
114
+ req.device.onModemBitsChanged = (bits) => {
115
+ if (ws.readyState !== WebSocket.OPEN)
116
+ return;
117
+ req.lastModemBits = { ...bits };
118
+ ws.send(JSON.stringify({ type: 'set_signals', signals: { dtr: bits.dtr, rts: bits.rts } }));
119
+ };
120
+ }
121
+ else {
122
+ // PTY fallback: poll modem bits (no callback support)
123
+ req.modemPollInterval = setInterval(() => {
124
+ if (req.device.closed || ws.readyState !== WebSocket.OPEN)
125
+ return;
126
+ const bits = req.device.getModemBits();
127
+ if (bits.dtr !== req.lastModemBits.dtr || bits.rts !== req.lastModemBits.rts) {
128
+ req.lastModemBits = { ...bits };
129
+ ws.send(JSON.stringify({ type: 'set_signals', signals: { dtr: bits.dtr, rts: bits.rts } }));
130
+ }
131
+ }, 50);
132
+ }
133
+ // Resolve the ready promise
134
+ req.resolveReady?.({ devicePath: req.devicePath, controlSignalsSupported: req.controlSignalsSupported, usbVendorId: null, usbProductId: null });
135
+ req.resolveReady = null;
136
+ req.rejectReady = null;
137
+ console.log(`[serial] Browser connected for request ${requestId}, device=${req.devicePath}, controlSignals=${req.controlSignalsSupported}`);
138
+ return true;
139
+ }
140
+ handleBrowserData(requestId, data) {
141
+ const req = this.requests.get(requestId);
142
+ if (!req || req.device.closed)
143
+ return;
144
+ req.device.write(data);
145
+ }
146
+ handleBrowserControl(requestId, msg) {
147
+ const req = this.requests.get(requestId);
148
+ if (!req)
149
+ return;
150
+ if (msg.type === 'ready') {
151
+ // Browser has opened the serial port - handled in connectBrowser
152
+ }
153
+ else if (msg.type === 'error' || msg.type === 'closed') {
154
+ console.log(`[serial] Browser reported ${msg.type} for ${requestId}: ${msg.message || ''}`);
155
+ this.closeRequest(requestId);
156
+ }
157
+ }
158
+ rejectRequest(requestId, err) {
159
+ const req = this.requests.get(requestId);
160
+ if (!req)
161
+ return;
162
+ req.rejectReady?.(err);
163
+ this.closeRequest(requestId);
164
+ }
165
+ closeRequest(requestId) {
166
+ const req = this.requests.get(requestId);
167
+ if (!req)
168
+ return;
169
+ console.log(`[serial] Closing request ${requestId}`);
170
+ if (req.readPollInterval)
171
+ clearInterval(req.readPollInterval);
172
+ if (req.modemPollInterval)
173
+ clearInterval(req.modemPollInterval);
174
+ if (!req.device.closed)
175
+ req.device.close();
176
+ if (req.browserWs && req.browserWs.readyState === WebSocket.OPEN) {
177
+ try {
178
+ req.browserWs.send(JSON.stringify({ type: 'close' }));
179
+ }
180
+ catch { }
181
+ try {
182
+ req.browserWs.close();
183
+ }
184
+ catch { }
185
+ }
186
+ // Reject if still pending
187
+ req.rejectReady?.(new Error('Serial request closed'));
188
+ req.status = 'closed';
189
+ this.requests.delete(requestId);
190
+ // Broadcast serial_closed to all browsers
191
+ const msg = JSON.stringify({ type: 'serial_closed', requestId });
192
+ for (const ws of store.statusClients) {
193
+ if (ws.readyState === 1)
194
+ ws.send(msg);
195
+ }
196
+ }
197
+ getActiveRequests() {
198
+ return Array.from(this.requests.values()).map(r => ({
199
+ requestId: r.requestId,
200
+ devicePath: r.devicePath,
201
+ status: r.status,
202
+ controlSignalsSupported: r.controlSignalsSupported,
203
+ }));
204
+ }
205
+ }
206
+ export const serialManager = new SerialManager();
@@ -0,0 +1,16 @@
1
+ export declare function isPtyAvailable(): boolean;
2
+ export interface PtyPair {
3
+ masterFd: number;
4
+ slavePath: string;
5
+ write(data: Buffer): number;
6
+ read(): Buffer | null;
7
+ getModemBits(): {
8
+ dtr: boolean;
9
+ rts: boolean;
10
+ };
11
+ setModemBits(dtr: boolean, rts: boolean): void;
12
+ close(): void;
13
+ closed: boolean;
14
+ controlSignalsSupported: false;
15
+ }
16
+ export declare function createPtyPair(): PtyPair;
@@ -0,0 +1,68 @@
1
+ import { createRequire } from 'module';
2
+ import path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
5
+ const require = createRequire(import.meta.url);
6
+ let native = null;
7
+ function loadNative() {
8
+ if (native)
9
+ return native;
10
+ try {
11
+ native = require(path.join(__dirname, 'native', 'build', 'Release', 'pty_pair.node'));
12
+ }
13
+ catch {
14
+ // Fallback: when running from dist/, the native dir is at the source location
15
+ native = require(path.join(__dirname, '..', '..', '..', 'src', 'serial', 'native', 'build', 'Release', 'pty_pair.node'));
16
+ }
17
+ return native;
18
+ }
19
+ export function isPtyAvailable() {
20
+ try {
21
+ loadNative();
22
+ return true;
23
+ }
24
+ catch {
25
+ return false;
26
+ }
27
+ }
28
+ const READ_BUF_SIZE = 4096;
29
+ export function createPtyPair() {
30
+ const n = loadNative();
31
+ const { masterFd, slavePath } = n.createPtyPair();
32
+ const readBuf = Buffer.alloc(READ_BUF_SIZE);
33
+ let closed = false;
34
+ return {
35
+ masterFd,
36
+ slavePath,
37
+ controlSignalsSupported: false,
38
+ get closed() { return closed; },
39
+ write(data) {
40
+ if (closed)
41
+ return -1;
42
+ return n.writeMaster(masterFd, data, data.length);
43
+ },
44
+ read() {
45
+ if (closed)
46
+ return null;
47
+ const nr = n.readMaster(masterFd, readBuf);
48
+ if (nr <= 0)
49
+ return null; // 0 = EAGAIN, -1 = closed/error
50
+ return Buffer.from(readBuf.subarray(0, nr));
51
+ },
52
+ getModemBits() {
53
+ if (closed)
54
+ return { dtr: false, rts: false };
55
+ return n.getModemBits(masterFd);
56
+ },
57
+ setModemBits(dtr, rts) {
58
+ if (!closed)
59
+ n.setModemBits(masterFd, dtr, rts);
60
+ },
61
+ close() {
62
+ if (!closed) {
63
+ closed = true;
64
+ n.closeFd(masterFd);
65
+ }
66
+ },
67
+ };
68
+ }
@@ -0,0 +1,14 @@
1
+ interface FileNode {
2
+ name: string;
3
+ type: 'file' | 'dir';
4
+ children?: FileNode[];
5
+ }
6
+ export declare function getFileTree(dirPath: string, depth?: number, showHidden?: boolean, maxDepth?: number): Promise<FileNode[]>;
7
+ export declare function isBinaryFile(filePath: string): boolean;
8
+ export declare function readFileContent(filePath: string): {
9
+ content: string;
10
+ lang: string;
11
+ isBinary?: boolean;
12
+ size?: number;
13
+ };
14
+ export {};