@creezio/electron-shell 0.22.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 (563) hide show
  1. package/README.md +351 -0
  2. package/dist/.creezio-src-hash.json +4 -0
  3. package/dist/admin-window.d.ts +18 -0
  4. package/dist/admin-window.d.ts.map +1 -0
  5. package/dist/admin-window.js +75 -0
  6. package/dist/admin-window.js.map +1 -0
  7. package/dist/boot.d.ts +36 -0
  8. package/dist/boot.d.ts.map +1 -0
  9. package/dist/boot.js +99 -0
  10. package/dist/boot.js.map +1 -0
  11. package/dist/desktop/assistant-chrome.d.ts +42 -0
  12. package/dist/desktop/assistant-chrome.d.ts.map +1 -0
  13. package/dist/desktop/assistant-chrome.js +178 -0
  14. package/dist/desktop/assistant-chrome.js.map +1 -0
  15. package/dist/desktop/brand-desktop-runtime.d.ts +72 -0
  16. package/dist/desktop/brand-desktop-runtime.d.ts.map +1 -0
  17. package/dist/desktop/brand-desktop-runtime.js +3926 -0
  18. package/dist/desktop/brand-desktop-runtime.js.map +1 -0
  19. package/dist/desktop/desktop-session.d.ts +85 -0
  20. package/dist/desktop/desktop-session.d.ts.map +1 -0
  21. package/dist/desktop/desktop-session.js +163 -0
  22. package/dist/desktop/desktop-session.js.map +1 -0
  23. package/dist/desktop/error-page-html.d.ts +16 -0
  24. package/dist/desktop/error-page-html.d.ts.map +1 -0
  25. package/dist/desktop/error-page-html.js +88 -0
  26. package/dist/desktop/error-page-html.js.map +1 -0
  27. package/dist/desktop/legacy-brand-compat.d.ts +45 -0
  28. package/dist/desktop/legacy-brand-compat.d.ts.map +1 -0
  29. package/dist/desktop/legacy-brand-compat.js +49 -0
  30. package/dist/desktop/legacy-brand-compat.js.map +1 -0
  31. package/dist/desktop/oauth-loopback.d.ts +28 -0
  32. package/dist/desktop/oauth-loopback.d.ts.map +1 -0
  33. package/dist/desktop/oauth-loopback.js +137 -0
  34. package/dist/desktop/oauth-loopback.js.map +1 -0
  35. package/dist/desktop/profile-picker-html.d.ts +27 -0
  36. package/dist/desktop/profile-picker-html.d.ts.map +1 -0
  37. package/dist/desktop/profile-picker-html.js +213 -0
  38. package/dist/desktop/profile-picker-html.js.map +1 -0
  39. package/dist/desktop/remote-offline-html.d.ts +14 -0
  40. package/dist/desktop/remote-offline-html.d.ts.map +1 -0
  41. package/dist/desktop/remote-offline-html.js +88 -0
  42. package/dist/desktop/remote-offline-html.js.map +1 -0
  43. package/dist/factory-reset-runtime.d.ts +11 -0
  44. package/dist/factory-reset-runtime.d.ts.map +1 -0
  45. package/dist/factory-reset-runtime.js +77 -0
  46. package/dist/factory-reset-runtime.js.map +1 -0
  47. package/dist/host/ai-workspace/actions.d.ts +12 -0
  48. package/dist/host/ai-workspace/actions.d.ts.map +1 -0
  49. package/dist/host/ai-workspace/actions.js +243 -0
  50. package/dist/host/ai-workspace/actions.js.map +1 -0
  51. package/dist/host/ai-workspace/bindings.d.ts +51 -0
  52. package/dist/host/ai-workspace/bindings.d.ts.map +1 -0
  53. package/dist/host/ai-workspace/bindings.js +40 -0
  54. package/dist/host/ai-workspace/bindings.js.map +1 -0
  55. package/dist/host/ai-workspace/index.d.ts +11 -0
  56. package/dist/host/ai-workspace/index.d.ts.map +1 -0
  57. package/dist/host/ai-workspace/index.js +6 -0
  58. package/dist/host/ai-workspace/index.js.map +1 -0
  59. package/dist/host/ai-workspace/manager.d.ts +128 -0
  60. package/dist/host/ai-workspace/manager.d.ts.map +1 -0
  61. package/dist/host/ai-workspace/manager.js +519 -0
  62. package/dist/host/ai-workspace/manager.js.map +1 -0
  63. package/dist/host/ai-workspace/profile-window.d.ts +37 -0
  64. package/dist/host/ai-workspace/profile-window.d.ts.map +1 -0
  65. package/dist/host/ai-workspace/profile-window.js +121 -0
  66. package/dist/host/ai-workspace/profile-window.js.map +1 -0
  67. package/dist/host/ai-workspace/screencast.d.ts +56 -0
  68. package/dist/host/ai-workspace/screencast.d.ts.map +1 -0
  69. package/dist/host/ai-workspace/screencast.js +245 -0
  70. package/dist/host/ai-workspace/screencast.js.map +1 -0
  71. package/dist/host/ai-workspace/types.d.ts +40 -0
  72. package/dist/host/ai-workspace/types.d.ts.map +1 -0
  73. package/dist/host/ai-workspace/types.js +6 -0
  74. package/dist/host/ai-workspace/types.js.map +1 -0
  75. package/dist/host/brand-host-runtime.d.ts +107 -0
  76. package/dist/host/brand-host-runtime.d.ts.map +1 -0
  77. package/dist/host/brand-host-runtime.js +274 -0
  78. package/dist/host/brand-host-runtime.js.map +1 -0
  79. package/dist/host/brand-host-stack.d.ts +117 -0
  80. package/dist/host/brand-host-stack.d.ts.map +1 -0
  81. package/dist/host/brand-host-stack.js +253 -0
  82. package/dist/host/brand-host-stack.js.map +1 -0
  83. package/dist/host/brand-kernel-http.d.ts +34 -0
  84. package/dist/host/brand-kernel-http.d.ts.map +1 -0
  85. package/dist/host/brand-kernel-http.js +95 -0
  86. package/dist/host/brand-kernel-http.js.map +1 -0
  87. package/dist/host/brand-meili-boot.d.ts +67 -0
  88. package/dist/host/brand-meili-boot.d.ts.map +1 -0
  89. package/dist/host/brand-meili-boot.js +100 -0
  90. package/dist/host/brand-meili-boot.js.map +1 -0
  91. package/dist/host/bridge-client.d.ts +54 -0
  92. package/dist/host/bridge-client.d.ts.map +1 -0
  93. package/dist/host/bridge-client.js +187 -0
  94. package/dist/host/bridge-client.js.map +1 -0
  95. package/dist/host/browser-tabs/browser-tab-driver.d.ts +45 -0
  96. package/dist/host/browser-tabs/browser-tab-driver.d.ts.map +1 -0
  97. package/dist/host/browser-tabs/browser-tab-driver.js +154 -0
  98. package/dist/host/browser-tabs/browser-tab-driver.js.map +1 -0
  99. package/dist/host/browser-tabs/browser-tab-manager.d.ts +208 -0
  100. package/dist/host/browser-tabs/browser-tab-manager.d.ts.map +1 -0
  101. package/dist/host/browser-tabs/browser-tab-manager.js +758 -0
  102. package/dist/host/browser-tabs/browser-tab-manager.js.map +1 -0
  103. package/dist/host/browser-tabs/browser-tab-preload-path.d.ts +2 -0
  104. package/dist/host/browser-tabs/browser-tab-preload-path.d.ts.map +1 -0
  105. package/dist/host/browser-tabs/browser-tab-preload-path.js +29 -0
  106. package/dist/host/browser-tabs/browser-tab-preload-path.js.map +1 -0
  107. package/dist/host/browser-tabs/browser-tab-preload.d.ts +11 -0
  108. package/dist/host/browser-tabs/browser-tab-preload.d.ts.map +1 -0
  109. package/dist/host/browser-tabs/browser-tab-preload.js +11 -0
  110. package/dist/host/browser-tabs/browser-tab-preload.js.map +1 -0
  111. package/dist/host/browser-tabs/chrome-ua.d.ts +19 -0
  112. package/dist/host/browser-tabs/chrome-ua.d.ts.map +1 -0
  113. package/dist/host/browser-tabs/chrome-ua.js +37 -0
  114. package/dist/host/browser-tabs/chrome-ua.js.map +1 -0
  115. package/dist/host/browser-tabs/fake-cursor-inject.d.ts +7 -0
  116. package/dist/host/browser-tabs/fake-cursor-inject.d.ts.map +1 -0
  117. package/dist/host/browser-tabs/fake-cursor-inject.js +7 -0
  118. package/dist/host/browser-tabs/fake-cursor-inject.js.map +1 -0
  119. package/dist/host/browser-tabs/index.d.ts +13 -0
  120. package/dist/host/browser-tabs/index.d.ts.map +1 -0
  121. package/dist/host/browser-tabs/index.js +13 -0
  122. package/dist/host/browser-tabs/index.js.map +1 -0
  123. package/dist/host/browser-tabs/tab-load-state.d.ts +56 -0
  124. package/dist/host/browser-tabs/tab-load-state.d.ts.map +1 -0
  125. package/dist/host/browser-tabs/tab-load-state.js +56 -0
  126. package/dist/host/browser-tabs/tab-load-state.js.map +1 -0
  127. package/dist/host/browser-tabs/tab-url.d.ts +10 -0
  128. package/dist/host/browser-tabs/tab-url.d.ts.map +1 -0
  129. package/dist/host/browser-tabs/tab-url.js +57 -0
  130. package/dist/host/browser-tabs/tab-url.js.map +1 -0
  131. package/dist/host/context.d.ts +70 -0
  132. package/dist/host/context.d.ts.map +1 -0
  133. package/dist/host/context.js +16 -0
  134. package/dist/host/context.js.map +1 -0
  135. package/dist/host/contracts.d.ts +39 -0
  136. package/dist/host/contracts.d.ts.map +1 -0
  137. package/dist/host/contracts.js +26 -0
  138. package/dist/host/contracts.js.map +1 -0
  139. package/dist/host/crash-reporter.d.ts +65 -0
  140. package/dist/host/crash-reporter.d.ts.map +1 -0
  141. package/dist/host/crash-reporter.js +371 -0
  142. package/dist/host/crash-reporter.js.map +1 -0
  143. package/dist/host/ensure-kit-binaries.d.ts +17 -0
  144. package/dist/host/ensure-kit-binaries.d.ts.map +1 -0
  145. package/dist/host/ensure-kit-binaries.js +205 -0
  146. package/dist/host/ensure-kit-binaries.js.map +1 -0
  147. package/dist/host/feature-off-host.d.ts +130 -0
  148. package/dist/host/feature-off-host.d.ts.map +1 -0
  149. package/dist/host/feature-off-host.js +138 -0
  150. package/dist/host/feature-off-host.js.map +1 -0
  151. package/dist/host/hermes/crm-key.d.ts +49 -0
  152. package/dist/host/hermes/crm-key.d.ts.map +1 -0
  153. package/dist/host/hermes/crm-key.js +126 -0
  154. package/dist/host/hermes/crm-key.js.map +1 -0
  155. package/dist/host/hermes/ensure-crm-key-db.d.ts +7 -0
  156. package/dist/host/hermes/ensure-crm-key-db.d.ts.map +1 -0
  157. package/dist/host/hermes/ensure-crm-key-db.js +84 -0
  158. package/dist/host/hermes/ensure-crm-key-db.js.map +1 -0
  159. package/dist/host/hermes/launcher.d.ts +98 -0
  160. package/dist/host/hermes/launcher.d.ts.map +1 -0
  161. package/dist/host/hermes/launcher.js +972 -0
  162. package/dist/host/hermes/launcher.js.map +1 -0
  163. package/dist/host/hermes/runtime-bootstrap.d.ts +172 -0
  164. package/dist/host/hermes/runtime-bootstrap.d.ts.map +1 -0
  165. package/dist/host/hermes/runtime-bootstrap.js +789 -0
  166. package/dist/host/hermes/runtime-bootstrap.js.map +1 -0
  167. package/dist/host/hermes/skills-seed.d.ts +40 -0
  168. package/dist/host/hermes/skills-seed.d.ts.map +1 -0
  169. package/dist/host/hermes/skills-seed.js +100 -0
  170. package/dist/host/hermes/skills-seed.js.map +1 -0
  171. package/dist/host/host-stack.d.ts +35 -0
  172. package/dist/host/host-stack.d.ts.map +1 -0
  173. package/dist/host/host-stack.js +38 -0
  174. package/dist/host/host-stack.js.map +1 -0
  175. package/dist/host/kit-os-resources.d.ts +6 -0
  176. package/dist/host/kit-os-resources.d.ts.map +1 -0
  177. package/dist/host/kit-os-resources.js +88 -0
  178. package/dist/host/kit-os-resources.js.map +1 -0
  179. package/dist/host/load-electron.d.ts +2 -0
  180. package/dist/host/load-electron.d.ts.map +1 -0
  181. package/dist/host/load-electron.js +44 -0
  182. package/dist/host/load-electron.js.map +1 -0
  183. package/dist/host/local-config.d.ts +120 -0
  184. package/dist/host/local-config.d.ts.map +1 -0
  185. package/dist/host/local-config.js +633 -0
  186. package/dist/host/local-config.js.map +1 -0
  187. package/dist/host/meili/browse.d.ts +58 -0
  188. package/dist/host/meili/browse.d.ts.map +1 -0
  189. package/dist/host/meili/browse.js +98 -0
  190. package/dist/host/meili/browse.js.map +1 -0
  191. package/dist/host/meili/coherence-db.d.ts +35 -0
  192. package/dist/host/meili/coherence-db.d.ts.map +1 -0
  193. package/dist/host/meili/coherence-db.js +129 -0
  194. package/dist/host/meili/coherence-db.js.map +1 -0
  195. package/dist/host/meili/coherence-query.d.ts +10 -0
  196. package/dist/host/meili/coherence-query.d.ts.map +1 -0
  197. package/dist/host/meili/coherence-query.js +23 -0
  198. package/dist/host/meili/coherence-query.js.map +1 -0
  199. package/dist/host/meili/coherence.d.ts +53 -0
  200. package/dist/host/meili/coherence.d.ts.map +1 -0
  201. package/dist/host/meili/coherence.js +148 -0
  202. package/dist/host/meili/coherence.js.map +1 -0
  203. package/dist/host/meili/feed.d.ts +82 -0
  204. package/dist/host/meili/feed.d.ts.map +1 -0
  205. package/dist/host/meili/feed.js +100 -0
  206. package/dist/host/meili/feed.js.map +1 -0
  207. package/dist/host/meili/generic-indexer.d.ts +34 -0
  208. package/dist/host/meili/generic-indexer.d.ts.map +1 -0
  209. package/dist/host/meili/generic-indexer.js +333 -0
  210. package/dist/host/meili/generic-indexer.js.map +1 -0
  211. package/dist/host/meili/index-schema.d.ts +64 -0
  212. package/dist/host/meili/index-schema.d.ts.map +1 -0
  213. package/dist/host/meili/index-schema.js +70 -0
  214. package/dist/host/meili/index-schema.js.map +1 -0
  215. package/dist/host/meili/index.d.ts +13 -0
  216. package/dist/host/meili/index.d.ts.map +1 -0
  217. package/dist/host/meili/index.js +8 -0
  218. package/dist/host/meili/index.js.map +1 -0
  219. package/dist/host/meili/indexer.d.ts +31 -0
  220. package/dist/host/meili/indexer.d.ts.map +1 -0
  221. package/dist/host/meili/indexer.js +49 -0
  222. package/dist/host/meili/indexer.js.map +1 -0
  223. package/dist/host/meili-launcher.d.ts +30 -0
  224. package/dist/host/meili-launcher.d.ts.map +1 -0
  225. package/dist/host/meili-launcher.js +115 -0
  226. package/dist/host/meili-launcher.js.map +1 -0
  227. package/dist/host/n8n/agent-isolation.d.ts +55 -0
  228. package/dist/host/n8n/agent-isolation.d.ts.map +1 -0
  229. package/dist/host/n8n/agent-isolation.js +158 -0
  230. package/dist/host/n8n/agent-isolation.js.map +1 -0
  231. package/dist/host/n8n/api-key.d.ts +67 -0
  232. package/dist/host/n8n/api-key.d.ts.map +1 -0
  233. package/dist/host/n8n/api-key.js +297 -0
  234. package/dist/host/n8n/api-key.js.map +1 -0
  235. package/dist/host/n8n/launcher.d.ts +126 -0
  236. package/dist/host/n8n/launcher.d.ts.map +1 -0
  237. package/dist/host/n8n/launcher.js +1170 -0
  238. package/dist/host/n8n/launcher.js.map +1 -0
  239. package/dist/host/n8n/runtime-bootstrap.d.ts +44 -0
  240. package/dist/host/n8n/runtime-bootstrap.d.ts.map +1 -0
  241. package/dist/host/n8n/runtime-bootstrap.js +230 -0
  242. package/dist/host/n8n/runtime-bootstrap.js.map +1 -0
  243. package/dist/host/node-runtime.d.ts +52 -0
  244. package/dist/host/node-runtime.d.ts.map +1 -0
  245. package/dist/host/node-runtime.js +257 -0
  246. package/dist/host/node-runtime.js.map +1 -0
  247. package/dist/host/npm-cli.d.ts +43 -0
  248. package/dist/host/npm-cli.d.ts.map +1 -0
  249. package/dist/host/npm-cli.js +213 -0
  250. package/dist/host/npm-cli.js.map +1 -0
  251. package/dist/host/plugins/accept-check.d.ts +19 -0
  252. package/dist/host/plugins/accept-check.d.ts.map +1 -0
  253. package/dist/host/plugins/accept-check.js +172 -0
  254. package/dist/host/plugins/accept-check.js.map +1 -0
  255. package/dist/host/plugins/brand-bindings.d.ts +103 -0
  256. package/dist/host/plugins/brand-bindings.d.ts.map +1 -0
  257. package/dist/host/plugins/brand-bindings.js +65 -0
  258. package/dist/host/plugins/brand-bindings.js.map +1 -0
  259. package/dist/host/plugins/control-adapters.d.ts +11 -0
  260. package/dist/host/plugins/control-adapters.d.ts.map +1 -0
  261. package/dist/host/plugins/control-adapters.js +83 -0
  262. package/dist/host/plugins/control-adapters.js.map +1 -0
  263. package/dist/host/plugins/control-extras.d.ts +61 -0
  264. package/dist/host/plugins/control-extras.d.ts.map +1 -0
  265. package/dist/host/plugins/control-extras.js +382 -0
  266. package/dist/host/plugins/control-extras.js.map +1 -0
  267. package/dist/host/plugins/control-plane.d.ts +42 -0
  268. package/dist/host/plugins/control-plane.d.ts.map +1 -0
  269. package/dist/host/plugins/control-plane.js +124 -0
  270. package/dist/host/plugins/control-plane.js.map +1 -0
  271. package/dist/host/plugins/control-token.d.ts +24 -0
  272. package/dist/host/plugins/control-token.d.ts.map +1 -0
  273. package/dist/host/plugins/control-token.js +77 -0
  274. package/dist/host/plugins/control-token.js.map +1 -0
  275. package/dist/host/plugins/crm-key.d.ts +25 -0
  276. package/dist/host/plugins/crm-key.d.ts.map +1 -0
  277. package/dist/host/plugins/crm-key.js +126 -0
  278. package/dist/host/plugins/crm-key.js.map +1 -0
  279. package/dist/host/plugins/data.d.ts +21 -0
  280. package/dist/host/plugins/data.d.ts.map +1 -0
  281. package/dist/host/plugins/data.js +100 -0
  282. package/dist/host/plugins/data.js.map +1 -0
  283. package/dist/host/plugins/events.d.ts +6 -0
  284. package/dist/host/plugins/events.d.ts.map +1 -0
  285. package/dist/host/plugins/events.js +6 -0
  286. package/dist/host/plugins/events.js.map +1 -0
  287. package/dist/host/plugins/execution-grant.d.ts +6 -0
  288. package/dist/host/plugins/execution-grant.d.ts.map +1 -0
  289. package/dist/host/plugins/execution-grant.js +6 -0
  290. package/dist/host/plugins/execution-grant.js.map +1 -0
  291. package/dist/host/plugins/git.d.ts +56 -0
  292. package/dist/host/plugins/git.d.ts.map +1 -0
  293. package/dist/host/plugins/git.js +357 -0
  294. package/dist/host/plugins/git.js.map +1 -0
  295. package/dist/host/plugins/host.d.ts +68 -0
  296. package/dist/host/plugins/host.d.ts.map +1 -0
  297. package/dist/host/plugins/host.js +276 -0
  298. package/dist/host/plugins/host.js.map +1 -0
  299. package/dist/host/plugins/launcher.d.ts +146 -0
  300. package/dist/host/plugins/launcher.d.ts.map +1 -0
  301. package/dist/host/plugins/launcher.js +489 -0
  302. package/dist/host/plugins/launcher.js.map +1 -0
  303. package/dist/host/plugins/runtime.d.ts +28 -0
  304. package/dist/host/plugins/runtime.d.ts.map +1 -0
  305. package/dist/host/plugins/runtime.js +430 -0
  306. package/dist/host/plugins/runtime.js.map +1 -0
  307. package/dist/host/plugins/test-runner.d.ts +15 -0
  308. package/dist/host/plugins/test-runner.d.ts.map +1 -0
  309. package/dist/host/plugins/test-runner.js +106 -0
  310. package/dist/host/plugins/test-runner.js.map +1 -0
  311. package/dist/host/safe-storage.d.ts +21 -0
  312. package/dist/host/safe-storage.d.ts.map +1 -0
  313. package/dist/host/safe-storage.js +55 -0
  314. package/dist/host/safe-storage.js.map +1 -0
  315. package/dist/host/sandbox/embed-sandbox.d.ts +133 -0
  316. package/dist/host/sandbox/embed-sandbox.d.ts.map +1 -0
  317. package/dist/host/sandbox/embed-sandbox.js +378 -0
  318. package/dist/host/sandbox/embed-sandbox.js.map +1 -0
  319. package/dist/host/sandbox/os-sandbox.d.ts +41 -0
  320. package/dist/host/sandbox/os-sandbox.d.ts.map +1 -0
  321. package/dist/host/sandbox/os-sandbox.js +98 -0
  322. package/dist/host/sandbox/os-sandbox.js.map +1 -0
  323. package/dist/host/server-env.d.ts +50 -0
  324. package/dist/host/server-env.d.ts.map +1 -0
  325. package/dist/host/server-env.js +64 -0
  326. package/dist/host/server-env.js.map +1 -0
  327. package/dist/host/server-launcher.d.ts +49 -0
  328. package/dist/host/server-launcher.d.ts.map +1 -0
  329. package/dist/host/server-launcher.js +43 -0
  330. package/dist/host/server-launcher.js.map +1 -0
  331. package/dist/host/tunnel/cloudflared-respawn.d.ts +58 -0
  332. package/dist/host/tunnel/cloudflared-respawn.d.ts.map +1 -0
  333. package/dist/host/tunnel/cloudflared-respawn.js +73 -0
  334. package/dist/host/tunnel/cloudflared-respawn.js.map +1 -0
  335. package/dist/host/tunnel/tunnel.d.ts +72 -0
  336. package/dist/host/tunnel/tunnel.d.ts.map +1 -0
  337. package/dist/host/tunnel/tunnel.js +462 -0
  338. package/dist/host/tunnel/tunnel.js.map +1 -0
  339. package/dist/host/web-telemetry.d.ts +16 -0
  340. package/dist/host/web-telemetry.d.ts.map +1 -0
  341. package/dist/host/web-telemetry.js +97 -0
  342. package/dist/host/web-telemetry.js.map +1 -0
  343. package/dist/index.d.ts +198 -0
  344. package/dist/index.d.ts.map +1 -0
  345. package/dist/index.js +102 -0
  346. package/dist/index.js.map +1 -0
  347. package/dist/logger.d.ts +44 -0
  348. package/dist/logger.d.ts.map +1 -0
  349. package/dist/logger.js +252 -0
  350. package/dist/logger.js.map +1 -0
  351. package/dist/main-facade.d.ts +51 -0
  352. package/dist/main-facade.d.ts.map +1 -0
  353. package/dist/main-facade.js +96 -0
  354. package/dist/main-facade.js.map +1 -0
  355. package/dist/meili.d.ts +19 -0
  356. package/dist/meili.d.ts.map +1 -0
  357. package/dist/meili.js +14 -0
  358. package/dist/meili.js.map +1 -0
  359. package/dist/splash-ui.d.ts +69 -0
  360. package/dist/splash-ui.d.ts.map +1 -0
  361. package/dist/splash-ui.js +431 -0
  362. package/dist/splash-ui.js.map +1 -0
  363. package/dist/tray.d.ts +44 -0
  364. package/dist/tray.d.ts.map +1 -0
  365. package/dist/tray.js +173 -0
  366. package/dist/tray.js.map +1 -0
  367. package/dist/updater.d.ts +36 -0
  368. package/dist/updater.d.ts.map +1 -0
  369. package/dist/updater.js +257 -0
  370. package/dist/updater.js.map +1 -0
  371. package/dist/window-chrome.d.ts +12 -0
  372. package/dist/window-chrome.d.ts.map +1 -0
  373. package/dist/window-chrome.js +93 -0
  374. package/dist/window-chrome.js.map +1 -0
  375. package/dist-cjs/admin-window.js +116 -0
  376. package/dist-cjs/admin-window.js.map +1 -0
  377. package/dist-cjs/boot.js +139 -0
  378. package/dist-cjs/boot.js.map +1 -0
  379. package/dist-cjs/desktop/assistant-chrome.js +184 -0
  380. package/dist-cjs/desktop/assistant-chrome.js.map +1 -0
  381. package/dist-cjs/desktop/brand-desktop-runtime.js +3932 -0
  382. package/dist-cjs/desktop/brand-desktop-runtime.js.map +1 -0
  383. package/dist-cjs/desktop/desktop-session.js +171 -0
  384. package/dist-cjs/desktop/desktop-session.js.map +1 -0
  385. package/dist-cjs/desktop/error-page-html.js +92 -0
  386. package/dist-cjs/desktop/error-page-html.js.map +1 -0
  387. package/dist-cjs/desktop/legacy-brand-compat.js +56 -0
  388. package/dist-cjs/desktop/legacy-brand-compat.js.map +1 -0
  389. package/dist-cjs/desktop/oauth-loopback.js +144 -0
  390. package/dist-cjs/desktop/oauth-loopback.js.map +1 -0
  391. package/dist-cjs/desktop/profile-picker-html.js +216 -0
  392. package/dist-cjs/desktop/profile-picker-html.js.map +1 -0
  393. package/dist-cjs/desktop/remote-offline-html.js +91 -0
  394. package/dist-cjs/desktop/remote-offline-html.js.map +1 -0
  395. package/dist-cjs/factory-reset-runtime.js +117 -0
  396. package/dist-cjs/factory-reset-runtime.js.map +1 -0
  397. package/dist-cjs/host/ai-workspace/actions.js +247 -0
  398. package/dist-cjs/host/ai-workspace/actions.js.map +1 -0
  399. package/dist-cjs/host/ai-workspace/bindings.js +49 -0
  400. package/dist-cjs/host/ai-workspace/bindings.js.map +1 -0
  401. package/dist-cjs/host/ai-workspace/index.js +21 -0
  402. package/dist-cjs/host/ai-workspace/index.js.map +1 -0
  403. package/dist-cjs/host/ai-workspace/manager.js +528 -0
  404. package/dist-cjs/host/ai-workspace/manager.js.map +1 -0
  405. package/dist-cjs/host/ai-workspace/profile-window.js +125 -0
  406. package/dist-cjs/host/ai-workspace/profile-window.js.map +1 -0
  407. package/dist-cjs/host/ai-workspace/screencast.js +249 -0
  408. package/dist-cjs/host/ai-workspace/screencast.js.map +1 -0
  409. package/dist-cjs/host/ai-workspace/types.js +7 -0
  410. package/dist-cjs/host/ai-workspace/types.js.map +1 -0
  411. package/dist-cjs/host/brand-host-runtime.js +286 -0
  412. package/dist-cjs/host/brand-host-runtime.js.map +1 -0
  413. package/dist-cjs/host/brand-host-stack.js +259 -0
  414. package/dist-cjs/host/brand-host-stack.js.map +1 -0
  415. package/dist-cjs/host/brand-kernel-http.js +101 -0
  416. package/dist-cjs/host/brand-kernel-http.js.map +1 -0
  417. package/dist-cjs/host/brand-meili-boot.js +106 -0
  418. package/dist-cjs/host/brand-meili-boot.js.map +1 -0
  419. package/dist-cjs/host/bridge-client.js +191 -0
  420. package/dist-cjs/host/bridge-client.js.map +1 -0
  421. package/dist-cjs/host/browser-tabs/browser-tab-driver.js +158 -0
  422. package/dist-cjs/host/browser-tabs/browser-tab-driver.js.map +1 -0
  423. package/dist-cjs/host/browser-tabs/browser-tab-manager.js +766 -0
  424. package/dist-cjs/host/browser-tabs/browser-tab-manager.js.map +1 -0
  425. package/dist-cjs/host/browser-tabs/browser-tab-preload-path.js +35 -0
  426. package/dist-cjs/host/browser-tabs/browser-tab-preload-path.js.map +1 -0
  427. package/dist-cjs/host/browser-tabs/browser-tab-preload.js +12 -0
  428. package/dist-cjs/host/browser-tabs/browser-tab-preload.js.map +1 -0
  429. package/dist-cjs/host/browser-tabs/chrome-ua.js +41 -0
  430. package/dist-cjs/host/browser-tabs/chrome-ua.js.map +1 -0
  431. package/dist-cjs/host/browser-tabs/fake-cursor-inject.js +11 -0
  432. package/dist-cjs/host/browser-tabs/fake-cursor-inject.js.map +1 -0
  433. package/dist-cjs/host/browser-tabs/index.js +29 -0
  434. package/dist-cjs/host/browser-tabs/index.js.map +1 -0
  435. package/dist-cjs/host/browser-tabs/tab-load-state.js +59 -0
  436. package/dist-cjs/host/browser-tabs/tab-load-state.js.map +1 -0
  437. package/dist-cjs/host/browser-tabs/tab-url.js +62 -0
  438. package/dist-cjs/host/browser-tabs/tab-url.js.map +1 -0
  439. package/dist-cjs/host/context.js +20 -0
  440. package/dist-cjs/host/context.js.map +1 -0
  441. package/dist-cjs/host/contracts.js +32 -0
  442. package/dist-cjs/host/contracts.js.map +1 -0
  443. package/dist-cjs/host/crash-reporter.js +422 -0
  444. package/dist-cjs/host/crash-reporter.js.map +1 -0
  445. package/dist-cjs/host/ensure-kit-binaries.js +212 -0
  446. package/dist-cjs/host/ensure-kit-binaries.js.map +1 -0
  447. package/dist-cjs/host/feature-off-host.js +144 -0
  448. package/dist-cjs/host/feature-off-host.js.map +1 -0
  449. package/dist-cjs/host/hermes/crm-key.js +137 -0
  450. package/dist-cjs/host/hermes/crm-key.js.map +1 -0
  451. package/dist-cjs/host/hermes/ensure-crm-key-db.js +89 -0
  452. package/dist-cjs/host/hermes/ensure-crm-key-db.js.map +1 -0
  453. package/dist-cjs/host/hermes/launcher.js +981 -0
  454. package/dist-cjs/host/hermes/launcher.js.map +1 -0
  455. package/dist-cjs/host/hermes/runtime-bootstrap.js +853 -0
  456. package/dist-cjs/host/hermes/runtime-bootstrap.js.map +1 -0
  457. package/dist-cjs/host/hermes/skills-seed.js +110 -0
  458. package/dist-cjs/host/hermes/skills-seed.js.map +1 -0
  459. package/dist-cjs/host/host-stack.js +42 -0
  460. package/dist-cjs/host/host-stack.js.map +1 -0
  461. package/dist-cjs/host/kit-os-resources.js +96 -0
  462. package/dist-cjs/host/kit-os-resources.js.map +1 -0
  463. package/dist-cjs/host/load-electron.js +47 -0
  464. package/dist-cjs/host/load-electron.js.map +1 -0
  465. package/dist-cjs/host/local-config.js +640 -0
  466. package/dist-cjs/host/local-config.js.map +1 -0
  467. package/dist-cjs/host/meili/browse.js +103 -0
  468. package/dist-cjs/host/meili/browse.js.map +1 -0
  469. package/dist-cjs/host/meili/coherence-db.js +139 -0
  470. package/dist-cjs/host/meili/coherence-db.js.map +1 -0
  471. package/dist-cjs/host/meili/coherence-query.js +25 -0
  472. package/dist-cjs/host/meili/coherence-query.js.map +1 -0
  473. package/dist-cjs/host/meili/coherence.js +158 -0
  474. package/dist-cjs/host/meili/coherence.js.map +1 -0
  475. package/dist-cjs/host/meili/feed.js +108 -0
  476. package/dist-cjs/host/meili/feed.js.map +1 -0
  477. package/dist-cjs/host/meili/generic-indexer.js +340 -0
  478. package/dist-cjs/host/meili/generic-indexer.js.map +1 -0
  479. package/dist-cjs/host/meili/index-schema.js +79 -0
  480. package/dist-cjs/host/meili/index-schema.js.map +1 -0
  481. package/dist-cjs/host/meili/index.js +45 -0
  482. package/dist-cjs/host/meili/index.js.map +1 -0
  483. package/dist-cjs/host/meili/indexer.js +85 -0
  484. package/dist-cjs/host/meili/indexer.js.map +1 -0
  485. package/dist-cjs/host/meili-launcher.js +121 -0
  486. package/dist-cjs/host/meili-launcher.js.map +1 -0
  487. package/dist-cjs/host/n8n/agent-isolation.js +173 -0
  488. package/dist-cjs/host/n8n/agent-isolation.js.map +1 -0
  489. package/dist-cjs/host/n8n/api-key.js +314 -0
  490. package/dist-cjs/host/n8n/api-key.js.map +1 -0
  491. package/dist-cjs/host/n8n/launcher.js +1209 -0
  492. package/dist-cjs/host/n8n/launcher.js.map +1 -0
  493. package/dist-cjs/host/n8n/runtime-bootstrap.js +244 -0
  494. package/dist-cjs/host/n8n/runtime-bootstrap.js.map +1 -0
  495. package/dist-cjs/host/node-runtime.js +274 -0
  496. package/dist-cjs/host/node-runtime.js.map +1 -0
  497. package/dist-cjs/host/npm-cli.js +224 -0
  498. package/dist-cjs/host/npm-cli.js.map +1 -0
  499. package/dist-cjs/host/plugins/accept-check.js +176 -0
  500. package/dist-cjs/host/plugins/accept-check.js.map +1 -0
  501. package/dist-cjs/host/plugins/brand-bindings.js +78 -0
  502. package/dist-cjs/host/plugins/brand-bindings.js.map +1 -0
  503. package/dist-cjs/host/plugins/control-adapters.js +89 -0
  504. package/dist-cjs/host/plugins/control-adapters.js.map +1 -0
  505. package/dist-cjs/host/plugins/control-extras.js +397 -0
  506. package/dist-cjs/host/plugins/control-extras.js.map +1 -0
  507. package/dist-cjs/host/plugins/control-plane.js +130 -0
  508. package/dist-cjs/host/plugins/control-plane.js.map +1 -0
  509. package/dist-cjs/host/plugins/control-token.js +90 -0
  510. package/dist-cjs/host/plugins/control-token.js.map +1 -0
  511. package/dist-cjs/host/plugins/crm-key.js +135 -0
  512. package/dist-cjs/host/plugins/crm-key.js.map +1 -0
  513. package/dist-cjs/host/plugins/data.js +107 -0
  514. package/dist-cjs/host/plugins/data.js.map +1 -0
  515. package/dist-cjs/host/plugins/events.js +19 -0
  516. package/dist-cjs/host/plugins/events.js.map +1 -0
  517. package/dist-cjs/host/plugins/execution-grant.js +11 -0
  518. package/dist-cjs/host/plugins/execution-grant.js.map +1 -0
  519. package/dist-cjs/host/plugins/git.js +371 -0
  520. package/dist-cjs/host/plugins/git.js.map +1 -0
  521. package/dist-cjs/host/plugins/host.js +283 -0
  522. package/dist-cjs/host/plugins/host.js.map +1 -0
  523. package/dist-cjs/host/plugins/launcher.js +514 -0
  524. package/dist-cjs/host/plugins/launcher.js.map +1 -0
  525. package/dist-cjs/host/plugins/runtime.js +446 -0
  526. package/dist-cjs/host/plugins/runtime.js.map +1 -0
  527. package/dist-cjs/host/plugins/test-runner.js +112 -0
  528. package/dist-cjs/host/plugins/test-runner.js.map +1 -0
  529. package/dist-cjs/host/safe-storage.js +95 -0
  530. package/dist-cjs/host/safe-storage.js.map +1 -0
  531. package/dist-cjs/host/sandbox/embed-sandbox.js +396 -0
  532. package/dist-cjs/host/sandbox/embed-sandbox.js.map +1 -0
  533. package/dist-cjs/host/sandbox/os-sandbox.js +106 -0
  534. package/dist-cjs/host/sandbox/os-sandbox.js.map +1 -0
  535. package/dist-cjs/host/server-env.js +69 -0
  536. package/dist-cjs/host/server-env.js.map +1 -0
  537. package/dist-cjs/host/server-launcher.js +52 -0
  538. package/dist-cjs/host/server-launcher.js.map +1 -0
  539. package/dist-cjs/host/tunnel/cloudflared-respawn.js +80 -0
  540. package/dist-cjs/host/tunnel/cloudflared-respawn.js.map +1 -0
  541. package/dist-cjs/host/tunnel/tunnel.js +470 -0
  542. package/dist-cjs/host/tunnel/tunnel.js.map +1 -0
  543. package/dist-cjs/host/web-telemetry.js +100 -0
  544. package/dist-cjs/host/web-telemetry.js.map +1 -0
  545. package/dist-cjs/index.js +496 -0
  546. package/dist-cjs/index.js.map +1 -0
  547. package/dist-cjs/logger.js +269 -0
  548. package/dist-cjs/logger.js.map +1 -0
  549. package/dist-cjs/main-facade.js +139 -0
  550. package/dist-cjs/main-facade.js.map +1 -0
  551. package/dist-cjs/meili.js +51 -0
  552. package/dist-cjs/meili.js.map +1 -0
  553. package/dist-cjs/package.json +3 -0
  554. package/dist-cjs/splash-ui.js +447 -0
  555. package/dist-cjs/splash-ui.js.map +1 -0
  556. package/dist-cjs/tray.js +182 -0
  557. package/dist-cjs/tray.js.map +1 -0
  558. package/dist-cjs/updater.js +304 -0
  559. package/dist-cjs/updater.js.map +1 -0
  560. package/dist-cjs/window-chrome.js +98 -0
  561. package/dist-cjs/window-chrome.js.map +1 -0
  562. package/package.json +87 -0
  563. package/scripts/ensure-kit-binaries.mjs +73 -0
@@ -0,0 +1,1170 @@
1
+ /**
2
+ * Sidecar n8n — factory brand-agnostic.
3
+ * SoT extrait de TempoFlow n8n-launcher.ts (R3.3) — chemins gold intacts.
4
+ * Clés API / agent = hooks verticaux (onN8nReady, getN8nNextEnvExtra, n8nAgentKeys).
5
+ */
6
+ import { spawn, execFileSync } from "node:child_process";
7
+ import crypto from "node:crypto";
8
+ import fs from "node:fs";
9
+ import http from "node:http";
10
+ import path from "node:path";
11
+ import { buildNextN8nEnv, buildN8nSpawnEnv, describeN8nSpawnKind, EMBED_TOOL_SITE_IDS, N8N_DESKTOP_PORT, normalizeN8nPublicBaseUrl, n8nHomeLooksWarm as n8nHomeLooksWarmPure, n8nPublicStatus, resolveN8nEntry, sanitizeN8nEmbedConfig, shouldSpawnEmbeddedN8n, } from "@creezio/platform-core";
12
+ import { hostLog, hostProductName } from "../context.js";
13
+ import { resolveSystemBinary } from "../sandbox/os-sandbox.js";
14
+ import { buildIsolatedNodeEnv, DESKTOP_NODE_MIN_FOR_EMBEDS, ensureDesktopNode, } from "../node-runtime.js";
15
+ import { findFreePort } from "../server-env.js";
16
+ import { ensureN8nRuntime, getN8nBootstrapError, getN8nBootstrapPhase, n8nEntryPath, n8nRuntimeCacheDir, } from "./runtime-bootstrap.js";
17
+ import { cookieHeaderFromSetCookie, n8nLoginSucceeded, n8nNeedsOwnerSetup, } from "./api-key.js";
18
+ export function createN8nHost(opts) {
19
+ const { ctx, store, agentKeys } = opts;
20
+ const homeDirPath = () => path.join(ctx.userDataDir, "n8n-home");
21
+ const homeDirEnsure = () => {
22
+ const d = homeDirPath();
23
+ fs.mkdirSync(d, { recursive: true });
24
+ return d;
25
+ };
26
+ const product = () => hostProductName(ctx);
27
+ const secretPrefix = () => ctx.secretFilePrefix || "desktop";
28
+ function n8nHomeDir() {
29
+ return homeDirEnsure();
30
+ }
31
+ const state = {
32
+ running: null,
33
+ lastError: null,
34
+ version: null,
35
+ logs: [],
36
+ entryPath: null,
37
+ installing: false,
38
+ ownerReady: false,
39
+ publicBaseUrl: null,
40
+ lastStartPath: null,
41
+ };
42
+ /** "bootstrap" = runtime n8n installé pendant ce boot ; "reuse" = déjà présent. */
43
+ function getN8nLastStartPath() {
44
+ return state.lastStartPath;
45
+ }
46
+ const LOG_MAX = 200;
47
+ function pushLog(line) {
48
+ const ts = new Date().toISOString().slice(11, 19);
49
+ state.logs.push("[" + ts + "] " + line);
50
+ if (state.logs.length > LOG_MAX)
51
+ state.logs.shift();
52
+ hostLog(ctx, "n8n", line);
53
+ }
54
+ function findN8nEntry() {
55
+ const runtime = n8nRuntimeCacheDir(ctx);
56
+ // Jamais `which n8n` : sous Windows → %AppData%\Roaming\npm\n8n (shim bash)
57
+ // que `node <shim> start` exécute comme JS → SyntaxError immédiat.
58
+ const resolved = resolveN8nEntry({
59
+ platform: process.platform,
60
+ env: process.env,
61
+ runtimeDir: runtime,
62
+ // Overrides env honorés uniquement hors build packagé (dev/tests).
63
+ allowEnvOverride: !ctx.isPackaged,
64
+ envPrefix: ctx.manifest.envPrefix,
65
+ existsSync: (p) => {
66
+ try {
67
+ return fs.existsSync(p);
68
+ }
69
+ catch {
70
+ return false;
71
+ }
72
+ },
73
+ readFileSync: (p, enc) => fs.readFileSync(p, enc),
74
+ });
75
+ state.entryPath = resolved || n8nEntryPath(ctx);
76
+ return state.entryPath;
77
+ }
78
+ function ensureEncryptionKey(home) {
79
+ const prefix = secretPrefix();
80
+ const keyFile = path.join(home, `.${prefix}-n8n-encryption-key`);
81
+ /** Legacy marques (Certivan/Fidu) : `.${prefix}-encryption-key` sans `-n8n-`. */
82
+ const brandLegacy = path.join(home, `.${prefix}-encryption-key`);
83
+ const legacy = path.join(home, ".tempoflow-encryption-key");
84
+ const desktop = path.join(home, ".desktop-n8n-encryption-key");
85
+ for (const f of [keyFile, brandLegacy, legacy, desktop]) {
86
+ try {
87
+ const existing = fs.readFileSync(f, "utf8").trim();
88
+ if (existing.length >= 16) {
89
+ if (f !== keyFile)
90
+ fs.writeFileSync(keyFile, existing, { mode: 0o600 });
91
+ return existing;
92
+ }
93
+ }
94
+ catch { /* */ }
95
+ }
96
+ const key = crypto.randomBytes(32).toString("hex");
97
+ fs.writeFileSync(keyFile, key, { mode: 0o600 });
98
+ return key;
99
+ }
100
+ /**
101
+ * Superadmin uniforme flotte : posé par l'opérateur au niveau du VPS/serveur
102
+ * (env `CREEZIO_SUPERADMIN_EMAIL` / `CREEZIO_SUPERADMIN_PASSWORD`, jamais
103
+ * commité). Prioritaire sur les creds owner générés — permet de se loguer sur
104
+ * le n8n de TOUTES les instances avec le même compte.
105
+ */
106
+ function superadminEnvCreds() {
107
+ const email = (process.env.CREEZIO_SUPERADMIN_EMAIL || "").trim();
108
+ const password = (process.env.CREEZIO_SUPERADMIN_PASSWORD || "").trim();
109
+ if (!email || !email.includes("@") || password.length < 12)
110
+ return null;
111
+ return { email, password, firstName: "Creezio", lastName: "Superadmin" };
112
+ }
113
+ function ownerCredsFile(home) {
114
+ return path.join(home, `.${secretPrefix()}-n8n-owner.json`);
115
+ }
116
+ function writeOwnerCreds(home, creds) {
117
+ fs.writeFileSync(ownerCredsFile(home), JSON.stringify(creds, null, 2) + "\n", { mode: 0o600 });
118
+ }
119
+ /** Creds owner persistés (fichier home) — sans l'override env superadmin. */
120
+ function readFileOwnerCreds(home) {
121
+ const keyFile = ownerCredsFile(home);
122
+ /** Legacy marques : `.${prefix}-owner.json` (Certivan `.certivan-owner.json`). */
123
+ const brandLegacy = path.join(home, `.${secretPrefix()}-owner.json`);
124
+ const legacy = path.join(home, ".tempoflow-owner.json");
125
+ for (const f of [keyFile, brandLegacy, legacy]) {
126
+ try {
127
+ const raw = JSON.parse(fs.readFileSync(f, "utf8"));
128
+ if (raw && typeof raw.email === "string" && typeof raw.password === "string" && raw.password.length >= 12) {
129
+ if (f !== keyFile)
130
+ fs.writeFileSync(keyFile, JSON.stringify(raw, null, 2) + "\n", { mode: 0o600 });
131
+ return {
132
+ email: raw.email,
133
+ password: raw.password,
134
+ firstName: raw.firstName || product(),
135
+ lastName: raw.lastName || "Desktop",
136
+ };
137
+ }
138
+ }
139
+ catch { /* */ }
140
+ }
141
+ return null;
142
+ }
143
+ function ensureOwnerCreds(home) {
144
+ // Superadmin flotte prioritaire — le fichier n'est mis à jour qu'après un
145
+ // login/setup RÉUSSI (ensureOwnerSilent), pour garder les anciens creds en
146
+ // fallback si l'instance a déjà été initialisée avec eux.
147
+ const env = superadminEnvCreds();
148
+ if (env)
149
+ return env;
150
+ const stored = readFileOwnerCreds(home);
151
+ if (stored)
152
+ return stored;
153
+ const creds = {
154
+ email: secretPrefix() + "-desktop@localhost.local",
155
+ password: crypto.randomBytes(24).toString("base64url"),
156
+ firstName: product(),
157
+ lastName: "Desktop",
158
+ };
159
+ writeOwnerCreds(home, creds);
160
+ return creds;
161
+ }
162
+ function httpJson(method, url, body, headers) {
163
+ return new Promise((resolve, reject) => {
164
+ const u = new URL(url);
165
+ const payload = body === undefined ? null : JSON.stringify(body);
166
+ const req = http.request({
167
+ hostname: u.hostname,
168
+ port: u.port,
169
+ path: `${u.pathname}${u.search}`,
170
+ method,
171
+ headers: {
172
+ Accept: "application/json",
173
+ ...(payload
174
+ ? {
175
+ "Content-Type": "application/json",
176
+ "Content-Length": Buffer.byteLength(payload),
177
+ }
178
+ : {}),
179
+ ...headers,
180
+ },
181
+ timeout: 15000,
182
+ }, (res) => {
183
+ const chunks = [];
184
+ res.on("data", (c) => chunks.push(c));
185
+ res.on("end", () => {
186
+ const raw = Buffer.concat(chunks).toString("utf8");
187
+ let json = null;
188
+ try {
189
+ json = raw ? JSON.parse(raw) : null;
190
+ }
191
+ catch {
192
+ json = null;
193
+ }
194
+ resolve({
195
+ status: res.statusCode || 0,
196
+ json,
197
+ headers: res.headers,
198
+ raw,
199
+ });
200
+ });
201
+ });
202
+ req.on("error", reject);
203
+ req.on("timeout", () => {
204
+ req.destroy();
205
+ reject(new Error("timeout HTTP n8n"));
206
+ });
207
+ if (payload)
208
+ req.write(payload);
209
+ req.end();
210
+ });
211
+ }
212
+ /**
213
+ * n8n 2.x (Node) est lourd au boot Windows : chargement modules + SQLite + AV.
214
+ * Warm = DB déjà là — souvent 30–90s ; cold (1er boot) 5–10 min possibles.
215
+ */
216
+ const N8N_HEALTH_TIMEOUT_COLD_MS = 600_000;
217
+ const N8N_HEALTH_TIMEOUT_WARM_MS = 180_000;
218
+ const N8N_HEALTH_GRACE_COLD_MS = 180_000;
219
+ const N8N_HEALTH_GRACE_WARM_MS = 90_000;
220
+ /** Signaux stdout/stderr qui indiquent que l’UI est joignable (avant healthz). */
221
+ function isN8nReadyLogLine(line) {
222
+ return /Editor is now accessible|n8n ready on|Editor UI available|Server is listening/i.test(line);
223
+ }
224
+ /** Chemins absolus utilitaires réseau (hors allowlist resolveSystemBinary). */
225
+ function resolvePortTool(name) {
226
+ const candidates = name === "lsof"
227
+ ? ["/usr/bin/lsof", "/bin/lsof", "/usr/sbin/lsof"]
228
+ : ["/usr/bin/fuser", "/bin/fuser", "/usr/sbin/fuser"];
229
+ for (const c of candidates) {
230
+ if (fs.existsSync(c))
231
+ return c;
232
+ }
233
+ return null;
234
+ }
235
+ /** PIDs écouteurs TCP (Linux/mac) — lsof d’abord (fuser souvent absent en CI). */
236
+ function listenerPidsOnPort(port) {
237
+ const pids = new Set();
238
+ const push = (raw) => {
239
+ for (const line of raw.split(/\r?\n/)) {
240
+ const n = Number(line.trim());
241
+ if (Number.isInteger(n) && n > 0)
242
+ pids.add(n);
243
+ }
244
+ };
245
+ try {
246
+ const lsof = resolvePortTool("lsof");
247
+ if (lsof) {
248
+ const out = execFileSync(lsof, ["-tiTCP:" + String(port), "-sTCP:LISTEN"], { timeout: 5000, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
249
+ push(out);
250
+ }
251
+ }
252
+ catch {
253
+ /* aucun listener / lsof KO */
254
+ }
255
+ try {
256
+ const fuser = resolvePortTool("fuser");
257
+ if (fuser) {
258
+ const out = execFileSync(fuser, [`${port}/tcp`], {
259
+ timeout: 5000,
260
+ encoding: "utf8",
261
+ stdio: ["ignore", "pipe", "pipe"],
262
+ });
263
+ for (const m of out.matchAll(/\b(\d+)\b/g)) {
264
+ const n = Number(m[1]);
265
+ if (n > 0)
266
+ pids.add(n);
267
+ }
268
+ }
269
+ }
270
+ catch {
271
+ /* */
272
+ }
273
+ return [...pids];
274
+ }
275
+ /** Best-effort : libérer le port desktop (zombie après crash / retry). */
276
+ function killListenerOnPort(port) {
277
+ try {
278
+ if (process.platform === "win32") {
279
+ const powershell = resolveSystemBinary("powershell");
280
+ if (!powershell)
281
+ return;
282
+ execFileSync(powershell, [
283
+ "-NoProfile",
284
+ "-Command",
285
+ `Get-NetTCPConnection -LocalPort ${port} -State Listen -ErrorAction SilentlyContinue | ForEach-Object { Stop-Process -Id $_.OwningProcess -Force -ErrorAction SilentlyContinue }`,
286
+ ], { timeout: 8000, windowsHide: true, stdio: "ignore" });
287
+ return;
288
+ }
289
+ for (const pid of listenerPidsOnPort(port)) {
290
+ try {
291
+ process.kill(pid, "SIGKILL");
292
+ }
293
+ catch {
294
+ /* déjà mort / permission */
295
+ }
296
+ }
297
+ // Fallback shell si lsof/fuser absents du PATH sandbox.
298
+ const bash = resolveSystemBinary("bash");
299
+ if (bash && listenerPidsOnPort(port).length > 0) {
300
+ execFileSync(bash, [
301
+ "-lc",
302
+ `fuser -k ${port}/tcp >/dev/null 2>&1 || true; ` +
303
+ `command -v lsof >/dev/null && lsof -tiTCP:${port} -sTCP:LISTEN 2>/dev/null | while read p; do kill -9 "$p" 2>/dev/null || true; done`,
304
+ ], { timeout: 8000, stdio: "ignore" });
305
+ }
306
+ }
307
+ catch {
308
+ /* best-effort */
309
+ }
310
+ }
311
+ /** Kill + attendre que le port desktop soit réellement libre. */
312
+ async function ensureN8nDesktopPortFree(log, attempts = 4) {
313
+ for (let i = 1; i <= attempts; i++) {
314
+ const probe = await findFreePort(N8N_DESKTOP_PORT);
315
+ if (probe === N8N_DESKTOP_PORT)
316
+ return true;
317
+ log(`port ${N8N_DESKTOP_PORT} occupé — free attempt ${i}/${attempts}`);
318
+ killListenerOnPort(N8N_DESKTOP_PORT);
319
+ await new Promise((r) => setTimeout(r, 400 * i));
320
+ }
321
+ return (await findFreePort(N8N_DESKTOP_PORT)) === N8N_DESKTOP_PORT;
322
+ }
323
+ /** DB déjà présente → pas de 1er install / grosses migrations. */
324
+ function n8nHomeLooksWarm(homeDir) {
325
+ return n8nHomeLooksWarmPure(homeDir || homeDirPath(), (p) => fs.existsSync(p));
326
+ }
327
+ function waitForN8nHealth(uiUrl, timeoutMs = N8N_HEALTH_TIMEOUT_COLD_MS,
328
+ /** Si true → sortir tôt (ex. log « Editor is now accessible »). */
329
+ earlyOk,
330
+ /** Si true → abandonner tout de suite (process mort). */
331
+ earlyFail) {
332
+ const deadline = Date.now() + timeoutMs;
333
+ const base = uiUrl.replace(/\/$/, "");
334
+ const started = Date.now();
335
+ let lastTickLog = 0;
336
+ return new Promise((resolve) => {
337
+ const tryOnce = () => {
338
+ const failReason = earlyFail?.();
339
+ if (failReason) {
340
+ resolve({ ok: false, detail: failReason });
341
+ return;
342
+ }
343
+ if (earlyOk?.()) {
344
+ resolve({ ok: true, version: null });
345
+ return;
346
+ }
347
+ const elapsed = Date.now() - started;
348
+ if (elapsed - lastTickLog >= 15_000) {
349
+ lastTickLog = elapsed;
350
+ pushLog(`attente n8n… ${Math.round(elapsed / 1000)}s (chargement modules / SQLite)`);
351
+ }
352
+ const req = http.get(`${base}/healthz`, { timeout: 2000 }, (res) => {
353
+ res.resume();
354
+ if (res.statusCode && res.statusCode >= 200 && res.statusCode < 500) {
355
+ resolve({ ok: true, version: null });
356
+ }
357
+ else {
358
+ next();
359
+ }
360
+ });
361
+ req.on("error", next);
362
+ req.on("timeout", () => {
363
+ req.destroy();
364
+ next();
365
+ });
366
+ };
367
+ const next = () => {
368
+ const failReason = earlyFail?.();
369
+ if (failReason) {
370
+ resolve({ ok: false, detail: failReason });
371
+ return;
372
+ }
373
+ if (earlyOk?.()) {
374
+ resolve({ ok: true, version: null });
375
+ return;
376
+ }
377
+ if (Date.now() > deadline) {
378
+ resolve({
379
+ ok: false,
380
+ detail: `n8n healthz timeout après ${Math.round(timeoutMs / 1000)}s`,
381
+ });
382
+ }
383
+ else {
384
+ setTimeout(tryOnce, 400);
385
+ }
386
+ };
387
+ tryOnce();
388
+ });
389
+ }
390
+ /**
391
+ * Attend que le routeur REST n8n soit RÉELLEMENT prêt : `/rest/settings`
392
+ * doit répondre 2xx avec `data.userManagement.showSetupOnFirstLoad` présent.
393
+ * Deux pièges vécus (2.31.5) :
394
+ * - healthz répond AVANT le montage des routes `/rest/*` (setup part en 404) ;
395
+ * - les routes répondent AVANT la fin de l'init DB : un POST /rest/owner/setup
396
+ * dans cette fenêtre renvoie 200 mais l'écriture est PERDUE (le shell user
397
+ * n'existe pas encore — vécu : setup « OK » à +7 s du spawn, owner absent,
398
+ * login 401 ensuite). Le flag userManagement n'apparaît qu'une fois la DB
399
+ * initialisée — c'est le signal fiable.
400
+ */
401
+ async function waitForN8nRestReady(base, timeoutMs, log) {
402
+ const deadline = Date.now() + timeoutMs;
403
+ let waited = false;
404
+ for (;;) {
405
+ try {
406
+ const res = await httpJson("GET", `${base}/rest/settings`);
407
+ if (res.status >= 200 &&
408
+ res.status < 300 &&
409
+ n8nNeedsOwnerSetup(res.json) !== null) {
410
+ if (waited)
411
+ log("owner: routeur REST n8n prêt (settings complets)");
412
+ return true;
413
+ }
414
+ }
415
+ catch {
416
+ /* n8n pas encore joignable */
417
+ }
418
+ if (Date.now() > deadline) {
419
+ log("owner: routeur REST n8n toujours indisponible (timeout)");
420
+ return false;
421
+ }
422
+ if (!waited) {
423
+ waited = true;
424
+ log("owner: attente du routeur REST n8n (init DB / settings incomplets)…");
425
+ }
426
+ await new Promise((r) => setTimeout(r, 800));
427
+ }
428
+ }
429
+ /**
430
+ * Provisionne l’owner si besoin + vérifie login (sans UI password).
431
+ * Retourne les creds RÉELLEMENT valides (env superadmin, ou fallback fichier
432
+ * si l'instance a été initialisée avec d'anciens creds), null si échec.
433
+ */
434
+ async function ensureOwnerSilent(uiUrl, creds, log, fallback) {
435
+ const base = uiUrl.replace(/\/$/, "");
436
+ const home = state.running?.homeDir || n8nHomeDir();
437
+ // Faux positif connu : n8n vierge répond 200 à /rest/login (shell user)
438
+ // SANS cookie de session → n8nLoginSucceeded exige le cookie n8n-auth.
439
+ const tryLogin = async (c) => {
440
+ const res = await httpJson("POST", `${base}/rest/login`, {
441
+ emailOrLdapLoginId: c.email,
442
+ password: c.password,
443
+ });
444
+ return n8nLoginSucceeded(res.status, res.headers["set-cookie"]);
445
+ };
446
+ try {
447
+ await waitForN8nRestReady(base, 90_000, log);
448
+ // État réel de l'instance : /rest/settings → showSetupOnFirstLoad.
449
+ let needsSetup = null;
450
+ try {
451
+ const settings = await httpJson("GET", `${base}/rest/settings`);
452
+ needsSetup = n8nNeedsOwnerSetup(settings.json);
453
+ }
454
+ catch {
455
+ /* signal indisponible — on retombe sur login puis setup */
456
+ }
457
+ if (needsSetup === true) {
458
+ log("owner: instance vierge détectée (showSetupOnFirstLoad) — setup…");
459
+ }
460
+ else if (await tryLogin(creds)) {
461
+ state.ownerReady = true;
462
+ log("owner: login OK (session silencieuse)");
463
+ writeOwnerCreds(home, creds);
464
+ return creds;
465
+ }
466
+ // Setup avec VÉRIFICATION : un 2xx sur /rest/owner/setup pendant l'init
467
+ // DB peut être perdu (vécu : owner « créé » mais DB vierge, login 401).
468
+ // Seul un login réel (cookie n8n-auth) prouve que l'owner existe.
469
+ const doSetup = () => httpJson("POST", `${base}/rest/owner/setup`, {
470
+ email: creds.email,
471
+ password: creds.password,
472
+ firstName: creds.firstName,
473
+ lastName: creds.lastName,
474
+ });
475
+ let setup = await doSetup();
476
+ for (let attempt = 0; attempt < 4; attempt++) {
477
+ if (setup.status >= 200 && setup.status < 300) {
478
+ if (await tryLogin(creds)) {
479
+ state.ownerReady = true;
480
+ log("owner: setup silencieux OK (login vérifié)");
481
+ writeOwnerCreds(home, creds);
482
+ return creds;
483
+ }
484
+ log("owner: setup 2xx mais login non vérifié (init DB en cours ?) — retry…");
485
+ }
486
+ else if (setup.status !== 404) {
487
+ // 400 « already set up » ou autre erreur définitive — sortir du retry.
488
+ break;
489
+ }
490
+ await new Promise((r) => setTimeout(r, 3000));
491
+ setup = await doSetup();
492
+ }
493
+ if (setup.status >= 200 && setup.status < 300 && (await tryLogin(creds))) {
494
+ state.ownerReady = true;
495
+ log("owner: setup silencieux OK (login vérifié)");
496
+ writeOwnerCreds(home, creds);
497
+ return creds;
498
+ }
499
+ // Instance déjà initialisée avec les creds fichier (ex. avant l'arrivée
500
+ // du superadmin flotte) : login fallback, puis rotation best-effort du
501
+ // mot de passe vers le superadmin pour converger.
502
+ if (fallback && fallback.password !== creds.password) {
503
+ const loginRes = await httpJson("POST", `${base}/rest/login`, {
504
+ emailOrLdapLoginId: fallback.email,
505
+ password: fallback.password,
506
+ });
507
+ if (n8nLoginSucceeded(loginRes.status, loginRes.headers["set-cookie"])) {
508
+ state.ownerReady = true;
509
+ log("owner: login OK via creds locaux (instance pré-superadmin)");
510
+ const cookie = cookieHeaderFromSetCookie(loginRes.headers["set-cookie"]);
511
+ if (cookie && superadminEnvCreds()) {
512
+ for (const method of ["PATCH", "POST"]) {
513
+ const rot = await httpJson(method, `${base}/rest/me/password`, { currentPassword: fallback.password, newPassword: creds.password }, { Cookie: cookie });
514
+ if (rot.status >= 200 && rot.status < 300) {
515
+ log("owner: mot de passe aligné sur le superadmin flotte");
516
+ writeOwnerCreds(home, { ...fallback, password: creds.password });
517
+ return { ...fallback, password: creds.password };
518
+ }
519
+ }
520
+ log("owner: rotation superadmin refusée — creds locaux conservés");
521
+ }
522
+ return fallback;
523
+ }
524
+ }
525
+ // Instance déjà initialisée avec d’autres creds — on log sans bloquer.
526
+ log(`owner: setup/login non conclusif (setup=${setup.status}) — UI pourra demander un login`);
527
+ state.ownerReady = false;
528
+ return null;
529
+ }
530
+ catch (e) {
531
+ log(`owner: ${e instanceof Error ? e.message : String(e)}`);
532
+ state.ownerReady = false;
533
+ return null;
534
+ }
535
+ }
536
+ function parseSetCookie(headers) {
537
+ const raw = headers["set-cookie"];
538
+ if (!raw)
539
+ return [];
540
+ return Array.isArray(raw) ? raw : [raw];
541
+ }
542
+ /**
543
+ * Login REST + injecte le cookie `n8n-auth` dans la partition onglet.
544
+ * Évite l’écran password à l’ouverture (équivalent fix Hermes 0.1.47).
545
+ */
546
+ async function prepareN8nUiSession() {
547
+ const config = sanitizeN8nEmbedConfig(store.getN8nEmbedConfig());
548
+ const uiUrl = state.running?.uiUrl ||
549
+ (config.mode === "remote" ? config.remoteUiUrl || null : null);
550
+ if (!uiUrl) {
551
+ return {
552
+ ok: false,
553
+ detail: "URL n8n absente — démarrez le mode embarqué ou configurez Distant.",
554
+ uiUrl: null,
555
+ };
556
+ }
557
+ if (config.mode === "remote" && !state.running) {
558
+ // Remote : pas de credentials TempoFlow — l’utilisateur gère l’auth distante.
559
+ return {
560
+ ok: true,
561
+ detail: "Mode distant — pas d’injection cookie locale.",
562
+ uiUrl,
563
+ };
564
+ }
565
+ const home = state.running?.homeDir || n8nHomeDir();
566
+ const creds = ensureOwnerCreds(home);
567
+ const base = uiUrl.replace(/\/$/, "");
568
+ try {
569
+ let res = await httpJson("POST", `${base}/rest/login`, {
570
+ emailOrLdapLoginId: creds.email,
571
+ password: creds.password,
572
+ });
573
+ if (!n8nLoginSucceeded(res.status, res.headers["set-cookie"])) {
574
+ // 200-sans-cookie inclus (instance vierge) : provisionner puis re-login.
575
+ const working = (await ensureOwnerSilent(uiUrl, creds, pushLog, readFileOwnerCreds(home))) || creds;
576
+ res = await httpJson("POST", `${base}/rest/login`, {
577
+ emailOrLdapLoginId: working.email,
578
+ password: working.password,
579
+ });
580
+ }
581
+ if (!(res.status >= 200 && res.status < 300)) {
582
+ return {
583
+ ok: false,
584
+ detail: `Login n8n échoué (HTTP ${res.status})`,
585
+ uiUrl,
586
+ };
587
+ }
588
+ const cookies = parseSetCookie(res.headers);
589
+ if (!cookies.length) {
590
+ return {
591
+ ok: false,
592
+ detail: "Login n8n OK mais aucun Set-Cookie — session non injectée",
593
+ uiUrl,
594
+ };
595
+ }
596
+ let electronSession;
597
+ try {
598
+ electronSession = (await import("electron")).session;
599
+ }
600
+ catch {
601
+ return { ok: false, detail: "electron session indisponible", uiUrl };
602
+ }
603
+ const ses = electronSession.fromPartition(`persist:extsite-${EMBED_TOOL_SITE_IDS.n8nUi}`);
604
+ const u = new URL(base);
605
+ // Chromium refuse souvent `domain` sur une IP (127.0.0.1) — url seul.
606
+ const hostIsIp = /^\d{1,3}(\.\d{1,3}){3}$/.test(u.hostname);
607
+ let injected = 0;
608
+ for (const line of cookies) {
609
+ const nameVal = line.split(";")[0] || "";
610
+ const eq = nameVal.indexOf("=");
611
+ if (eq <= 0)
612
+ continue;
613
+ const name = nameVal.slice(0, eq).trim();
614
+ const value = nameVal.slice(eq + 1).trim();
615
+ if (!name)
616
+ continue;
617
+ const payload = {
618
+ url: base,
619
+ name,
620
+ value,
621
+ path: "/",
622
+ httpOnly: /httponly/i.test(line),
623
+ secure: u.protocol === "https:",
624
+ sameSite: "lax",
625
+ };
626
+ if (!hostIsIp)
627
+ payload.domain = u.hostname;
628
+ await ses.cookies.set(payload);
629
+ injected += 1;
630
+ }
631
+ try {
632
+ await ses.cookies.flushStore();
633
+ }
634
+ catch {
635
+ /* best-effort */
636
+ }
637
+ pushLog(`session: ${injected} cookie(s) injecté(s) → partition extsite-${EMBED_TOOL_SITE_IDS.n8nUi}`);
638
+ return {
639
+ ok: injected > 0,
640
+ detail: injected > 0
641
+ ? "Session n8n préparée (login silencieux)"
642
+ : "Aucun cookie injecté",
643
+ uiUrl,
644
+ };
645
+ }
646
+ catch (e) {
647
+ const detail = e instanceof Error ? e.message : String(e);
648
+ return { ok: false, detail, uiUrl };
649
+ }
650
+ }
651
+ async function startN8n(opts) {
652
+ const n8nConfig = sanitizeN8nEmbedConfig(opts.n8nConfig ?? store.getN8nEmbedConfig());
653
+ const desiredPublic = normalizeN8nPublicBaseUrl(opts.publicBaseUrl);
654
+ if (!shouldSpawnEmbeddedN8n({
655
+ connectionMode: opts.connectionMode,
656
+ n8n: n8nConfig,
657
+ })) {
658
+ pushLog(opts.connectionMode === "remote"
659
+ ? "skip spawn (client distant)"
660
+ : `skip spawn (mode=${n8nConfig.mode})`);
661
+ return null;
662
+ }
663
+ const log = (line) => {
664
+ pushLog(line);
665
+ opts.onLog?.(line);
666
+ };
667
+ // Idempotent sauf si URL publique changée ou forceRestart.
668
+ if (state.running) {
669
+ const publicMatches = desiredPublic == null
670
+ ? state.running.publicBaseUrl.startsWith("http://127.0.0.1")
671
+ : state.running.publicBaseUrl === desiredPublic;
672
+ if (!opts.forceRestart && publicMatches) {
673
+ log(`déjà prêt ${state.running.uiUrl} (webhooks=${state.running.publicBaseUrl})`);
674
+ return state.running;
675
+ }
676
+ log(`restart n8n — webhooks ${state.running.publicBaseUrl} → ${desiredPublic || "loopback"}`);
677
+ stopN8n();
678
+ }
679
+ const nodeReady = await ensureDesktopNode(ctx, {
680
+ minVersion: DESKTOP_NODE_MIN_FOR_EMBEDS,
681
+ });
682
+ if (!nodeReady.ok) {
683
+ state.lastError = nodeReady.detail;
684
+ log(state.lastError);
685
+ return null;
686
+ }
687
+ const node = nodeReady.node;
688
+ let entry = findN8nEntry();
689
+ // Honnêteté splash + télémétrie : install réelle vs runtime réutilisé.
690
+ state.lastStartPath = entry ? "reuse" : "bootstrap";
691
+ if (!entry && opts.autoBootstrap !== false) {
692
+ state.installing = true;
693
+ log("runtime n8n manquant — bootstrap npm (Node TempoFlow)…");
694
+ try {
695
+ const boot = await ensureN8nRuntime(ctx, { onLog: log });
696
+ log(boot.detail);
697
+ entry = boot.entry || findN8nEntry();
698
+ if (!boot.ok && !entry) {
699
+ state.lastError = boot.detail;
700
+ state.installing = false;
701
+ return null;
702
+ }
703
+ }
704
+ finally {
705
+ state.installing = false;
706
+ }
707
+ }
708
+ if (!entry) {
709
+ state.lastError = "Entry n8n introuvable (bootstrap / TF2_N8N_BIN)";
710
+ log(state.lastError);
711
+ return null;
712
+ }
713
+ try {
714
+ const home = n8nHomeDir();
715
+ // Warm AVANT d’écrire les marqueurs TempoFlow (sinon faux « warm » au 1er boot).
716
+ const warm = n8nHomeLooksWarm(home);
717
+ const encryptionKey = ensureEncryptionKey(home);
718
+ const creds = ensureOwnerCreds(home);
719
+ // Réutiliser une instance déjà saine sur le port desktop (retry / zombie).
720
+ // Évite un 2ᵉ spawn sur un autre port partageant la même DB.
721
+ const existingUrl = `http://127.0.0.1:${N8N_DESKTOP_PORT}`;
722
+ const existing = await waitForN8nHealth(existingUrl, 2500);
723
+ // Si on a une URL tunnel à injecter, il faut re-spawner (env au boot).
724
+ if (existing.ok && !desiredPublic && !opts.forceRestart) {
725
+ log(`réutilise n8n déjà prêt sur ${existingUrl} (pas de re-spawn)`);
726
+ state.lastError = null;
727
+ const working = await ensureOwnerSilent(existingUrl, creds, log, readFileOwnerCreds(home));
728
+ if (working && ctx.onN8nReady) {
729
+ try {
730
+ await ctx.onN8nReady({
731
+ uiUrl: existingUrl,
732
+ homeDir: home,
733
+ email: working.email,
734
+ password: working.password,
735
+ log,
736
+ });
737
+ }
738
+ catch (e) {
739
+ log("api-key: " + (e instanceof Error ? e.message : e));
740
+ }
741
+ }
742
+ const publicBase = `${existingUrl.replace(/\/$/, "")}/`;
743
+ const running = {
744
+ uiUrl: existingUrl,
745
+ homeDir: home,
746
+ publicBaseUrl: publicBase,
747
+ child: { kill: () => undefined },
748
+ stop: () => killListenerOnPort(N8N_DESKTOP_PORT),
749
+ };
750
+ state.running = running;
751
+ state.publicBaseUrl = publicBase;
752
+ return running;
753
+ }
754
+ // Port occupé mais healthz KO (zombie après crash / Réessayer) : libérer
755
+ // avant findFreePort, sinon n8n démarre sur :15679 avec la même DB → crash.
756
+ if (existing.ok) {
757
+ log(`n8n déjà sur ${existingUrl} — stop pour appliquer WEBHOOK_URL=${desiredPublic || "loopback"}`);
758
+ }
759
+ else {
760
+ log(`port ${N8N_DESKTOP_PORT} non prêt — kill éventuel zombie avant spawn`);
761
+ }
762
+ const portFree = await ensureN8nDesktopPortFree(log);
763
+ if (!portFree) {
764
+ state.lastError = `port n8n ${N8N_DESKTOP_PORT} occupé par un autre process — fermez-le puis réessayez`;
765
+ log(state.lastError);
766
+ return null;
767
+ }
768
+ const boundPort = N8N_DESKTOP_PORT;
769
+ const uiUrl = `http://127.0.0.1:${boundPort}`;
770
+ const publicBase = desiredPublic || `${uiUrl.replace(/\/$/, "")}/`;
771
+ const healthTimeout = warm
772
+ ? N8N_HEALTH_TIMEOUT_WARM_MS
773
+ : N8N_HEALTH_TIMEOUT_COLD_MS;
774
+ log(describeN8nSpawnKind({
775
+ warm,
776
+ node,
777
+ entry,
778
+ home,
779
+ uiUrl,
780
+ healthTimeoutSec: Math.round(healthTimeout / 1000),
781
+ }));
782
+ log(`WEBHOOK_URL / N8N_EDITOR_BASE_URL = ${publicBase}`);
783
+ const osHome = path.join(home, "os-home");
784
+ const childEnv = buildIsolatedNodeEnv({
785
+ nodeBin: node,
786
+ baseEnv: buildN8nSpawnEnv({
787
+ port: boundPort,
788
+ userFolder: home,
789
+ encryptionKey,
790
+ publicBaseUrl: desiredPublic,
791
+ userEnv: store.getEmbedUserEnv("n8n"),
792
+ baseEnv: process.env,
793
+ }),
794
+ sandbox: { profileHome: osHome, userData: ctx.userDataDir },
795
+ });
796
+ const child = spawn(node, [entry, "start"], {
797
+ cwd: home,
798
+ env: childEnv,
799
+ stdio: ["ignore", "pipe", "pipe"],
800
+ windowsHide: true,
801
+ });
802
+ const errTail = [];
803
+ let readyFromLog = false;
804
+ const onLine = (l, asStderr = false) => {
805
+ if (asStderr) {
806
+ errTail.push(l);
807
+ if (errTail.length > 30)
808
+ errTail.shift();
809
+ log(`stderr: ${l}`);
810
+ }
811
+ else {
812
+ log(l);
813
+ }
814
+ if (isN8nReadyLogLine(l)) {
815
+ readyFromLog = true;
816
+ log("signal prêt (log n8n) — UI accessible");
817
+ }
818
+ };
819
+ child.stdout?.on("data", (d) => d
820
+ .toString()
821
+ .split("\n")
822
+ .filter(Boolean)
823
+ .forEach((l) => onLine(l, false)));
824
+ child.stderr?.on("data", (d) => d
825
+ .toString()
826
+ .split("\n")
827
+ .filter(Boolean)
828
+ .forEach((l) => onLine(l, true)));
829
+ const spawnErr = { current: null };
830
+ child.on("error", (e) => {
831
+ spawnErr.current = e;
832
+ log(`spawn error: ${e.message}`);
833
+ });
834
+ child.on("exit", (code, signal) => {
835
+ log(`exit code=${code} signal=${signal}`);
836
+ if (state.running?.child === child) {
837
+ state.running = null;
838
+ }
839
+ });
840
+ const childDeadReason = () => {
841
+ if (spawnErr.current)
842
+ return `spawn n8n: ${spawnErr.current.message}`;
843
+ if (child.exitCode !== null || child.killed) {
844
+ const interesting = errTail.find((l) => /SyntaxError|Error:|Cannot find module/i.test(l)) ||
845
+ errTail.slice(-3).join(" | ");
846
+ const tail = interesting ? ` — ${interesting}` : "";
847
+ return `process n8n arrêté (code=${child.exitCode}, signal=${child.signalCode})${tail}`;
848
+ }
849
+ return null;
850
+ };
851
+ // Attente combinée : healthz OU log « Editor is now accessible ».
852
+ const bootStarted = Date.now();
853
+ let health = await waitForN8nHealth(uiUrl, healthTimeout, () => readyFromLog, childDeadReason);
854
+ if (!health.ok && readyFromLog && !childDeadReason()) {
855
+ // Petite fenêtre pour que healthz suive le log.
856
+ health = await waitForN8nHealth(uiUrl, 15_000, undefined, childDeadReason);
857
+ if (!health.ok && !childDeadReason()) {
858
+ log("UI signalée prête par log — on continue (healthz encore en retard)");
859
+ health = { ok: true };
860
+ }
861
+ }
862
+ const childAlive = !childDeadReason();
863
+ if (!health.ok) {
864
+ if (!childAlive) {
865
+ state.lastError =
866
+ health.detail ||
867
+ spawnErr.current?.message ||
868
+ (errTail.length
869
+ ? errTail.slice(-5).join(" | ")
870
+ : "démarrage n8n échoué");
871
+ log(`échec health: ${state.lastError}`);
872
+ return null;
873
+ }
874
+ const elapsedSec = Math.round((Date.now() - bootStarted) / 1000);
875
+ log(`n8n charge encore ses modules (${elapsedSec}s, process vivant) — poursuite…`);
876
+ const health2 = await waitForN8nHealth(uiUrl, warm ? N8N_HEALTH_GRACE_WARM_MS : N8N_HEALTH_GRACE_COLD_MS, () => readyFromLog, childDeadReason);
877
+ if (!health2.ok && childDeadReason()) {
878
+ state.lastError = health2.detail || childDeadReason() || "démarrage n8n échoué";
879
+ log(`échec health: ${state.lastError}`);
880
+ return null;
881
+ }
882
+ if (!health2.ok && readyFromLog) {
883
+ log("signal prêt (log) après attente prolongée");
884
+ }
885
+ else if (!health2.ok) {
886
+ log(`healthz encore KO après ${Math.round((Date.now() - bootStarted) / 1000)}s — URL ${uiUrl} (process vivant, pas de kill)`);
887
+ }
888
+ }
889
+ const workingCreds = await ensureOwnerSilent(uiUrl, creds, log, readFileOwnerCreds(home));
890
+ if (workingCreds && ctx.onN8nReady) {
891
+ try {
892
+ await ctx.onN8nReady({
893
+ uiUrl,
894
+ homeDir: home,
895
+ email: workingCreds.email,
896
+ password: workingCreds.password,
897
+ log,
898
+ });
899
+ }
900
+ catch (e) {
901
+ log("api-key: " + (e instanceof Error ? e.message : String(e)));
902
+ }
903
+ }
904
+ // Version best-effort depuis package installé
905
+ try {
906
+ const pkg = path.join(n8nRuntimeCacheDir(ctx), "node_modules", "n8n", "package.json");
907
+ if (fs.existsSync(pkg)) {
908
+ const v = JSON.parse(fs.readFileSync(pkg, "utf8"));
909
+ state.version = v.version || null;
910
+ }
911
+ }
912
+ catch {
913
+ state.version = null;
914
+ }
915
+ state.lastError = null;
916
+ const running = {
917
+ uiUrl,
918
+ homeDir: home,
919
+ publicBaseUrl: publicBase,
920
+ child,
921
+ stop: () => {
922
+ try {
923
+ child.kill();
924
+ }
925
+ catch {
926
+ /* already dead */
927
+ }
928
+ },
929
+ };
930
+ state.running = running;
931
+ state.publicBaseUrl = publicBase;
932
+ log(`ready ${uiUrl}${state.version ? ` v${state.version}` : ""} · webhooks ${publicBase}`);
933
+ return running;
934
+ }
935
+ catch (e) {
936
+ state.lastError = e instanceof Error ? e.message : String(e);
937
+ log(`exception: ${state.lastError}`);
938
+ return null;
939
+ }
940
+ }
941
+ /**
942
+ * Applique l’URL tunnel aux webhooks n8n (restart si nécessaire).
943
+ * Appelé après syncTunnelIngress / réserve slug.
944
+ */
945
+ async function applyN8nPublicBaseUrl(opts) {
946
+ const desired = normalizeN8nPublicBaseUrl(opts.publicBaseUrl);
947
+ if (!desired)
948
+ return state.running;
949
+ if (state.running?.publicBaseUrl === desired) {
950
+ opts.onLog?.(`n8n webhooks déjà sur ${desired}`);
951
+ return state.running;
952
+ }
953
+ return startN8n({
954
+ connectionMode: opts.connectionMode || "local",
955
+ publicBaseUrl: desired,
956
+ forceRestart: true,
957
+ onLog: opts.onLog,
958
+ autoBootstrap: true,
959
+ });
960
+ }
961
+ function stopN8n() {
962
+ if (state.running) {
963
+ pushLog("stop");
964
+ state.running.stop();
965
+ state.running = null;
966
+ }
967
+ state.ownerReady = false;
968
+ state.publicBaseUrl = null;
969
+ }
970
+ function getRunningN8n() {
971
+ return state.running;
972
+ }
973
+ /**
974
+ * Q2 (étanchéité par agent) : API key n8n DÉDIÉE à un collaborateur IA,
975
+ * créée via le login owner silencieux du n8n embarqué. Idempotent.
976
+ * n8n non démarré → échec doux (l'appelant journalise, jamais bloquant).
977
+ */
978
+ async function provisionN8nAgentApiKey(aiUserId, opts) {
979
+ const running = state.running;
980
+ if (!running) {
981
+ return { ok: false, apiKey: null, detail: "n8n embarqué non démarré" };
982
+ }
983
+ const creds = ensureOwnerCreds(running.homeDir);
984
+ if (!agentKeys)
985
+ return { ok: false, apiKey: null, detail: "n8nAgentKeys hook absent" };
986
+ return agentKeys.provision({
987
+ uiUrl: running.uiUrl,
988
+ homeDir: running.homeDir,
989
+ email: creds.email,
990
+ password: creds.password,
991
+ aiUserId,
992
+ log: pushLog,
993
+ forceNew: opts?.forceNew,
994
+ });
995
+ }
996
+ /** Révocation de la clé n8n d'un agent (vraie fermeture / suppression). */
997
+ async function revokeN8nAgentKey(aiUserId) {
998
+ const running = state.running;
999
+ if (!running) {
1000
+ // Sans n8n actif on retire quand même l'entrée locale (fichier home).
1001
+ const home = n8nHomeDir();
1002
+ if (agentKeys) {
1003
+ const keys = agentKeys.readStored(home);
1004
+ if (keys[aiUserId]) {
1005
+ delete keys[aiUserId];
1006
+ agentKeys.writeStored(home, keys);
1007
+ }
1008
+ }
1009
+ return { ok: true, detail: "n8n non démarré — clé retirée localement" };
1010
+ }
1011
+ const creds = ensureOwnerCreds(running.homeDir);
1012
+ if (!agentKeys)
1013
+ return { ok: false, detail: "n8nAgentKeys hook absent" };
1014
+ return agentKeys.revoke({
1015
+ uiUrl: running.uiUrl,
1016
+ homeDir: running.homeDir,
1017
+ email: creds.email,
1018
+ password: creds.password,
1019
+ aiUserId,
1020
+ log: pushLog,
1021
+ });
1022
+ }
1023
+ function getN8nNextEnv(connectionMode) {
1024
+ if (connectionMode !== "local")
1025
+ return {};
1026
+ const config = sanitizeN8nEmbedConfig(store.getN8nEmbedConfig());
1027
+ if (state.running) {
1028
+ // Le serveur Next a besoin de l'API n8n complète (clé incluse) pour
1029
+ // l'onglet n8n du Product Hub (n8nConfig() exige N8N_API_URL+N8N_API_KEY).
1030
+ // La clé est provisionnée pendant le boot n8n (avant Next) ; si elle
1031
+ // apparaît plus tard, restartNextServer ré-évalue cet env.
1032
+ return {
1033
+ ...buildNextN8nEnv({ uiUrl: state.running.uiUrl }),
1034
+ ...(ctx.getN8nNextEnvExtra?.({
1035
+ connectionMode,
1036
+ homeDir: state.running.homeDir,
1037
+ localUiUrl: state.running.uiUrl,
1038
+ }) || {}),
1039
+ };
1040
+ }
1041
+ if (config.mode === "remote" && config.remoteUiUrl) {
1042
+ return buildNextN8nEnv({ uiUrl: config.remoteUiUrl });
1043
+ }
1044
+ return {};
1045
+ }
1046
+ function getN8nStatusPayload(connectionMode, opts) {
1047
+ const config = sanitizeN8nEmbedConfig(store.getN8nEmbedConfig());
1048
+ const entry = state.entryPath || findN8nEntry();
1049
+ let pub = n8nPublicStatus({
1050
+ connectionMode,
1051
+ config,
1052
+ entryFound: Boolean(entry),
1053
+ running: Boolean(state.running),
1054
+ uiUrl: state.running?.uiUrl || config.remoteUiUrl || null,
1055
+ lastError: state.lastError,
1056
+ version: state.version,
1057
+ installing: state.installing,
1058
+ remoteCrmOrigin: opts?.remoteCrmOrigin,
1059
+ tunnelRootDomain: ctx.manifest.tunnelRootDomain,
1060
+ tunnelHostMode: (() => {
1061
+ const env = String(process.env.CREEZIO_TUNNEL_FLAT_HOSTS || "").trim();
1062
+ if (env === "1" || /^true$/i.test(env))
1063
+ return "flat";
1064
+ if (env === "0" || /^false$/i.test(env))
1065
+ return "nested";
1066
+ return ctx.manifest.tunnelHostMode;
1067
+ })(),
1068
+ productName: product(),
1069
+ });
1070
+ if (state.installing && pub.status === "missing") {
1071
+ pub = {
1072
+ ...pub,
1073
+ status: "installing",
1074
+ detail: `Installation runtime en cours (${getN8nBootstrapPhase()})…`,
1075
+ };
1076
+ }
1077
+ const localUiUrl = state.running?.uiUrl || null;
1078
+ const publicWebhookUrl = state.running?.publicBaseUrl || state.publicBaseUrl || null;
1079
+ let listenPort = N8N_DESKTOP_PORT;
1080
+ try {
1081
+ if (localUiUrl)
1082
+ listenPort = Number(new URL(localUiUrl).port) || N8N_DESKTOP_PORT;
1083
+ }
1084
+ catch {
1085
+ /* keep default */
1086
+ }
1087
+ return {
1088
+ ...pub,
1089
+ entryPath: entry,
1090
+ // Chemin pur : un simple status ne doit pas créer n8n-home (client léger).
1091
+ homeDir: state.running?.homeDir || homeDirPath(),
1092
+ bootstrapPhase: getN8nBootstrapPhase(),
1093
+ bootstrapError: getN8nBootstrapError() || state.lastError,
1094
+ installing: state.installing,
1095
+ ownerReady: state.ownerReady,
1096
+ logs: state.logs.slice(-80),
1097
+ localUiUrl,
1098
+ publicWebhookUrl,
1099
+ listenHost: "127.0.0.1",
1100
+ listenPort,
1101
+ };
1102
+ }
1103
+ function getN8nLogs() {
1104
+ return state.logs.slice(-80);
1105
+ }
1106
+ /** Env bridge n8n → Hermes (lecture fichier + URL locale). */
1107
+ function getN8nBridgeEnvForHermes() {
1108
+ const home = state.running?.homeDir || n8nHomeDir();
1109
+ const localUiUrl = state.running?.uiUrl || `http://127.0.0.1:${N8N_DESKTOP_PORT}`;
1110
+ return (ctx.getN8nNextEnvExtra?.({
1111
+ connectionMode: "local",
1112
+ homeDir: home,
1113
+ localUiUrl,
1114
+ }) || {});
1115
+ }
1116
+ async function ensureN8nRuntimeFromUi(opts) {
1117
+ state.installing = true;
1118
+ const log = (line) => {
1119
+ pushLog(line);
1120
+ opts?.onLog?.(line);
1121
+ };
1122
+ try {
1123
+ const r = await ensureN8nRuntime(ctx, { onLog: log });
1124
+ if (r.entry)
1125
+ state.entryPath = r.entry;
1126
+ return {
1127
+ ok: r.ok,
1128
+ detail: r.detail,
1129
+ entryPath: r.entry,
1130
+ runtimeDir: n8nRuntimeCacheDir(ctx),
1131
+ };
1132
+ }
1133
+ finally {
1134
+ state.installing = false;
1135
+ }
1136
+ }
1137
+ /** Exposé pour tests. */
1138
+ function __resetN8nStateForTests() {
1139
+ state.running = null;
1140
+ state.lastError = null;
1141
+ state.version = null;
1142
+ state.logs = [];
1143
+ state.entryPath = null;
1144
+ state.installing = false;
1145
+ state.ownerReady = false;
1146
+ }
1147
+ return {
1148
+ startN8n,
1149
+ stopN8n,
1150
+ getRunningN8n,
1151
+ getN8nStatusPayload,
1152
+ getN8nNextEnv,
1153
+ getN8nLogs,
1154
+ ensureN8nRuntimeFromUi: async (uiOpts) => {
1155
+ const r = await ensureN8nRuntimeFromUi(uiOpts);
1156
+ return { ...r, phase: getN8nBootstrapPhase() };
1157
+ },
1158
+ findN8nEntry,
1159
+ applyN8nPublicBaseUrl,
1160
+ n8nHomeLooksWarm,
1161
+ getN8nLastStartPath,
1162
+ prepareN8nUiSession,
1163
+ provisionN8nAgentApiKey,
1164
+ revokeN8nAgentKey,
1165
+ getN8nBridgeEnvForHermes,
1166
+ n8nHomeDir,
1167
+ __resetForTests: __resetN8nStateForTests,
1168
+ };
1169
+ }
1170
+ //# sourceMappingURL=launcher.js.map