@interactive-inc/claude-funnel 0.8.1 → 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/README.md +179 -80
- package/dist/bin.js +726 -658
- package/dist/connector-adapter-CXB-q_XC.d.ts +11 -0
- package/dist/connector-adapter-D5Utumgz.js +4 -0
- package/dist/connectors/discord.d.ts +76 -0
- package/dist/connectors/discord.js +2 -0
- package/dist/connectors/gh.d.ts +38 -0
- package/dist/connectors/gh.js +2 -0
- package/dist/connectors/schedule.d.ts +53 -0
- package/dist/connectors/schedule.js +2 -0
- package/dist/connectors/slack.d.ts +34 -0
- package/dist/connectors/slack.js +2 -0
- package/dist/discord-connector-schema-Dww2I4zH.d.ts +14 -0
- package/dist/discord-connector-schema-ygf5Df-2.js +173 -0
- package/dist/file-system-Co60LrmR.d.ts +74 -0
- package/dist/gateway/daemon.js +233 -183
- package/dist/gh-connector-schema-2ml29MBC.js +218 -0
- package/dist/gh-connector-schema-BZFAS-p-.d.ts +45 -0
- package/dist/index.d.ts +3881 -36
- package/dist/index.js +6217 -3483
- package/dist/logger-CTlXs7z4.d.ts +33 -0
- package/dist/node-logger-DQz_BGOD.js +61 -0
- package/dist/schedule-connector-schema-CkuIQ0JQ.js +325 -0
- package/dist/slack-connector-schema-Cd22WiHB.js +153 -0
- package/dist/slack-event-processor-CS-bAit9.d.ts +43 -0
- package/package.json +34 -28
- package/dist/cli/factory.d.ts +0 -7
- package/dist/cli/router/query-to-cli-args.d.ts +0 -1
- package/dist/cli/router/to-request.d.ts +0 -5
- package/dist/cli/router/validator.d.ts +0 -5
- package/dist/cli/routes/channels.$channel.connectors.$connector.d.ts +0 -42
- package/dist/cli/routes/channels.$channel.connectors.$connector.rename.$newName.d.ts +0 -46
- package/dist/cli/routes/channels.$channel.connectors.$connector.request.d.ts +0 -54
- package/dist/cli/routes/channels.$channel.connectors.$connector.schedules.add.$id.d.ts +0 -66
- package/dist/cli/routes/channels.$channel.connectors.$connector.schedules.d.ts +0 -42
- package/dist/cli/routes/channels.$channel.connectors.$connector.schedules.remove.$id.d.ts +0 -46
- package/dist/cli/routes/channels.$channel.connectors.add.$connector.d.ts +0 -90
- package/dist/cli/routes/channels.$channel.connectors.d.ts +0 -38
- package/dist/cli/routes/channels.$channel.connectors.remove.$connector.d.ts +0 -42
- package/dist/cli/routes/channels.$channel.connectors.set.$connector.d.ts +0 -62
- package/dist/cli/routes/channels.$channel.d.ts +0 -38
- package/dist/cli/routes/channels.$channel.rename.$newName.d.ts +0 -42
- package/dist/cli/routes/channels.$channel.set.delivery.$mode.d.ts +0 -28
- package/dist/cli/routes/channels.add.$channel.d.ts +0 -46
- package/dist/cli/routes/channels.d.ts +0 -16
- package/dist/cli/routes/channels.remove.$channel.d.ts +0 -38
- package/dist/cli/routes/claude.d.ts +0 -32
- package/dist/cli/routes/gateway.d.ts +0 -20
- package/dist/cli/routes/gateway.listeners.d.ts +0 -17
- package/dist/cli/routes/gateway.logs.d.ts +0 -24
- package/dist/cli/routes/gateway.restart.d.ts +0 -24
- package/dist/cli/routes/gateway.run.d.ts +0 -24
- package/dist/cli/routes/gateway.start.d.ts +0 -24
- package/dist/cli/routes/gateway.status.d.ts +0 -13
- package/dist/cli/routes/gateway.stop.d.ts +0 -16
- package/dist/cli/routes/index.d.ts +0 -1222
- package/dist/cli/routes/profiles.$profile.as-default.d.ts +0 -38
- package/dist/cli/routes/profiles.$profile.rename.$newName.d.ts +0 -42
- package/dist/cli/routes/profiles.$profile.run.d.ts +0 -46
- package/dist/cli/routes/profiles.add.$profile.d.ts +0 -54
- package/dist/cli/routes/profiles.d.ts +0 -16
- package/dist/cli/routes/profiles.remove.$profile.d.ts +0 -38
- package/dist/cli/routes/profiles.set.$profile.d.ts +0 -54
- package/dist/cli/routes/status.d.ts +0 -16
- package/dist/cli/routes/update.d.ts +0 -16
- package/dist/connectors/connector-adapter.d.ts +0 -8
- package/dist/connectors/connector-config-schema.d.ts +0 -43
- package/dist/connectors/connector-factory.d.ts +0 -32
- package/dist/connectors/connector-listener.d.ts +0 -17
- package/dist/connectors/discord-adapter.d.ts +0 -14
- package/dist/connectors/discord-connector-schema.d.ts +0 -10
- package/dist/connectors/discord-event-processor.d.ts +0 -26
- package/dist/connectors/discord-listener.d.ts +0 -17
- package/dist/connectors/gh-adapter.d.ts +0 -11
- package/dist/connectors/gh-connector-schema.d.ts +0 -10
- package/dist/connectors/gh-listener.d.ts +0 -26
- package/dist/connectors/match-cron.d.ts +0 -1
- package/dist/connectors/schedule-connector-schema.d.ts +0 -45
- package/dist/connectors/schedule-listener.d.ts +0 -30
- package/dist/connectors/schedule-state-store.d.ts +0 -19
- package/dist/connectors/slack-adapter.d.ts +0 -15
- package/dist/connectors/slack-connector-schema.d.ts +0 -11
- package/dist/connectors/slack-event-processor.d.ts +0 -27
- package/dist/connectors/slack-listener.d.ts +0 -17
- package/dist/engine/channels/channels.d.ts +0 -106
- package/dist/engine/claude/claude.d.ts +0 -49
- package/dist/engine/claude/gateway-controller.d.ts +0 -6
- package/dist/engine/fs/file-system.d.ts +0 -24
- package/dist/engine/fs/memory-file-system.d.ts +0 -31
- package/dist/engine/fs/node-file-system.d.ts +0 -15
- package/dist/engine/http/http-client.d.ts +0 -15
- package/dist/engine/http/memory-http-client.d.ts +0 -12
- package/dist/engine/http/node-http-client.d.ts +0 -5
- package/dist/engine/id/id-generator.d.ts +0 -7
- package/dist/engine/id/memory-id-generator.d.ts +0 -11
- package/dist/engine/id/node-id-generator.d.ts +0 -4
- package/dist/engine/logger/logger.d.ts +0 -11
- package/dist/engine/logger/memory-logger.d.ts +0 -14
- package/dist/engine/logger/node-logger.d.ts +0 -15
- package/dist/engine/logger/noop-logger.d.ts +0 -7
- package/dist/engine/mcp/channel-server.d.ts +0 -1
- package/dist/engine/mcp/mcp.d.ts +0 -22
- package/dist/engine/process/memory-process-runner.d.ts +0 -43
- package/dist/engine/process/node-process-runner.d.ts +0 -9
- package/dist/engine/process/process-runner.d.ts +0 -29
- package/dist/engine/profiles/profile-channel-checker.d.ts +0 -7
- package/dist/engine/profiles/profiles.d.ts +0 -31
- package/dist/engine/settings/mock-settings-reader.d.ts +0 -9
- package/dist/engine/settings/settings-reader.d.ts +0 -5
- package/dist/engine/settings/settings-schema.d.ts +0 -132
- package/dist/engine/settings/settings-store.d.ts +0 -18
- package/dist/engine/time/clock.d.ts +0 -9
- package/dist/engine/time/memory-clock.d.ts +0 -12
- package/dist/engine/time/node-clock.d.ts +0 -4
- package/dist/funnel.d.ts +0 -95
- package/dist/gateway/auth-middleware.d.ts +0 -14
- package/dist/gateway/broadcaster.d.ts +0 -122
- package/dist/gateway/daemon.d.ts +0 -2
- package/dist/gateway/factory.d.ts +0 -7
- package/dist/gateway/funnel-event-store.d.ts +0 -81
- package/dist/gateway/gateway-server.d.ts +0 -94
- package/dist/gateway/gateway-token.d.ts +0 -33
- package/dist/gateway/gateway.d.ts +0 -58
- package/dist/gateway/kill-competing-slack-gateways.d.ts +0 -9
- package/dist/gateway/listener-supervisor.d.ts +0 -85
- package/dist/gateway/listeners-client.d.ts +0 -53
- package/dist/gateway/resolve-daemon-script.d.ts +0 -11
- package/dist/gateway/routes/channels.connectors.call.d.ts +0 -41
- package/dist/gateway/routes/health.d.ts +0 -17
- package/dist/gateway/routes/index.d.ts +0 -209
- package/dist/gateway/routes/listeners.list.d.ts +0 -14
- package/dist/gateway/routes/listeners.restart.d.ts +0 -34
- package/dist/gateway/routes/listeners.start.d.ts +0 -34
- package/dist/gateway/routes/listeners.stop.d.ts +0 -34
- package/dist/gateway/routes/route-deps.d.ts +0 -10
- package/dist/gateway/routes/status.d.ts +0 -30
- package/dist/gateway/routes/validator.d.ts +0 -19
- package/dist/logger/leuco-human-file-writer.d.ts +0 -33
- package/dist/logger/leuco-human-logger.d.ts +0 -46
- package/dist/logger/leuco-human-record.d.ts +0 -15
- package/dist/logger/leuco-human-stdout-writer.d.ts +0 -20
- package/dist/logger/leuco-human-writer.d.ts +0 -13
- package/dist/logger/leuco-logger-memory-sink.d.ts +0 -33
- package/dist/logger/leuco-logger-record.d.ts +0 -13
- package/dist/logger/leuco-logger-sink.d.ts +0 -34
- package/dist/logger/leuco-logger-sqlite-sink.d.ts +0 -102
- package/dist/logger/leuco-logger.d.ts +0 -56
- package/lib/bin.ts +0 -78
- package/lib/cli/factory.ts +0 -10
- package/lib/cli/router/query-to-cli-args.ts +0 -20
- package/lib/cli/router/to-request.ts +0 -112
- 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.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 -69
- 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 -202
- 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 -46
- package/lib/cli/routes/profiles.remove.$profile.ts +0 -20
- package/lib/cli/routes/profiles.set.$profile.ts +0 -46
- 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/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/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/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/engine/channels/channels.ts +0 -520
- package/lib/engine/claude/claude.ts +0 -199
- 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 -204
- package/lib/engine/mcp/mcp.ts +0 -126
- 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 -46
- 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 -187
- package/lib/gateway/auth-middleware.ts +0 -44
- package/lib/gateway/broadcaster.ts +0 -319
- 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 -414
- 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/resolve-daemon-script.ts +0 -26
- package/lib/gateway/routes/channels.connectors.call.ts +0 -39
- package/lib/gateway/routes/health.ts +0 -13
- package/lib/gateway/routes/index.ts +0 -24
- 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 -11
- package/lib/gateway/routes/status.ts +0 -15
- package/lib/gateway/routes/validator.ts +0 -17
- package/lib/index.ts +0 -52
- 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
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { z } from "zod"
|
|
2
|
-
import { connectorConfigSchema } from "@/connectors/connector-config-schema"
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Routing mode when multiple WS clients are subscribed to the same channel.
|
|
6
|
-
*
|
|
7
|
-
* - `fanout` (default): every connected client receives every event. Right when each
|
|
8
|
-
* subscriber has its own job (e.g., TUI mirrors, distinct Claude profiles each running
|
|
9
|
-
* their own pipeline against the same source).
|
|
10
|
-
* - `exclusive`: each event is delivered to exactly one connected client, picked
|
|
11
|
-
* round-robin per channel. Right when subscribers are interchangeable workers and you
|
|
12
|
-
* want each event handled once. Tap=all clients (TUI dashboard) always receive,
|
|
13
|
-
* regardless of mode, so they can passively observe.
|
|
14
|
-
*/
|
|
15
|
-
export const channelDeliveryModeSchema = z.enum(["fanout", "exclusive"])
|
|
16
|
-
|
|
17
|
-
export type ChannelDeliveryMode = z.infer<typeof channelDeliveryModeSchema>
|
|
18
|
-
|
|
19
|
-
export const channelConfigSchema = z.object({
|
|
20
|
-
id: z.string(),
|
|
21
|
-
name: z.string(),
|
|
22
|
-
delivery: channelDeliveryModeSchema.default("fanout"),
|
|
23
|
-
connectors: z.array(connectorConfigSchema).default([]),
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
export type ChannelConfig = z.infer<typeof channelConfigSchema>
|
|
27
|
-
|
|
28
|
-
export const profileConfigSchema = z.object({
|
|
29
|
-
name: z.string(),
|
|
30
|
-
path: z.string(),
|
|
31
|
-
subAgent: z.string(),
|
|
32
|
-
channelId: z.string(),
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
export type ProfileConfig = z.infer<typeof profileConfigSchema>
|
|
36
|
-
|
|
37
|
-
export const SETTINGS_VERSION = 1
|
|
38
|
-
|
|
39
|
-
export const settingsSchema = z.object({
|
|
40
|
-
/** Schema version. New files always write the current version; older files without one are read as v1. */
|
|
41
|
-
version: z.literal(SETTINGS_VERSION).default(SETTINGS_VERSION),
|
|
42
|
-
channels: z.array(channelConfigSchema).default([]),
|
|
43
|
-
profiles: z.array(profileConfigSchema).default([]),
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
export type Settings = z.infer<typeof settingsSchema>
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import { homedir } from "node:os"
|
|
2
|
-
import { dirname, join } from "node:path"
|
|
3
|
-
import { FunnelFileSystem } from "@/engine/fs/file-system"
|
|
4
|
-
import { NodeFunnelFileSystem } from "@/engine/fs/node-file-system"
|
|
5
|
-
import { FunnelSettingsReader } from "@/engine/settings/settings-reader"
|
|
6
|
-
import { SETTINGS_VERSION, settingsSchema } from "@/engine/settings/settings-schema"
|
|
7
|
-
import type { Settings } from "@/engine/settings/settings-schema"
|
|
8
|
-
|
|
9
|
-
export const FUNNEL_DIR = join(homedir(), ".funnel")
|
|
10
|
-
export const SETTINGS_PATH = join(FUNNEL_DIR, "settings.json")
|
|
11
|
-
|
|
12
|
-
type Deps = {
|
|
13
|
-
path?: string
|
|
14
|
-
fs?: FunnelFileSystem
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const defaultFs = new NodeFunnelFileSystem()
|
|
18
|
-
|
|
19
|
-
export class FunnelSettingsStore extends FunnelSettingsReader {
|
|
20
|
-
private readonly path: string
|
|
21
|
-
private readonly fs: FunnelFileSystem
|
|
22
|
-
|
|
23
|
-
constructor(deps: Deps = {}) {
|
|
24
|
-
super()
|
|
25
|
-
this.path = deps.path ?? SETTINGS_PATH
|
|
26
|
-
this.fs = deps.fs ?? defaultFs
|
|
27
|
-
Object.freeze(this)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
read(): Settings {
|
|
31
|
-
if (!this.fs.existsSync(this.path)) {
|
|
32
|
-
return {
|
|
33
|
-
version: SETTINGS_VERSION,
|
|
34
|
-
channels: [],
|
|
35
|
-
profiles: [],
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const content = this.fs.readFileSync(this.path)
|
|
40
|
-
const parsed: unknown = JSON.parse(content)
|
|
41
|
-
|
|
42
|
-
if (this.looksLikeLegacy(parsed)) {
|
|
43
|
-
throw new Error(
|
|
44
|
-
`legacy settings.json detected at ${this.path}. The schema changed (channel.connectors are now nested objects with ids; profile fields renamed). Migration is intentionally not provided. Back up and remove the old file:\n mv ${this.path} ${this.path}.bak`,
|
|
45
|
-
)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (
|
|
49
|
-
parsed &&
|
|
50
|
-
typeof parsed === "object" &&
|
|
51
|
-
"version" in parsed &&
|
|
52
|
-
parsed.version !== SETTINGS_VERSION
|
|
53
|
-
) {
|
|
54
|
-
throw new Error(
|
|
55
|
-
`unsupported settings.json version (${this.path}): expected ${SETTINGS_VERSION}, got ${String(parsed.version)}`,
|
|
56
|
-
)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const result = settingsSchema.safeParse(parsed)
|
|
60
|
-
|
|
61
|
-
if (!result.success) {
|
|
62
|
-
throw new Error(
|
|
63
|
-
`invalid settings.json (${this.path}): ${result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join(", ")}`,
|
|
64
|
-
)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return result.data
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
private looksLikeLegacy(parsed: unknown): boolean {
|
|
71
|
-
if (!parsed || typeof parsed !== "object") return false
|
|
72
|
-
|
|
73
|
-
const obj = parsed as Record<string, unknown>
|
|
74
|
-
|
|
75
|
-
if (Array.isArray(obj.channels)) {
|
|
76
|
-
for (const channel of obj.channels) {
|
|
77
|
-
if (!channel || typeof channel !== "object") continue
|
|
78
|
-
const ch = channel as Record<string, unknown>
|
|
79
|
-
|
|
80
|
-
if (Array.isArray(ch.connectors) && ch.connectors.some((x) => typeof x === "string")) {
|
|
81
|
-
return true
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (!("id" in ch) && "name" in ch) return true
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (Array.isArray(obj.connectors)) return true
|
|
89
|
-
if (Array.isArray(obj.repositories)) return true
|
|
90
|
-
|
|
91
|
-
if (Array.isArray(obj.profiles)) {
|
|
92
|
-
for (const profile of obj.profiles) {
|
|
93
|
-
if (!profile || typeof profile !== "object") continue
|
|
94
|
-
const p = profile as Record<string, unknown>
|
|
95
|
-
|
|
96
|
-
if ("repository" in p || "envFiles" in p || ("channel" in p && !("channelId" in p))) {
|
|
97
|
-
return true
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return false
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
write(settings: Settings): void {
|
|
106
|
-
this.fs.mkdirSync(dirname(this.path), { recursive: true })
|
|
107
|
-
const versioned: Settings = { ...settings, version: SETTINGS_VERSION }
|
|
108
|
-
this.fs.writeFileSync(this.path, `${JSON.stringify(versioned, null, 2)}\n`)
|
|
109
|
-
}
|
|
110
|
-
}
|
package/lib/engine/time/clock.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Time boundary. Default NodeFunnelClock returns `new Date()`; MemoryFunnelClock
|
|
3
|
-
* is settable and `advance(ms)`-able for deterministic schedule / timeout tests.
|
|
4
|
-
*/
|
|
5
|
-
export abstract class FunnelClock {
|
|
6
|
-
abstract now(): Date
|
|
7
|
-
|
|
8
|
-
millis(): number {
|
|
9
|
-
return this.now().getTime()
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
iso(): string {
|
|
13
|
-
return this.now().toISOString()
|
|
14
|
-
}
|
|
15
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { FunnelClock } from "@/engine/time/clock"
|
|
2
|
-
|
|
3
|
-
type Props = {
|
|
4
|
-
start?: Date
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export class MemoryFunnelClock extends FunnelClock {
|
|
8
|
-
private current: Date
|
|
9
|
-
|
|
10
|
-
constructor(props: Props = {}) {
|
|
11
|
-
super()
|
|
12
|
-
this.current = props.start ?? new Date(0)
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
now(): Date {
|
|
16
|
-
return new Date(this.current.getTime())
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
set(date: Date): void {
|
|
20
|
-
this.current = date
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
advance(ms: number): void {
|
|
24
|
-
this.current = new Date(this.current.getTime() + ms)
|
|
25
|
-
}
|
|
26
|
-
}
|
package/lib/funnel.ts
DELETED
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
import { join } from "node:path"
|
|
2
|
-
import { FunnelConnectorFactory } from "@/connectors/connector-factory"
|
|
3
|
-
import { FunnelChannels } from "@/engine/channels/channels"
|
|
4
|
-
import { FunnelClaude } from "@/engine/claude/claude"
|
|
5
|
-
import type { FunnelFileSystem } from "@/engine/fs/file-system"
|
|
6
|
-
import type { FunnelIdGenerator } from "@/engine/id/id-generator"
|
|
7
|
-
import { FunnelLogger } from "@/engine/logger/logger"
|
|
8
|
-
import { NodeFunnelLogger } from "@/engine/logger/node-logger"
|
|
9
|
-
import { FunnelMcp } from "@/engine/mcp/mcp"
|
|
10
|
-
import { FunnelProcessRunner } from "@/engine/process/process-runner"
|
|
11
|
-
import { NodeFunnelProcessRunner } from "@/engine/process/node-process-runner"
|
|
12
|
-
import { FunnelProfiles } from "@/engine/profiles/profiles"
|
|
13
|
-
import { FunnelSettingsReader } from "@/engine/settings/settings-reader"
|
|
14
|
-
import { FUNNEL_DIR, FunnelSettingsStore } from "@/engine/settings/settings-store"
|
|
15
|
-
import type { FunnelClock } from "@/engine/time/clock"
|
|
16
|
-
import { FunnelGateway } from "@/gateway/gateway"
|
|
17
|
-
import { FunnelGatewayServer } from "@/gateway/gateway-server"
|
|
18
|
-
import { FunnelGatewayToken } from "@/gateway/gateway-token"
|
|
19
|
-
import { FunnelListenersClient } from "@/gateway/listeners-client"
|
|
20
|
-
|
|
21
|
-
type Props = {
|
|
22
|
-
/** Settings persistence (channels with nested connectors / profiles). Defaults to a FunnelSettingsStore rooted at `dir`. */
|
|
23
|
-
store?: FunnelSettingsReader
|
|
24
|
-
/** Filesystem boundary. Replace with MemoryFunnelFileSystem to sandbox all disk I/O. */
|
|
25
|
-
fs?: FunnelFileSystem
|
|
26
|
-
/** Process runner used by gateway / claude / gh listener. Replace with MemoryFunnelProcessRunner for tests. */
|
|
27
|
-
process?: FunnelProcessRunner
|
|
28
|
-
/** Logger flowed into every facet. Replace with MemoryFunnelLogger or NoopFunnelLogger to silence/inspect. */
|
|
29
|
-
logger?: FunnelLogger
|
|
30
|
-
/** Clock used by schedule listener, gh poll watermarks, and gateway timeouts. */
|
|
31
|
-
clock?: FunnelClock
|
|
32
|
-
/** ID generator for channel and connector ids. Use MemoryFunnelIdGenerator for deterministic tests. */
|
|
33
|
-
idGenerator?: FunnelIdGenerator
|
|
34
|
-
/** Funnel home directory (settings.json + per-channel/per-connector dirs). Defaults to ~/.funnel. */
|
|
35
|
-
dir?: string
|
|
36
|
-
/** Temp / runtime directory (gateway logs and PID adjacent files). Defaults to /tmp/funnel. */
|
|
37
|
-
tmpDir?: string
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Facade exposing every funnel facet as a getter.
|
|
42
|
-
*
|
|
43
|
-
* The same `Funnel` is used by the CLI, the TUI, and as a programmable library.
|
|
44
|
-
* All side-effecting boundaries (filesystem, process, logger, clock, id, paths) are
|
|
45
|
-
* injectable via `Props` — passing memory implementations gives a fully sandboxed
|
|
46
|
-
* Funnel that touches no real disk, processes, or wall-clock time.
|
|
47
|
-
*
|
|
48
|
-
* Connectors live nested inside their owning channel (channels[].connectors[]),
|
|
49
|
-
* so connector CRUD is reached via `funnel.channels.addConnector(...)` etc.
|
|
50
|
-
*
|
|
51
|
-
* @example
|
|
52
|
-
* ```ts
|
|
53
|
-
* const funnel = new Funnel({})
|
|
54
|
-
* const channel = funnel.channels.add({ name: "inbox" })
|
|
55
|
-
* funnel.channels.addConnector("inbox", { type: "slack", name: "ops", botToken, appToken })
|
|
56
|
-
* await funnel.gatewayServer({ port: 9742 }).start()
|
|
57
|
-
* ```
|
|
58
|
-
*/
|
|
59
|
-
export class Funnel {
|
|
60
|
-
constructor(private readonly props: Props = {}) {
|
|
61
|
-
Object.freeze(this)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/** Settings reader. If not injected, a FunnelSettingsStore rooted at `dir` is created. */
|
|
65
|
-
get store(): FunnelSettingsReader {
|
|
66
|
-
return (
|
|
67
|
-
this.props.store ??
|
|
68
|
-
new FunnelSettingsStore({
|
|
69
|
-
path: join(this.props.dir ?? FUNNEL_DIR, "settings.json"),
|
|
70
|
-
fs: this.props.fs,
|
|
71
|
-
})
|
|
72
|
-
)
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/** Process runner boundary. Defaults to NodeFunnelProcessRunner. */
|
|
76
|
-
get process(): FunnelProcessRunner {
|
|
77
|
-
return this.props.process ?? new NodeFunnelProcessRunner()
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/** Logger boundary. Defaults to NodeFunnelLogger. */
|
|
81
|
-
get logger(): FunnelLogger {
|
|
82
|
-
return this.props.logger ?? new NodeFunnelLogger()
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/** Pure factory that constructs per-type listeners and adapters from connector configs. */
|
|
86
|
-
get factory(): FunnelConnectorFactory {
|
|
87
|
-
return new FunnelConnectorFactory({
|
|
88
|
-
fs: this.props.fs,
|
|
89
|
-
process: this.props.process,
|
|
90
|
-
logger: this.props.logger,
|
|
91
|
-
dir: this.props.dir,
|
|
92
|
-
})
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/** Channel CRUD + nested connector CRUD + schedule entries + listener/adapter dispatch. */
|
|
96
|
-
get channels(): FunnelChannels {
|
|
97
|
-
return new FunnelChannels({
|
|
98
|
-
store: this.store,
|
|
99
|
-
factory: this.factory,
|
|
100
|
-
profileChecker: this.profiles,
|
|
101
|
-
clock: this.props.clock,
|
|
102
|
-
idGenerator: this.props.idGenerator,
|
|
103
|
-
})
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/** Launch profiles (named presets for `fnl claude`: path + sub-agent + channel id). */
|
|
107
|
-
get profiles(): FunnelProfiles {
|
|
108
|
-
return new FunnelProfiles({ store: this.store })
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/** funnel MCP installer (writes/removes `.mcp.json` entries in target repos). */
|
|
112
|
-
get mcp(): FunnelMcp {
|
|
113
|
-
return new FunnelMcp({ fs: this.props.fs })
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/** Launch Claude Code with a channel injected via env, MCP installed, gateway ensured. */
|
|
117
|
-
get claude(): FunnelClaude {
|
|
118
|
-
return new FunnelClaude({
|
|
119
|
-
channels: this.channels,
|
|
120
|
-
mcp: this.mcp,
|
|
121
|
-
gateway: this.gateway,
|
|
122
|
-
fs: this.props.fs,
|
|
123
|
-
process: this.props.process,
|
|
124
|
-
logger: this.props.logger,
|
|
125
|
-
dir: this.props.dir,
|
|
126
|
-
})
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/** Gateway daemon controller (PID-file, start/stop the separate `bun daemon.ts` process). */
|
|
130
|
-
get gateway(): FunnelGateway {
|
|
131
|
-
return new FunnelGateway({
|
|
132
|
-
fs: this.props.fs,
|
|
133
|
-
process: this.props.process,
|
|
134
|
-
clock: this.props.clock,
|
|
135
|
-
dir: this.props.dir,
|
|
136
|
-
tmpDir: this.props.tmpDir,
|
|
137
|
-
})
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/** Read / generate the daemon's gateway token (mode 0600 file under `dir`). */
|
|
141
|
-
get gatewayToken(): FunnelGatewayToken {
|
|
142
|
-
return new FunnelGatewayToken({ fs: this.props.fs, dir: this.props.dir })
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* HTTP client for listener operations on the running gateway daemon.
|
|
147
|
-
* Returns `{ state: "offline" }` when the daemon is offline so hot-reload
|
|
148
|
-
* paths stay write-only without parsing strings.
|
|
149
|
-
*/
|
|
150
|
-
get listeners(): FunnelListenersClient {
|
|
151
|
-
const gateway = this.gateway
|
|
152
|
-
const token = this.gatewayToken
|
|
153
|
-
|
|
154
|
-
return new FunnelListenersClient({
|
|
155
|
-
port: gateway.getPort(),
|
|
156
|
-
isDaemonRunning: () => gateway.isRunning(),
|
|
157
|
-
getToken: () => token.read(),
|
|
158
|
-
})
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* In-process gateway server. Unlike `gateway.start()` (which spawns a daemon),
|
|
163
|
-
* this returns a class that runs `Bun.serve` + listeners inside the current process —
|
|
164
|
-
* useful for tests, embedding, or custom hosts.
|
|
165
|
-
*/
|
|
166
|
-
gatewayServer(
|
|
167
|
-
options: {
|
|
168
|
-
port?: number
|
|
169
|
-
logDir?: string
|
|
170
|
-
killCompetingSlack?: boolean
|
|
171
|
-
/** Override the auth token. Defaults to the persisted gateway.token. Pass "" to disable auth (tests). */
|
|
172
|
-
token?: string
|
|
173
|
-
} = {},
|
|
174
|
-
): FunnelGatewayServer {
|
|
175
|
-
return new FunnelGatewayServer({
|
|
176
|
-
channels: this.channels,
|
|
177
|
-
settings: this.store,
|
|
178
|
-
port: options.port,
|
|
179
|
-
logDir: options.logDir,
|
|
180
|
-
process: this.props.process,
|
|
181
|
-
clock: this.props.clock,
|
|
182
|
-
logger: this.props.logger,
|
|
183
|
-
killCompetingSlack: options.killCompetingSlack,
|
|
184
|
-
token: options.token ?? this.gatewayToken.ensure(),
|
|
185
|
-
})
|
|
186
|
-
}
|
|
187
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { timingSafeEqual } from "node:crypto"
|
|
2
|
-
import type { MiddlewareHandler } from "hono"
|
|
3
|
-
import type { Env } from "@/gateway/factory"
|
|
4
|
-
|
|
5
|
-
type Deps = {
|
|
6
|
-
expected: string
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Verifies `Authorization: Bearer <token>` against the daemon's gateway token.
|
|
11
|
-
* Mounted on the routes that mutate listener state or expose detailed status.
|
|
12
|
-
* `/health` is intentionally left unauthenticated so the daemon manager can
|
|
13
|
-
* probe liveness without needing the token.
|
|
14
|
-
*/
|
|
15
|
-
export const requireBearerToken = (deps: Deps): MiddlewareHandler<Env> => {
|
|
16
|
-
return async (c, next) => {
|
|
17
|
-
const header = c.req.header("authorization") ?? ""
|
|
18
|
-
const match = header.match(/^Bearer\s+(.+)$/i)
|
|
19
|
-
const presented = match?.[1] ?? ""
|
|
20
|
-
|
|
21
|
-
if (!constantTimeEqual(presented, deps.expected)) {
|
|
22
|
-
return c.text("unauthorized", 401)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return await next()
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export const constantTimeEqual = (a: string, b: string): boolean => {
|
|
30
|
-
const bufA = Buffer.from(a, "utf-8")
|
|
31
|
-
const bufB = Buffer.from(b, "utf-8")
|
|
32
|
-
const maxLen = Math.max(bufA.length, bufB.length, 1)
|
|
33
|
-
const padA = Buffer.alloc(maxLen)
|
|
34
|
-
const padB = Buffer.alloc(maxLen)
|
|
35
|
-
|
|
36
|
-
bufA.copy(padA)
|
|
37
|
-
bufB.copy(padB)
|
|
38
|
-
|
|
39
|
-
// timingSafeEqual on equal-length padded buffers, then AND with length match
|
|
40
|
-
// so a length-only probe still requires the full comparison time.
|
|
41
|
-
const equal = timingSafeEqual(padA, padB)
|
|
42
|
-
|
|
43
|
-
return equal && bufA.length === bufB.length
|
|
44
|
-
}
|