@interactive-inc/claude-funnel 0.4.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 +233 -111
  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} +57 -22
  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} +39 -14
  69. package/lib/engine/channels/channels.ts +520 -0
  70. package/lib/{modules/claude/funnel-claude.ts → engine/claude/claude.ts} +47 -62
  71. package/lib/engine/claude/gateway-controller.ts +4 -0
  72. package/lib/{modules/fs/funnel-file-system.ts → engine/fs/file-system.ts} +9 -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/engine/id/id-generator.ts +7 -0
  78. package/lib/engine/id/memory-id-generator.ts +20 -0
  79. package/lib/engine/id/node-id-generator.ts +7 -0
  80. package/lib/engine/logger/logger.ts +11 -0
  81. package/lib/engine/logger/memory-logger.ts +28 -0
  82. package/lib/engine/logger/node-logger.ts +49 -0
  83. package/lib/engine/logger/noop-logger.ts +9 -0
  84. package/lib/engine/mcp/channel-server.ts +204 -0
  85. package/lib/{modules/mcp/funnel-mcp.ts → engine/mcp/mcp.ts} +29 -10
  86. package/lib/{modules/process/memory-funnel-process-runner.ts → engine/process/memory-process-runner.ts} +1 -1
  87. package/lib/{modules/process/node-funnel-process-runner.ts → engine/process/node-process-runner.ts} +12 -21
  88. package/lib/{modules/process/funnel-process-runner.ts → engine/process/process-runner.ts} +5 -0
  89. package/lib/engine/profiles/profile-channel-checker.ts +7 -0
  90. package/lib/engine/profiles/profiles.ts +126 -0
  91. package/lib/{modules/settings/mock-funnel-settings-reader.ts → engine/settings/mock-settings-reader.ts} +4 -3
  92. package/lib/{modules/settings/funnel-settings-reader.ts → engine/settings/settings-reader.ts} +1 -1
  93. package/lib/engine/settings/settings-schema.ts +46 -0
  94. package/lib/engine/settings/settings-store.ts +110 -0
  95. package/lib/engine/time/clock.ts +15 -0
  96. package/lib/engine/time/memory-clock.ts +26 -0
  97. package/lib/engine/time/node-clock.ts +7 -0
  98. package/lib/funnel.ts +148 -56
  99. package/lib/gateway/auth-middleware.ts +44 -0
  100. package/lib/gateway/broadcaster.ts +319 -0
  101. package/lib/gateway/daemon.ts +47 -0
  102. package/lib/gateway/factory.ts +10 -0
  103. package/lib/gateway/funnel-event-store.ts +155 -0
  104. package/lib/gateway/gateway-server.ts +414 -0
  105. package/lib/gateway/gateway-token.ts +79 -0
  106. package/lib/{modules/gateway/funnel-gateway.ts → gateway/gateway.ts} +70 -27
  107. package/lib/{modules/gateway → gateway}/kill-competing-slack-gateways.ts +7 -3
  108. package/lib/gateway/listener-supervisor.ts +339 -0
  109. package/lib/gateway/listeners-client.ts +128 -0
  110. package/lib/gateway/resolve-daemon-script.ts +26 -0
  111. package/lib/gateway/routes/channels.connectors.call.ts +39 -0
  112. package/lib/gateway/routes/health.ts +13 -0
  113. package/lib/gateway/routes/index.ts +24 -0
  114. package/lib/gateway/routes/listeners.list.ts +6 -0
  115. package/lib/gateway/routes/listeners.restart.ts +15 -0
  116. package/lib/gateway/routes/listeners.start.ts +15 -0
  117. package/lib/gateway/routes/listeners.stop.ts +15 -0
  118. package/lib/gateway/routes/route-deps.ts +11 -0
  119. package/lib/gateway/routes/status.ts +15 -0
  120. package/lib/gateway/routes/validator.ts +17 -0
  121. package/lib/index.ts +50 -92
  122. package/lib/logger/leuco-human-file-writer.ts +65 -0
  123. package/lib/logger/leuco-human-logger.ts +98 -0
  124. package/lib/logger/leuco-human-record.ts +16 -0
  125. package/lib/logger/leuco-human-stdout-writer.ts +26 -0
  126. package/lib/logger/leuco-human-writer.ts +14 -0
  127. package/lib/logger/leuco-logger-memory-sink.ts +67 -0
  128. package/lib/logger/leuco-logger-record.ts +13 -0
  129. package/lib/logger/leuco-logger-sink.ts +33 -0
  130. package/lib/logger/leuco-logger-sqlite-sink.ts +355 -0
  131. package/lib/logger/leuco-logger.ts +135 -0
  132. package/lib/tui/app.tsx +357 -0
  133. package/lib/tui/components/add-row.tsx +18 -0
  134. package/lib/tui/components/brand.tsx +27 -0
  135. package/lib/tui/components/card.tsx +44 -0
  136. package/lib/tui/components/detail-bar.tsx +46 -0
  137. package/lib/tui/components/editable-field.tsx +33 -0
  138. package/lib/tui/components/empty-state.tsx +11 -0
  139. package/lib/tui/components/gateway-status.tsx +66 -0
  140. package/lib/tui/components/keymap.tsx +29 -0
  141. package/lib/tui/components/menu-item.tsx +73 -0
  142. package/lib/tui/components/menu.tsx +26 -0
  143. package/lib/tui/components/panel-header.tsx +22 -0
  144. package/lib/tui/components/readonly-field.tsx +18 -0
  145. package/lib/tui/components/section-header.tsx +25 -0
  146. package/lib/tui/components/selection-accent.tsx +32 -0
  147. package/lib/tui/components/session-item.tsx +33 -0
  148. package/lib/tui/components/session-list.tsx +33 -0
  149. package/lib/tui/components/ui/hascii/accordion-item.tsx +88 -0
  150. package/lib/tui/components/ui/hascii/accordion.tsx +96 -0
  151. package/lib/tui/components/ui/hascii/alert-dialog.tsx +43 -0
  152. package/lib/tui/components/ui/hascii/badge.tsx +51 -0
  153. package/lib/tui/components/ui/hascii/breadcrumb.tsx +58 -0
  154. package/lib/tui/components/ui/hascii/button.tsx +194 -0
  155. package/lib/tui/components/ui/hascii/card-content.tsx +14 -0
  156. package/lib/tui/components/ui/hascii/card-description.tsx +13 -0
  157. package/lib/tui/components/ui/hascii/card-footer.tsx +14 -0
  158. package/lib/tui/components/ui/hascii/card-header.tsx +14 -0
  159. package/lib/tui/components/ui/hascii/card-title.tsx +13 -0
  160. package/lib/tui/components/ui/hascii/card.tsx +27 -0
  161. package/lib/tui/components/ui/hascii/checkbox.tsx +65 -0
  162. package/lib/tui/components/ui/hascii/command.tsx +159 -0
  163. package/lib/tui/components/ui/hascii/dialog-content.tsx +14 -0
  164. package/lib/tui/components/ui/hascii/dialog-description.tsx +13 -0
  165. package/lib/tui/components/ui/hascii/dialog-footer.tsx +14 -0
  166. package/lib/tui/components/ui/hascii/dialog-header.tsx +14 -0
  167. package/lib/tui/components/ui/hascii/dialog-title.tsx +13 -0
  168. package/lib/tui/components/ui/hascii/dialog.tsx +27 -0
  169. package/lib/tui/components/ui/hascii/file-tree.tsx +142 -0
  170. package/lib/tui/components/ui/hascii/focus-group.tsx +62 -0
  171. package/lib/tui/components/ui/hascii/form-item.tsx +43 -0
  172. package/lib/tui/components/ui/hascii/input-otp.tsx +86 -0
  173. package/lib/tui/components/ui/hascii/input.tsx +130 -0
  174. package/lib/tui/components/ui/hascii/pagination.tsx +105 -0
  175. package/lib/tui/components/ui/hascii/progress.tsx +28 -0
  176. package/lib/tui/components/ui/hascii/select.tsx +131 -0
  177. package/lib/tui/components/ui/hascii/separator.tsx +35 -0
  178. package/lib/tui/components/ui/hascii/sidebar-content.tsx +23 -0
  179. package/lib/tui/components/ui/hascii/sidebar-header.tsx +14 -0
  180. package/lib/tui/components/ui/hascii/sidebar-menu-item.tsx +67 -0
  181. package/lib/tui/components/ui/hascii/sidebar.tsx +24 -0
  182. package/lib/tui/components/ui/hascii/skeleton.tsx +60 -0
  183. package/lib/tui/components/ui/hascii/slider.tsx +91 -0
  184. package/lib/tui/components/ui/hascii/snackbar.tsx +75 -0
  185. package/lib/tui/components/ui/hascii/sparkline.tsx +53 -0
  186. package/lib/tui/components/ui/hascii/spinner.tsx +47 -0
  187. package/lib/tui/components/ui/hascii/stepper.tsx +54 -0
  188. package/lib/tui/components/ui/hascii/switch.tsx +66 -0
  189. package/lib/tui/components/ui/hascii/table.tsx +95 -0
  190. package/lib/tui/components/ui/hascii/tabs.tsx +59 -0
  191. package/lib/tui/components/ui/hascii/toggle-group-item.tsx +45 -0
  192. package/lib/tui/components/ui/hascii/toggle-group.tsx +99 -0
  193. package/lib/tui/components/ui/hascii/tree.tsx +104 -0
  194. package/lib/tui/components/view-shell.tsx +44 -0
  195. package/lib/tui/filter-input.tsx +33 -0
  196. package/lib/tui/hooks/hascii/use-pressable.ts +54 -0
  197. package/lib/tui/parse-comma-list.ts +14 -0
  198. package/lib/tui/profile-launcher.tsx +61 -0
  199. package/lib/tui/scrollbar-options.ts +19 -0
  200. package/lib/tui/sidebar.tsx +50 -0
  201. package/lib/tui/theme.ts +40 -0
  202. package/lib/tui/tui.tsx +20 -0
  203. package/lib/tui/types.ts +38 -0
  204. package/lib/tui/unique-name.ts +18 -0
  205. package/lib/tui/use-event-stream.ts +133 -0
  206. package/lib/tui/use-snapshot.ts +99 -0
  207. package/lib/tui/utils/hascii/form-item-context.tsx +23 -0
  208. package/lib/tui/utils/hascii/input-focus-context.tsx +31 -0
  209. package/lib/tui/utils/hascii/theme-context.tsx +26 -0
  210. package/lib/tui/utils/hascii/theme.ts +176 -0
  211. package/lib/tui/views/channels-view.tsx +108 -0
  212. package/lib/tui/views/connectors-view.tsx +164 -0
  213. package/lib/tui/views/events-view.tsx +160 -0
  214. package/lib/tui/views/listeners-view.tsx +80 -0
  215. package/lib/tui/views/profiles-view.tsx +152 -0
  216. package/package.json +51 -34
  217. package/lib/modules/channels/channel-connector-ref-updater.ts +0 -4
  218. package/lib/modules/channels/funnel-channels.ts +0 -155
  219. package/lib/modules/connectors/connector-config-schema.ts +0 -16
  220. package/lib/modules/connectors/connector-existence-checker.ts +0 -3
  221. package/lib/modules/connectors/funnel-callable-connector-store.ts +0 -9
  222. package/lib/modules/connectors/funnel-connector-listener.ts +0 -5
  223. package/lib/modules/connectors/funnel-connector-stores.ts +0 -24
  224. package/lib/modules/connectors/funnel-connector-type-store.ts +0 -24
  225. package/lib/modules/connectors/funnel-connectors.ts +0 -145
  226. package/lib/modules/connectors/funnel-discord-listener.ts +0 -65
  227. package/lib/modules/connectors/funnel-discord-store.ts +0 -84
  228. package/lib/modules/connectors/funnel-gh-store.ts +0 -84
  229. package/lib/modules/connectors/funnel-json-connector-store.ts +0 -100
  230. package/lib/modules/connectors/funnel-schedule-listener.ts +0 -124
  231. package/lib/modules/connectors/funnel-schedule-store.ts +0 -178
  232. package/lib/modules/connectors/funnel-slack-adapter.ts +0 -31
  233. package/lib/modules/connectors/funnel-slack-store.ts +0 -86
  234. package/lib/modules/connectors/migrate-legacy-connectors.ts +0 -77
  235. package/lib/modules/connectors/schedule-connector-schema.ts +0 -18
  236. package/lib/modules/connectors/schedule-last-fired-store.ts +0 -48
  237. package/lib/modules/gateway/daemon.ts +0 -207
  238. package/lib/modules/gateway/funnel-broadcaster.ts +0 -37
  239. package/lib/modules/gateway/funnel-event-logger.ts +0 -59
  240. package/lib/modules/logger.ts +0 -26
  241. package/lib/modules/mcp/channel-server.ts +0 -76
  242. package/lib/modules/profiles/funnel-profiles.ts +0 -123
  243. package/lib/modules/profiles/profile-channel-checker.ts +0 -3
  244. package/lib/modules/profiles/profile-channel-ref-updater.ts +0 -3
  245. package/lib/modules/repos/funnel-repositories.ts +0 -107
  246. package/lib/modules/schedule/funnel-schedule.ts +0 -34
  247. package/lib/modules/settings/funnel-settings-store.ts +0 -56
  248. package/lib/modules/settings/settings-schema.ts +0 -33
  249. package/lib/modules/tui/app.tsx +0 -44
  250. package/lib/modules/tui/tui.tsx +0 -13
  251. package/lib/routes/channels/add.help.ts +0 -3
  252. package/lib/routes/channels/add.ts +0 -21
  253. package/lib/routes/channels/connectors-attach.help.ts +0 -3
  254. package/lib/routes/channels/connectors-attach.ts +0 -17
  255. package/lib/routes/channels/connectors-detach.help.ts +0 -3
  256. package/lib/routes/channels/connectors-detach.ts +0 -17
  257. package/lib/routes/channels/group.help.ts +0 -16
  258. package/lib/routes/channels/group.ts +0 -22
  259. package/lib/routes/channels/remove.help.ts +0 -3
  260. package/lib/routes/channels/remove.ts +0 -17
  261. package/lib/routes/channels/rename.help.ts +0 -5
  262. package/lib/routes/channels/rename.ts +0 -17
  263. package/lib/routes/channels/routes.ts +0 -19
  264. package/lib/routes/channels/show.help.ts +0 -1
  265. package/lib/routes/channels/show.ts +0 -26
  266. package/lib/routes/claude/claude.help.ts +0 -16
  267. package/lib/routes/claude/claude.ts +0 -76
  268. package/lib/routes/claude/routes.ts +0 -4
  269. package/lib/routes/connectors/add.help.ts +0 -28
  270. package/lib/routes/connectors/add.ts +0 -64
  271. package/lib/routes/connectors/group.help.ts +0 -14
  272. package/lib/routes/connectors/group.ts +0 -18
  273. package/lib/routes/connectors/remove.help.ts +0 -3
  274. package/lib/routes/connectors/remove.ts +0 -17
  275. package/lib/routes/connectors/rename.help.ts +0 -5
  276. package/lib/routes/connectors/rename.ts +0 -17
  277. package/lib/routes/connectors/routes.ts +0 -23
  278. package/lib/routes/connectors/schedules-add.help.ts +0 -11
  279. package/lib/routes/connectors/schedules-add.ts +0 -33
  280. package/lib/routes/connectors/schedules-group.help.ts +0 -1
  281. package/lib/routes/connectors/schedules-group.ts +0 -38
  282. package/lib/routes/connectors/schedules-remove.help.ts +0 -3
  283. package/lib/routes/connectors/schedules-remove.ts +0 -17
  284. package/lib/routes/connectors/set.help.ts +0 -8
  285. package/lib/routes/connectors/set.ts +0 -72
  286. package/lib/routes/connectors/show.help.ts +0 -1
  287. package/lib/routes/connectors/show.ts +0 -41
  288. package/lib/routes/gateway/group.help.ts +0 -15
  289. package/lib/routes/gateway/group.ts +0 -28
  290. package/lib/routes/gateway/logs.help.ts +0 -13
  291. package/lib/routes/gateway/logs.ts +0 -100
  292. package/lib/routes/gateway/restart.help.ts +0 -10
  293. package/lib/routes/gateway/routes.ts +0 -18
  294. package/lib/routes/gateway/run.help.ts +0 -12
  295. package/lib/routes/gateway/run.ts +0 -35
  296. package/lib/routes/gateway/start.help.ts +0 -15
  297. package/lib/routes/gateway/start.ts +0 -32
  298. package/lib/routes/gateway/status.help.ts +0 -9
  299. package/lib/routes/gateway/status.ts +0 -28
  300. package/lib/routes/gateway/stop.help.ts +0 -8
  301. package/lib/routes/gateway/stop.ts +0 -21
  302. package/lib/routes/profiles/add.help.ts +0 -3
  303. package/lib/routes/profiles/add.ts +0 -33
  304. package/lib/routes/profiles/group.help.ts +0 -16
  305. package/lib/routes/profiles/group.ts +0 -25
  306. package/lib/routes/profiles/launch.help.ts +0 -4
  307. package/lib/routes/profiles/launch.ts +0 -36
  308. package/lib/routes/profiles/remove.help.ts +0 -3
  309. package/lib/routes/profiles/remove.ts +0 -17
  310. package/lib/routes/profiles/rename.help.ts +0 -5
  311. package/lib/routes/profiles/rename.ts +0 -17
  312. package/lib/routes/profiles/routes.ts +0 -18
  313. package/lib/routes/profiles/set.help.ts +0 -5
  314. package/lib/routes/profiles/set.ts +0 -32
  315. package/lib/routes/repos/add.help.ts +0 -6
  316. package/lib/routes/repos/add.ts +0 -20
  317. package/lib/routes/repos/group.help.ts +0 -11
  318. package/lib/routes/repos/group.ts +0 -18
  319. package/lib/routes/repos/remove.help.ts +0 -3
  320. package/lib/routes/repos/remove.ts +0 -17
  321. package/lib/routes/repos/rename.help.ts +0 -5
  322. package/lib/routes/repos/rename.ts +0 -17
  323. package/lib/routes/repos/routes.ts +0 -17
  324. package/lib/routes/repos/set.help.ts +0 -5
  325. package/lib/routes/repos/set.ts +0 -21
  326. package/lib/routes/repos/show.help.ts +0 -1
  327. package/lib/routes/repos/show.ts +0 -19
  328. package/lib/routes/request/discord-help.ts +0 -9
  329. package/lib/routes/request/discord.help.ts +0 -19
  330. package/lib/routes/request/discord.ts +0 -65
  331. package/lib/routes/request/group.help.ts +0 -15
  332. package/lib/routes/request/group.ts +0 -9
  333. package/lib/routes/request/routes.ts +0 -14
  334. package/lib/routes/request/slack-help.ts +0 -9
  335. package/lib/routes/request/slack.help.ts +0 -19
  336. package/lib/routes/request/slack.ts +0 -61
  337. package/lib/routes/status/routes.ts +0 -4
  338. package/lib/routes/status/status.help.ts +0 -6
  339. package/lib/routes/status/status.ts +0 -77
  340. package/lib/routes/update/routes.ts +0 -4
  341. package/lib/routes/update/update.help.ts +0 -5
  342. package/lib/routes/update/update.ts +0 -21
  343. package/lib/routes.ts +0 -40
  344. /package/lib/{factory.ts → cli/factory.ts} +0 -0
  345. /package/lib/{modules → cli}/router/query-to-cli-args.ts +0 -0
  346. /package/lib/{modules → cli}/router/validator.ts +0 -0
  347. /package/lib/{modules/connectors/funnel-connector-adapter.ts → connectors/connector-adapter.ts} +0 -0
  348. /package/lib/{modules/connectors/funnel-discord-event-processor.ts → connectors/discord-event-processor.ts} +0 -0
  349. /package/lib/{modules/http/funnel-http-client.ts → engine/http/http-client.ts} +0 -0
@@ -0,0 +1,194 @@
1
+ import { useKeyboard } from "@opentui/react"
2
+ import { useState } from "react"
3
+ import type { ReactNode } from "react"
4
+ import { useHasciiFocus } from "@/tui/components/ui/hascii/focus-group"
5
+ import { useHasciiTheme } from "@/tui/utils/hascii/theme-context"
6
+ import { usePressable } from "@/tui/hooks/hascii/use-pressable"
7
+
8
+ type Variant = "default" | "secondary" | "outline" | "ghost" | "destructive"
9
+ type Size = "default" | "sm" | "md" | "lg"
10
+
11
+ export type Props = {
12
+ variant?: Variant
13
+ size?: Size
14
+ focusId?: string
15
+ isFocused?: boolean
16
+ isDisabled?: boolean
17
+ onPress?: () => void
18
+ children?: ReactNode
19
+ }
20
+
21
+ type ResolvedSize = "sm" | "md" | "lg"
22
+
23
+ const sizeDims: Record<ResolvedSize, { paddingX: number; height: number }> = {
24
+ sm: { paddingX: 1, height: 1 },
25
+ md: { paddingX: 2, height: 1 },
26
+ lg: { paddingX: 2, height: 3 },
27
+ }
28
+
29
+ const resolveSize = (size: Size): ResolvedSize => (size === "default" ? "md" : size)
30
+
31
+ const pickBg = (
32
+ rest: string | undefined,
33
+ hover: string,
34
+ active: string,
35
+ isHover: boolean,
36
+ isActive: boolean,
37
+ ): string | undefined => {
38
+ if (isActive) return active
39
+ if (isHover) return hover
40
+ return rest
41
+ }
42
+
43
+ /** A focusable terminal button. Background cycles through rest, hover, and active states. */
44
+ export function HasciiButton(props: Props) {
45
+ const variant = props.variant ?? "default"
46
+ const size = props.size ?? "default"
47
+ const groupFocused = useHasciiFocus(props.focusId)
48
+ const isFocused = props.isFocused ?? groupFocused
49
+ const isDisabled = props.isDisabled ?? false
50
+
51
+ const theme = useHasciiTheme()
52
+ const resolvedSize = resolveSize(size)
53
+ const dims = sizeDims[resolvedSize]
54
+
55
+ const press = usePressable({ isDisabled, onPress: props.onPress })
56
+
57
+ const flashState = useState(false)
58
+ const flashed = flashState[0]
59
+ const setFlashed = flashState[1]
60
+
61
+ const isHover = press.isHovered && !press.isPressed && !flashed
62
+ const isActive = press.isPressed || flashed
63
+
64
+ useKeyboard((key) => {
65
+ if (!isFocused || isDisabled) return
66
+
67
+ if (key.name === "return" || key.name === "space") {
68
+ setFlashed(true)
69
+ props.onPress?.()
70
+ setTimeout(() => setFlashed(false), 120)
71
+ }
72
+ })
73
+
74
+ if (variant === "outline") {
75
+ const tone = isDisabled
76
+ ? theme.color.border
77
+ : isActive
78
+ ? theme.color.primaryActive
79
+ : isHover
80
+ ? theme.color.primaryHover
81
+ : theme.color.primary
82
+
83
+ const outlinePaddingX = resolvedSize === "sm" ? 0 : resolvedSize === "md" ? 1 : 2
84
+ const outlineHeight = 3
85
+
86
+ return (
87
+ <box
88
+ paddingLeft={outlinePaddingX}
89
+ paddingRight={outlinePaddingX}
90
+ height={outlineHeight}
91
+ border={outlineHeight >= 3}
92
+ borderStyle="rounded"
93
+ borderColor={tone}
94
+ alignItems="center"
95
+ justifyContent="center"
96
+ {...press.bind}
97
+ >
98
+ <text fg={tone}>{props.children}</text>
99
+ </box>
100
+ )
101
+ }
102
+
103
+ if (variant === "ghost") {
104
+ const fg = isDisabled ? theme.color.mutedForeground : theme.color.foreground
105
+ const bg = pickBg(undefined, theme.color.accentHover, theme.color.accent, isHover, isActive)
106
+
107
+ return (
108
+ <box
109
+ paddingLeft={dims.paddingX}
110
+ paddingRight={dims.paddingX}
111
+ height={dims.height}
112
+ backgroundColor={bg}
113
+ alignItems="center"
114
+ justifyContent="center"
115
+ {...press.bind}
116
+ >
117
+ <text fg={fg}>{props.children}</text>
118
+ </box>
119
+ )
120
+ }
121
+
122
+ if (variant === "secondary") {
123
+ const fg = isDisabled ? theme.color.mutedForeground : theme.color.secondaryForeground
124
+ const bg = pickBg(
125
+ theme.color.secondary,
126
+ theme.color.secondaryHover,
127
+ theme.color.secondaryActive,
128
+ isHover,
129
+ isActive,
130
+ )
131
+
132
+ return (
133
+ <box
134
+ paddingLeft={dims.paddingX}
135
+ paddingRight={dims.paddingX}
136
+ height={dims.height}
137
+ backgroundColor={bg}
138
+ alignItems="center"
139
+ justifyContent="center"
140
+ {...press.bind}
141
+ >
142
+ <text fg={fg}>{props.children}</text>
143
+ </box>
144
+ )
145
+ }
146
+
147
+ if (variant === "destructive") {
148
+ const fg = isDisabled ? theme.color.mutedForeground : theme.color.destructiveForeground
149
+ const bg = pickBg(
150
+ theme.color.destructive,
151
+ theme.color.destructiveHover,
152
+ theme.color.destructiveActive,
153
+ isHover,
154
+ isActive,
155
+ )
156
+
157
+ return (
158
+ <box
159
+ paddingLeft={dims.paddingX}
160
+ paddingRight={dims.paddingX}
161
+ height={dims.height}
162
+ backgroundColor={bg}
163
+ alignItems="center"
164
+ justifyContent="center"
165
+ {...press.bind}
166
+ >
167
+ <text fg={fg}>{props.children}</text>
168
+ </box>
169
+ )
170
+ }
171
+
172
+ const fg = isDisabled ? theme.color.mutedForeground : theme.color.primaryForeground
173
+ const bg = pickBg(
174
+ theme.color.primary,
175
+ theme.color.primaryHover,
176
+ theme.color.primaryActive,
177
+ isHover,
178
+ isActive,
179
+ )
180
+
181
+ return (
182
+ <box
183
+ paddingLeft={dims.paddingX}
184
+ paddingRight={dims.paddingX}
185
+ height={dims.height}
186
+ backgroundColor={bg}
187
+ alignItems="center"
188
+ justifyContent="center"
189
+ {...press.bind}
190
+ >
191
+ <text fg={fg}>{props.children}</text>
192
+ </box>
193
+ )
194
+ }
@@ -0,0 +1,14 @@
1
+ import type { ReactNode } from "react"
2
+
3
+ export type Props = {
4
+ children?: ReactNode
5
+ }
6
+
7
+ /** Vertical content region inside a HasciiCard. paddingY=1 keeps the body separated from neighbouring header and footer. */
8
+ export function HasciiCardContent(props: Props) {
9
+ return (
10
+ <box flexDirection="column" gap={1} paddingTop={1} paddingBottom={1}>
11
+ {props.children}
12
+ </box>
13
+ )
14
+ }
@@ -0,0 +1,13 @@
1
+ import type { ReactNode } from "react"
2
+ import { useHasciiTheme } from "@/tui/utils/hascii/theme-context"
3
+
4
+ export type Props = {
5
+ children?: ReactNode
6
+ }
7
+
8
+ /** Secondary descriptive text rendered under a HasciiCardTitle. */
9
+ export function HasciiCardDescription(props: Props) {
10
+ const theme = useHasciiTheme()
11
+
12
+ return <text fg={theme.color.mutedForeground}>{props.children}</text>
13
+ }
@@ -0,0 +1,14 @@
1
+ import type { ReactNode } from "react"
2
+
3
+ export type Props = {
4
+ children?: ReactNode
5
+ }
6
+
7
+ /** Horizontal footer region for action rows inside a HasciiCard. */
8
+ export function HasciiCardFooter(props: Props) {
9
+ return (
10
+ <box flexDirection="row" justifyContent="flex-end" gap={1}>
11
+ {props.children}
12
+ </box>
13
+ )
14
+ }
@@ -0,0 +1,14 @@
1
+ import type { ReactNode } from "react"
2
+
3
+ export type Props = {
4
+ children?: ReactNode
5
+ }
6
+
7
+ /** Vertical heading group typically holding HasciiCardTitle and HasciiCardDescription. */
8
+ export function HasciiCardHeader(props: Props) {
9
+ return (
10
+ <box flexDirection="column" gap={0}>
11
+ {props.children}
12
+ </box>
13
+ )
14
+ }
@@ -0,0 +1,13 @@
1
+ import type { ReactNode } from "react"
2
+ import { useHasciiTheme } from "@/tui/utils/hascii/theme-context"
3
+
4
+ export type Props = {
5
+ children?: ReactNode
6
+ }
7
+
8
+ /** Primary title text inside a card header. */
9
+ export function HasciiCardTitle(props: Props) {
10
+ const theme = useHasciiTheme()
11
+
12
+ return <text fg={theme.color.foreground}>{props.children}</text>
13
+ }
@@ -0,0 +1,27 @@
1
+ import type { ReactNode } from "react"
2
+ import { useHasciiTheme } from "@/tui/utils/hascii/theme-context"
3
+
4
+ export type Props = {
5
+ width?: number
6
+ children?: ReactNode
7
+ }
8
+
9
+ /** Filled container that frames its children. Use with HasciiCardHeader, HasciiCardContent, and HasciiCardFooter. */
10
+ export function HasciiCard(props: Props) {
11
+ const theme = useHasciiTheme()
12
+
13
+ return (
14
+ <box
15
+ backgroundColor={theme.color.card}
16
+ flexDirection="column"
17
+ paddingTop={1}
18
+ paddingBottom={1}
19
+ paddingLeft={2}
20
+ paddingRight={2}
21
+ gap={0}
22
+ width={props.width}
23
+ >
24
+ {props.children}
25
+ </box>
26
+ )
27
+ }
@@ -0,0 +1,65 @@
1
+ import type { ReactNode } from "react"
2
+ import { useState } from "react"
3
+ import { useHasciiTheme } from "@/tui/utils/hascii/theme-context"
4
+ import { usePressable } from "@/tui/hooks/hascii/use-pressable"
5
+
6
+ type Type = "ballot" | "square"
7
+
8
+ export type Props = {
9
+ type?: Type
10
+ isChecked?: boolean
11
+ defaultChecked?: boolean
12
+ isDisabled?: boolean
13
+ onChange?: (next: boolean) => void
14
+ children?: ReactNode
15
+ }
16
+
17
+ const GLYPHS: Record<Type, { checked: string; unchecked: string }> = {
18
+ ballot: { checked: "☑", unchecked: "☐" },
19
+ square: { checked: "■", unchecked: "□" },
20
+ }
21
+
22
+ /** Single checkbox row. type="ballot" (default) uses ☐/☑; type="square" matches the stepper's ■/□ glyphs. */
23
+ export function HasciiCheckbox(props: Props) {
24
+ const type = props.type ?? "ballot"
25
+ const isDisabled = props.isDisabled ?? false
26
+ const theme = useHasciiTheme()
27
+
28
+ const internalState = useState(props.defaultChecked ?? false)
29
+ const internal = internalState[0]
30
+ const setInternal = internalState[1]
31
+
32
+ const isChecked = props.isChecked ?? internal
33
+
34
+ const toggle = () => {
35
+ const next = !isChecked
36
+
37
+ if (props.isChecked === undefined) setInternal(next)
38
+ props.onChange?.(next)
39
+ }
40
+
41
+ const press = usePressable({ isDisabled, onPress: toggle })
42
+
43
+ const glyphFg = isDisabled
44
+ ? theme.color.mutedForeground
45
+ : isChecked
46
+ ? theme.color.primary
47
+ : press.isHovered
48
+ ? theme.color.foreground
49
+ : theme.color.mutedForeground
50
+
51
+ const labelFg = isDisabled ? theme.color.mutedForeground : theme.color.foreground
52
+
53
+ const glyphs = GLYPHS[type]
54
+
55
+ return (
56
+ <box flexDirection="row" alignItems="center" {...press.bind}>
57
+ <text fg={glyphFg}>{isChecked ? glyphs.checked : glyphs.unchecked}</text>
58
+ {props.children !== undefined ? (
59
+ <box paddingLeft={2}>
60
+ <text fg={labelFg}>{props.children}</text>
61
+ </box>
62
+ ) : null}
63
+ </box>
64
+ )
65
+ }
@@ -0,0 +1,159 @@
1
+ import { useKeyboard } from "@opentui/react"
2
+ import { useState } from "react"
3
+ import { useHasciiTheme } from "@/tui/utils/hascii/theme-context"
4
+ import { usePressable } from "@/tui/hooks/hascii/use-pressable"
5
+ import { HasciiInput } from "@/tui/components/ui/hascii/input"
6
+
7
+ export type CommandItem = {
8
+ id: string
9
+ label: string
10
+ hint?: string
11
+ }
12
+
13
+ export type Props = {
14
+ items: CommandItem[]
15
+ placeholder?: string
16
+ width?: number
17
+ maxRows?: number
18
+ isFocused?: boolean
19
+ onRun?: (id: string) => void
20
+ }
21
+
22
+ type RowProps = {
23
+ item: CommandItem
24
+ isActive: boolean
25
+ onHover: () => void
26
+ onPress: () => void
27
+ }
28
+
29
+ const ROW_HEIGHT = 1
30
+
31
+ /** Internal row used by HasciiCommand. Hover moves the active cursor; only the active row gets a bg + ▏ left rule. */
32
+ function HasciiCommandRow(props: RowProps) {
33
+ const theme = useHasciiTheme()
34
+ const press = usePressable({ onPress: props.onPress })
35
+
36
+ const bg = props.isActive ? theme.color.secondaryActive : undefined
37
+
38
+ return (
39
+ <box
40
+ flexDirection="row"
41
+ alignItems="center"
42
+ justifyContent="space-between"
43
+ paddingLeft={2}
44
+ paddingRight={2}
45
+ height={ROW_HEIGHT}
46
+ backgroundColor={bg}
47
+ onMouseOver={() => {
48
+ press.bind.onMouseOver()
49
+ props.onHover()
50
+ }}
51
+ onMouseOut={press.bind.onMouseOut}
52
+ onMouseDown={press.bind.onMouseDown}
53
+ onMouseUp={press.bind.onMouseUp}
54
+ >
55
+ {props.isActive ? (
56
+ <box position="absolute" left={0} top={0} bottom={0} flexDirection="column">
57
+ {Array.from({ length: ROW_HEIGHT }, (_, index) => (
58
+ <text key={index} fg={theme.color.primary}>
59
+
60
+ </text>
61
+ ))}
62
+ </box>
63
+ ) : null}
64
+ <text fg={theme.color.foreground}>{props.item.label}</text>
65
+ {props.item.hint !== undefined ? (
66
+ <text fg={theme.color.mutedForeground}>{props.item.hint}</text>
67
+ ) : null}
68
+ </box>
69
+ )
70
+ }
71
+
72
+ const matches = (item: CommandItem, query: string): boolean => {
73
+ if (query.length === 0) return true
74
+
75
+ const needle = query.toLowerCase()
76
+ return item.label.toLowerCase().includes(needle)
77
+ }
78
+
79
+ /** Keyboard-driven palette: type to filter, ↑/↓ moves the cursor (also moved by hover), Enter runs. The input bar is HasciiInput. */
80
+ export function HasciiCommand(props: Props) {
81
+ const width = props.width ?? 48
82
+ const maxRows = props.maxRows ?? 8
83
+ const isFocused = props.isFocused ?? true
84
+ const placeholder = props.placeholder ?? "type a command…"
85
+ const theme = useHasciiTheme()
86
+
87
+ const queryState = useState("")
88
+ const query = queryState[0]
89
+ const setQuery = queryState[1]
90
+
91
+ const indexState = useState(0)
92
+ const activeIndex = indexState[0]
93
+ const setActiveIndex = indexState[1]
94
+
95
+ const filtered = props.items.filter((item) => matches(item, query))
96
+ const safeIndex = filtered.length === 0 ? 0 : Math.min(activeIndex, filtered.length - 1)
97
+
98
+ useKeyboard((key) => {
99
+ if (!isFocused) return
100
+
101
+ if (key.name === "up") {
102
+ setActiveIndex(Math.max(0, safeIndex - 1))
103
+ return
104
+ }
105
+
106
+ if (key.name === "down") {
107
+ setActiveIndex(Math.min(filtered.length - 1, safeIndex + 1))
108
+ return
109
+ }
110
+
111
+ if (key.name === "return") {
112
+ const item = filtered[safeIndex]
113
+ if (item) props.onRun?.(item.id)
114
+ return
115
+ }
116
+ })
117
+
118
+ return (
119
+ <box width={width} backgroundColor={theme.color.card} flexDirection="column">
120
+ <HasciiInput
121
+ defaultFocused={isFocused}
122
+ width={width}
123
+ value={query}
124
+ placeholder={placeholder}
125
+ onInput={(value) => {
126
+ setQuery(value)
127
+ setActiveIndex(0)
128
+ }}
129
+ />
130
+ <box height={maxRows}>
131
+ {filtered.length === 0 ? (
132
+ <box paddingLeft={2} paddingRight={2} height={1}>
133
+ <text fg={theme.color.mutedForeground}>no matches</text>
134
+ </box>
135
+ ) : (
136
+ <scrollbox
137
+ flexGrow={1}
138
+ scrollY
139
+ stickyScroll={false}
140
+ contentOptions={{ flexDirection: "column", gap: 0 }}
141
+ >
142
+ {filtered.map((item, index) => (
143
+ <HasciiCommandRow
144
+ key={item.id}
145
+ item={item}
146
+ isActive={index === safeIndex}
147
+ onHover={() => setActiveIndex(index)}
148
+ onPress={() => {
149
+ setActiveIndex(index)
150
+ props.onRun?.(item.id)
151
+ }}
152
+ />
153
+ ))}
154
+ </scrollbox>
155
+ )}
156
+ </box>
157
+ </box>
158
+ )
159
+ }
@@ -0,0 +1,14 @@
1
+ import type { ReactNode } from "react"
2
+
3
+ export type Props = {
4
+ children?: ReactNode
5
+ }
6
+
7
+ /** Vertical body region inside a HasciiDialog. */
8
+ export function HasciiDialogContent(props: Props) {
9
+ return (
10
+ <box flexDirection="column" gap={1}>
11
+ {props.children}
12
+ </box>
13
+ )
14
+ }
@@ -0,0 +1,13 @@
1
+ import type { ReactNode } from "react"
2
+ import { useHasciiTheme } from "@/tui/utils/hascii/theme-context"
3
+
4
+ export type Props = {
5
+ children?: ReactNode
6
+ }
7
+
8
+ /** Secondary descriptive text rendered under a HasciiDialogTitle. */
9
+ export function HasciiDialogDescription(props: Props) {
10
+ const theme = useHasciiTheme()
11
+
12
+ return <text fg={theme.color.mutedForeground}>{props.children}</text>
13
+ }
@@ -0,0 +1,14 @@
1
+ import type { ReactNode } from "react"
2
+
3
+ export type Props = {
4
+ children?: ReactNode
5
+ }
6
+
7
+ /** Horizontal action row, right-aligned, at the bottom of a HasciiDialog. */
8
+ export function HasciiDialogFooter(props: Props) {
9
+ return (
10
+ <box flexDirection="row" gap={1} justifyContent="flex-end" marginTop={1}>
11
+ {props.children}
12
+ </box>
13
+ )
14
+ }
@@ -0,0 +1,14 @@
1
+ import type { ReactNode } from "react"
2
+
3
+ export type Props = {
4
+ children?: ReactNode
5
+ }
6
+
7
+ /** Dialog header. Stacks the children vertically with the standard 1-cell gap. */
8
+ export function HasciiDialogHeader(props: Props) {
9
+ return (
10
+ <box flexDirection="column" gap={1}>
11
+ {props.children}
12
+ </box>
13
+ )
14
+ }
@@ -0,0 +1,13 @@
1
+ import type { ReactNode } from "react"
2
+ import { useHasciiTheme } from "@/tui/utils/hascii/theme-context"
3
+
4
+ export type Props = {
5
+ children?: ReactNode
6
+ }
7
+
8
+ /** Primary title text inside a HasciiDialogHeader. */
9
+ export function HasciiDialogTitle(props: Props) {
10
+ const theme = useHasciiTheme()
11
+
12
+ return <text fg={theme.color.foreground}>{props.children}</text>
13
+ }
@@ -0,0 +1,27 @@
1
+ import type { ReactNode } from "react"
2
+ import { HasciiButton } from "@/tui/components/ui/hascii/button"
3
+ import { HasciiCard } from "@/tui/components/ui/hascii/card"
4
+
5
+ export type Props = {
6
+ width?: number
7
+ onClose?: () => void
8
+ children?: ReactNode
9
+ }
10
+
11
+ /** Floating dialog. Wraps a HasciiCard for layout and renders a default-variant x button just above the card's top-right corner when onClose is provided. */
12
+ export function HasciiDialog(props: Props) {
13
+ const width = props.width ?? 48
14
+
15
+ return (
16
+ <box width={width} paddingTop={1}>
17
+ <HasciiCard width={width}>{props.children}</HasciiCard>
18
+ {props.onClose ? (
19
+ <box position="absolute" top={0} right={0}>
20
+ <HasciiButton variant="secondary" size="default" onPress={props.onClose}>
21
+ x
22
+ </HasciiButton>
23
+ </box>
24
+ ) : null}
25
+ </box>
26
+ )
27
+ }