@interactive-inc/claude-funnel 0.10.0 → 0.15.1

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 (236) hide show
  1. package/README.md +106 -56
  2. package/dist/bin.js +557 -530
  3. package/dist/connectors/schedule.d.ts +2 -49
  4. package/dist/connectors/schedule.js +1 -1
  5. package/dist/connectors/slack.d.ts +4 -48
  6. package/dist/connectors/slack.js +1 -1
  7. package/dist/gateway/daemon.js +213 -211
  8. package/dist/index.d.ts +465 -173
  9. package/dist/index.js +692 -154
  10. package/dist/{schedule-connector-schema-CkuIQ0JQ.js → schedule-connector-schema-FxP7LPlx.js} +11 -0
  11. package/dist/{file-system-Co60LrmR.d.ts → schedule-listener-BPodvbld.d.ts} +56 -1
  12. package/dist/{slack-connector-schema-Cd22WiHB.js → slack-connector-schema-B4hsf3AY.js} +10 -1
  13. package/dist/slack-listener-CHj6uMY-.d.ts +74 -0
  14. package/package.json +2 -6
  15. package/schemas/funnel.schema.json +144 -0
  16. package/dist/slack-connector-schema-D7zAHN8k.d.ts +0 -15
  17. package/lib/bin.ts +0 -3
  18. package/lib/cli/factory.ts +0 -10
  19. package/lib/cli/index.ts +0 -85
  20. package/lib/cli/router/query-to-cli-args.ts +0 -20
  21. package/lib/cli/router/to-request.ts +0 -113
  22. package/lib/cli/router/validator.ts +0 -27
  23. package/lib/cli/routes/channels.$channel.connectors.$connector.rename.$newName.ts +0 -27
  24. package/lib/cli/routes/channels.$channel.connectors.$connector.request.ts +0 -40
  25. package/lib/cli/routes/channels.$channel.connectors.$connector.schedules.add.$id.ts +0 -41
  26. package/lib/cli/routes/channels.$channel.connectors.$connector.schedules.remove.$id.ts +0 -22
  27. package/lib/cli/routes/channels.$channel.connectors.$connector.schedules.ts +0 -23
  28. package/lib/cli/routes/channels.$channel.connectors.$connector.ts +0 -26
  29. package/lib/cli/routes/channels.$channel.connectors.add.$connector.ts +0 -92
  30. package/lib/cli/routes/channels.$channel.connectors.remove.$connector.ts +0 -22
  31. package/lib/cli/routes/channels.$channel.connectors.set.$connector.ts +0 -63
  32. package/lib/cli/routes/channels.$channel.connectors.ts +0 -26
  33. package/lib/cli/routes/channels.$channel.publish.ts +0 -52
  34. package/lib/cli/routes/channels.$channel.rename.$newName.ts +0 -22
  35. package/lib/cli/routes/channels.$channel.set.delivery.$mode.ts +0 -34
  36. package/lib/cli/routes/channels.$channel.ts +0 -34
  37. package/lib/cli/routes/channels.add.$channel.ts +0 -33
  38. package/lib/cli/routes/channels.remove.$channel.ts +0 -20
  39. package/lib/cli/routes/channels.ts +0 -39
  40. package/lib/cli/routes/claude.ts +0 -70
  41. package/lib/cli/routes/gateway.listeners.ts +0 -41
  42. package/lib/cli/routes/gateway.logs.ts +0 -123
  43. package/lib/cli/routes/gateway.restart.ts +0 -50
  44. package/lib/cli/routes/gateway.run.ts +0 -41
  45. package/lib/cli/routes/gateway.start.ts +0 -50
  46. package/lib/cli/routes/gateway.status.ts +0 -19
  47. package/lib/cli/routes/gateway.stop.ts +0 -32
  48. package/lib/cli/routes/gateway.ts +0 -55
  49. package/lib/cli/routes/index.ts +0 -219
  50. package/lib/cli/routes/profiles.$profile.as-default.ts +0 -22
  51. package/lib/cli/routes/profiles.$profile.rename.$newName.ts +0 -22
  52. package/lib/cli/routes/profiles.$profile.run.ts +0 -36
  53. package/lib/cli/routes/profiles.add.$profile.ts +0 -49
  54. package/lib/cli/routes/profiles.remove.$profile.ts +0 -20
  55. package/lib/cli/routes/profiles.set.$profile.ts +0 -45
  56. package/lib/cli/routes/profiles.ts +0 -40
  57. package/lib/cli/routes/status.ts +0 -93
  58. package/lib/cli/routes/update.ts +0 -27
  59. package/lib/connectors/connector-adapter.ts +0 -9
  60. package/lib/connectors/connector-config-schema.ts +0 -16
  61. package/lib/connectors/connector-factory.ts +0 -94
  62. package/lib/connectors/connector-listener.ts +0 -20
  63. package/lib/connectors/discord-adapter.ts +0 -51
  64. package/lib/connectors/discord-connector-schema.ts +0 -12
  65. package/lib/connectors/discord-event-processor.ts +0 -48
  66. package/lib/connectors/discord-listener.ts +0 -111
  67. package/lib/connectors/discord.ts +0 -4
  68. package/lib/connectors/gh-adapter.ts +0 -48
  69. package/lib/connectors/gh-connector-schema.ts +0 -12
  70. package/lib/connectors/gh-listener.ts +0 -137
  71. package/lib/connectors/gh.ts +0 -3
  72. package/lib/connectors/match-cron.ts +0 -78
  73. package/lib/connectors/schedule-connector-schema.ts +0 -33
  74. package/lib/connectors/schedule-listener.ts +0 -207
  75. package/lib/connectors/schedule-state-store.ts +0 -54
  76. package/lib/connectors/schedule.ts +0 -4
  77. package/lib/connectors/slack-adapter.ts +0 -36
  78. package/lib/connectors/slack-connector-schema.ts +0 -13
  79. package/lib/connectors/slack-event-processor.ts +0 -97
  80. package/lib/connectors/slack-listener.ts +0 -97
  81. package/lib/connectors/slack.ts +0 -4
  82. package/lib/engine/channels/channels.ts +0 -520
  83. package/lib/engine/claude/claude.ts +0 -205
  84. package/lib/engine/claude/gateway-controller.ts +0 -4
  85. package/lib/engine/fs/file-system.ts +0 -23
  86. package/lib/engine/fs/memory-file-system.ts +0 -102
  87. package/lib/engine/fs/node-file-system.ts +0 -68
  88. package/lib/engine/http/http-client.ts +0 -17
  89. package/lib/engine/http/memory-http-client.ts +0 -36
  90. package/lib/engine/http/node-http-client.ts +0 -23
  91. package/lib/engine/id/id-generator.ts +0 -7
  92. package/lib/engine/id/memory-id-generator.ts +0 -20
  93. package/lib/engine/id/node-id-generator.ts +0 -7
  94. package/lib/engine/logger/logger.ts +0 -11
  95. package/lib/engine/logger/memory-logger.ts +0 -28
  96. package/lib/engine/logger/node-logger.ts +0 -49
  97. package/lib/engine/logger/noop-logger.ts +0 -9
  98. package/lib/engine/mcp/channel-server.ts +0 -123
  99. package/lib/engine/mcp/channel-subscriber.ts +0 -82
  100. package/lib/engine/mcp/mcp.ts +0 -126
  101. package/lib/engine/mcp/read-channel-connectors.ts +0 -34
  102. package/lib/engine/mcp/read-gateway-token.ts +0 -16
  103. package/lib/engine/mcp/usage-hint-for-type.ts +0 -15
  104. package/lib/engine/process/memory-process-runner.ts +0 -88
  105. package/lib/engine/process/node-process-runner.ts +0 -91
  106. package/lib/engine/process/process-runner.ts +0 -33
  107. package/lib/engine/profiles/profile-channel-checker.ts +0 -7
  108. package/lib/engine/profiles/profiles.ts +0 -126
  109. package/lib/engine/settings/mock-settings-reader.ts +0 -27
  110. package/lib/engine/settings/settings-reader.ts +0 -6
  111. package/lib/engine/settings/settings-schema.ts +0 -48
  112. package/lib/engine/settings/settings-store.ts +0 -110
  113. package/lib/engine/time/clock.ts +0 -15
  114. package/lib/engine/time/memory-clock.ts +0 -26
  115. package/lib/engine/time/node-clock.ts +0 -7
  116. package/lib/funnel.ts +0 -294
  117. package/lib/gateway/auth-middleware.ts +0 -44
  118. package/lib/gateway/broadcaster.ts +0 -319
  119. package/lib/gateway/channel-publisher.ts +0 -67
  120. package/lib/gateway/daemon.ts +0 -47
  121. package/lib/gateway/factory.ts +0 -10
  122. package/lib/gateway/funnel-event-store.ts +0 -155
  123. package/lib/gateway/gateway-server.ts +0 -426
  124. package/lib/gateway/gateway-token.ts +0 -79
  125. package/lib/gateway/gateway.ts +0 -209
  126. package/lib/gateway/kill-competing-slack-gateways.ts +0 -56
  127. package/lib/gateway/listener-supervisor.ts +0 -339
  128. package/lib/gateway/listeners-client.ts +0 -128
  129. package/lib/gateway/publish-schema.ts +0 -27
  130. package/lib/gateway/resolve-daemon-script.ts +0 -26
  131. package/lib/gateway/routes/channels.connectors.call.ts +0 -39
  132. package/lib/gateway/routes/channels.publish.ts +0 -44
  133. package/lib/gateway/routes/health.ts +0 -13
  134. package/lib/gateway/routes/index.ts +0 -26
  135. package/lib/gateway/routes/listeners.list.ts +0 -6
  136. package/lib/gateway/routes/listeners.restart.ts +0 -15
  137. package/lib/gateway/routes/listeners.start.ts +0 -15
  138. package/lib/gateway/routes/listeners.stop.ts +0 -15
  139. package/lib/gateway/routes/route-deps.ts +0 -19
  140. package/lib/gateway/routes/status.ts +0 -15
  141. package/lib/gateway/routes/validator.ts +0 -17
  142. package/lib/index.ts +0 -67
  143. package/lib/logger/leuco-human-file-writer.ts +0 -65
  144. package/lib/logger/leuco-human-logger.ts +0 -98
  145. package/lib/logger/leuco-human-record.ts +0 -16
  146. package/lib/logger/leuco-human-stdout-writer.ts +0 -26
  147. package/lib/logger/leuco-human-writer.ts +0 -14
  148. package/lib/logger/leuco-logger-memory-sink.ts +0 -67
  149. package/lib/logger/leuco-logger-record.ts +0 -13
  150. package/lib/logger/leuco-logger-sink.ts +0 -33
  151. package/lib/logger/leuco-logger-sqlite-sink.ts +0 -355
  152. package/lib/logger/leuco-logger.ts +0 -135
  153. package/lib/tui/app.tsx +0 -357
  154. package/lib/tui/components/add-row.tsx +0 -18
  155. package/lib/tui/components/brand.tsx +0 -27
  156. package/lib/tui/components/card.tsx +0 -44
  157. package/lib/tui/components/detail-bar.tsx +0 -46
  158. package/lib/tui/components/editable-field.tsx +0 -33
  159. package/lib/tui/components/empty-state.tsx +0 -11
  160. package/lib/tui/components/gateway-status.tsx +0 -66
  161. package/lib/tui/components/keymap.tsx +0 -29
  162. package/lib/tui/components/menu-item.tsx +0 -73
  163. package/lib/tui/components/menu.tsx +0 -26
  164. package/lib/tui/components/panel-header.tsx +0 -22
  165. package/lib/tui/components/readonly-field.tsx +0 -18
  166. package/lib/tui/components/section-header.tsx +0 -25
  167. package/lib/tui/components/selection-accent.tsx +0 -32
  168. package/lib/tui/components/session-item.tsx +0 -33
  169. package/lib/tui/components/session-list.tsx +0 -33
  170. package/lib/tui/components/ui/hascii/accordion-item.tsx +0 -88
  171. package/lib/tui/components/ui/hascii/accordion.tsx +0 -96
  172. package/lib/tui/components/ui/hascii/alert-dialog.tsx +0 -43
  173. package/lib/tui/components/ui/hascii/badge.tsx +0 -51
  174. package/lib/tui/components/ui/hascii/breadcrumb.tsx +0 -58
  175. package/lib/tui/components/ui/hascii/button.tsx +0 -194
  176. package/lib/tui/components/ui/hascii/card-content.tsx +0 -14
  177. package/lib/tui/components/ui/hascii/card-description.tsx +0 -13
  178. package/lib/tui/components/ui/hascii/card-footer.tsx +0 -14
  179. package/lib/tui/components/ui/hascii/card-header.tsx +0 -14
  180. package/lib/tui/components/ui/hascii/card-title.tsx +0 -13
  181. package/lib/tui/components/ui/hascii/card.tsx +0 -27
  182. package/lib/tui/components/ui/hascii/checkbox.tsx +0 -65
  183. package/lib/tui/components/ui/hascii/command.tsx +0 -159
  184. package/lib/tui/components/ui/hascii/dialog-content.tsx +0 -14
  185. package/lib/tui/components/ui/hascii/dialog-description.tsx +0 -13
  186. package/lib/tui/components/ui/hascii/dialog-footer.tsx +0 -14
  187. package/lib/tui/components/ui/hascii/dialog-header.tsx +0 -14
  188. package/lib/tui/components/ui/hascii/dialog-title.tsx +0 -13
  189. package/lib/tui/components/ui/hascii/dialog.tsx +0 -27
  190. package/lib/tui/components/ui/hascii/file-tree.tsx +0 -142
  191. package/lib/tui/components/ui/hascii/focus-group.tsx +0 -62
  192. package/lib/tui/components/ui/hascii/form-item.tsx +0 -43
  193. package/lib/tui/components/ui/hascii/input-otp.tsx +0 -86
  194. package/lib/tui/components/ui/hascii/input.tsx +0 -130
  195. package/lib/tui/components/ui/hascii/pagination.tsx +0 -105
  196. package/lib/tui/components/ui/hascii/progress.tsx +0 -28
  197. package/lib/tui/components/ui/hascii/select.tsx +0 -131
  198. package/lib/tui/components/ui/hascii/separator.tsx +0 -35
  199. package/lib/tui/components/ui/hascii/sidebar-content.tsx +0 -23
  200. package/lib/tui/components/ui/hascii/sidebar-header.tsx +0 -14
  201. package/lib/tui/components/ui/hascii/sidebar-menu-item.tsx +0 -67
  202. package/lib/tui/components/ui/hascii/sidebar.tsx +0 -24
  203. package/lib/tui/components/ui/hascii/skeleton.tsx +0 -60
  204. package/lib/tui/components/ui/hascii/slider.tsx +0 -91
  205. package/lib/tui/components/ui/hascii/snackbar.tsx +0 -75
  206. package/lib/tui/components/ui/hascii/sparkline.tsx +0 -53
  207. package/lib/tui/components/ui/hascii/spinner.tsx +0 -47
  208. package/lib/tui/components/ui/hascii/stepper.tsx +0 -54
  209. package/lib/tui/components/ui/hascii/switch.tsx +0 -66
  210. package/lib/tui/components/ui/hascii/table.tsx +0 -95
  211. package/lib/tui/components/ui/hascii/tabs.tsx +0 -59
  212. package/lib/tui/components/ui/hascii/toggle-group-item.tsx +0 -45
  213. package/lib/tui/components/ui/hascii/toggle-group.tsx +0 -99
  214. package/lib/tui/components/ui/hascii/tree.tsx +0 -104
  215. package/lib/tui/components/view-shell.tsx +0 -44
  216. package/lib/tui/filter-input.tsx +0 -33
  217. package/lib/tui/hooks/hascii/use-pressable.ts +0 -54
  218. package/lib/tui/parse-comma-list.ts +0 -14
  219. package/lib/tui/profile-launcher.tsx +0 -61
  220. package/lib/tui/scrollbar-options.ts +0 -19
  221. package/lib/tui/sidebar.tsx +0 -50
  222. package/lib/tui/theme.ts +0 -40
  223. package/lib/tui/tui.tsx +0 -20
  224. package/lib/tui/types.ts +0 -38
  225. package/lib/tui/unique-name.ts +0 -18
  226. package/lib/tui/use-event-stream.ts +0 -133
  227. package/lib/tui/use-snapshot.ts +0 -99
  228. package/lib/tui/utils/hascii/form-item-context.tsx +0 -23
  229. package/lib/tui/utils/hascii/input-focus-context.tsx +0 -31
  230. package/lib/tui/utils/hascii/theme-context.tsx +0 -26
  231. package/lib/tui/utils/hascii/theme.ts +0 -176
  232. package/lib/tui/views/channels-view.tsx +0 -108
  233. package/lib/tui/views/connectors-view.tsx +0 -164
  234. package/lib/tui/views/events-view.tsx +0 -160
  235. package/lib/tui/views/listeners-view.tsx +0 -80
  236. package/lib/tui/views/profiles-view.tsx +0 -152
@@ -1,26 +0,0 @@
1
- import { factory } from "@/gateway/factory"
2
- import { channelsConnectorsCallHandler } from "@/gateway/routes/channels.connectors.call"
3
- import { channelsPublishHandler } from "@/gateway/routes/channels.publish"
4
- import { healthHandler } from "@/gateway/routes/health"
5
- import { listenersListHandler } from "@/gateway/routes/listeners.list"
6
- import { listenersRestartHandler } from "@/gateway/routes/listeners.restart"
7
- import { listenersStartHandler } from "@/gateway/routes/listeners.start"
8
- import { listenersStopHandler } from "@/gateway/routes/listeners.stop"
9
- import { statusHandler } from "@/gateway/routes/status"
10
-
11
- /**
12
- * Top-level Hono app for the gateway daemon. Mounts every HTTP endpoint flat
13
- * (the WebSocket /ws upgrade is handled directly by `Bun.serve`). Deps come
14
- * from the `deps` variable set by `FunnelGatewayServer`'s middleware — same
15
- * shape as CLI's `c.var.funnel`.
16
- */
17
- export const gatewayRoutes = factory
18
- .createApp()
19
- .get("/health", ...healthHandler)
20
- .get("/status", ...statusHandler)
21
- .get("/listeners", ...listenersListHandler)
22
- .post("/listeners/:channel/:connector/start", ...listenersStartHandler)
23
- .delete("/listeners/:channel/:connector", ...listenersStopHandler)
24
- .post("/listeners/:channel/:connector/restart", ...listenersRestartHandler)
25
- .post("/channels/:channel/connectors/:connector/call", ...channelsConnectorsCallHandler)
26
- .post("/channels/:channel/publish", ...channelsPublishHandler)
@@ -1,6 +0,0 @@
1
- import { factory } from "@/gateway/factory"
2
-
3
- /** GET /listeners — running connector listeners with alive/dead status. */
4
- export const listenersListHandler = factory.createHandlers((c) => {
5
- return c.json({ listeners: c.var.deps.supervisor.list() })
6
- })
@@ -1,15 +0,0 @@
1
- import { z } from "zod"
2
- import { factory } from "@/gateway/factory"
3
- import { zParam } from "@/gateway/routes/validator"
4
-
5
- /** POST /listeners/:channel/:connector/restart — stop + start a connector listener. */
6
- export const listenersRestartHandler = factory.createHandlers(
7
- zParam(z.object({ channel: z.string().min(1), connector: z.string().min(1) })),
8
- async (c) => {
9
- const param = c.req.valid("param")
10
-
11
- const result = await c.var.deps.supervisor.restart(param.channel, param.connector)
12
-
13
- return c.json(result, result.ok ? 200 : 400)
14
- },
15
- )
@@ -1,15 +0,0 @@
1
- import { z } from "zod"
2
- import { factory } from "@/gateway/factory"
3
- import { zParam } from "@/gateway/routes/validator"
4
-
5
- /** POST /listeners/:channel/:connector/start — start a connector listener. */
6
- export const listenersStartHandler = factory.createHandlers(
7
- zParam(z.object({ channel: z.string().min(1), connector: z.string().min(1) })),
8
- async (c) => {
9
- const param = c.req.valid("param")
10
-
11
- const result = await c.var.deps.supervisor.start(param.channel, param.connector)
12
-
13
- return c.json(result, result.ok ? 200 : 400)
14
- },
15
- )
@@ -1,15 +0,0 @@
1
- import { z } from "zod"
2
- import { factory } from "@/gateway/factory"
3
- import { zParam } from "@/gateway/routes/validator"
4
-
5
- /** DELETE /listeners/:channel/:connector — stop a connector listener. */
6
- export const listenersStopHandler = factory.createHandlers(
7
- zParam(z.object({ channel: z.string().min(1), connector: z.string().min(1) })),
8
- async (c) => {
9
- const param = c.req.valid("param")
10
-
11
- const result = await c.var.deps.supervisor.stop(param.channel, param.connector)
12
-
13
- return c.json(result, result.ok ? 200 : 400)
14
- },
15
- )
@@ -1,19 +0,0 @@
1
- import type { FunnelChannels } from "@/engine/channels/channels"
2
- import type { FunnelBroadcaster } from "@/gateway/broadcaster"
3
- import type { FunnelListenerSupervisor } from "@/gateway/listener-supervisor"
4
-
5
- export type GatewayEmitInput = {
6
- channel: string
7
- connector?: string
8
- content: string
9
- meta?: Record<string, string>
10
- }
11
-
12
- export type GatewayRouteDeps = {
13
- selfPid: number
14
- broadcaster: FunnelBroadcaster
15
- supervisor: FunnelListenerSupervisor
16
- channels: FunnelChannels
17
- uptimeMs: () => number
18
- emit: (input: GatewayEmitInput) => { offset: number }
19
- }
@@ -1,15 +0,0 @@
1
- import { factory } from "@/gateway/factory"
2
-
3
- /** GET /status — listener registry, connected channels, and broadcaster metrics. */
4
- export const statusHandler = factory.createHandlers((c) => {
5
- const deps = c.var.deps
6
-
7
- return c.json({
8
- ok: true,
9
- pid: deps.selfPid,
10
- uptimeMs: deps.uptimeMs(),
11
- clients: deps.broadcaster.listChannels(),
12
- listeners: deps.supervisor.list(),
13
- broadcaster: deps.broadcaster.getMetrics(),
14
- })
15
- })
@@ -1,17 +0,0 @@
1
- import { zValidator } from "@hono/zod-validator"
2
- import type { ZodType } from "zod"
3
-
4
- /**
5
- * Path-param validator for gateway routes. On failure it answers with the same
6
- * `{ ok: false, reason }` shape the listener routes already use, so
7
- * `FunnelListenersClient` can surface the message without special-casing.
8
- */
9
- export const zParam = <T extends ZodType>(schema: T) =>
10
- zValidator("param", schema, (result, c) => {
11
- if (result.success) return
12
-
13
- const issue = result.error.issues[0]
14
- const reason = issue ? `${issue.path.join(".")}: ${issue.message}` : "invalid request"
15
-
16
- return c.json({ ok: false, reason }, 400)
17
- })
package/lib/index.ts DELETED
@@ -1,67 +0,0 @@
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/mcp/channel-server"
12
- export * from "@/engine/profiles/profiles"
13
- export * from "@/engine/settings/settings-reader"
14
- export * from "@/engine/settings/settings-store"
15
- export * from "@/engine/settings/mock-settings-reader"
16
- export * from "@/engine/settings/settings-schema"
17
-
18
- // Engine — boundaries (abstract + Node / Memory implementations)
19
- export * from "@/engine/fs/file-system"
20
- export * from "@/engine/fs/node-file-system"
21
- export * from "@/engine/fs/memory-file-system"
22
-
23
- export * from "@/engine/process/process-runner"
24
- export * from "@/engine/process/node-process-runner"
25
- export * from "@/engine/process/memory-process-runner"
26
-
27
- export * from "@/engine/logger/logger"
28
- export * from "@/engine/logger/node-logger"
29
- export * from "@/engine/logger/memory-logger"
30
- export * from "@/engine/logger/noop-logger"
31
-
32
- export * from "@/engine/time/clock"
33
- export * from "@/engine/time/node-clock"
34
- export * from "@/engine/time/memory-clock"
35
-
36
- export * from "@/engine/id/id-generator"
37
- export * from "@/engine/id/node-id-generator"
38
- export * from "@/engine/id/memory-id-generator"
39
-
40
- // Connectors
41
- export * from "@/connectors/connector-factory"
42
- export * from "@/connectors/connector-config-schema"
43
- export * from "@/connectors/connector-listener"
44
- export * from "@/connectors/discord-connector-schema"
45
- export * from "@/connectors/gh-connector-schema"
46
- export * from "@/connectors/schedule-connector-schema"
47
- export * from "@/connectors/slack-connector-schema"
48
-
49
- // Gateway
50
- export * from "@/gateway/gateway"
51
- export * from "@/gateway/gateway-server"
52
- export * from "@/gateway/gateway-token"
53
- export * from "@/gateway/broadcaster"
54
- export * from "@/gateway/channel-publisher"
55
- export * from "@/gateway/funnel-event-store"
56
- export * from "@/gateway/listener-supervisor"
57
- export * from "@/gateway/listeners-client"
58
- export * from "@/gateway/publish-schema"
59
-
60
- // CLI — embeddable Hono app + argv translator
61
- export * from "@/cli/factory"
62
- export * from "@/cli/router/to-request"
63
- export * from "@/cli/router/query-to-cli-args"
64
- export { app as cliApp, createCliApp } from "@/cli/routes"
65
-
66
- // TUI — launcher (consumers can spawn the OpenTUI dashboard with their own Funnel)
67
- export * from "@/tui/tui"
@@ -1,65 +0,0 @@
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
- }
@@ -1,98 +0,0 @@
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
- }
@@ -1,16 +0,0 @@
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
- }
@@ -1,26 +0,0 @@
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
- }
@@ -1,14 +0,0 @@
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
- }
@@ -1,67 +0,0 @@
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
- }
@@ -1,13 +0,0 @@
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
- }
@@ -1,33 +0,0 @@
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
- }