@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.
- package/dist/bin.js +448 -448
- package/dist/connectors/slack.d.ts +1 -29
- package/dist/gateway/daemon.js +166 -166
- package/dist/index.d.ts +4 -11
- package/dist/index.js +133 -120
- package/dist/slack-event-processor-CS-bAit9.d.ts +43 -0
- package/package.json +1 -6
- package/dist/slack-connector-schema-D7zAHN8k.d.ts +0 -15
- package/lib/bin.ts +0 -3
- package/lib/cli/factory.ts +0 -10
- package/lib/cli/index.ts +0 -85
- package/lib/cli/router/query-to-cli-args.ts +0 -20
- package/lib/cli/router/to-request.ts +0 -113
- package/lib/cli/router/validator.ts +0 -27
- package/lib/cli/routes/channels.$channel.connectors.$connector.rename.$newName.ts +0 -27
- package/lib/cli/routes/channels.$channel.connectors.$connector.request.ts +0 -40
- package/lib/cli/routes/channels.$channel.connectors.$connector.schedules.add.$id.ts +0 -41
- package/lib/cli/routes/channels.$channel.connectors.$connector.schedules.remove.$id.ts +0 -22
- package/lib/cli/routes/channels.$channel.connectors.$connector.schedules.ts +0 -23
- package/lib/cli/routes/channels.$channel.connectors.$connector.ts +0 -26
- package/lib/cli/routes/channels.$channel.connectors.add.$connector.ts +0 -92
- package/lib/cli/routes/channels.$channel.connectors.remove.$connector.ts +0 -22
- package/lib/cli/routes/channels.$channel.connectors.set.$connector.ts +0 -63
- package/lib/cli/routes/channels.$channel.connectors.ts +0 -26
- package/lib/cli/routes/channels.$channel.publish.ts +0 -52
- package/lib/cli/routes/channels.$channel.rename.$newName.ts +0 -22
- package/lib/cli/routes/channels.$channel.set.delivery.$mode.ts +0 -34
- package/lib/cli/routes/channels.$channel.ts +0 -34
- package/lib/cli/routes/channels.add.$channel.ts +0 -33
- package/lib/cli/routes/channels.remove.$channel.ts +0 -20
- package/lib/cli/routes/channels.ts +0 -39
- package/lib/cli/routes/claude.ts +0 -70
- package/lib/cli/routes/gateway.listeners.ts +0 -41
- package/lib/cli/routes/gateway.logs.ts +0 -123
- package/lib/cli/routes/gateway.restart.ts +0 -50
- package/lib/cli/routes/gateway.run.ts +0 -41
- package/lib/cli/routes/gateway.start.ts +0 -50
- package/lib/cli/routes/gateway.status.ts +0 -19
- package/lib/cli/routes/gateway.stop.ts +0 -32
- package/lib/cli/routes/gateway.ts +0 -55
- package/lib/cli/routes/index.ts +0 -219
- package/lib/cli/routes/profiles.$profile.as-default.ts +0 -22
- package/lib/cli/routes/profiles.$profile.rename.$newName.ts +0 -22
- package/lib/cli/routes/profiles.$profile.run.ts +0 -36
- package/lib/cli/routes/profiles.add.$profile.ts +0 -49
- package/lib/cli/routes/profiles.remove.$profile.ts +0 -20
- package/lib/cli/routes/profiles.set.$profile.ts +0 -45
- package/lib/cli/routes/profiles.ts +0 -40
- package/lib/cli/routes/status.ts +0 -93
- package/lib/cli/routes/update.ts +0 -27
- package/lib/connectors/connector-adapter.ts +0 -9
- package/lib/connectors/connector-config-schema.ts +0 -16
- package/lib/connectors/connector-factory.ts +0 -94
- package/lib/connectors/connector-listener.ts +0 -20
- package/lib/connectors/discord-adapter.ts +0 -51
- package/lib/connectors/discord-connector-schema.ts +0 -12
- package/lib/connectors/discord-event-processor.ts +0 -48
- package/lib/connectors/discord-listener.ts +0 -111
- package/lib/connectors/discord.ts +0 -4
- package/lib/connectors/gh-adapter.ts +0 -48
- package/lib/connectors/gh-connector-schema.ts +0 -12
- package/lib/connectors/gh-listener.ts +0 -137
- package/lib/connectors/gh.ts +0 -3
- package/lib/connectors/match-cron.ts +0 -78
- package/lib/connectors/schedule-connector-schema.ts +0 -33
- package/lib/connectors/schedule-listener.ts +0 -207
- package/lib/connectors/schedule-state-store.ts +0 -54
- package/lib/connectors/schedule.ts +0 -4
- package/lib/connectors/slack-adapter.ts +0 -36
- package/lib/connectors/slack-connector-schema.ts +0 -13
- package/lib/connectors/slack-event-processor.ts +0 -97
- package/lib/connectors/slack-listener.ts +0 -97
- package/lib/connectors/slack.ts +0 -4
- package/lib/engine/channels/channels.ts +0 -520
- package/lib/engine/claude/claude.ts +0 -205
- package/lib/engine/claude/gateway-controller.ts +0 -4
- package/lib/engine/fs/file-system.ts +0 -23
- package/lib/engine/fs/memory-file-system.ts +0 -102
- package/lib/engine/fs/node-file-system.ts +0 -68
- package/lib/engine/http/http-client.ts +0 -17
- package/lib/engine/http/memory-http-client.ts +0 -36
- package/lib/engine/http/node-http-client.ts +0 -23
- package/lib/engine/id/id-generator.ts +0 -7
- package/lib/engine/id/memory-id-generator.ts +0 -20
- package/lib/engine/id/node-id-generator.ts +0 -7
- package/lib/engine/logger/logger.ts +0 -11
- package/lib/engine/logger/memory-logger.ts +0 -28
- package/lib/engine/logger/node-logger.ts +0 -49
- package/lib/engine/logger/noop-logger.ts +0 -9
- package/lib/engine/mcp/channel-server.ts +0 -123
- package/lib/engine/mcp/channel-subscriber.ts +0 -82
- package/lib/engine/mcp/mcp.ts +0 -126
- package/lib/engine/mcp/read-channel-connectors.ts +0 -34
- package/lib/engine/mcp/read-gateway-token.ts +0 -16
- package/lib/engine/mcp/usage-hint-for-type.ts +0 -15
- package/lib/engine/process/memory-process-runner.ts +0 -88
- package/lib/engine/process/node-process-runner.ts +0 -91
- package/lib/engine/process/process-runner.ts +0 -33
- package/lib/engine/profiles/profile-channel-checker.ts +0 -7
- package/lib/engine/profiles/profiles.ts +0 -126
- package/lib/engine/settings/mock-settings-reader.ts +0 -27
- package/lib/engine/settings/settings-reader.ts +0 -6
- package/lib/engine/settings/settings-schema.ts +0 -48
- package/lib/engine/settings/settings-store.ts +0 -110
- package/lib/engine/time/clock.ts +0 -15
- package/lib/engine/time/memory-clock.ts +0 -26
- package/lib/engine/time/node-clock.ts +0 -7
- package/lib/funnel.ts +0 -294
- package/lib/gateway/auth-middleware.ts +0 -44
- package/lib/gateway/broadcaster.ts +0 -319
- package/lib/gateway/channel-publisher.ts +0 -67
- package/lib/gateway/daemon.ts +0 -47
- package/lib/gateway/factory.ts +0 -10
- package/lib/gateway/funnel-event-store.ts +0 -155
- package/lib/gateway/gateway-server.ts +0 -426
- package/lib/gateway/gateway-token.ts +0 -79
- package/lib/gateway/gateway.ts +0 -209
- package/lib/gateway/kill-competing-slack-gateways.ts +0 -56
- package/lib/gateway/listener-supervisor.ts +0 -339
- package/lib/gateway/listeners-client.ts +0 -128
- package/lib/gateway/publish-schema.ts +0 -27
- package/lib/gateway/resolve-daemon-script.ts +0 -26
- package/lib/gateway/routes/channels.connectors.call.ts +0 -39
- package/lib/gateway/routes/channels.publish.ts +0 -44
- package/lib/gateway/routes/health.ts +0 -13
- package/lib/gateway/routes/index.ts +0 -26
- package/lib/gateway/routes/listeners.list.ts +0 -6
- package/lib/gateway/routes/listeners.restart.ts +0 -15
- package/lib/gateway/routes/listeners.start.ts +0 -15
- package/lib/gateway/routes/listeners.stop.ts +0 -15
- package/lib/gateway/routes/route-deps.ts +0 -19
- package/lib/gateway/routes/status.ts +0 -15
- package/lib/gateway/routes/validator.ts +0 -17
- package/lib/index.ts +0 -67
- package/lib/logger/leuco-human-file-writer.ts +0 -65
- package/lib/logger/leuco-human-logger.ts +0 -98
- package/lib/logger/leuco-human-record.ts +0 -16
- package/lib/logger/leuco-human-stdout-writer.ts +0 -26
- package/lib/logger/leuco-human-writer.ts +0 -14
- package/lib/logger/leuco-logger-memory-sink.ts +0 -67
- package/lib/logger/leuco-logger-record.ts +0 -13
- package/lib/logger/leuco-logger-sink.ts +0 -33
- package/lib/logger/leuco-logger-sqlite-sink.ts +0 -355
- package/lib/logger/leuco-logger.ts +0 -135
- package/lib/tui/app.tsx +0 -357
- package/lib/tui/components/add-row.tsx +0 -18
- package/lib/tui/components/brand.tsx +0 -27
- package/lib/tui/components/card.tsx +0 -44
- package/lib/tui/components/detail-bar.tsx +0 -46
- package/lib/tui/components/editable-field.tsx +0 -33
- package/lib/tui/components/empty-state.tsx +0 -11
- package/lib/tui/components/gateway-status.tsx +0 -66
- package/lib/tui/components/keymap.tsx +0 -29
- package/lib/tui/components/menu-item.tsx +0 -73
- package/lib/tui/components/menu.tsx +0 -26
- package/lib/tui/components/panel-header.tsx +0 -22
- package/lib/tui/components/readonly-field.tsx +0 -18
- package/lib/tui/components/section-header.tsx +0 -25
- package/lib/tui/components/selection-accent.tsx +0 -32
- package/lib/tui/components/session-item.tsx +0 -33
- package/lib/tui/components/session-list.tsx +0 -33
- package/lib/tui/components/ui/hascii/accordion-item.tsx +0 -88
- package/lib/tui/components/ui/hascii/accordion.tsx +0 -96
- package/lib/tui/components/ui/hascii/alert-dialog.tsx +0 -43
- package/lib/tui/components/ui/hascii/badge.tsx +0 -51
- package/lib/tui/components/ui/hascii/breadcrumb.tsx +0 -58
- package/lib/tui/components/ui/hascii/button.tsx +0 -194
- package/lib/tui/components/ui/hascii/card-content.tsx +0 -14
- package/lib/tui/components/ui/hascii/card-description.tsx +0 -13
- package/lib/tui/components/ui/hascii/card-footer.tsx +0 -14
- package/lib/tui/components/ui/hascii/card-header.tsx +0 -14
- package/lib/tui/components/ui/hascii/card-title.tsx +0 -13
- package/lib/tui/components/ui/hascii/card.tsx +0 -27
- package/lib/tui/components/ui/hascii/checkbox.tsx +0 -65
- package/lib/tui/components/ui/hascii/command.tsx +0 -159
- package/lib/tui/components/ui/hascii/dialog-content.tsx +0 -14
- package/lib/tui/components/ui/hascii/dialog-description.tsx +0 -13
- package/lib/tui/components/ui/hascii/dialog-footer.tsx +0 -14
- package/lib/tui/components/ui/hascii/dialog-header.tsx +0 -14
- package/lib/tui/components/ui/hascii/dialog-title.tsx +0 -13
- package/lib/tui/components/ui/hascii/dialog.tsx +0 -27
- package/lib/tui/components/ui/hascii/file-tree.tsx +0 -142
- package/lib/tui/components/ui/hascii/focus-group.tsx +0 -62
- package/lib/tui/components/ui/hascii/form-item.tsx +0 -43
- package/lib/tui/components/ui/hascii/input-otp.tsx +0 -86
- package/lib/tui/components/ui/hascii/input.tsx +0 -130
- package/lib/tui/components/ui/hascii/pagination.tsx +0 -105
- package/lib/tui/components/ui/hascii/progress.tsx +0 -28
- package/lib/tui/components/ui/hascii/select.tsx +0 -131
- package/lib/tui/components/ui/hascii/separator.tsx +0 -35
- package/lib/tui/components/ui/hascii/sidebar-content.tsx +0 -23
- package/lib/tui/components/ui/hascii/sidebar-header.tsx +0 -14
- package/lib/tui/components/ui/hascii/sidebar-menu-item.tsx +0 -67
- package/lib/tui/components/ui/hascii/sidebar.tsx +0 -24
- package/lib/tui/components/ui/hascii/skeleton.tsx +0 -60
- package/lib/tui/components/ui/hascii/slider.tsx +0 -91
- package/lib/tui/components/ui/hascii/snackbar.tsx +0 -75
- package/lib/tui/components/ui/hascii/sparkline.tsx +0 -53
- package/lib/tui/components/ui/hascii/spinner.tsx +0 -47
- package/lib/tui/components/ui/hascii/stepper.tsx +0 -54
- package/lib/tui/components/ui/hascii/switch.tsx +0 -66
- package/lib/tui/components/ui/hascii/table.tsx +0 -95
- package/lib/tui/components/ui/hascii/tabs.tsx +0 -59
- package/lib/tui/components/ui/hascii/toggle-group-item.tsx +0 -45
- package/lib/tui/components/ui/hascii/toggle-group.tsx +0 -99
- package/lib/tui/components/ui/hascii/tree.tsx +0 -104
- package/lib/tui/components/view-shell.tsx +0 -44
- package/lib/tui/filter-input.tsx +0 -33
- package/lib/tui/hooks/hascii/use-pressable.ts +0 -54
- package/lib/tui/parse-comma-list.ts +0 -14
- package/lib/tui/profile-launcher.tsx +0 -61
- package/lib/tui/scrollbar-options.ts +0 -19
- package/lib/tui/sidebar.tsx +0 -50
- package/lib/tui/theme.ts +0 -40
- package/lib/tui/tui.tsx +0 -20
- package/lib/tui/types.ts +0 -38
- package/lib/tui/unique-name.ts +0 -18
- package/lib/tui/use-event-stream.ts +0 -133
- package/lib/tui/use-snapshot.ts +0 -99
- package/lib/tui/utils/hascii/form-item-context.tsx +0 -23
- package/lib/tui/utils/hascii/input-focus-context.tsx +0 -31
- package/lib/tui/utils/hascii/theme-context.tsx +0 -26
- package/lib/tui/utils/hascii/theme.ts +0 -176
- package/lib/tui/views/channels-view.tsx +0 -108
- package/lib/tui/views/connectors-view.tsx +0 -164
- package/lib/tui/views/events-view.tsx +0 -160
- package/lib/tui/views/listeners-view.tsx +0 -80
- 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
|
-
)
|