@interactive-inc/claude-funnel 0.7.1 → 0.8.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 (349) hide show
  1. package/README.md +155 -133
  2. package/dist/bin.js +1417 -0
  3. package/dist/gateway/daemon.js +513 -0
  4. package/dist/highlights-eq9cgrbb.scm +604 -0
  5. package/dist/highlights-ghv9g403.scm +205 -0
  6. package/dist/highlights-hk7bwhj4.scm +284 -0
  7. package/dist/highlights-r812a2qc.scm +150 -0
  8. package/dist/highlights-x6tmsnaa.scm +115 -0
  9. package/dist/injections-73j83es3.scm +27 -0
  10. package/dist/tree-sitter-javascript-nd0q4pe9.wasm +0 -0
  11. package/dist/tree-sitter-markdown-411r6y9b.wasm +0 -0
  12. package/dist/tree-sitter-markdown_inline-j5349f42.wasm +0 -0
  13. package/dist/tree-sitter-typescript-zxjzwt75.wasm +0 -0
  14. package/dist/tree-sitter-zig-e78zbjpm.wasm +0 -0
  15. package/lib/bin.ts +78 -0
  16. package/lib/{modules → cli}/router/to-request.ts +13 -20
  17. package/lib/cli/routes/channels.$channel.connectors.$connector.rename.$newName.ts +27 -0
  18. package/lib/cli/routes/channels.$channel.connectors.$connector.request.ts +40 -0
  19. package/lib/cli/routes/channels.$channel.connectors.$connector.schedules.add.$id.ts +41 -0
  20. package/lib/cli/routes/channels.$channel.connectors.$connector.schedules.remove.$id.ts +22 -0
  21. package/lib/cli/routes/channels.$channel.connectors.$connector.schedules.ts +23 -0
  22. package/lib/cli/routes/channels.$channel.connectors.$connector.ts +26 -0
  23. package/lib/cli/routes/channels.$channel.connectors.add.$connector.ts +92 -0
  24. package/lib/cli/routes/channels.$channel.connectors.remove.$connector.ts +22 -0
  25. package/lib/cli/routes/channels.$channel.connectors.set.$connector.ts +63 -0
  26. package/lib/cli/routes/channels.$channel.connectors.ts +26 -0
  27. package/lib/cli/routes/channels.$channel.rename.$newName.ts +22 -0
  28. package/lib/cli/routes/channels.$channel.set.delivery.$mode.ts +34 -0
  29. package/lib/cli/routes/channels.$channel.ts +34 -0
  30. package/lib/cli/routes/channels.add.$channel.ts +33 -0
  31. package/lib/cli/routes/channels.remove.$channel.ts +20 -0
  32. package/lib/cli/routes/channels.ts +39 -0
  33. package/lib/cli/routes/claude.ts +69 -0
  34. package/lib/cli/routes/gateway.listeners.ts +41 -0
  35. package/lib/cli/routes/gateway.logs.ts +123 -0
  36. package/lib/{routes/gateway/restart.ts → cli/routes/gateway.restart.ts} +20 -5
  37. package/lib/cli/routes/gateway.run.ts +41 -0
  38. package/lib/cli/routes/gateway.start.ts +50 -0
  39. package/lib/cli/routes/gateway.status.ts +19 -0
  40. package/lib/cli/routes/gateway.stop.ts +32 -0
  41. package/lib/cli/routes/gateway.ts +55 -0
  42. package/lib/cli/routes/index.ts +202 -0
  43. package/lib/cli/routes/profiles.$profile.as-default.ts +22 -0
  44. package/lib/cli/routes/profiles.$profile.rename.$newName.ts +22 -0
  45. package/lib/cli/routes/profiles.$profile.run.ts +36 -0
  46. package/lib/cli/routes/profiles.add.$profile.ts +46 -0
  47. package/lib/cli/routes/profiles.remove.$profile.ts +20 -0
  48. package/lib/cli/routes/profiles.set.$profile.ts +46 -0
  49. package/lib/cli/routes/profiles.ts +40 -0
  50. package/lib/cli/routes/status.ts +93 -0
  51. package/lib/cli/routes/update.ts +27 -0
  52. package/lib/connectors/connector-config-schema.ts +16 -0
  53. package/lib/connectors/connector-factory.ts +94 -0
  54. package/lib/connectors/connector-listener.ts +20 -0
  55. package/lib/{modules/connectors/funnel-discord-adapter.ts → connectors/discord-adapter.ts} +6 -11
  56. package/lib/{modules/connectors → connectors}/discord-connector-schema.ts +4 -1
  57. package/lib/connectors/discord-listener.ts +111 -0
  58. package/lib/{modules/connectors/funnel-gh-adapter.ts → connectors/gh-adapter.ts} +3 -6
  59. package/lib/{modules/connectors → connectors}/gh-connector-schema.ts +4 -1
  60. package/lib/{modules/connectors/funnel-gh-listener.ts → connectors/gh-listener.ts} +45 -19
  61. package/lib/{modules/connectors → connectors}/match-cron.ts +10 -4
  62. package/lib/connectors/schedule-connector-schema.ts +33 -0
  63. package/lib/connectors/schedule-listener.ts +207 -0
  64. package/lib/connectors/schedule-state-store.ts +54 -0
  65. package/lib/connectors/slack-adapter.ts +36 -0
  66. package/lib/{modules/connectors → connectors}/slack-connector-schema.ts +4 -1
  67. package/lib/{modules/connectors/funnel-slack-event-processor.ts → connectors/slack-event-processor.ts} +15 -9
  68. package/lib/{modules/connectors/funnel-slack-listener.ts → connectors/slack-listener.ts} +33 -14
  69. package/lib/engine/channels/channels.ts +520 -0
  70. package/lib/{modules/claude/funnel-claude.ts → engine/claude/claude.ts} +28 -55
  71. package/lib/engine/claude/gateway-controller.ts +4 -0
  72. package/lib/{modules/fs/funnel-file-system.ts → engine/fs/file-system.ts} +4 -0
  73. package/lib/{modules/fs/memory-funnel-file-system.ts → engine/fs/memory-file-system.ts} +20 -3
  74. package/lib/{modules/fs/node-funnel-file-system.ts → engine/fs/node-file-system.ts} +14 -2
  75. package/lib/{modules/http/memory-funnel-http-client.ts → engine/http/memory-http-client.ts} +1 -5
  76. package/lib/{modules/http/node-funnel-http-client.ts → engine/http/node-http-client.ts} +1 -5
  77. package/lib/{modules/id/memory-funnel-id-generator.ts → engine/id/memory-id-generator.ts} +1 -1
  78. package/lib/{modules/id/node-funnel-id-generator.ts → engine/id/node-id-generator.ts} +1 -1
  79. package/lib/{modules/logger/memory-funnel-logger.ts → engine/logger/memory-logger.ts} +1 -1
  80. package/lib/{modules/logger/node-funnel-logger.ts → engine/logger/node-logger.ts} +1 -1
  81. package/lib/{modules/logger/noop-funnel-logger.ts → engine/logger/noop-logger.ts} +1 -1
  82. package/lib/engine/mcp/channel-server.ts +204 -0
  83. package/lib/{modules/mcp/funnel-mcp.ts → engine/mcp/mcp.ts} +24 -10
  84. package/lib/{modules/process/memory-funnel-process-runner.ts → engine/process/memory-process-runner.ts} +1 -1
  85. package/lib/{modules/process/node-funnel-process-runner.ts → engine/process/node-process-runner.ts} +12 -21
  86. package/lib/engine/profiles/profile-channel-checker.ts +7 -0
  87. package/lib/{modules/profiles/funnel-profiles.ts → engine/profiles/profiles.ts} +41 -43
  88. package/lib/{modules/settings/mock-funnel-settings-reader.ts → engine/settings/mock-settings-reader.ts} +4 -3
  89. package/lib/{modules/settings/funnel-settings-reader.ts → engine/settings/settings-reader.ts} +1 -1
  90. package/lib/engine/settings/settings-schema.ts +46 -0
  91. package/lib/engine/settings/settings-store.ts +110 -0
  92. package/lib/{modules/time/memory-funnel-clock.ts → engine/time/memory-clock.ts} +1 -1
  93. package/lib/{modules/time/node-funnel-clock.ts → engine/time/node-clock.ts} +1 -1
  94. package/lib/funnel.ts +83 -78
  95. package/lib/gateway/auth-middleware.ts +44 -0
  96. package/lib/gateway/broadcaster.ts +319 -0
  97. package/lib/gateway/daemon.ts +47 -0
  98. package/lib/gateway/factory.ts +10 -0
  99. package/lib/gateway/funnel-event-store.ts +155 -0
  100. package/lib/gateway/gateway-server.ts +414 -0
  101. package/lib/gateway/gateway-token.ts +79 -0
  102. package/lib/{modules/gateway/funnel-gateway.ts → gateway/gateway.ts} +27 -13
  103. package/lib/{modules/gateway → gateway}/kill-competing-slack-gateways.ts +4 -4
  104. package/lib/gateway/listener-supervisor.ts +339 -0
  105. package/lib/gateway/listeners-client.ts +128 -0
  106. package/lib/gateway/resolve-daemon-script.ts +26 -0
  107. package/lib/gateway/routes/channels.connectors.call.ts +39 -0
  108. package/lib/gateway/routes/health.ts +13 -0
  109. package/lib/gateway/routes/index.ts +24 -0
  110. package/lib/gateway/routes/listeners.list.ts +6 -0
  111. package/lib/gateway/routes/listeners.restart.ts +15 -0
  112. package/lib/gateway/routes/listeners.start.ts +15 -0
  113. package/lib/gateway/routes/listeners.stop.ts +15 -0
  114. package/lib/gateway/routes/route-deps.ts +11 -0
  115. package/lib/gateway/routes/status.ts +15 -0
  116. package/lib/gateway/routes/validator.ts +17 -0
  117. package/lib/index.ts +50 -92
  118. package/lib/logger/leuco-human-file-writer.ts +65 -0
  119. package/lib/logger/leuco-human-logger.ts +98 -0
  120. package/lib/logger/leuco-human-record.ts +16 -0
  121. package/lib/logger/leuco-human-stdout-writer.ts +26 -0
  122. package/lib/logger/leuco-human-writer.ts +14 -0
  123. package/lib/logger/leuco-logger-memory-sink.ts +67 -0
  124. package/lib/logger/leuco-logger-record.ts +13 -0
  125. package/lib/logger/leuco-logger-sink.ts +33 -0
  126. package/lib/logger/leuco-logger-sqlite-sink.ts +355 -0
  127. package/lib/logger/leuco-logger.ts +135 -0
  128. package/lib/tui/app.tsx +357 -0
  129. package/lib/tui/components/add-row.tsx +18 -0
  130. package/lib/tui/components/brand.tsx +27 -0
  131. package/lib/tui/components/card.tsx +44 -0
  132. package/lib/tui/components/detail-bar.tsx +46 -0
  133. package/lib/tui/components/editable-field.tsx +33 -0
  134. package/lib/tui/components/empty-state.tsx +11 -0
  135. package/lib/tui/components/gateway-status.tsx +66 -0
  136. package/lib/tui/components/keymap.tsx +29 -0
  137. package/lib/tui/components/menu-item.tsx +73 -0
  138. package/lib/tui/components/menu.tsx +26 -0
  139. package/lib/tui/components/panel-header.tsx +22 -0
  140. package/lib/tui/components/readonly-field.tsx +18 -0
  141. package/lib/tui/components/section-header.tsx +25 -0
  142. package/lib/tui/components/selection-accent.tsx +32 -0
  143. package/lib/tui/components/session-item.tsx +33 -0
  144. package/lib/tui/components/session-list.tsx +33 -0
  145. package/lib/tui/components/ui/hascii/accordion-item.tsx +88 -0
  146. package/lib/tui/components/ui/hascii/accordion.tsx +96 -0
  147. package/lib/tui/components/ui/hascii/alert-dialog.tsx +43 -0
  148. package/lib/tui/components/ui/hascii/badge.tsx +51 -0
  149. package/lib/tui/components/ui/hascii/breadcrumb.tsx +58 -0
  150. package/lib/tui/components/ui/hascii/button.tsx +194 -0
  151. package/lib/tui/components/ui/hascii/card-content.tsx +14 -0
  152. package/lib/tui/components/ui/hascii/card-description.tsx +13 -0
  153. package/lib/tui/components/ui/hascii/card-footer.tsx +14 -0
  154. package/lib/tui/components/ui/hascii/card-header.tsx +14 -0
  155. package/lib/tui/components/ui/hascii/card-title.tsx +13 -0
  156. package/lib/tui/components/ui/hascii/card.tsx +27 -0
  157. package/lib/tui/components/ui/hascii/checkbox.tsx +65 -0
  158. package/lib/tui/components/ui/hascii/command.tsx +159 -0
  159. package/lib/tui/components/ui/hascii/dialog-content.tsx +14 -0
  160. package/lib/tui/components/ui/hascii/dialog-description.tsx +13 -0
  161. package/lib/tui/components/ui/hascii/dialog-footer.tsx +14 -0
  162. package/lib/tui/components/ui/hascii/dialog-header.tsx +14 -0
  163. package/lib/tui/components/ui/hascii/dialog-title.tsx +13 -0
  164. package/lib/tui/components/ui/hascii/dialog.tsx +27 -0
  165. package/lib/tui/components/ui/hascii/file-tree.tsx +142 -0
  166. package/lib/tui/components/ui/hascii/focus-group.tsx +62 -0
  167. package/lib/tui/components/ui/hascii/form-item.tsx +43 -0
  168. package/lib/tui/components/ui/hascii/input-otp.tsx +86 -0
  169. package/lib/tui/components/ui/hascii/input.tsx +130 -0
  170. package/lib/tui/components/ui/hascii/pagination.tsx +105 -0
  171. package/lib/tui/components/ui/hascii/progress.tsx +28 -0
  172. package/lib/tui/components/ui/hascii/select.tsx +131 -0
  173. package/lib/tui/components/ui/hascii/separator.tsx +35 -0
  174. package/lib/tui/components/ui/hascii/sidebar-content.tsx +23 -0
  175. package/lib/tui/components/ui/hascii/sidebar-header.tsx +14 -0
  176. package/lib/tui/components/ui/hascii/sidebar-menu-item.tsx +67 -0
  177. package/lib/tui/components/ui/hascii/sidebar.tsx +24 -0
  178. package/lib/tui/components/ui/hascii/skeleton.tsx +60 -0
  179. package/lib/tui/components/ui/hascii/slider.tsx +91 -0
  180. package/lib/tui/components/ui/hascii/snackbar.tsx +75 -0
  181. package/lib/tui/components/ui/hascii/sparkline.tsx +53 -0
  182. package/lib/tui/components/ui/hascii/spinner.tsx +47 -0
  183. package/lib/tui/components/ui/hascii/stepper.tsx +54 -0
  184. package/lib/tui/components/ui/hascii/switch.tsx +66 -0
  185. package/lib/tui/components/ui/hascii/table.tsx +95 -0
  186. package/lib/tui/components/ui/hascii/tabs.tsx +59 -0
  187. package/lib/tui/components/ui/hascii/toggle-group-item.tsx +45 -0
  188. package/lib/tui/components/ui/hascii/toggle-group.tsx +99 -0
  189. package/lib/tui/components/ui/hascii/tree.tsx +104 -0
  190. package/lib/tui/components/view-shell.tsx +44 -0
  191. package/lib/tui/filter-input.tsx +33 -0
  192. package/lib/tui/hooks/hascii/use-pressable.ts +54 -0
  193. package/lib/tui/parse-comma-list.ts +14 -0
  194. package/lib/tui/profile-launcher.tsx +61 -0
  195. package/lib/tui/scrollbar-options.ts +19 -0
  196. package/lib/tui/sidebar.tsx +50 -0
  197. package/lib/tui/theme.ts +40 -0
  198. package/lib/tui/tui.tsx +20 -0
  199. package/lib/tui/types.ts +38 -0
  200. package/lib/tui/unique-name.ts +18 -0
  201. package/lib/tui/use-event-stream.ts +133 -0
  202. package/lib/tui/use-snapshot.ts +99 -0
  203. package/lib/tui/utils/hascii/form-item-context.tsx +23 -0
  204. package/lib/tui/utils/hascii/input-focus-context.tsx +31 -0
  205. package/lib/tui/utils/hascii/theme-context.tsx +26 -0
  206. package/lib/tui/utils/hascii/theme.ts +176 -0
  207. package/lib/tui/views/channels-view.tsx +108 -0
  208. package/lib/tui/views/connectors-view.tsx +164 -0
  209. package/lib/tui/views/events-view.tsx +160 -0
  210. package/lib/tui/views/listeners-view.tsx +80 -0
  211. package/lib/tui/views/profiles-view.tsx +152 -0
  212. package/package.json +50 -44
  213. package/lib/api.ts +0 -54
  214. package/lib/modules/channels/channel-connector-ref-updater.ts +0 -4
  215. package/lib/modules/channels/funnel-channels.ts +0 -160
  216. package/lib/modules/connectors/connector-config-schema.ts +0 -16
  217. package/lib/modules/connectors/connector-existence-checker.ts +0 -3
  218. package/lib/modules/connectors/funnel-callable-connector-store.ts +0 -9
  219. package/lib/modules/connectors/funnel-connector-listener.ts +0 -5
  220. package/lib/modules/connectors/funnel-connector-stores.ts +0 -52
  221. package/lib/modules/connectors/funnel-connector-type-store.ts +0 -24
  222. package/lib/modules/connectors/funnel-connectors.ts +0 -151
  223. package/lib/modules/connectors/funnel-discord-listener.ts +0 -71
  224. package/lib/modules/connectors/funnel-discord-store.ts +0 -88
  225. package/lib/modules/connectors/funnel-gh-store.ts +0 -101
  226. package/lib/modules/connectors/funnel-json-connector-store.ts +0 -100
  227. package/lib/modules/connectors/funnel-schedule-listener.ts +0 -130
  228. package/lib/modules/connectors/funnel-schedule-store.ts +0 -195
  229. package/lib/modules/connectors/funnel-slack-adapter.ts +0 -31
  230. package/lib/modules/connectors/funnel-slack-store.ts +0 -90
  231. package/lib/modules/connectors/migrate-legacy-connectors.ts +0 -81
  232. package/lib/modules/connectors/schedule-connector-schema.ts +0 -18
  233. package/lib/modules/connectors/schedule-last-fired-store.ts +0 -48
  234. package/lib/modules/gateway/daemon.ts +0 -74
  235. package/lib/modules/gateway/funnel-broadcaster.ts +0 -37
  236. package/lib/modules/gateway/funnel-event-logger.ts +0 -59
  237. package/lib/modules/gateway/funnel-gateway-server.ts +0 -241
  238. package/lib/modules/mcp/channel-server.ts +0 -76
  239. package/lib/modules/profiles/profile-channel-checker.ts +0 -3
  240. package/lib/modules/profiles/profile-channel-ref-updater.ts +0 -3
  241. package/lib/modules/repos/funnel-repositories.ts +0 -112
  242. package/lib/modules/schedule/funnel-schedule.ts +0 -39
  243. package/lib/modules/settings/funnel-settings-store.ts +0 -56
  244. package/lib/modules/settings/settings-schema.ts +0 -33
  245. package/lib/modules/tui/app.tsx +0 -44
  246. package/lib/modules/tui/tui.tsx +0 -13
  247. package/lib/routes/channels/add.help.ts +0 -3
  248. package/lib/routes/channels/add.ts +0 -21
  249. package/lib/routes/channels/connectors-attach.help.ts +0 -3
  250. package/lib/routes/channels/connectors-attach.ts +0 -17
  251. package/lib/routes/channels/connectors-detach.help.ts +0 -3
  252. package/lib/routes/channels/connectors-detach.ts +0 -17
  253. package/lib/routes/channels/group.help.ts +0 -16
  254. package/lib/routes/channels/group.ts +0 -22
  255. package/lib/routes/channels/remove.help.ts +0 -3
  256. package/lib/routes/channels/remove.ts +0 -17
  257. package/lib/routes/channels/rename.help.ts +0 -5
  258. package/lib/routes/channels/rename.ts +0 -17
  259. package/lib/routes/channels/routes.ts +0 -19
  260. package/lib/routes/channels/show.help.ts +0 -1
  261. package/lib/routes/channels/show.ts +0 -26
  262. package/lib/routes/claude/claude.help.ts +0 -16
  263. package/lib/routes/claude/claude.ts +0 -76
  264. package/lib/routes/claude/routes.ts +0 -4
  265. package/lib/routes/connectors/add.help.ts +0 -28
  266. package/lib/routes/connectors/add.ts +0 -64
  267. package/lib/routes/connectors/group.help.ts +0 -14
  268. package/lib/routes/connectors/group.ts +0 -18
  269. package/lib/routes/connectors/remove.help.ts +0 -3
  270. package/lib/routes/connectors/remove.ts +0 -17
  271. package/lib/routes/connectors/rename.help.ts +0 -5
  272. package/lib/routes/connectors/rename.ts +0 -17
  273. package/lib/routes/connectors/routes.ts +0 -23
  274. package/lib/routes/connectors/schedules-add.help.ts +0 -11
  275. package/lib/routes/connectors/schedules-add.ts +0 -33
  276. package/lib/routes/connectors/schedules-group.help.ts +0 -1
  277. package/lib/routes/connectors/schedules-group.ts +0 -38
  278. package/lib/routes/connectors/schedules-remove.help.ts +0 -3
  279. package/lib/routes/connectors/schedules-remove.ts +0 -17
  280. package/lib/routes/connectors/set.help.ts +0 -8
  281. package/lib/routes/connectors/set.ts +0 -72
  282. package/lib/routes/connectors/show.help.ts +0 -1
  283. package/lib/routes/connectors/show.ts +0 -41
  284. package/lib/routes/gateway/group.help.ts +0 -15
  285. package/lib/routes/gateway/group.ts +0 -28
  286. package/lib/routes/gateway/logs.help.ts +0 -13
  287. package/lib/routes/gateway/logs.ts +0 -102
  288. package/lib/routes/gateway/restart.help.ts +0 -10
  289. package/lib/routes/gateway/routes.ts +0 -18
  290. package/lib/routes/gateway/run.help.ts +0 -12
  291. package/lib/routes/gateway/run.ts +0 -35
  292. package/lib/routes/gateway/start.help.ts +0 -15
  293. package/lib/routes/gateway/start.ts +0 -32
  294. package/lib/routes/gateway/status.help.ts +0 -9
  295. package/lib/routes/gateway/status.ts +0 -28
  296. package/lib/routes/gateway/stop.help.ts +0 -8
  297. package/lib/routes/gateway/stop.ts +0 -21
  298. package/lib/routes/profiles/add.help.ts +0 -3
  299. package/lib/routes/profiles/add.ts +0 -33
  300. package/lib/routes/profiles/group.help.ts +0 -16
  301. package/lib/routes/profiles/group.ts +0 -25
  302. package/lib/routes/profiles/launch.help.ts +0 -4
  303. package/lib/routes/profiles/launch.ts +0 -36
  304. package/lib/routes/profiles/remove.help.ts +0 -3
  305. package/lib/routes/profiles/remove.ts +0 -17
  306. package/lib/routes/profiles/rename.help.ts +0 -5
  307. package/lib/routes/profiles/rename.ts +0 -17
  308. package/lib/routes/profiles/routes.ts +0 -18
  309. package/lib/routes/profiles/set.help.ts +0 -5
  310. package/lib/routes/profiles/set.ts +0 -32
  311. package/lib/routes/repos/add.help.ts +0 -6
  312. package/lib/routes/repos/add.ts +0 -20
  313. package/lib/routes/repos/group.help.ts +0 -11
  314. package/lib/routes/repos/group.ts +0 -18
  315. package/lib/routes/repos/remove.help.ts +0 -3
  316. package/lib/routes/repos/remove.ts +0 -17
  317. package/lib/routes/repos/rename.help.ts +0 -5
  318. package/lib/routes/repos/rename.ts +0 -17
  319. package/lib/routes/repos/routes.ts +0 -17
  320. package/lib/routes/repos/set.help.ts +0 -5
  321. package/lib/routes/repos/set.ts +0 -21
  322. package/lib/routes/repos/show.help.ts +0 -1
  323. package/lib/routes/repos/show.ts +0 -19
  324. package/lib/routes/request/discord-help.ts +0 -9
  325. package/lib/routes/request/discord.help.ts +0 -19
  326. package/lib/routes/request/discord.ts +0 -65
  327. package/lib/routes/request/group.help.ts +0 -15
  328. package/lib/routes/request/group.ts +0 -9
  329. package/lib/routes/request/routes.ts +0 -14
  330. package/lib/routes/request/slack-help.ts +0 -9
  331. package/lib/routes/request/slack.help.ts +0 -19
  332. package/lib/routes/request/slack.ts +0 -61
  333. package/lib/routes/status/routes.ts +0 -4
  334. package/lib/routes/status/status.help.ts +0 -6
  335. package/lib/routes/status/status.ts +0 -77
  336. package/lib/routes/update/routes.ts +0 -4
  337. package/lib/routes/update/update.help.ts +0 -5
  338. package/lib/routes/update/update.ts +0 -21
  339. package/lib/routes.ts +0 -40
  340. /package/lib/{factory.ts → cli/factory.ts} +0 -0
  341. /package/lib/{modules → cli}/router/query-to-cli-args.ts +0 -0
  342. /package/lib/{modules → cli}/router/validator.ts +0 -0
  343. /package/lib/{modules/connectors/funnel-connector-adapter.ts → connectors/connector-adapter.ts} +0 -0
  344. /package/lib/{modules/connectors/funnel-discord-event-processor.ts → connectors/discord-event-processor.ts} +0 -0
  345. /package/lib/{modules/http/funnel-http-client.ts → engine/http/http-client.ts} +0 -0
  346. /package/lib/{modules/id/funnel-id-generator.ts → engine/id/id-generator.ts} +0 -0
  347. /package/lib/{modules/logger/funnel-logger.ts → engine/logger/logger.ts} +0 -0
  348. /package/lib/{modules/process/funnel-process-runner.ts → engine/process/process-runner.ts} +0 -0
  349. /package/lib/{modules/time/funnel-clock.ts → engine/time/clock.ts} +0 -0
package/lib/index.ts CHANGED
@@ -1,92 +1,50 @@
1
- #!/usr/bin/env bun
2
- import pkg from "../package.json" with { type: "json" }
3
- import { createConnectorStores } from "@/modules/connectors/funnel-connector-stores"
4
- import { migrateLegacyConnectors } from "@/modules/connectors/migrate-legacy-connectors"
5
- import { startChannelServer } from "@/modules/mcp/channel-server"
6
- import { toRequest } from "@/modules/router/to-request"
7
- import { launchTui } from "@/modules/tui/tui"
8
- import { app } from "@/routes"
9
-
10
- process.title = "funnel"
11
-
12
- migrateLegacyConnectors({ stores: createConnectorStores() })
13
-
14
- const HELP = `funnel — Open Claude Funnel
15
-
16
- usage: funnel [command]
17
-
18
- commands:
19
- (none) launch TUI
20
- claude launch Claude Code (default profile or --profile)
21
- connectors manage external connections (Slack, etc.)
22
- channels manage subscription boxes
23
- profiles manage launch profiles
24
- request send an outbound API call via a connector
25
- repos manage repositories (extra)
26
- gateway manage the gateway
27
- status show overall connection status
28
- update update funnel to the latest version
29
- mcp run as an MCP server (invoked from .mcp.json)
30
-
31
- options:
32
- --help, -h show help
33
- --version, -v show version
34
-
35
- more: funnel <command> --help`
36
-
37
- const args = process.argv.slice(2)
38
-
39
- if (args.length === 0) {
40
- await launchTui()
41
- process.exit(0)
42
- }
43
-
44
- if (args[0] === "--version" || args[0] === "-v") {
45
- process.stdout.write(`${pkg.version}\n`)
46
- process.exit(0)
47
- }
48
-
49
- if (args[0] === "mcp") {
50
- await startChannelServer()
51
- } else {
52
- const { method, url } = toRequest(args)
53
-
54
- const parsed = new URL(url)
55
-
56
- if (parsed.searchParams.has("help")) {
57
- if (parsed.pathname === "/") {
58
- process.stdout.write(`${HELP}\n`)
59
- process.exit(0)
60
- }
61
-
62
- let res = await app.request(url, { method })
63
-
64
- if (!res.ok && method !== "GET") {
65
- res = await app.request(url, { method: "GET" })
66
- }
67
-
68
- if (!res.ok) {
69
- const group = parsed.pathname.split("/").filter(Boolean)[0]
70
-
71
- if (group) {
72
- res = await app.request(`http://localhost/${group}?help=true`, { method: "GET" })
73
- }
74
- }
75
-
76
- const text = res.ok ? await res.text() : HELP
77
- process.stdout.write(`${text}\n`)
78
- process.exit(0)
79
- }
80
-
81
- const res = await app.request(url, { method })
82
-
83
- if (!res.ok) {
84
- const text = await res.text()
85
- if (text) process.stderr.write(`${text}\n`)
86
- process.exit(1)
87
- }
88
-
89
- const body = await res.text()
90
-
91
- if (body) process.stdout.write(`${body}\n`)
92
- }
1
+ // Public API surface for the @interactive-inc/claude-funnel package.
2
+ // Organized by layer so consumers can find what they need at a glance.
3
+
4
+ // Facade
5
+ export * from "@/funnel"
6
+
7
+ // Engine domain
8
+ export * from "@/engine/channels/channels"
9
+ export * from "@/engine/claude/claude"
10
+ export * from "@/engine/mcp/mcp"
11
+ export * from "@/engine/profiles/profiles"
12
+ export * from "@/engine/settings/settings-reader"
13
+ export * from "@/engine/settings/settings-store"
14
+ export * from "@/engine/settings/mock-settings-reader"
15
+ export * from "@/engine/settings/settings-schema"
16
+
17
+ // Engine — boundaries (abstract + Node / Memory implementations)
18
+ export * from "@/engine/fs/file-system"
19
+ export * from "@/engine/fs/node-file-system"
20
+ export * from "@/engine/fs/memory-file-system"
21
+
22
+ export * from "@/engine/process/process-runner"
23
+ export * from "@/engine/process/node-process-runner"
24
+ export * from "@/engine/process/memory-process-runner"
25
+
26
+ export * from "@/engine/logger/logger"
27
+ export * from "@/engine/logger/node-logger"
28
+ export * from "@/engine/logger/memory-logger"
29
+ export * from "@/engine/logger/noop-logger"
30
+
31
+ export * from "@/engine/time/clock"
32
+ export * from "@/engine/time/node-clock"
33
+ export * from "@/engine/time/memory-clock"
34
+
35
+ export * from "@/engine/id/id-generator"
36
+ export * from "@/engine/id/node-id-generator"
37
+ export * from "@/engine/id/memory-id-generator"
38
+
39
+ // Connectors
40
+ export * from "@/connectors/connector-factory"
41
+ export * from "@/connectors/connector-config-schema"
42
+ export * from "@/connectors/schedule-connector-schema"
43
+
44
+ // Gateway
45
+ export * from "@/gateway/gateway"
46
+ export * from "@/gateway/gateway-server"
47
+ export * from "@/gateway/broadcaster"
48
+ export * from "@/gateway/funnel-event-store"
49
+ export * from "@/gateway/listener-supervisor"
50
+ export * from "@/gateway/listeners-client"
@@ -0,0 +1,65 @@
1
+ import { appendFileSync, existsSync, mkdirSync, renameSync, statSync, unlinkSync } from "node:fs"
2
+ import { dirname } from "node:path"
3
+ import type { LeucoHumanRecord } from "@/logger/leuco-human-record"
4
+ import type { LeucoHumanWriter } from "@/logger/leuco-human-writer"
5
+
6
+ type Props = {
7
+ /** Filesystem path. Parent directory is created on construct. */
8
+ path: string
9
+ /**
10
+ * Optional size cap in bytes. When the next write would push the file
11
+ * over the cap, the existing file becomes `<path>.1` (replacing any
12
+ * prior `.1`) and a fresh file takes its place. Single-keep rotation —
13
+ * a second cycle drops the previous `.1`.
14
+ */
15
+ maxBytes?: number
16
+ }
17
+
18
+ /**
19
+ * Appends one JSON line per record to a file. Optional one-keep size
20
+ * rotation. Designed for diagnostic logs a human tails (`tail -f file |
21
+ * jq`); not for replay or queries — use `LeucoLoggerSqliteSink` if you
22
+ * need indexed lookups.
23
+ *
24
+ * Writes are synchronous (`appendFileSync`), so each line is durable
25
+ * before `write` returns. Throughput matches the OS file cache; for
26
+ * high-volume logging consider buffering at the call site or using a
27
+ * different writer.
28
+ */
29
+ export class LeucoHumanFileWriter implements LeucoHumanWriter {
30
+ private readonly path: string
31
+ private readonly maxBytes: number | null
32
+
33
+ constructor(props: Props) {
34
+ this.path = props.path
35
+ this.maxBytes = props.maxBytes ?? null
36
+ this.ensureDir()
37
+ }
38
+
39
+ write(record: LeucoHumanRecord): void | Error {
40
+ try {
41
+ const line = `${JSON.stringify(record)}\n`
42
+ this.rotateIfNeeded(Buffer.byteLength(line))
43
+ appendFileSync(this.path, line)
44
+ } catch (e) {
45
+ return e instanceof Error ? e : new Error(String(e))
46
+ }
47
+ }
48
+
49
+ private ensureDir(): void {
50
+ const dir = dirname(this.path)
51
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true })
52
+ }
53
+
54
+ private rotateIfNeeded(incomingBytes: number): void {
55
+ if (this.maxBytes === null) return
56
+ if (!existsSync(this.path)) return
57
+
58
+ const size = statSync(this.path).size
59
+ if (size + incomingBytes <= this.maxBytes) return
60
+
61
+ const backup = `${this.path}.1`
62
+ if (existsSync(backup)) unlinkSync(backup)
63
+ renameSync(this.path, backup)
64
+ }
65
+ }
@@ -0,0 +1,98 @@
1
+ import type { LeucoHumanLevel, LeucoHumanRecord } from "@/logger/leuco-human-record"
2
+ import type { LeucoHumanWriter } from "@/logger/leuco-human-writer"
3
+
4
+ type WriteErrorHandler = (error: Error, record: LeucoHumanRecord) => void
5
+
6
+ type Props = {
7
+ /** Where records go. Use `LeucoHumanStdoutWriter`, `LeucoHumanFileWriter`, or your own. */
8
+ writer: LeucoHumanWriter
9
+ /** Minimum level to emit. Lower-rank records are dropped. Default: "info". */
10
+ level?: LeucoHumanLevel
11
+ /** Override for tests. Defaults to `Date.now`. */
12
+ now?: () => number
13
+ /** Observer for writer failures. Default: silently swallow. */
14
+ onWriteError?: WriteErrorHandler
15
+ }
16
+
17
+ const LEVEL_RANK: Record<LeucoHumanLevel, number> = {
18
+ info: 0,
19
+ warn: 1,
20
+ error: 2,
21
+ }
22
+
23
+ /**
24
+ * Human-facing diagnostic logger. The companion to `LeucoLogger`: where
25
+ * `LeucoLogger` is for schema-validated, replayable domain events,
26
+ * `LeucoHumanLogger` is for free-form info/warn/error messages destined
27
+ * for a human tailing a log or skimming during incident response.
28
+ *
29
+ * Keeping the two separate matters operationally:
30
+ * - Diagnostics typically out-volume domain events 10–1000x; mixing
31
+ * them in the same store would push events out under retention.
32
+ * - Diagnostics are unstructured by design; mixing them in would defeat
33
+ * the schema-first guarantee that makes domain events replayable.
34
+ * - Different audiences and queries (humans grep `tail -f` vs. tools
35
+ * query `WHERE seq > ?`).
36
+ *
37
+ * The writer is a port. Level gating happens here so writers receive only
38
+ * what is worth persisting. Failure isolation matches `LeucoLogger`: a
39
+ * writer that throws or returns Error is contained, surfaced via
40
+ * `onWriteError`, and never blocks the caller.
41
+ */
42
+ export class LeucoHumanLogger {
43
+ private readonly writer: LeucoHumanWriter
44
+ private readonly minRank: number
45
+ private readonly now: () => number
46
+ private readonly onWriteError: WriteErrorHandler | null
47
+
48
+ constructor(props: Props) {
49
+ this.writer = props.writer
50
+ this.minRank = LEVEL_RANK[props.level ?? "info"]
51
+ this.now = props.now ?? (() => Date.now())
52
+ this.onWriteError = props.onWriteError ?? null
53
+ }
54
+
55
+ info(message: string, meta?: Record<string, unknown>): void {
56
+ this.emit("info", message, meta)
57
+ }
58
+
59
+ warn(message: string, meta?: Record<string, unknown>): void {
60
+ this.emit("warn", message, meta)
61
+ }
62
+
63
+ error(message: string, meta?: Record<string, unknown>): void {
64
+ this.emit("error", message, meta)
65
+ }
66
+
67
+ close(): void {
68
+ if (!this.writer.close) return
69
+ try {
70
+ this.writer.close()
71
+ } catch {
72
+ // close failures are best-effort by definition
73
+ }
74
+ }
75
+
76
+ private emit(level: LeucoHumanLevel, message: string, meta?: Record<string, unknown>): void {
77
+ if (LEVEL_RANK[level] < this.minRank) return
78
+
79
+ const record: LeucoHumanRecord = {
80
+ ts: this.now(),
81
+ level,
82
+ message,
83
+ meta: meta ?? null,
84
+ }
85
+
86
+ const error = this.callWriter(record)
87
+ if (error && this.onWriteError) this.onWriteError(error, record)
88
+ }
89
+
90
+ private callWriter(record: LeucoHumanRecord): Error | null {
91
+ try {
92
+ const outcome = this.writer.write(record)
93
+ return outcome instanceof Error ? outcome : null
94
+ } catch (e) {
95
+ return e instanceof Error ? e : new Error(String(e))
96
+ }
97
+ }
98
+ }
@@ -0,0 +1,16 @@
1
+ export type LeucoHumanLevel = "info" | "warn" | "error"
2
+
3
+ /**
4
+ * One human-facing diagnostic log entry. Distinct from `LeucoLoggerRecord`
5
+ * (which wraps a schema-validated domain event) — this is the free-form,
6
+ * for-humans-tailing-a-log shape: a level, a message, and optional meta.
7
+ *
8
+ * `meta` is `null` rather than `undefined` when absent so writers can
9
+ * persist a uniform shape (no missing-key ambiguity in JSON Lines).
10
+ */
11
+ export type LeucoHumanRecord = {
12
+ ts: number
13
+ level: LeucoHumanLevel
14
+ message: string
15
+ meta: Record<string, unknown> | null
16
+ }
@@ -0,0 +1,26 @@
1
+ import type { LeucoHumanRecord } from "@/logger/leuco-human-record"
2
+ import type { LeucoHumanWriter } from "@/logger/leuco-human-writer"
3
+
4
+ type Stream = { write(s: string): void }
5
+
6
+ type Props = {
7
+ /** Override for tests. Defaults to `process.stdout`. */
8
+ out?: Stream
9
+ }
10
+
11
+ /**
12
+ * Writes one JSON line per record to stdout. Useful as the default writer
13
+ * for foreground daemons, dev runs, and short-lived processes where a
14
+ * file-backed log would be overkill.
15
+ */
16
+ export class LeucoHumanStdoutWriter implements LeucoHumanWriter {
17
+ private readonly out: Stream
18
+
19
+ constructor(props: Props = {}) {
20
+ this.out = props.out ?? process.stdout
21
+ }
22
+
23
+ write(record: LeucoHumanRecord): void {
24
+ this.out.write(`${JSON.stringify(record)}\n`)
25
+ }
26
+ }
@@ -0,0 +1,14 @@
1
+ import type { LeucoHumanRecord } from "@/logger/leuco-human-record"
2
+
3
+ /**
4
+ * Plugin port for `LeucoHumanLogger`. Writers decide where diagnostic
5
+ * records land — stdout, JSONL file, syslog, network, etc. — without the
6
+ * logger having to know about persistence shape.
7
+ *
8
+ * `write` returns `void` on success or an `Error` the logger surfaces via
9
+ * `onWriteError`. Throwing is also tolerated; the logger catches.
10
+ */
11
+ export type LeucoHumanWriter = {
12
+ write(record: LeucoHumanRecord): void | Error
13
+ close?(): void
14
+ }
@@ -0,0 +1,67 @@
1
+ import type { LeucoLoggerRecord } from "@/logger/leuco-logger-record"
2
+ import type { LeucoLoggerPrimarySink, LeucoLoggerSink } from "@/logger/leuco-logger-sink"
3
+
4
+ type Props = {
5
+ /** Hard cap on retained records. The oldest is evicted on overflow. 0 disables retention. */
6
+ capacity?: number
7
+ }
8
+
9
+ /**
10
+ * In-memory ring buffer that doubles as primary or relay. As primary it
11
+ * owns its own seq counter (single-process only — for multi-process
12
+ * safety, use `LeucoLoggerSqliteSink` as primary and place this as a
13
+ * relay). As relay it accepts whatever seq the primary assigned and
14
+ * advances its own counter to match, so `getMaxSeq` stays meaningful.
15
+ *
16
+ * Useful as a test double, as a short-window replay buffer paired with a
17
+ * persistent primary (covering reconnects without round-tripping disk),
18
+ * or as a backing store for live subscribers.
19
+ */
20
+ export class LeucoLoggerMemorySink<E> implements LeucoLoggerPrimarySink<E>, LeucoLoggerSink<E> {
21
+ private readonly capacity: number
22
+ private readonly buffer: LeucoLoggerRecord<E>[] = []
23
+ private seq = 0
24
+
25
+ constructor(props: Props = {}) {
26
+ this.capacity = Math.max(0, props.capacity ?? 1000)
27
+ }
28
+
29
+ insert(input: { ts: number; event: E }): LeucoLoggerRecord<E> {
30
+ this.seq += 1
31
+ const record: LeucoLoggerRecord<E> = {
32
+ seq: this.seq,
33
+ ts: input.ts,
34
+ event: input.event,
35
+ }
36
+ this.append(record)
37
+ return record
38
+ }
39
+
40
+ write(record: LeucoLoggerRecord<E>): void {
41
+ if (record.seq > this.seq) this.seq = record.seq
42
+ this.append(record)
43
+ }
44
+
45
+ getMaxSeq(): number {
46
+ return this.seq
47
+ }
48
+
49
+ getRecords(): ReadonlyArray<LeucoLoggerRecord<E>> {
50
+ return this.buffer
51
+ }
52
+
53
+ clear(): void {
54
+ this.buffer.length = 0
55
+ this.seq = 0
56
+ }
57
+
58
+ private append(record: LeucoLoggerRecord<E>): void {
59
+ if (this.capacity === 0) return
60
+
61
+ this.buffer.push(record)
62
+
63
+ if (this.buffer.length > this.capacity) {
64
+ this.buffer.shift()
65
+ }
66
+ }
67
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Wrapper that `LeucoLogger.emit` puts around every event before handing it
3
+ * to a sink. `seq` is monotonic across the lifetime of the underlying store —
4
+ * sinks persist it as the primary key so replay (and broadcaster seeding
5
+ * after restart) is an indexed range scan, not a full table walk. `ts` is
6
+ * epoch milliseconds. `event` is the caller-defined payload validated by the
7
+ * Zod schema passed to the bus.
8
+ */
9
+ export type LeucoLoggerRecord<E> = {
10
+ seq: number
11
+ ts: number
12
+ event: E
13
+ }
@@ -0,0 +1,33 @@
1
+ import type { LeucoLoggerRecord } from "@/logger/leuco-logger-record"
2
+
3
+ /**
4
+ * Relay sink. Receives records that already have a `seq` assigned by the
5
+ * primary and stores or forwards them — memory ring, stdout, network push,
6
+ * a second SQLite mirror, etc. Does not generate seq itself, so any number
7
+ * can be attached and they all observe the same monotonic stream.
8
+ *
9
+ * `write` returns `void` on success or an `Error` the bus surfaces via
10
+ * `onSinkError`. Throwing is also tolerated (the bus catches), but
11
+ * returning is preferred so the failure path is part of the type.
12
+ */
13
+ export type LeucoLoggerSink<E> = {
14
+ write(record: LeucoLoggerRecord<E>): void | Error
15
+ close?(): void
16
+ }
17
+
18
+ /**
19
+ * Primary sink. Owns the canonical seq sequence for the bus. `insert` is
20
+ * the atomic boundary — it assigns a seq strictly greater than every
21
+ * previously assigned one, persists the record, and returns it. SQLite
22
+ * implementations get atomicity for free by delegating to `INTEGER PRIMARY
23
+ * KEY` so two processes sharing one database file see one monotonic
24
+ * stream without bus-level coordination.
25
+ *
26
+ * `getMaxSeq` is the highest seq currently in the sink — used for
27
+ * observability and for replay seeding by clients reading the store.
28
+ */
29
+ export type LeucoLoggerPrimarySink<E> = {
30
+ insert(input: { ts: number; event: E }): LeucoLoggerRecord<E> | Error
31
+ getMaxSeq(): number
32
+ close?(): void
33
+ }