@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
package/lib/cli/index.ts DELETED
@@ -1,85 +0,0 @@
1
- import pkg from "@/../package.json" with { type: "json" }
2
- import { startChannelServer } from "@/engine/mcp/channel-server"
3
- import { toRequest } from "@/cli/router/to-request"
4
- import { launchTui } from "@/tui/tui"
5
- import { createCliApp } from "@/cli/routes"
6
- import { Funnel } from "@/funnel"
7
-
8
- process.title = "funnel"
9
-
10
- const funnel = new Funnel()
11
-
12
- const app = createCliApp(funnel)
13
-
14
- const HELP = `funnel — Open Claude Funnel
15
-
16
- usage: funnel [command]
17
-
18
- commands:
19
- (none) launch TUI
20
- claude launch Claude Code (default profile or --profile)
21
- channels manage subscription boxes (and their nested connectors)
22
- profiles manage launch profiles
23
- gateway manage the gateway daemon (HTTP + WS)
24
- status show overall connection status
25
- update update funnel to the latest version
26
- mcp run as an MCP server (invoked from .mcp.json)
27
-
28
- options:
29
- --help, -h show help
30
- --version, -v show version
31
-
32
- more: funnel <command> --help`
33
-
34
- const args = process.argv.slice(2)
35
-
36
- if (args.length === 0) {
37
- await launchTui(funnel)
38
- process.exit(0)
39
- }
40
-
41
- if (args[0] === "--version" || args[0] === "-v") {
42
- process.stdout.write(`${pkg.version}\n`)
43
- process.exit(0)
44
- }
45
-
46
- if (args[0] === "mcp") {
47
- await startChannelServer({ dir: funnel.paths.dir })
48
- }
49
-
50
- if (args[0] !== "mcp") {
51
- const { method, url } = toRequest(args)
52
-
53
- const parsed = new URL(url)
54
-
55
- const wantsHelp = parsed.searchParams.has("help")
56
-
57
- if (wantsHelp && parsed.pathname === "/") {
58
- process.stdout.write(`${HELP}\n`)
59
- process.exit(0)
60
- }
61
-
62
- const res = await app.request(url, { method })
63
-
64
- if (res.ok) {
65
- const body = await res.text()
66
- if (body) process.stdout.write(`${body}\n`)
67
- process.exit(0)
68
- }
69
-
70
- if (wantsHelp) {
71
- const segments = parsed.pathname.split("/").filter(Boolean)
72
- const group = segments[0]
73
- const fallback = group
74
- ? await app.request(`http://localhost/${group}?help=true`, { method: "GET" })
75
- : null
76
-
77
- const text = fallback?.ok ? await fallback.text() : HELP
78
- process.stdout.write(`${text}\n`)
79
- process.exit(0)
80
- }
81
-
82
- const text = await res.text()
83
- if (text) process.stderr.write(`${text}\n`)
84
- process.exit(1)
85
- }
@@ -1,20 +0,0 @@
1
- const BUILTIN_SKIP = new Set(["help"])
2
-
3
- export const queryToCliArgs = (url: string, reservedKeys: string[] = []): string[] => {
4
- const skipped = new Set([...BUILTIN_SKIP, ...reservedKeys])
5
- const args: string[] = []
6
- const searchParams = new URL(url).searchParams
7
-
8
- for (const entry of searchParams.entries()) {
9
- const key = entry[0]
10
- const value = entry[1]
11
-
12
- if (skipped.has(key)) continue
13
-
14
- args.push(`--${key}`)
15
-
16
- if (value !== "true") args.push(value)
17
- }
18
-
19
- return args
20
- }
@@ -1,113 +0,0 @@
1
- const SHORT_FLAGS: Record<string, string> = {
2
- h: "help",
3
- n: "name",
4
- p: "profile",
5
- }
6
-
7
- // All CLI verbs map to POST and stay in the URL (no method-stripping).
8
- // Hono routes disambiguate by URL segment (e.g. /channels/add/:channel vs /channels/remove/:channel).
9
- const METHOD_KEYWORDS = new Set([
10
- "add",
11
- "set",
12
- "remove",
13
- "rename",
14
- "as-default",
15
- "request",
16
- "publish",
17
- ])
18
-
19
- const API_CALL_METHODS = new Set(["get", "post", "put", "patch", "delete", "head", "options"])
20
-
21
- const isValue = (arg: string | undefined): arg is string => {
22
- return typeof arg === "string" && !arg.startsWith("-")
23
- }
24
-
25
- const consumeApiCall = (args: string[], i: number, params: URLSearchParams): number => {
26
- const nextPath = args[i + 1]
27
-
28
- if (!isValue(nextPath)) return 1
29
-
30
- params.set("path", nextPath)
31
-
32
- const nextBody = args[i + 2]
33
-
34
- if (!isValue(nextBody)) return 2
35
-
36
- params.set("body", nextBody)
37
-
38
- return 3
39
- }
40
-
41
- export const toRequest = (args: string[]) => {
42
- const segments: string[] = []
43
- const params = new URLSearchParams()
44
- let method = "GET"
45
-
46
- let i = 0
47
- while (i < args.length) {
48
- const arg = args[i]!
49
-
50
- if (arg.startsWith("--")) {
51
- const key = arg.slice(2)
52
- const next = args[i + 1]
53
-
54
- if (isValue(next)) {
55
- params.set(key, next)
56
- i += 2
57
- } else {
58
- params.set(key, "true")
59
- i++
60
- }
61
-
62
- continue
63
- }
64
-
65
- if (arg.startsWith("-") && arg.length === 2) {
66
- const long = SHORT_FLAGS[arg[1]!]
67
-
68
- if (!long) {
69
- i++
70
- continue
71
- }
72
-
73
- const next = args[i + 1]
74
-
75
- if (isValue(next)) {
76
- params.set(long, next)
77
- i += 2
78
- } else {
79
- params.set(long, "true")
80
- i++
81
- }
82
-
83
- continue
84
- }
85
-
86
- if (METHOD_KEYWORDS.has(arg)) {
87
- method = "POST"
88
- segments.push(arg)
89
- i++
90
- continue
91
- }
92
-
93
- if (API_CALL_METHODS.has(arg) && !params.has("path")) {
94
- segments.push(arg)
95
- i += consumeApiCall(args, i, params)
96
- continue
97
- }
98
-
99
- if (arg.includes("/") && !params.has("path")) {
100
- params.set("path", arg)
101
- i++
102
- continue
103
- }
104
-
105
- segments.push(arg)
106
- i++
107
- }
108
-
109
- const path = segments.length > 0 ? `/${segments.join("/")}` : "/"
110
- const query = params.size > 0 ? `?${params}` : ""
111
-
112
- return { method, path, url: `http://localhost${path}${query}` }
113
- }
@@ -1,27 +0,0 @@
1
- import { zValidator as zv } from "@hono/zod-validator"
2
- import { HTTPException } from "hono/http-exception"
3
- import type { ZodType } from "zod"
4
-
5
- export const zValidator = <Target extends "param" | "query" | "json", T extends ZodType>(
6
- target: Target,
7
- schema: T,
8
- helpText?: string,
9
- ) =>
10
- zv(target, schema, (result, c) => {
11
- if (helpText && c.req.query("help")) {
12
- return c.text(helpText)
13
- }
14
-
15
- if (result.success) return
16
-
17
- const issue = result.error.issues[0]
18
-
19
- if (!issue) {
20
- throw new HTTPException(400, { message: "invalid request" })
21
- }
22
-
23
- const path = issue.path.join(".")
24
- const message = path ? `${path}: ${issue.message}` : issue.message
25
-
26
- throw new HTTPException(400, { message })
27
- })
@@ -1,27 +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 <channel> connectors rename <connector> <new-name>
6
-
7
- usage: funnel channels <channel> connectors rename <connector> <new-name>`
8
-
9
- export const channelsConnectorsRenameHandler = factory.createHandlers(
10
- zValidator(
11
- "param",
12
- z.object({ channel: z.string(), connector: z.string(), newName: z.string() }),
13
- ),
14
- zValidator("query", z.object({}), renameHelp),
15
- async (c) => {
16
- const param = c.req.valid("param")
17
- const funnel = c.var.funnel
18
-
19
- await funnel.listeners.stop(param.channel, param.connector)
20
-
21
- funnel.channels.renameConnector(param.channel, param.connector, param.newName)
22
-
23
- await funnel.listeners.start(param.channel, param.newName)
24
-
25
- return c.text(`renamed connector "${param.connector}" to "${param.newName}"`)
26
- },
27
- )
@@ -1,40 +0,0 @@
1
- import { z } from "zod"
2
- import { factory } from "@/cli/factory"
3
- import { zValidator } from "@/cli/router/validator"
4
-
5
- export const requestHelp = `funnel channels <channel> connectors <connector> request — call a connector's outbound API
6
-
7
- usage: funnel channels <channel> connectors <connector> request --method=<api.method> [--key=value ...]`
8
-
9
- export const channelsConnectorsRequestHandler = factory.createHandlers(
10
- zValidator("param", z.object({ channel: z.string(), connector: z.string() })),
11
- zValidator(
12
- "query",
13
- z
14
- .object({
15
- method: z.string(),
16
- })
17
- .passthrough(),
18
- requestHelp,
19
- ),
20
- async (c) => {
21
- const param = c.req.valid("param")
22
- const query = c.req.valid("query")
23
- const funnel = c.var.funnel
24
-
25
- const passthrough: Record<string, string> = {}
26
-
27
- for (const [k, v] of new URL(c.req.url).searchParams) {
28
- if (k === "method") continue
29
- passthrough[k] = v
30
- }
31
-
32
- const response = await funnel.channels.call(param.channel, param.connector, {
33
- method: query.method,
34
- path: query.method,
35
- body: passthrough,
36
- })
37
-
38
- return c.text(typeof response === "string" ? response : JSON.stringify(response, null, 2))
39
- },
40
- )
@@ -1,41 +0,0 @@
1
- import { z } from "zod"
2
- import { factory } from "@/cli/factory"
3
- import { zValidator } from "@/cli/router/validator"
4
- import { scheduleCatchupPolicySchema } from "@/connectors/schedule-connector-schema"
5
-
6
- export const addHelp = `funnel channels <ch> connectors <conn> schedules add <id> — add a schedule entry
7
-
8
- usage: funnel channels <ch> connectors <conn> schedules add <id> --cron="*/5 * * * *" --prompt="..." [--enabled=true] [--catchup-policy=latest|all|skip]`
9
-
10
- export const channelsConnectorsSchedulesAddHandler = factory.createHandlers(
11
- zValidator("param", z.object({ channel: z.string(), connector: z.string(), id: z.string() })),
12
- zValidator(
13
- "query",
14
- z.object({
15
- cron: z.string(),
16
- prompt: z.string(),
17
- enabled: z.coerce.boolean().optional(),
18
- "catchup-policy": scheduleCatchupPolicySchema.optional(),
19
- }),
20
- addHelp,
21
- ),
22
- async (c) => {
23
- const param = c.req.valid("param")
24
- const query = c.req.valid("query")
25
- const funnel = c.var.funnel
26
-
27
- const entry = funnel.channels.addScheduleEntry(param.channel, param.connector, {
28
- id: param.id,
29
- cron: query.cron,
30
- prompt: query.prompt,
31
- ...(query.enabled !== undefined ? { enabled: query.enabled } : {}),
32
- ...(query["catchup-policy"] !== undefined
33
- ? { catchupPolicy: query["catchup-policy"] }
34
- : {}),
35
- })
36
-
37
- await funnel.listeners.restart(param.channel, param.connector)
38
-
39
- return c.text(`added schedule entry "${entry.id}"`)
40
- },
41
- )
@@ -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 removeHelp = `funnel channels <ch> connectors <conn> schedules remove <id>
6
-
7
- usage: funnel channels <ch> connectors <conn> schedules remove <id>`
8
-
9
- export const channelsConnectorsSchedulesRemoveHandler = factory.createHandlers(
10
- zValidator("param", z.object({ channel: z.string(), connector: z.string(), id: z.string() })),
11
- zValidator("query", z.object({}), removeHelp),
12
- async (c) => {
13
- const param = c.req.valid("param")
14
- const funnel = c.var.funnel
15
-
16
- funnel.channels.removeScheduleEntry(param.channel, param.connector, param.id)
17
-
18
- await funnel.listeners.restart(param.channel, param.connector)
19
-
20
- return c.text(`removed schedule entry "${param.id}"`)
21
- },
22
- )
@@ -1,23 +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 <ch> connectors <conn> schedules — list schedule entries
6
-
7
- usage: funnel channels <ch> connectors <conn> schedules`
8
-
9
- export const channelsConnectorsSchedulesGroupHandler = factory.createHandlers(
10
- zValidator("param", z.object({ channel: z.string(), connector: z.string() })),
11
- zValidator("query", z.object({}), groupHelp),
12
- (c) => {
13
- const param = c.req.valid("param")
14
- const funnel = c.var.funnel
15
- const entries = funnel.channels.listScheduleEntries(param.channel, param.connector)
16
-
17
- if (entries.length === 0) return c.text("no schedule entries")
18
-
19
- return c.text(
20
- entries.map((e) => `${e.id}\t${e.cron}\t${e.enabled ? "on" : "off"}\t${e.prompt}`).join("\n"),
21
- )
22
- },
23
- )
@@ -1,26 +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 <channel> connectors show <connector> — show connector config
7
-
8
- usage: funnel channels <channel> connectors show <connector>`
9
-
10
- export const channelsConnectorsShowHandler = factory.createHandlers(
11
- zValidator("param", z.object({ channel: z.string(), connector: z.string() })),
12
- zValidator("query", z.object({}), showHelp),
13
- (c) => {
14
- const param = c.req.valid("param")
15
- const funnel = c.var.funnel
16
- const connector = funnel.channels.getConnector(param.channel, param.connector)
17
-
18
- if (!connector) {
19
- throw new HTTPException(404, {
20
- message: `connector "${param.connector}" not found in channel "${param.channel}"`,
21
- })
22
- }
23
-
24
- return c.text(JSON.stringify(connector, null, 2))
25
- },
26
- )
@@ -1,92 +0,0 @@
1
- import { z } from "zod"
2
- import { factory } from "@/cli/factory"
3
- import { zValidator } from "@/cli/router/validator"
4
-
5
- export const addHelp = `funnel channels <channel> connectors add <connector> — add a connector to a channel
6
-
7
- usage:
8
- funnel channels <channel> connectors add <connector> --type=slack --bot-token=xoxb-... --app-token=xapp-...
9
- funnel channels <channel> connectors add <connector> --type=gh [--poll-interval=60]
10
- funnel channels <channel> connectors add <connector> --type=discord --bot-token=...
11
- funnel channels <channel> connectors add <connector> --type=schedule
12
-
13
- Token uniqueness is enforced across all channels.`
14
-
15
- const slackBody = z.object({
16
- type: z.literal("slack"),
17
- "bot-token": z.string().startsWith("xoxb-"),
18
- "app-token": z.string().startsWith("xapp-"),
19
- })
20
-
21
- const ghBody = z.object({
22
- type: z.literal("gh"),
23
- "poll-interval": z.coerce.number().int().positive().optional(),
24
- })
25
-
26
- const discordBody = z.object({
27
- type: z.literal("discord"),
28
- "bot-token": z.string().min(10),
29
- })
30
-
31
- const scheduleBody = z.object({
32
- type: z.literal("schedule"),
33
- })
34
-
35
- const addBody = z.discriminatedUnion("type", [slackBody, ghBody, discordBody, scheduleBody])
36
-
37
- export const channelsConnectorsAddHandler = factory.createHandlers(
38
- zValidator("param", z.object({ channel: z.string(), connector: z.string() })),
39
- zValidator("query", addBody, addHelp),
40
- async (c) => {
41
- const param = c.req.valid("param")
42
- const query = c.req.valid("query")
43
- const funnel = c.var.funnel
44
-
45
- if (query.type === "slack") {
46
- const created = funnel.channels.addConnector(param.channel, {
47
- type: "slack",
48
- name: param.connector,
49
- botToken: query["bot-token"],
50
- appToken: query["app-token"],
51
- })
52
-
53
- await funnel.listeners.start(param.channel, created.name)
54
-
55
- return c.text(`added slack connector "${created.name}" to channel "${param.channel}"`)
56
- }
57
-
58
- if (query.type === "gh") {
59
- const created = funnel.channels.addConnector(param.channel, {
60
- type: "gh",
61
- name: param.connector,
62
- ...(query["poll-interval"] !== undefined ? { pollInterval: query["poll-interval"] } : {}),
63
- })
64
-
65
- await funnel.listeners.start(param.channel, created.name)
66
-
67
- return c.text(`added gh connector "${created.name}" to channel "${param.channel}"`)
68
- }
69
-
70
- if (query.type === "discord") {
71
- const created = funnel.channels.addConnector(param.channel, {
72
- type: "discord",
73
- name: param.connector,
74
- botToken: query["bot-token"],
75
- })
76
-
77
- await funnel.listeners.start(param.channel, created.name)
78
-
79
- return c.text(`added discord connector "${created.name}" to channel "${param.channel}"`)
80
- }
81
-
82
- const created = funnel.channels.addConnector(param.channel, {
83
- type: "schedule",
84
- name: param.connector,
85
- entries: [],
86
- })
87
-
88
- await funnel.listeners.start(param.channel, created.name)
89
-
90
- return c.text(`added schedule connector "${created.name}" to channel "${param.channel}"`)
91
- },
92
- )
@@ -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 removeHelp = `funnel channels <channel> connectors remove <connector> — remove a connector
6
-
7
- usage: funnel channels <channel> connectors remove <connector>`
8
-
9
- export const channelsConnectorsRemoveHandler = factory.createHandlers(
10
- zValidator("param", z.object({ channel: z.string(), connector: z.string() })),
11
- zValidator("query", z.object({}), removeHelp),
12
- async (c) => {
13
- const param = c.req.valid("param")
14
- const funnel = c.var.funnel
15
-
16
- await funnel.listeners.stop(param.channel, param.connector)
17
-
18
- funnel.channels.removeConnector(param.channel, param.connector)
19
-
20
- return c.text(`removed connector "${param.connector}" from channel "${param.channel}"`)
21
- },
22
- )
@@ -1,63 +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 setHelp = `funnel channels <channel> connectors set <connector> — update connector fields
7
-
8
- usage:
9
- funnel channels <ch> connectors set <conn> [--bot-token=...] [--app-token=...] # slack
10
- funnel channels <ch> connectors set <conn> [--bot-token=...] # discord
11
- funnel channels <ch> connectors set <conn> [--poll-interval=N] # gh`
12
-
13
- export const channelsConnectorsSetHandler = factory.createHandlers(
14
- zValidator("param", z.object({ channel: z.string(), connector: z.string() })),
15
- zValidator(
16
- "query",
17
- z
18
- .object({
19
- "bot-token": z.string().optional(),
20
- "app-token": z.string().optional(),
21
- "poll-interval": z.coerce.number().int().positive().optional(),
22
- })
23
- .passthrough(),
24
- setHelp,
25
- ),
26
- async (c) => {
27
- const param = c.req.valid("param")
28
- const query = c.req.valid("query")
29
- const funnel = c.var.funnel
30
- const existing = funnel.channels.getConnector(param.channel, param.connector)
31
-
32
- if (!existing) {
33
- throw new HTTPException(404, {
34
- message: `connector "${param.connector}" not found in channel "${param.channel}"`,
35
- })
36
- }
37
-
38
- if (existing.type === "slack") {
39
- funnel.channels.updateSlackConnector(param.channel, param.connector, {
40
- ...(query["bot-token"] !== undefined ? { botToken: query["bot-token"] } : {}),
41
- ...(query["app-token"] !== undefined ? { appToken: query["app-token"] } : {}),
42
- })
43
- } else if (existing.type === "discord") {
44
- funnel.channels.updateDiscordConnector(
45
- param.channel,
46
- param.connector,
47
- query["bot-token"] !== undefined ? { botToken: query["bot-token"] } : {},
48
- )
49
- } else if (existing.type === "gh") {
50
- funnel.channels.updateGhConnector(
51
- param.channel,
52
- param.connector,
53
- query["poll-interval"] !== undefined ? { pollInterval: query["poll-interval"] } : {},
54
- )
55
- } else {
56
- throw new HTTPException(400, { message: "schedule connectors have no settable fields" })
57
- }
58
-
59
- await funnel.listeners.restart(param.channel, param.connector)
60
-
61
- return c.text(`updated connector "${param.connector}" in channel "${param.channel}"`)
62
- },
63
- )
@@ -1,26 +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 groupHelp = `funnel channels <channel> connectors — list connectors in a channel
7
-
8
- usage: funnel channels <channel> connectors`
9
-
10
- export const channelsConnectorsGroupHandler = factory.createHandlers(
11
- zValidator("param", z.object({ channel: z.string() })),
12
- zValidator("query", z.object({}), groupHelp),
13
- (c) => {
14
- const param = c.req.valid("param")
15
- const funnel = c.var.funnel
16
- const channel = funnel.channels.get(param.channel)
17
-
18
- if (!channel) {
19
- throw new HTTPException(404, { message: `channel "${param.channel}" not found` })
20
- }
21
-
22
- if (channel.connectors.length === 0) return c.text(`no connectors in channel "${channel.name}"`)
23
-
24
- return c.text(channel.connectors.map((c) => `${c.name} (${c.type}, id: ${c.id})`).join("\n"))
25
- },
26
- )