@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
@@ -0,0 +1,115 @@
1
+ ; Query from: https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/99ddf573531c4dbe53f743ecbc1595af5eb1d32f/queries/markdown_inline/highlights.scm
2
+ ; From MDeiml/tree-sitter-markdown
3
+ (code_span) @markup.raw @nospell
4
+
5
+ (emphasis) @markup.italic
6
+
7
+ (strong_emphasis) @markup.strong
8
+
9
+ (strikethrough) @markup.strikethrough
10
+
11
+ (shortcut_link
12
+ (link_text) @nospell)
13
+
14
+ [
15
+ (backslash_escape)
16
+ (hard_line_break)
17
+ ] @string.escape
18
+
19
+ ; Conceal codeblock and text style markers
20
+ ([
21
+ (code_span_delimiter)
22
+ (emphasis_delimiter)
23
+ ] @conceal
24
+ (#set! conceal ""))
25
+
26
+ ; Inline links - style all parts
27
+ (inline_link
28
+ ["[" "(" ")"] @markup.link)
29
+
30
+ (inline_link
31
+ "]" @markup.link.bracket.close)
32
+
33
+ ; Conceal opening bracket
34
+ ((inline_link
35
+ "[" @conceal)
36
+ (#set! conceal ""))
37
+
38
+ ; Conceal closing bracket with space replacement
39
+ ((inline_link
40
+ "]" @conceal)
41
+ (#set! conceal " "))
42
+
43
+ ; Conceal image links
44
+ (image
45
+ [
46
+ "!"
47
+ "["
48
+ "]"
49
+ "("
50
+ (link_destination)
51
+ ")"
52
+ ] @markup.link
53
+ (#set! conceal ""))
54
+
55
+ ; Conceal full reference links
56
+ (full_reference_link
57
+ [
58
+ "["
59
+ "]"
60
+ (link_label)
61
+ ] @markup.link
62
+ (#set! conceal ""))
63
+
64
+ ; Conceal collapsed reference links
65
+ (collapsed_reference_link
66
+ [
67
+ "["
68
+ "]"
69
+ ] @markup.link
70
+ (#set! conceal ""))
71
+
72
+ ; Conceal shortcut links
73
+ (shortcut_link
74
+ [
75
+ "["
76
+ "]"
77
+ ] @markup.link
78
+ (#set! conceal ""))
79
+
80
+ [
81
+ (link_destination)
82
+ (uri_autolink)
83
+ ] @markup.link.url @nospell
84
+
85
+ [
86
+ (link_label)
87
+ (link_text)
88
+ (link_title)
89
+ (image_description)
90
+ ] @markup.link.label
91
+
92
+ ; Replace common HTML entities.
93
+ ((entity_reference) @character.special
94
+ (#eq? @character.special " ")
95
+ (#set! conceal ""))
96
+
97
+ ((entity_reference) @character.special
98
+ (#eq? @character.special "<")
99
+ (#set! conceal "<"))
100
+
101
+ ((entity_reference) @character.special
102
+ (#eq? @character.special "&gt;")
103
+ (#set! conceal ">"))
104
+
105
+ ((entity_reference) @character.special
106
+ (#eq? @character.special "&amp;")
107
+ (#set! conceal "&"))
108
+
109
+ ((entity_reference) @character.special
110
+ (#eq? @character.special "&quot;")
111
+ (#set! conceal "\""))
112
+
113
+ ((entity_reference) @character.special
114
+ (#any-of? @character.special "&ensp;" "&emsp;")
115
+ (#set! conceal " "))
@@ -0,0 +1,27 @@
1
+ ; Query from: https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/markdown/injections.scm
2
+ (fenced_code_block
3
+ (info_string
4
+ (language) @_lang)
5
+ (code_fence_content) @injection.content
6
+ (#set-lang-from-info-string! @_lang))
7
+
8
+ ((html_block) @injection.content
9
+ (#set! injection.language "html")
10
+ (#set! injection.combined)
11
+ (#set! injection.include-children))
12
+
13
+ ((minus_metadata) @injection.content
14
+ (#set! injection.language "yaml")
15
+ (#offset! @injection.content 1 0 -1 0)
16
+ (#set! injection.include-children))
17
+
18
+ ((plus_metadata) @injection.content
19
+ (#set! injection.language "toml")
20
+ (#offset! @injection.content 1 0 -1 0)
21
+ (#set! injection.include-children))
22
+
23
+ ([
24
+ (inline)
25
+ (pipe_table_cell)
26
+ ] @injection.content
27
+ (#set! injection.language "markdown_inline"))
package/lib/bin.ts ADDED
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env bun
2
+ import pkg from "../package.json" with { type: "json" }
3
+ import { startChannelServer } from "@/engine/mcp/channel-server"
4
+ import { toRequest } from "@/cli/router/to-request"
5
+ import { launchTui } from "@/tui/tui"
6
+ import { app } from "@/cli/routes"
7
+ import { Funnel } from "@/funnel"
8
+
9
+ process.title = "funnel"
10
+
11
+ const HELP = `funnel — Open Claude Funnel
12
+
13
+ usage: funnel [command]
14
+
15
+ commands:
16
+ (none) launch TUI
17
+ claude launch Claude Code (default profile or --profile)
18
+ channels manage subscription boxes (and their nested connectors)
19
+ profiles manage launch profiles
20
+ gateway manage the gateway daemon (HTTP + WS)
21
+ status show overall connection status
22
+ update update funnel to the latest version
23
+ mcp run as an MCP server (invoked from .mcp.json)
24
+
25
+ options:
26
+ --help, -h show help
27
+ --version, -v show version
28
+
29
+ more: funnel <command> --help`
30
+
31
+ const args = process.argv.slice(2)
32
+
33
+ if (args.length === 0) {
34
+ await launchTui(new Funnel())
35
+ process.exit(0)
36
+ }
37
+
38
+ if (args[0] === "--version" || args[0] === "-v") {
39
+ process.stdout.write(`${pkg.version}\n`)
40
+ process.exit(0)
41
+ }
42
+
43
+ if (args[0] === "mcp") {
44
+ await startChannelServer()
45
+ } else {
46
+ const { method, url } = toRequest(args)
47
+ const parsed = new URL(url)
48
+ const wantsHelp = parsed.searchParams.has("help")
49
+
50
+ if (wantsHelp && parsed.pathname === "/") {
51
+ process.stdout.write(`${HELP}\n`)
52
+ process.exit(0)
53
+ }
54
+
55
+ const res = await app.request(url, { method })
56
+
57
+ if (res.ok) {
58
+ const body = await res.text()
59
+ if (body) process.stdout.write(`${body}\n`)
60
+ process.exit(0)
61
+ }
62
+
63
+ if (wantsHelp) {
64
+ const segments = parsed.pathname.split("/").filter(Boolean)
65
+ const group = segments[0]
66
+ const fallback = group
67
+ ? await app.request(`http://localhost/${group}?help=true`, { method: "GET" })
68
+ : null
69
+
70
+ const text = fallback?.ok ? await fallback.text() : HELP
71
+ process.stdout.write(`${text}\n`)
72
+ process.exit(0)
73
+ }
74
+
75
+ const text = await res.text()
76
+ if (text) process.stderr.write(`${text}\n`)
77
+ process.exit(1)
78
+ }
@@ -1,20 +1,19 @@
1
1
  const SHORT_FLAGS: Record<string, string> = {
2
2
  h: "help",
3
3
  n: "name",
4
+ p: "profile",
4
5
  }
5
6
 
6
- const STRIPPED_METHOD_KEYWORDS: Record<string, string> = {
7
- add: "POST",
8
- remove: "DELETE",
9
- set: "PUT",
10
- }
11
-
12
- const KEPT_METHOD_KEYWORDS: Record<string, string> = {
13
- rename: "PUT",
14
- attach: "PUT",
15
- detach: "DELETE",
16
- default: "PUT",
17
- }
7
+ // All CLI verbs map to POST and stay in the URL (no method-stripping).
8
+ // Hono routes disambiguate by URL segment (e.g. /channels/add/:channel vs /channels/remove/:channel).
9
+ const METHOD_KEYWORDS = new Set([
10
+ "add",
11
+ "set",
12
+ "remove",
13
+ "rename",
14
+ "as-default",
15
+ "request",
16
+ ])
18
17
 
19
18
  const API_CALL_METHODS = new Set(["get", "post", "put", "patch", "delete", "head", "options"])
20
19
 
@@ -83,14 +82,8 @@ export const toRequest = (args: string[]) => {
83
82
  continue
84
83
  }
85
84
 
86
- if (STRIPPED_METHOD_KEYWORDS[arg]) {
87
- method = STRIPPED_METHOD_KEYWORDS[arg]!
88
- i++
89
- continue
90
- }
91
-
92
- if (KEPT_METHOD_KEYWORDS[arg]) {
93
- method = KEPT_METHOD_KEYWORDS[arg]!
85
+ if (METHOD_KEYWORDS.has(arg)) {
86
+ method = "POST"
94
87
  segments.push(arg)
95
88
  i++
96
89
  continue
@@ -0,0 +1,27 @@
1
+ import { z } from "zod"
2
+ import { factory } from "@/cli/factory"
3
+ import { zValidator } from "@/cli/router/validator"
4
+
5
+ export const renameHelp = `funnel channels <channel> connectors rename <connector> <new-name>
6
+
7
+ usage: funnel channels <channel> connectors rename <connector> <new-name>`
8
+
9
+ export const channelsConnectorsRenameHandler = factory.createHandlers(
10
+ zValidator(
11
+ "param",
12
+ z.object({ channel: z.string(), connector: z.string(), newName: z.string() }),
13
+ ),
14
+ zValidator("query", z.object({}), renameHelp),
15
+ async (c) => {
16
+ const param = c.req.valid("param")
17
+ const funnel = c.var.funnel
18
+
19
+ await funnel.listeners.stop(param.channel, param.connector)
20
+
21
+ funnel.channels.renameConnector(param.channel, param.connector, param.newName)
22
+
23
+ await funnel.listeners.start(param.channel, param.newName)
24
+
25
+ return c.text(`renamed connector "${param.connector}" to "${param.newName}"`)
26
+ },
27
+ )
@@ -0,0 +1,40 @@
1
+ import { z } from "zod"
2
+ import { factory } from "@/cli/factory"
3
+ import { zValidator } from "@/cli/router/validator"
4
+
5
+ export const requestHelp = `funnel channels <channel> connectors <connector> request — call a connector's outbound API
6
+
7
+ usage: funnel channels <channel> connectors <connector> request --method=<api.method> [--key=value ...]`
8
+
9
+ export const channelsConnectorsRequestHandler = factory.createHandlers(
10
+ zValidator("param", z.object({ channel: z.string(), connector: z.string() })),
11
+ zValidator(
12
+ "query",
13
+ z
14
+ .object({
15
+ method: z.string(),
16
+ })
17
+ .passthrough(),
18
+ requestHelp,
19
+ ),
20
+ async (c) => {
21
+ const param = c.req.valid("param")
22
+ const query = c.req.valid("query")
23
+ const funnel = c.var.funnel
24
+
25
+ const passthrough: Record<string, string> = {}
26
+
27
+ for (const [k, v] of new URL(c.req.url).searchParams) {
28
+ if (k === "method") continue
29
+ passthrough[k] = v
30
+ }
31
+
32
+ const response = await funnel.channels.call(param.channel, param.connector, {
33
+ method: query.method,
34
+ path: query.method,
35
+ body: passthrough,
36
+ })
37
+
38
+ return c.text(typeof response === "string" ? response : JSON.stringify(response, null, 2))
39
+ },
40
+ )
@@ -0,0 +1,41 @@
1
+ import { z } from "zod"
2
+ import { factory } from "@/cli/factory"
3
+ import { zValidator } from "@/cli/router/validator"
4
+ import { scheduleCatchupPolicySchema } from "@/connectors/schedule-connector-schema"
5
+
6
+ export const addHelp = `funnel channels <ch> connectors <conn> schedules add <id> — add a schedule entry
7
+
8
+ usage: funnel channels <ch> connectors <conn> schedules add <id> --cron="*/5 * * * *" --prompt="..." [--enabled=true] [--catchup-policy=latest|all|skip]`
9
+
10
+ export const channelsConnectorsSchedulesAddHandler = factory.createHandlers(
11
+ zValidator("param", z.object({ channel: z.string(), connector: z.string(), id: z.string() })),
12
+ zValidator(
13
+ "query",
14
+ z.object({
15
+ cron: z.string(),
16
+ prompt: z.string(),
17
+ enabled: z.coerce.boolean().optional(),
18
+ "catchup-policy": scheduleCatchupPolicySchema.optional(),
19
+ }),
20
+ addHelp,
21
+ ),
22
+ async (c) => {
23
+ const param = c.req.valid("param")
24
+ const query = c.req.valid("query")
25
+ const funnel = c.var.funnel
26
+
27
+ const entry = funnel.channels.addScheduleEntry(param.channel, param.connector, {
28
+ id: param.id,
29
+ cron: query.cron,
30
+ prompt: query.prompt,
31
+ ...(query.enabled !== undefined ? { enabled: query.enabled } : {}),
32
+ ...(query["catchup-policy"] !== undefined
33
+ ? { catchupPolicy: query["catchup-policy"] }
34
+ : {}),
35
+ })
36
+
37
+ await funnel.listeners.restart(param.channel, param.connector)
38
+
39
+ return c.text(`added schedule entry "${entry.id}"`)
40
+ },
41
+ )
@@ -0,0 +1,22 @@
1
+ import { z } from "zod"
2
+ import { factory } from "@/cli/factory"
3
+ import { zValidator } from "@/cli/router/validator"
4
+
5
+ export const removeHelp = `funnel channels <ch> connectors <conn> schedules remove <id>
6
+
7
+ usage: funnel channels <ch> connectors <conn> schedules remove <id>`
8
+
9
+ export const channelsConnectorsSchedulesRemoveHandler = factory.createHandlers(
10
+ zValidator("param", z.object({ channel: z.string(), connector: z.string(), id: z.string() })),
11
+ zValidator("query", z.object({}), removeHelp),
12
+ async (c) => {
13
+ const param = c.req.valid("param")
14
+ const funnel = c.var.funnel
15
+
16
+ funnel.channels.removeScheduleEntry(param.channel, param.connector, param.id)
17
+
18
+ await funnel.listeners.restart(param.channel, param.connector)
19
+
20
+ return c.text(`removed schedule entry "${param.id}"`)
21
+ },
22
+ )
@@ -0,0 +1,23 @@
1
+ import { z } from "zod"
2
+ import { factory } from "@/cli/factory"
3
+ import { zValidator } from "@/cli/router/validator"
4
+
5
+ export const groupHelp = `funnel channels <ch> connectors <conn> schedules — list schedule entries
6
+
7
+ usage: funnel channels <ch> connectors <conn> schedules`
8
+
9
+ export const channelsConnectorsSchedulesGroupHandler = factory.createHandlers(
10
+ zValidator("param", z.object({ channel: z.string(), connector: z.string() })),
11
+ zValidator("query", z.object({}), groupHelp),
12
+ (c) => {
13
+ const param = c.req.valid("param")
14
+ const funnel = c.var.funnel
15
+ const entries = funnel.channels.listScheduleEntries(param.channel, param.connector)
16
+
17
+ if (entries.length === 0) return c.text("no schedule entries")
18
+
19
+ return c.text(
20
+ entries.map((e) => `${e.id}\t${e.cron}\t${e.enabled ? "on" : "off"}\t${e.prompt}`).join("\n"),
21
+ )
22
+ },
23
+ )
@@ -0,0 +1,26 @@
1
+ import { HTTPException } from "hono/http-exception"
2
+ import { z } from "zod"
3
+ import { factory } from "@/cli/factory"
4
+ import { zValidator } from "@/cli/router/validator"
5
+
6
+ export const showHelp = `funnel channels <channel> connectors show <connector> — show connector config
7
+
8
+ usage: funnel channels <channel> connectors show <connector>`
9
+
10
+ export const channelsConnectorsShowHandler = factory.createHandlers(
11
+ zValidator("param", z.object({ channel: z.string(), connector: z.string() })),
12
+ zValidator("query", z.object({}), showHelp),
13
+ (c) => {
14
+ const param = c.req.valid("param")
15
+ const funnel = c.var.funnel
16
+ const connector = funnel.channels.getConnector(param.channel, param.connector)
17
+
18
+ if (!connector) {
19
+ throw new HTTPException(404, {
20
+ message: `connector "${param.connector}" not found in channel "${param.channel}"`,
21
+ })
22
+ }
23
+
24
+ return c.text(JSON.stringify(connector, null, 2))
25
+ },
26
+ )
@@ -0,0 +1,92 @@
1
+ import { z } from "zod"
2
+ import { factory } from "@/cli/factory"
3
+ import { zValidator } from "@/cli/router/validator"
4
+
5
+ export const addHelp = `funnel channels <channel> connectors add <connector> — add a connector to a channel
6
+
7
+ usage:
8
+ funnel channels <channel> connectors add <connector> --type=slack --bot-token=xoxb-... --app-token=xapp-...
9
+ funnel channels <channel> connectors add <connector> --type=gh [--poll-interval=60]
10
+ funnel channels <channel> connectors add <connector> --type=discord --bot-token=...
11
+ funnel channels <channel> connectors add <connector> --type=schedule
12
+
13
+ Token uniqueness is enforced across all channels.`
14
+
15
+ const slackBody = z.object({
16
+ type: z.literal("slack"),
17
+ "bot-token": z.string().startsWith("xoxb-"),
18
+ "app-token": z.string().startsWith("xapp-"),
19
+ })
20
+
21
+ const ghBody = z.object({
22
+ type: z.literal("gh"),
23
+ "poll-interval": z.coerce.number().int().positive().optional(),
24
+ })
25
+
26
+ const discordBody = z.object({
27
+ type: z.literal("discord"),
28
+ "bot-token": z.string().min(10),
29
+ })
30
+
31
+ const scheduleBody = z.object({
32
+ type: z.literal("schedule"),
33
+ })
34
+
35
+ const addBody = z.discriminatedUnion("type", [slackBody, ghBody, discordBody, scheduleBody])
36
+
37
+ export const channelsConnectorsAddHandler = factory.createHandlers(
38
+ zValidator("param", z.object({ channel: z.string(), connector: z.string() })),
39
+ zValidator("query", addBody, addHelp),
40
+ async (c) => {
41
+ const param = c.req.valid("param")
42
+ const query = c.req.valid("query")
43
+ const funnel = c.var.funnel
44
+
45
+ if (query.type === "slack") {
46
+ const created = funnel.channels.addConnector(param.channel, {
47
+ type: "slack",
48
+ name: param.connector,
49
+ botToken: query["bot-token"],
50
+ appToken: query["app-token"],
51
+ })
52
+
53
+ await funnel.listeners.start(param.channel, created.name)
54
+
55
+ return c.text(`added slack connector "${created.name}" to channel "${param.channel}"`)
56
+ }
57
+
58
+ if (query.type === "gh") {
59
+ const created = funnel.channels.addConnector(param.channel, {
60
+ type: "gh",
61
+ name: param.connector,
62
+ ...(query["poll-interval"] !== undefined ? { pollInterval: query["poll-interval"] } : {}),
63
+ })
64
+
65
+ await funnel.listeners.start(param.channel, created.name)
66
+
67
+ return c.text(`added gh connector "${created.name}" to channel "${param.channel}"`)
68
+ }
69
+
70
+ if (query.type === "discord") {
71
+ const created = funnel.channels.addConnector(param.channel, {
72
+ type: "discord",
73
+ name: param.connector,
74
+ botToken: query["bot-token"],
75
+ })
76
+
77
+ await funnel.listeners.start(param.channel, created.name)
78
+
79
+ return c.text(`added discord connector "${created.name}" to channel "${param.channel}"`)
80
+ }
81
+
82
+ const created = funnel.channels.addConnector(param.channel, {
83
+ type: "schedule",
84
+ name: param.connector,
85
+ entries: [],
86
+ })
87
+
88
+ await funnel.listeners.start(param.channel, created.name)
89
+
90
+ return c.text(`added schedule connector "${created.name}" to channel "${param.channel}"`)
91
+ },
92
+ )
@@ -0,0 +1,22 @@
1
+ import { z } from "zod"
2
+ import { factory } from "@/cli/factory"
3
+ import { zValidator } from "@/cli/router/validator"
4
+
5
+ export const removeHelp = `funnel channels <channel> connectors remove <connector> — remove a connector
6
+
7
+ usage: funnel channels <channel> connectors remove <connector>`
8
+
9
+ export const channelsConnectorsRemoveHandler = factory.createHandlers(
10
+ zValidator("param", z.object({ channel: z.string(), connector: z.string() })),
11
+ zValidator("query", z.object({}), removeHelp),
12
+ async (c) => {
13
+ const param = c.req.valid("param")
14
+ const funnel = c.var.funnel
15
+
16
+ await funnel.listeners.stop(param.channel, param.connector)
17
+
18
+ funnel.channels.removeConnector(param.channel, param.connector)
19
+
20
+ return c.text(`removed connector "${param.connector}" from channel "${param.channel}"`)
21
+ },
22
+ )
@@ -0,0 +1,63 @@
1
+ import { HTTPException } from "hono/http-exception"
2
+ import { z } from "zod"
3
+ import { factory } from "@/cli/factory"
4
+ import { zValidator } from "@/cli/router/validator"
5
+
6
+ export const setHelp = `funnel channels <channel> connectors set <connector> — update connector fields
7
+
8
+ usage:
9
+ funnel channels <ch> connectors set <conn> [--bot-token=...] [--app-token=...] # slack
10
+ funnel channels <ch> connectors set <conn> [--bot-token=...] # discord
11
+ funnel channels <ch> connectors set <conn> [--poll-interval=N] # gh`
12
+
13
+ export const channelsConnectorsSetHandler = factory.createHandlers(
14
+ zValidator("param", z.object({ channel: z.string(), connector: z.string() })),
15
+ zValidator(
16
+ "query",
17
+ z
18
+ .object({
19
+ "bot-token": z.string().optional(),
20
+ "app-token": z.string().optional(),
21
+ "poll-interval": z.coerce.number().int().positive().optional(),
22
+ })
23
+ .passthrough(),
24
+ setHelp,
25
+ ),
26
+ async (c) => {
27
+ const param = c.req.valid("param")
28
+ const query = c.req.valid("query")
29
+ const funnel = c.var.funnel
30
+ const existing = funnel.channels.getConnector(param.channel, param.connector)
31
+
32
+ if (!existing) {
33
+ throw new HTTPException(404, {
34
+ message: `connector "${param.connector}" not found in channel "${param.channel}"`,
35
+ })
36
+ }
37
+
38
+ if (existing.type === "slack") {
39
+ funnel.channels.updateSlackConnector(param.channel, param.connector, {
40
+ ...(query["bot-token"] !== undefined ? { botToken: query["bot-token"] } : {}),
41
+ ...(query["app-token"] !== undefined ? { appToken: query["app-token"] } : {}),
42
+ })
43
+ } else if (existing.type === "discord") {
44
+ funnel.channels.updateDiscordConnector(
45
+ param.channel,
46
+ param.connector,
47
+ query["bot-token"] !== undefined ? { botToken: query["bot-token"] } : {},
48
+ )
49
+ } else if (existing.type === "gh") {
50
+ funnel.channels.updateGhConnector(
51
+ param.channel,
52
+ param.connector,
53
+ query["poll-interval"] !== undefined ? { pollInterval: query["poll-interval"] } : {},
54
+ )
55
+ } else {
56
+ throw new HTTPException(400, { message: "schedule connectors have no settable fields" })
57
+ }
58
+
59
+ await funnel.listeners.restart(param.channel, param.connector)
60
+
61
+ return c.text(`updated connector "${param.connector}" in channel "${param.channel}"`)
62
+ },
63
+ )
@@ -0,0 +1,26 @@
1
+ import { HTTPException } from "hono/http-exception"
2
+ import { z } from "zod"
3
+ import { factory } from "@/cli/factory"
4
+ import { zValidator } from "@/cli/router/validator"
5
+
6
+ export const groupHelp = `funnel channels <channel> connectors — list connectors in a channel
7
+
8
+ usage: funnel channels <channel> connectors`
9
+
10
+ export const channelsConnectorsGroupHandler = factory.createHandlers(
11
+ zValidator("param", z.object({ channel: z.string() })),
12
+ zValidator("query", z.object({}), groupHelp),
13
+ (c) => {
14
+ const param = c.req.valid("param")
15
+ const funnel = c.var.funnel
16
+ const channel = funnel.channels.get(param.channel)
17
+
18
+ if (!channel) {
19
+ throw new HTTPException(404, { message: `channel "${param.channel}" not found` })
20
+ }
21
+
22
+ if (channel.connectors.length === 0) return c.text(`no connectors in channel "${channel.name}"`)
23
+
24
+ return c.text(channel.connectors.map((c) => `${c.name} (${c.type}, id: ${c.id})`).join("\n"))
25
+ },
26
+ )