@interactive-inc/claude-funnel 0.10.0 → 0.10.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 (228) hide show
  1. package/dist/bin.js +448 -448
  2. package/dist/connectors/slack.d.ts +1 -29
  3. package/dist/gateway/daemon.js +166 -166
  4. package/dist/index.d.ts +4 -11
  5. package/dist/index.js +133 -120
  6. package/dist/slack-event-processor-CS-bAit9.d.ts +43 -0
  7. package/package.json +1 -6
  8. package/dist/slack-connector-schema-D7zAHN8k.d.ts +0 -15
  9. package/lib/bin.ts +0 -3
  10. package/lib/cli/factory.ts +0 -10
  11. package/lib/cli/index.ts +0 -85
  12. package/lib/cli/router/query-to-cli-args.ts +0 -20
  13. package/lib/cli/router/to-request.ts +0 -113
  14. package/lib/cli/router/validator.ts +0 -27
  15. package/lib/cli/routes/channels.$channel.connectors.$connector.rename.$newName.ts +0 -27
  16. package/lib/cli/routes/channels.$channel.connectors.$connector.request.ts +0 -40
  17. package/lib/cli/routes/channels.$channel.connectors.$connector.schedules.add.$id.ts +0 -41
  18. package/lib/cli/routes/channels.$channel.connectors.$connector.schedules.remove.$id.ts +0 -22
  19. package/lib/cli/routes/channels.$channel.connectors.$connector.schedules.ts +0 -23
  20. package/lib/cli/routes/channels.$channel.connectors.$connector.ts +0 -26
  21. package/lib/cli/routes/channels.$channel.connectors.add.$connector.ts +0 -92
  22. package/lib/cli/routes/channels.$channel.connectors.remove.$connector.ts +0 -22
  23. package/lib/cli/routes/channels.$channel.connectors.set.$connector.ts +0 -63
  24. package/lib/cli/routes/channels.$channel.connectors.ts +0 -26
  25. package/lib/cli/routes/channels.$channel.publish.ts +0 -52
  26. package/lib/cli/routes/channels.$channel.rename.$newName.ts +0 -22
  27. package/lib/cli/routes/channels.$channel.set.delivery.$mode.ts +0 -34
  28. package/lib/cli/routes/channels.$channel.ts +0 -34
  29. package/lib/cli/routes/channels.add.$channel.ts +0 -33
  30. package/lib/cli/routes/channels.remove.$channel.ts +0 -20
  31. package/lib/cli/routes/channels.ts +0 -39
  32. package/lib/cli/routes/claude.ts +0 -70
  33. package/lib/cli/routes/gateway.listeners.ts +0 -41
  34. package/lib/cli/routes/gateway.logs.ts +0 -123
  35. package/lib/cli/routes/gateway.restart.ts +0 -50
  36. package/lib/cli/routes/gateway.run.ts +0 -41
  37. package/lib/cli/routes/gateway.start.ts +0 -50
  38. package/lib/cli/routes/gateway.status.ts +0 -19
  39. package/lib/cli/routes/gateway.stop.ts +0 -32
  40. package/lib/cli/routes/gateway.ts +0 -55
  41. package/lib/cli/routes/index.ts +0 -219
  42. package/lib/cli/routes/profiles.$profile.as-default.ts +0 -22
  43. package/lib/cli/routes/profiles.$profile.rename.$newName.ts +0 -22
  44. package/lib/cli/routes/profiles.$profile.run.ts +0 -36
  45. package/lib/cli/routes/profiles.add.$profile.ts +0 -49
  46. package/lib/cli/routes/profiles.remove.$profile.ts +0 -20
  47. package/lib/cli/routes/profiles.set.$profile.ts +0 -45
  48. package/lib/cli/routes/profiles.ts +0 -40
  49. package/lib/cli/routes/status.ts +0 -93
  50. package/lib/cli/routes/update.ts +0 -27
  51. package/lib/connectors/connector-adapter.ts +0 -9
  52. package/lib/connectors/connector-config-schema.ts +0 -16
  53. package/lib/connectors/connector-factory.ts +0 -94
  54. package/lib/connectors/connector-listener.ts +0 -20
  55. package/lib/connectors/discord-adapter.ts +0 -51
  56. package/lib/connectors/discord-connector-schema.ts +0 -12
  57. package/lib/connectors/discord-event-processor.ts +0 -48
  58. package/lib/connectors/discord-listener.ts +0 -111
  59. package/lib/connectors/discord.ts +0 -4
  60. package/lib/connectors/gh-adapter.ts +0 -48
  61. package/lib/connectors/gh-connector-schema.ts +0 -12
  62. package/lib/connectors/gh-listener.ts +0 -137
  63. package/lib/connectors/gh.ts +0 -3
  64. package/lib/connectors/match-cron.ts +0 -78
  65. package/lib/connectors/schedule-connector-schema.ts +0 -33
  66. package/lib/connectors/schedule-listener.ts +0 -207
  67. package/lib/connectors/schedule-state-store.ts +0 -54
  68. package/lib/connectors/schedule.ts +0 -4
  69. package/lib/connectors/slack-adapter.ts +0 -36
  70. package/lib/connectors/slack-connector-schema.ts +0 -13
  71. package/lib/connectors/slack-event-processor.ts +0 -97
  72. package/lib/connectors/slack-listener.ts +0 -97
  73. package/lib/connectors/slack.ts +0 -4
  74. package/lib/engine/channels/channels.ts +0 -520
  75. package/lib/engine/claude/claude.ts +0 -205
  76. package/lib/engine/claude/gateway-controller.ts +0 -4
  77. package/lib/engine/fs/file-system.ts +0 -23
  78. package/lib/engine/fs/memory-file-system.ts +0 -102
  79. package/lib/engine/fs/node-file-system.ts +0 -68
  80. package/lib/engine/http/http-client.ts +0 -17
  81. package/lib/engine/http/memory-http-client.ts +0 -36
  82. package/lib/engine/http/node-http-client.ts +0 -23
  83. package/lib/engine/id/id-generator.ts +0 -7
  84. package/lib/engine/id/memory-id-generator.ts +0 -20
  85. package/lib/engine/id/node-id-generator.ts +0 -7
  86. package/lib/engine/logger/logger.ts +0 -11
  87. package/lib/engine/logger/memory-logger.ts +0 -28
  88. package/lib/engine/logger/node-logger.ts +0 -49
  89. package/lib/engine/logger/noop-logger.ts +0 -9
  90. package/lib/engine/mcp/channel-server.ts +0 -123
  91. package/lib/engine/mcp/channel-subscriber.ts +0 -82
  92. package/lib/engine/mcp/mcp.ts +0 -126
  93. package/lib/engine/mcp/read-channel-connectors.ts +0 -34
  94. package/lib/engine/mcp/read-gateway-token.ts +0 -16
  95. package/lib/engine/mcp/usage-hint-for-type.ts +0 -15
  96. package/lib/engine/process/memory-process-runner.ts +0 -88
  97. package/lib/engine/process/node-process-runner.ts +0 -91
  98. package/lib/engine/process/process-runner.ts +0 -33
  99. package/lib/engine/profiles/profile-channel-checker.ts +0 -7
  100. package/lib/engine/profiles/profiles.ts +0 -126
  101. package/lib/engine/settings/mock-settings-reader.ts +0 -27
  102. package/lib/engine/settings/settings-reader.ts +0 -6
  103. package/lib/engine/settings/settings-schema.ts +0 -48
  104. package/lib/engine/settings/settings-store.ts +0 -110
  105. package/lib/engine/time/clock.ts +0 -15
  106. package/lib/engine/time/memory-clock.ts +0 -26
  107. package/lib/engine/time/node-clock.ts +0 -7
  108. package/lib/funnel.ts +0 -294
  109. package/lib/gateway/auth-middleware.ts +0 -44
  110. package/lib/gateway/broadcaster.ts +0 -319
  111. package/lib/gateway/channel-publisher.ts +0 -67
  112. package/lib/gateway/daemon.ts +0 -47
  113. package/lib/gateway/factory.ts +0 -10
  114. package/lib/gateway/funnel-event-store.ts +0 -155
  115. package/lib/gateway/gateway-server.ts +0 -426
  116. package/lib/gateway/gateway-token.ts +0 -79
  117. package/lib/gateway/gateway.ts +0 -209
  118. package/lib/gateway/kill-competing-slack-gateways.ts +0 -56
  119. package/lib/gateway/listener-supervisor.ts +0 -339
  120. package/lib/gateway/listeners-client.ts +0 -128
  121. package/lib/gateway/publish-schema.ts +0 -27
  122. package/lib/gateway/resolve-daemon-script.ts +0 -26
  123. package/lib/gateway/routes/channels.connectors.call.ts +0 -39
  124. package/lib/gateway/routes/channels.publish.ts +0 -44
  125. package/lib/gateway/routes/health.ts +0 -13
  126. package/lib/gateway/routes/index.ts +0 -26
  127. package/lib/gateway/routes/listeners.list.ts +0 -6
  128. package/lib/gateway/routes/listeners.restart.ts +0 -15
  129. package/lib/gateway/routes/listeners.start.ts +0 -15
  130. package/lib/gateway/routes/listeners.stop.ts +0 -15
  131. package/lib/gateway/routes/route-deps.ts +0 -19
  132. package/lib/gateway/routes/status.ts +0 -15
  133. package/lib/gateway/routes/validator.ts +0 -17
  134. package/lib/index.ts +0 -67
  135. package/lib/logger/leuco-human-file-writer.ts +0 -65
  136. package/lib/logger/leuco-human-logger.ts +0 -98
  137. package/lib/logger/leuco-human-record.ts +0 -16
  138. package/lib/logger/leuco-human-stdout-writer.ts +0 -26
  139. package/lib/logger/leuco-human-writer.ts +0 -14
  140. package/lib/logger/leuco-logger-memory-sink.ts +0 -67
  141. package/lib/logger/leuco-logger-record.ts +0 -13
  142. package/lib/logger/leuco-logger-sink.ts +0 -33
  143. package/lib/logger/leuco-logger-sqlite-sink.ts +0 -355
  144. package/lib/logger/leuco-logger.ts +0 -135
  145. package/lib/tui/app.tsx +0 -357
  146. package/lib/tui/components/add-row.tsx +0 -18
  147. package/lib/tui/components/brand.tsx +0 -27
  148. package/lib/tui/components/card.tsx +0 -44
  149. package/lib/tui/components/detail-bar.tsx +0 -46
  150. package/lib/tui/components/editable-field.tsx +0 -33
  151. package/lib/tui/components/empty-state.tsx +0 -11
  152. package/lib/tui/components/gateway-status.tsx +0 -66
  153. package/lib/tui/components/keymap.tsx +0 -29
  154. package/lib/tui/components/menu-item.tsx +0 -73
  155. package/lib/tui/components/menu.tsx +0 -26
  156. package/lib/tui/components/panel-header.tsx +0 -22
  157. package/lib/tui/components/readonly-field.tsx +0 -18
  158. package/lib/tui/components/section-header.tsx +0 -25
  159. package/lib/tui/components/selection-accent.tsx +0 -32
  160. package/lib/tui/components/session-item.tsx +0 -33
  161. package/lib/tui/components/session-list.tsx +0 -33
  162. package/lib/tui/components/ui/hascii/accordion-item.tsx +0 -88
  163. package/lib/tui/components/ui/hascii/accordion.tsx +0 -96
  164. package/lib/tui/components/ui/hascii/alert-dialog.tsx +0 -43
  165. package/lib/tui/components/ui/hascii/badge.tsx +0 -51
  166. package/lib/tui/components/ui/hascii/breadcrumb.tsx +0 -58
  167. package/lib/tui/components/ui/hascii/button.tsx +0 -194
  168. package/lib/tui/components/ui/hascii/card-content.tsx +0 -14
  169. package/lib/tui/components/ui/hascii/card-description.tsx +0 -13
  170. package/lib/tui/components/ui/hascii/card-footer.tsx +0 -14
  171. package/lib/tui/components/ui/hascii/card-header.tsx +0 -14
  172. package/lib/tui/components/ui/hascii/card-title.tsx +0 -13
  173. package/lib/tui/components/ui/hascii/card.tsx +0 -27
  174. package/lib/tui/components/ui/hascii/checkbox.tsx +0 -65
  175. package/lib/tui/components/ui/hascii/command.tsx +0 -159
  176. package/lib/tui/components/ui/hascii/dialog-content.tsx +0 -14
  177. package/lib/tui/components/ui/hascii/dialog-description.tsx +0 -13
  178. package/lib/tui/components/ui/hascii/dialog-footer.tsx +0 -14
  179. package/lib/tui/components/ui/hascii/dialog-header.tsx +0 -14
  180. package/lib/tui/components/ui/hascii/dialog-title.tsx +0 -13
  181. package/lib/tui/components/ui/hascii/dialog.tsx +0 -27
  182. package/lib/tui/components/ui/hascii/file-tree.tsx +0 -142
  183. package/lib/tui/components/ui/hascii/focus-group.tsx +0 -62
  184. package/lib/tui/components/ui/hascii/form-item.tsx +0 -43
  185. package/lib/tui/components/ui/hascii/input-otp.tsx +0 -86
  186. package/lib/tui/components/ui/hascii/input.tsx +0 -130
  187. package/lib/tui/components/ui/hascii/pagination.tsx +0 -105
  188. package/lib/tui/components/ui/hascii/progress.tsx +0 -28
  189. package/lib/tui/components/ui/hascii/select.tsx +0 -131
  190. package/lib/tui/components/ui/hascii/separator.tsx +0 -35
  191. package/lib/tui/components/ui/hascii/sidebar-content.tsx +0 -23
  192. package/lib/tui/components/ui/hascii/sidebar-header.tsx +0 -14
  193. package/lib/tui/components/ui/hascii/sidebar-menu-item.tsx +0 -67
  194. package/lib/tui/components/ui/hascii/sidebar.tsx +0 -24
  195. package/lib/tui/components/ui/hascii/skeleton.tsx +0 -60
  196. package/lib/tui/components/ui/hascii/slider.tsx +0 -91
  197. package/lib/tui/components/ui/hascii/snackbar.tsx +0 -75
  198. package/lib/tui/components/ui/hascii/sparkline.tsx +0 -53
  199. package/lib/tui/components/ui/hascii/spinner.tsx +0 -47
  200. package/lib/tui/components/ui/hascii/stepper.tsx +0 -54
  201. package/lib/tui/components/ui/hascii/switch.tsx +0 -66
  202. package/lib/tui/components/ui/hascii/table.tsx +0 -95
  203. package/lib/tui/components/ui/hascii/tabs.tsx +0 -59
  204. package/lib/tui/components/ui/hascii/toggle-group-item.tsx +0 -45
  205. package/lib/tui/components/ui/hascii/toggle-group.tsx +0 -99
  206. package/lib/tui/components/ui/hascii/tree.tsx +0 -104
  207. package/lib/tui/components/view-shell.tsx +0 -44
  208. package/lib/tui/filter-input.tsx +0 -33
  209. package/lib/tui/hooks/hascii/use-pressable.ts +0 -54
  210. package/lib/tui/parse-comma-list.ts +0 -14
  211. package/lib/tui/profile-launcher.tsx +0 -61
  212. package/lib/tui/scrollbar-options.ts +0 -19
  213. package/lib/tui/sidebar.tsx +0 -50
  214. package/lib/tui/theme.ts +0 -40
  215. package/lib/tui/tui.tsx +0 -20
  216. package/lib/tui/types.ts +0 -38
  217. package/lib/tui/unique-name.ts +0 -18
  218. package/lib/tui/use-event-stream.ts +0 -133
  219. package/lib/tui/use-snapshot.ts +0 -99
  220. package/lib/tui/utils/hascii/form-item-context.tsx +0 -23
  221. package/lib/tui/utils/hascii/input-focus-context.tsx +0 -31
  222. package/lib/tui/utils/hascii/theme-context.tsx +0 -26
  223. package/lib/tui/utils/hascii/theme.ts +0 -176
  224. package/lib/tui/views/channels-view.tsx +0 -108
  225. package/lib/tui/views/connectors-view.tsx +0 -164
  226. package/lib/tui/views/events-view.tsx +0 -160
  227. package/lib/tui/views/listeners-view.tsx +0 -80
  228. package/lib/tui/views/profiles-view.tsx +0 -152
@@ -1,52 +0,0 @@
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 publishHelp = `funnel channels <channel> publish — push arbitrary content into a channel
7
-
8
- usage: funnel channels <channel> publish --content="<text>" [--connector=<name>] [--meta-<key>=<value> ...]
9
-
10
- options:
11
- --content Required. The event body delivered to subscribers.
12
- --connector Optional. Stamp the event with a connector name (resolved to id when found).
13
- --meta-<key> Optional. Repeatable. Added to meta. Example: --meta-source=cron`
14
-
15
- const querySchema = z
16
- .object({
17
- content: z.string().min(1, { message: "--content is required" }),
18
- connector: z.string().min(1).optional(),
19
- })
20
- .passthrough()
21
-
22
- export const channelsPublishHandler = factory.createHandlers(
23
- zValidator("param", z.object({ channel: z.string() })),
24
- zValidator("query", querySchema, publishHelp),
25
- async (c) => {
26
- const param = c.req.valid("param")
27
- const query = c.req.valid("query")
28
- const funnel = c.var.funnel
29
-
30
- const meta: Record<string, string> = {}
31
-
32
- for (const [k, v] of new URL(c.req.url).searchParams) {
33
- if (k.startsWith("meta-")) meta[k.slice("meta-".length)] = v
34
- }
35
-
36
- const result = await funnel.publisher.publish(param.channel, {
37
- content: query.content,
38
- connector: query.connector,
39
- meta: Object.keys(meta).length > 0 ? meta : undefined,
40
- })
41
-
42
- if (result.state === "offline") {
43
- throw new HTTPException(503, { message: "gateway daemon is not running — start it with `fnl gateway start`" })
44
- }
45
-
46
- if (result.state === "error") {
47
- throw new HTTPException(502, { message: result.reason })
48
- }
49
-
50
- return c.text(`published (offset=${result.offset})`)
51
- },
52
- )
@@ -1,22 +0,0 @@
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 rename — rename a channel
6
-
7
- usage:
8
- funnel channels rename <old> <new>
9
- funnel channels <old> rename <new>`
10
-
11
- export const channelsRenameHandler = factory.createHandlers(
12
- zValidator("param", z.object({ channel: z.string(), newName: z.string() })),
13
- zValidator("query", z.object({}), renameHelp),
14
- (c) => {
15
- const param = c.req.valid("param")
16
- const funnel = c.var.funnel
17
-
18
- funnel.channels.rename(param.channel, param.newName)
19
-
20
- return c.text(`renamed channel "${param.channel}" to "${param.newName}"`)
21
- },
22
- )
@@ -1,34 +0,0 @@
1
- import { z } from "zod"
2
- import { factory } from "@/cli/factory"
3
- import { zValidator } from "@/cli/router/validator"
4
- import { channelDeliveryModeSchema } from "@/engine/settings/settings-schema"
5
-
6
- export const setDeliveryHelp = `funnel channels <name> set delivery <mode> — change a channel's routing mode
7
-
8
- usage: funnel channels <name> set delivery fanout | exclusive
9
-
10
- modes:
11
- fanout every connected WS client receives every event (default)
12
- exclusive each event is delivered to exactly one connected client (round-robin)
13
-
14
- tap=all clients (TUI dashboard, debugging) always receive regardless of mode.
15
- `
16
-
17
- export const channelsSetDeliveryHandler = factory.createHandlers(
18
- zValidator(
19
- "param",
20
- z.object({
21
- channel: z.string(),
22
- mode: channelDeliveryModeSchema,
23
- }),
24
- setDeliveryHelp,
25
- ),
26
- (c) => {
27
- const param = c.req.valid("param")
28
- const funnel = c.var.funnel
29
-
30
- funnel.channels.setDelivery(param.channel, param.mode)
31
-
32
- return c.text(`channel "${param.channel}" delivery set to ${param.mode}`)
33
- },
34
- )
@@ -1,34 +0,0 @@
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 <name> — show channel details`
7
-
8
- export const channelsShowHandler = factory.createHandlers(
9
- zValidator("param", z.object({ channel: z.string() })),
10
- zValidator("query", z.object({}), showHelp),
11
- (c) => {
12
- const param = c.req.valid("param")
13
- const funnel = c.var.funnel
14
- const channel = funnel.channels.get(param.channel)
15
-
16
- if (!channel) {
17
- throw new HTTPException(404, { message: `channel "${param.channel}" not found` })
18
- }
19
-
20
- const connectorLines = channel.connectors.length
21
- ? channel.connectors.map((c) => ` - ${c.name} (${c.type}, id: ${c.id})`)
22
- : [" (none)"]
23
-
24
- const lines = [
25
- `id: ${channel.id}`,
26
- `name: ${channel.name}`,
27
- `delivery: ${channel.delivery}`,
28
- `connectors:`,
29
- ...connectorLines,
30
- ]
31
-
32
- return c.text(lines.join("\n"))
33
- },
34
- )
@@ -1,33 +0,0 @@
1
- import { z } from "zod"
2
- import { factory } from "@/cli/factory"
3
- import { zValidator } from "@/cli/router/validator"
4
- import { channelDeliveryModeSchema } from "@/engine/settings/settings-schema"
5
-
6
- export const addHelp = `funnel channels add — add a channel
7
-
8
- usage: funnel channels add <name> [--delivery fanout|exclusive]
9
-
10
- options:
11
- --delivery routing mode (default fanout):
12
- fanout every connected client receives every event
13
- exclusive each event delivered to exactly one client (round-robin)`
14
-
15
- export const channelsAddHandler = factory.createHandlers(
16
- zValidator("param", z.object({ channel: z.string() })),
17
- zValidator(
18
- "query",
19
- z.object({
20
- delivery: channelDeliveryModeSchema.optional(),
21
- }),
22
- addHelp,
23
- ),
24
- (c) => {
25
- const param = c.req.valid("param")
26
- const query = c.req.valid("query")
27
- const funnel = c.var.funnel
28
-
29
- const created = funnel.channels.add({ name: param.channel, delivery: query.delivery })
30
-
31
- return c.text(`added channel "${created.name}" (id: ${created.id})`)
32
- },
33
- )
@@ -1,20 +0,0 @@
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 remove — remove a channel
6
-
7
- usage: funnel channels remove <name>`
8
-
9
- export const channelsRemoveHandler = factory.createHandlers(
10
- zValidator("param", z.object({ channel: z.string() })),
11
- zValidator("query", z.object({}), removeHelp),
12
- (c) => {
13
- const param = c.req.valid("param")
14
- const funnel = c.var.funnel
15
-
16
- funnel.channels.remove(param.channel)
17
-
18
- return c.text(`removed channel "${param.channel}"`)
19
- },
20
- )
@@ -1,39 +0,0 @@
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 — manage subscription boxes
6
-
7
- usage: funnel channels [subcommand]
8
-
9
- subcommands:
10
- (none) list
11
- add <name> add
12
- remove <name> remove
13
- <name> show details
14
- <name> connectors list connectors
15
- <name> connectors add <c> --type=... add a connector
16
-
17
- examples:
18
- funnel channels add prod-inbox
19
- funnel channels prod-inbox connectors add prod-slack --type=slack --bot-token=xoxb-... --app-token=xapp-...
20
- funnel channels prod-inbox`
21
-
22
- export const channelsGroupHandler = factory.createHandlers(
23
- zValidator("query", z.object({}), groupHelp),
24
- (c) => {
25
- const funnel = c.var.funnel
26
- const channels = funnel.channels.list()
27
-
28
- if (channels.length === 0) return c.text("no channels")
29
-
30
- const lines = channels.map((ch) => {
31
- const names = ch.connectors.map((c) => c.name)
32
- const connectors = names.length > 0 ? names.join(", ") : "(none)"
33
-
34
- return `${ch.name} [${connectors}]`
35
- })
36
-
37
- return c.text(lines.join("\n"))
38
- },
39
- )
@@ -1,70 +0,0 @@
1
- import { HTTPException } from "hono/http-exception"
2
- import { z } from "zod"
3
- import { factory } from "@/cli/factory"
4
- import { queryToCliArgs } from "@/cli/router/query-to-cli-args"
5
- import { zValidator } from "@/cli/router/validator"
6
-
7
- export const claudeHelp = `funnel claude — launch Claude Code
8
-
9
- usage:
10
- funnel claude launch the default profile (first in the list)
11
- funnel claude -p <name> launch a named profile
12
- funnel claude --profile <name> (long form)
13
- funnel claude --channel <name> raw launch (no profile, cwd = current dir)
14
-
15
- options:
16
- -p, --profile profile name to launch
17
- --channel channel name (raw launch, ignored when --profile is given)
18
-
19
- Any other arguments are forwarded to the claude CLI.
20
- On launch the FUNNEL_CHANNEL_ID env var is set and MCP connects to the gateway.`
21
-
22
- const RESERVED_KEYS = ["profile", "channel"]
23
-
24
- export const claudeHandler = factory.createHandlers(
25
- zValidator(
26
- "query",
27
- z
28
- .object({
29
- profile: z.string().optional(),
30
- channel: z.string().optional(),
31
- })
32
- .passthrough(),
33
- claudeHelp,
34
- ),
35
- async (c) => {
36
- const query = c.req.valid("query")
37
- const funnel = c.var.funnel
38
-
39
- if (query.channel && !query.profile) {
40
- const exitCode = await funnel.claude.launch({
41
- channel: query.channel,
42
- userArgs: queryToCliArgs(c.req.url, RESERVED_KEYS),
43
- })
44
-
45
- process.exit(exitCode)
46
- }
47
-
48
- const profile = query.profile
49
- ? funnel.profiles.get(query.profile)
50
- : funnel.profiles.getDefault()
51
-
52
- if (!profile) {
53
- if (query.profile) {
54
- throw new HTTPException(404, { message: `profile "${query.profile}" not found` })
55
- }
56
- return c.text(claudeHelp)
57
- }
58
-
59
- const exitCode = await funnel.claude.launch({
60
- channel: profile.channelId,
61
- cwd: profile.path,
62
- subAgent: profile.subAgent,
63
- userArgs: queryToCliArgs(c.req.url, RESERVED_KEYS),
64
- profileName: profile.name,
65
- brief: profile.brief,
66
- })
67
-
68
- process.exit(exitCode)
69
- },
70
- )
@@ -1,41 +0,0 @@
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 listenersHelp = `funnel gateway listeners — show running connector listeners
7
-
8
- usage: funnel gateway listeners
9
-
10
- Reads /listeners from the running gateway daemon and prints the live registry.
11
-
12
- examples:
13
- funnel gateway listeners`
14
-
15
- export const gatewayListenersHandler = factory.createHandlers(
16
- zValidator("query", z.object({}), listenersHelp),
17
- async (c) => {
18
- const funnel = c.var.funnel
19
- const result = await funnel.listeners.list()
20
-
21
- if (result.state === "offline") {
22
- throw new HTTPException(503, { message: "funnel gateway: not running" })
23
- }
24
-
25
- if (result.state === "error") {
26
- throw new HTTPException(503, { message: `funnel gateway: ${result.reason}` })
27
- }
28
-
29
- if (result.listeners.length === 0) {
30
- return c.text("funnel gateway: no running listeners")
31
- }
32
-
33
- const lines = result.listeners.map((entry) => {
34
- const health = entry.alive ? "alive" : "dead"
35
-
36
- return ` [${health.padEnd(5)}] ${entry.type.padEnd(8)} ${entry.name}`
37
- })
38
-
39
- return c.text(`funnel gateway: running listeners\n${lines.join("\n")}`)
40
- },
41
- )
@@ -1,123 +0,0 @@
1
- import { existsSync } from "node:fs"
2
- import { stringify } from "yaml"
3
- import { z } from "zod"
4
- import { factory } from "@/cli/factory"
5
- import { NodeFunnelLogger } from "@/engine/logger/node-logger"
6
- import { zValidator } from "@/cli/router/validator"
7
-
8
- export const logsHelp = `funnel gateway logs — tail diagnostic logs
9
-
10
- usage: funnel gateway logs [-n <N>]
11
-
12
- options:
13
- -n <N> number of trailing lines to show (default: 20)
14
-
15
- Tails /tmp/funnel/funnel.log (the daemon's diagnostic stream — gateway
16
- lifecycle, channel connect/disconnect, listener boot). Exit with SIGINT.
17
- Output is formatted as YAML.
18
-
19
- Domain events fanned out to WebSocket clients live in the SQLite event
20
- store (<logDir>/events.db); they are not shown here. Subscribe via the
21
- WS endpoint or query the store directly.
22
-
23
- examples:
24
- funnel gateway logs
25
- funnel gateway logs -n 100`
26
-
27
- const logger = new NodeFunnelLogger()
28
-
29
- type LogEntry = {
30
- time: string
31
- level: string
32
- message: string
33
- meta?: unknown
34
- }
35
-
36
- const tryParseJson = (line: string): unknown => {
37
- try {
38
- return JSON.parse(line)
39
- } catch {
40
- return null
41
- }
42
- }
43
-
44
- const isLogEntry = (value: unknown): value is LogEntry => {
45
- if (value === null || typeof value !== "object") return false
46
- if (!("time" in value) || typeof value.time !== "string") return false
47
- if (!("level" in value) || typeof value.level !== "string") return false
48
- if (!("message" in value) || typeof value.message !== "string") return false
49
-
50
- return true
51
- }
52
-
53
- export const gatewayLogsHandler = factory.createHandlers(
54
- zValidator(
55
- "query",
56
- z.object({
57
- n: z.string().optional(),
58
- }),
59
- logsHelp,
60
- ),
61
- async (c) => {
62
- const query = c.req.valid("query")
63
- const path = logger.file
64
-
65
- if (!path || !existsSync(path)) {
66
- return c.text("no logs")
67
- }
68
-
69
- const lineCount = query.n ? Number(query.n) : 20
70
-
71
- const tail = Bun.spawn(["tail", "-f", "-n", String(lineCount), path], {
72
- stdout: "pipe",
73
- stderr: "inherit",
74
- })
75
-
76
- const forward = (signal: "SIGINT" | "SIGTERM") => {
77
- tail.kill(signal)
78
- }
79
-
80
- process.on("SIGINT", () => forward("SIGINT"))
81
- process.on("SIGTERM", () => forward("SIGTERM"))
82
-
83
- const reader = tail.stdout.getReader()
84
- const decoder = new TextDecoder()
85
- let buffer = ""
86
-
87
- logger.info("gateway.logs tail start", { file: path })
88
-
89
- while (true) {
90
- const result = await reader.read()
91
-
92
- if (result.done) break
93
-
94
- buffer += decoder.decode(result.value, { stream: true })
95
-
96
- const lines = buffer.split("\n")
97
- buffer = lines.pop() ?? ""
98
-
99
- for (const line of lines) {
100
- if (!line.trim()) continue
101
-
102
- const parsed = tryParseJson(line)
103
-
104
- if (!isLogEntry(parsed)) {
105
- process.stdout.write(`${line}\n`)
106
- continue
107
- }
108
-
109
- const output = {
110
- time: parsed.time,
111
- level: parsed.level,
112
- message: parsed.message,
113
- ...(parsed.meta ? { meta: parsed.meta } : {}),
114
- }
115
-
116
- process.stdout.write(`---\n${stringify(output)}`)
117
- }
118
- }
119
-
120
- await tail.exited
121
- process.exit(0)
122
- },
123
- )
@@ -1,50 +0,0 @@
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 restartHelp = `funnel gateway restart — restart the gateway
7
-
8
- usage: funnel gateway restart [--no-caffeine]
9
-
10
- Stops the running process then starts it again in background.
11
- On macOS wraps with caffeinate -i by default. Use --no-caffeine to disable.
12
-
13
- examples:
14
- funnel gateway restart
15
- funnel gateway restart --no-caffeine`
16
-
17
- export const gatewayRestartHandler = factory.createHandlers(
18
- zValidator(
19
- "query",
20
- z.object({
21
- "no-caffeine": z.string().optional(),
22
- }),
23
- restartHelp,
24
- ),
25
- async (c) => {
26
- const query = c.req.valid("query")
27
- const funnel = c.var.funnel
28
-
29
- const result = await funnel.gateway.restart({
30
- caffeinate: query["no-caffeine"] !== "true",
31
- })
32
- const lines: string[] = []
33
-
34
- if (result.wasRunning) {
35
- lines.push(result.stopped ? "funnel gateway: stopped" : "funnel gateway: failed to stop")
36
- }
37
-
38
- if (result.stopped) {
39
- lines.push(result.started ? "funnel gateway: started" : "funnel gateway: failed to start")
40
- }
41
-
42
- const body = lines.join("\n")
43
-
44
- if (!result.ok) {
45
- throw new HTTPException(500, { message: body })
46
- }
47
-
48
- return c.text(body)
49
- },
50
- )
@@ -1,41 +0,0 @@
1
- import { z } from "zod"
2
- import { factory } from "@/cli/factory"
3
- import { zValidator } from "@/cli/router/validator"
4
- import { resolveDaemonScript } from "@/gateway/resolve-daemon-script"
5
-
6
- export const runHelp = `funnel gateway run — run the gateway in foreground
7
-
8
- usage: funnel gateway run [--no-caffeine]
9
-
10
- For developers. The process is tied to the current terminal and exits on SIGINT / SIGTERM.
11
- On macOS wraps with caffeinate -i by default. Use --no-caffeine to disable.
12
-
13
- For normal usage prefer funnel gateway start.
14
-
15
- examples:
16
- funnel gateway run
17
- funnel gateway run --no-caffeine`
18
-
19
- export const gatewayRunHandler = factory.createHandlers(
20
- zValidator(
21
- "query",
22
- z.object({
23
- "no-caffeine": z.string().optional(),
24
- }),
25
- runHelp,
26
- ),
27
- async (c) => {
28
- const query = c.req.valid("query")
29
- const funnel = c.var.funnel
30
-
31
- const gatewayScript = resolveDaemonScript()
32
- const useCaffeinate = query["no-caffeine"] !== "true" && process.platform === "darwin"
33
- const command = useCaffeinate
34
- ? ["caffeinate", "-i", "bun", gatewayScript]
35
- : ["bun", gatewayScript]
36
-
37
- const exitCode = await funnel.process.attach(command)
38
-
39
- process.exit(exitCode)
40
- },
41
- )
@@ -1,50 +0,0 @@
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 startHelp = `funnel gateway start — start the gateway in background
7
-
8
- usage: funnel gateway start [--no-caffeine]
9
-
10
- Daemonized with nohup, so it keeps running after the terminal is closed.
11
- On macOS wraps the process with caffeinate -i by default to prevent idle sleep.
12
- Use --no-caffeine to disable caffeinate.
13
-
14
- port: 9742 (override via FUNNEL_PORT)
15
- pid: ~/.funnel/gateway.pid
16
- log: /tmp/funnel/gateway.log
17
-
18
- examples:
19
- funnel gateway start
20
- funnel gateway start --no-caffeine`
21
-
22
- export const gatewayStartHandler = factory.createHandlers(
23
- zValidator(
24
- "query",
25
- z.object({
26
- "no-caffeine": z.string().optional(),
27
- }),
28
- startHelp,
29
- ),
30
- async (c) => {
31
- const query = c.req.valid("query")
32
- const funnel = c.var.funnel
33
-
34
- if (funnel.gateway.isRunning()) {
35
- const status = funnel.gateway.getStatus()
36
-
37
- return c.text(`funnel gateway: already running (pid ${status.pid})`)
38
- }
39
-
40
- const started = await funnel.gateway.start({
41
- caffeinate: query["no-caffeine"] !== "true",
42
- })
43
-
44
- if (!started) {
45
- throw new HTTPException(500, { message: "funnel gateway: failed to start" })
46
- }
47
-
48
- return c.text("funnel gateway: started")
49
- },
50
- )
@@ -1,19 +0,0 @@
1
- import { z } from "zod"
2
- import { factory } from "@/cli/factory"
3
- import { zValidator } from "@/cli/router/validator"
4
- import { renderGatewayStatus } from "@/cli/routes/gateway"
5
-
6
- export const statusHelp = `funnel gateway status — show gateway running status
7
-
8
- usage: funnel gateway status
9
-
10
- When running, prints PID, port, and connected channel count. When not running, exits with 503.
11
-
12
- examples:
13
- funnel gateway status
14
- funnel gateway`
15
-
16
- export const gatewayStatusHandler = factory.createHandlers(
17
- zValidator("query", z.object({}), statusHelp),
18
- renderGatewayStatus,
19
- )
@@ -1,32 +0,0 @@
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 stopHelp = `funnel gateway stop — stop the gateway
7
-
8
- usage: funnel gateway stop
9
-
10
- Terminates the process whose PID is stored in ~/.funnel/gateway.pid.
11
-
12
- examples:
13
- funnel gateway stop`
14
-
15
- export const gatewayStopHandler = factory.createHandlers(
16
- zValidator("query", z.object({}), stopHelp),
17
- async (c) => {
18
- const funnel = c.var.funnel
19
-
20
- if (!funnel.gateway.isRunning()) {
21
- return c.text("funnel gateway: no running process")
22
- }
23
-
24
- const stopped = await funnel.gateway.stop()
25
-
26
- if (!stopped) {
27
- throw new HTTPException(500, { message: "funnel gateway: failed to stop" })
28
- }
29
-
30
- return c.text("funnel gateway: stopped")
31
- },
32
- )