@interactive-inc/claude-funnel 0.41.0 → 0.50.0

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 (55) hide show
  1. package/README.md +34 -9
  2. package/dist/bin.js +255 -256
  3. package/dist/claude-CB1WkV77.d.ts +115 -0
  4. package/dist/claude.d.ts +59 -0
  5. package/dist/claude.js +322 -0
  6. package/dist/{connector-diagnostic-log-OPpPi9V9.d.ts → connector-diagnostic-log-yTOojKUR.d.ts} +14 -14
  7. package/dist/{logger-Czli2OKh.js → connector-listener-DU54DN-f.js} +1 -9
  8. package/dist/connectors/discord.d.ts +3 -3
  9. package/dist/connectors/discord.js +2 -1
  10. package/dist/connectors/gh.d.ts +4 -3
  11. package/dist/connectors/gh.js +2 -1
  12. package/dist/connectors/schedule.d.ts +1 -1
  13. package/dist/connectors/schedule.js +2 -1
  14. package/dist/connectors/slack.d.ts +2 -2
  15. package/dist/connectors/slack.js +2 -1
  16. package/dist/discord-connector-schema-CBDyGdOI.js +21 -0
  17. package/dist/{discord-connector-schema-BeThExJp.js → discord-listener-_jSE3HsQ.js} +2 -22
  18. package/dist/file-system-BeOKXjlV.d.ts +26 -0
  19. package/dist/file-system-PWKKU7lA.js +9 -0
  20. package/dist/gateway/daemon.js +151 -152
  21. package/dist/gateway.d.ts +3 -0
  22. package/dist/gateway.js +2 -0
  23. package/dist/gh-connector-schema-eoTtHbY6.d.ts +14 -0
  24. package/dist/{gh-connector-schema-eYE4g77K.js → gh-connector-schema-o3Q1-ojL.js} +1 -176
  25. package/dist/gh-listener-DH-fClQm.js +178 -0
  26. package/dist/index-ChomoTZ5.d.ts +3404 -0
  27. package/dist/index.d.ts +11 -4214
  28. package/dist/index.js +195 -3869
  29. package/dist/local-config-json-schema-8IHjS4Q7.js +439 -0
  30. package/dist/local-config-sync-BdsrDZOu.d.ts +381 -0
  31. package/dist/local-config.d.ts +3 -0
  32. package/dist/local-config.js +3 -0
  33. package/dist/logger-BP6SisKt.js +9 -0
  34. package/dist/mcp-Dr-nIBwN.js +253 -0
  35. package/dist/memory-connector-diagnostic-log-CrW1ltLM.js +2245 -0
  36. package/dist/memory-token-prompter-B5FFCsGP.d.ts +57 -0
  37. package/dist/memory-token-prompter-CLerGsgM.js +61 -0
  38. package/dist/node-file-system-BcrmWN9I.js +48 -0
  39. package/dist/{gh-connector-schema-CQmEWzdV.d.ts → process-runner-DfniuWVU.d.ts} +1 -14
  40. package/dist/profiles-f0mNmEyP.d.ts +64 -0
  41. package/dist/profiles-wMRnjSid.js +129 -0
  42. package/dist/profiles.d.ts +2 -0
  43. package/dist/profiles.js +2 -0
  44. package/dist/schedule-connector-schema-iCI61gzU.js +31 -0
  45. package/dist/{schedule-listener-3M6WkH1Y.d.ts → schedule-listener-CUyUFFR1.d.ts} +22 -46
  46. package/dist/{schedule-connector-schema-CM-sRkac.js → schedule-listener-ePAjians.js} +3 -86
  47. package/dist/settings-reader-BSU6JyvM.d.ts +167 -0
  48. package/dist/settings-reader-DPqrpV7s.js +11 -0
  49. package/dist/settings-store-D2XSXTyt.js +186 -0
  50. package/dist/slack-connector-schema-BCNWluHM.js +32 -0
  51. package/dist/{slack-listener-9UdAn_ui.d.ts → slack-listener-Bv5xI9gC.d.ts} +31 -31
  52. package/dist/{slack-connector-schema-DDbSGPZn.js → slack-listener-ClQuHhEF.js} +2 -32
  53. package/package.json +16 -1
  54. /package/dist/{connector-adapter-VA6undzc.d.ts → connector-adapter-DKgsVuMH.d.ts} +0 -0
  55. /package/dist/{discord-connector-schema-DF4pL3Sc.d.ts → discord-connector-schema-R0Uu-3ns.d.ts} +0 -0
package/dist/index.d.ts CHANGED
@@ -1,4214 +1,11 @@
1
- import { n as FunnelConnectorAdapter, t as CallInput } from "./connector-adapter-VA6undzc.js";
2
- import { n as discordConnectorSchema, t as DiscordConnectorConfig } from "./discord-connector-schema-DF4pL3Sc.js";
3
- import { S as NotifyFn, _ as connectorConnectionEventSchema, a as ConnectorConnectionStatus, b as FunnelLogger, c as ConnectorProcessedQuery, d as ConnectorRawEvent, f as ConnectorRawQuery, g as StoredRawEvent, h as StoredProcessedEvent, i as ConnectorConnectionRecord, l as ConnectorProcessedRecord, m as StoredConnectionEvent, n as ConnectorConnectionEvent, o as ConnectorDiagnosticLog, p as ConnectorRawRecord, r as ConnectorConnectionQuery, s as ConnectorProcessedEvent, t as CONNECTOR_CONNECTION_STATUSES, u as ConnectorQuery, v as connectorProcessedEventSchema, x as FunnelConnectorListener, y as connectorRawEventSchema } from "./connector-diagnostic-log-OPpPi9V9.js";
4
- import { a as FunnelProcessRunner, c as RunResult, i as DetachOptions, n as ghConnectorSchema, o as ProcessSnapshot, r as AttachOptions, s as RunOptions, t as GhConnectorConfig } from "./gh-connector-schema-CQmEWzdV.js";
5
- import { a as FunnelFileSystem, c as ScheduleEntry, d as scheduleEntrySchema, i as FileStat, l as scheduleCatchupPolicySchema, n as ScheduleOnFired, o as ScheduleCatchupPolicy, s as ScheduleConnectorConfig, u as scheduleConnectorSchema } from "./schedule-listener-3M6WkH1Y.js";
6
- import { a as SlackProcessed, c as SlackRawEvent, d as slackConnectorSchema, i as FunnelSlackEventProcessor, l as SlackSkipReason, n as SlackOnAppCreated, o as SlackProcessedEmit, r as SlackPreprocessEvent, s as SlackProcessedSkip, u as SlackConnectorConfig } from "./slack-listener-9UdAn_ui.js";
7
- import { hc } from "hono/client";
8
- import { z } from "zod";
9
- import * as _$hono_factory0 from "hono/factory";
10
- import { Hono } from "hono";
11
- import { Server, ServerWebSocket } from "bun";
12
- import * as _$hono_utils_http_status0 from "hono/utils/http-status";
13
- import * as _$hono_utils_types0 from "hono/utils/types";
14
- import * as _$hono_hono_base0 from "hono/hono-base";
15
-
16
- //#region lib/connectors/connector-config-schema.d.ts
17
- declare const connectorConfigSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
18
- id: z.ZodString;
19
- name: z.ZodString;
20
- type: z.ZodLiteral<"slack">;
21
- botToken: z.ZodOptional<z.ZodString>;
22
- appToken: z.ZodOptional<z.ZodString>;
23
- botTokenEnv: z.ZodOptional<z.ZodString>;
24
- appTokenEnv: z.ZodOptional<z.ZodString>;
25
- minify: z.ZodDefault<z.ZodBoolean>;
26
- createdAt: z.ZodOptional<z.ZodString>;
27
- updatedAt: z.ZodOptional<z.ZodString>;
28
- }, z.core.$strip>, z.ZodObject<{
29
- id: z.ZodString;
30
- name: z.ZodString;
31
- type: z.ZodLiteral<"gh">;
32
- pollInterval: z.ZodOptional<z.ZodNumber>;
33
- createdAt: z.ZodOptional<z.ZodString>;
34
- updatedAt: z.ZodOptional<z.ZodString>;
35
- }, z.core.$strip>, z.ZodObject<{
36
- id: z.ZodString;
37
- name: z.ZodString;
38
- type: z.ZodLiteral<"discord">;
39
- botToken: z.ZodOptional<z.ZodString>;
40
- botTokenEnv: z.ZodOptional<z.ZodString>;
41
- createdAt: z.ZodOptional<z.ZodString>;
42
- updatedAt: z.ZodOptional<z.ZodString>;
43
- }, z.core.$strip>, z.ZodObject<{
44
- id: z.ZodString;
45
- name: z.ZodString;
46
- type: z.ZodLiteral<"schedule">;
47
- entries: z.ZodDefault<z.ZodArray<z.ZodObject<{
48
- id: z.ZodString;
49
- cron: z.ZodString;
50
- prompt: z.ZodString;
51
- enabled: z.ZodDefault<z.ZodBoolean>;
52
- catchupPolicy: z.ZodDefault<z.ZodEnum<{
53
- latest: "latest";
54
- all: "all";
55
- skip: "skip";
56
- }>>;
57
- }, z.core.$strip>>>;
58
- createdAt: z.ZodOptional<z.ZodString>;
59
- updatedAt: z.ZodOptional<z.ZodString>;
60
- }, z.core.$strip>], "type">;
61
- type ConnectorConfig = z.infer<typeof connectorConfigSchema>;
62
- type ConnectorType = ConnectorConfig["type"];
63
- //#endregion
64
- //#region lib/connectors/connector-factory.d.ts
65
- type SlackListenerOptions = {
66
- onAppCreated?: SlackOnAppCreated;
67
- preprocessEvent?: SlackPreprocessEvent;
68
- };
69
- type ScheduleListenerOptions = {
70
- onFired?: ScheduleOnFired;
71
- };
72
- type Deps$15 = {
73
- fs?: FunnelFileSystem;
74
- process?: FunnelProcessRunner;
75
- logger?: FunnelLogger;
76
- dir?: string; /** Diagnostic log of inbound connector traffic. Threaded into listeners that record raw/processed events. No-op when absent. */
77
- diagnosticLog?: ConnectorDiagnosticLog; /** Per-listener hooks for the slack connector type. Threaded into every Slack listener built by this factory. */
78
- slackListenerOptions?: SlackListenerOptions; /** Per-listener hooks for the schedule connector type. Threaded into every Schedule listener built by this factory. */
79
- scheduleListenerOptions?: ScheduleListenerOptions;
80
- };
81
- /**
82
- * Pure factory for per-type listeners and adapters. The factory has no CRUD
83
- * responsibility — connector configs live inside settings.json under their
84
- * channel, and FunnelChannels passes them in by value.
85
- *
86
- * `dir` is the funnel home (defaults to ~/.funnel); per-connector state files
87
- * land at `<dir>/channels/<channel-id>/connectors/<connector-id>/state.json`.
88
- *
89
- * Host integrations can supply per-type listener hooks via
90
- * `slackListenerOptions` / `scheduleListenerOptions` — e.g. to attach a
91
- * Bolt `app.action` handler or to drop one-shot schedule entries on fire.
92
- */
93
- declare class FunnelConnectorFactory {
94
- private readonly fs;
95
- private readonly process;
96
- private readonly logger;
97
- private readonly diagnosticLog;
98
- private readonly dir;
99
- private readonly slackListenerOptions;
100
- private readonly scheduleListenerOptions;
101
- constructor(deps?: Deps$15);
102
- createListener(channelId: string, config: ConnectorConfig): FunnelConnectorListener;
103
- createAdapter(config: ConnectorConfig): FunnelConnectorAdapter | null;
104
- connectorDir(channelId: string, connectorId: string): string;
105
- channelDir(channelId: string): string;
106
- }
107
- //#endregion
108
- //#region lib/engine/profiles/profile-channel-checker.d.ts
109
- /**
110
- * Read-side dependency that lets FunnelChannels ask whether a profile
111
- * references a given channel id, without depending on FunnelProfiles directly.
112
- */
113
- type ProfileChannelChecker = {
114
- hasChannelRef(channelId: string): boolean;
115
- };
116
- //#endregion
117
- //#region lib/engine/time/clock.d.ts
118
- /**
119
- * Time boundary. Default NodeFunnelClock returns `new Date()`; MemoryFunnelClock
120
- * is settable and `advance(ms)`-able for deterministic schedule / timeout tests.
121
- */
122
- declare abstract class FunnelClock {
123
- abstract now(): Date;
124
- millis(): number;
125
- iso(): string;
126
- }
127
- //#endregion
128
- //#region lib/engine/id/id-generator.d.ts
129
- /**
130
- * ID generator boundary. Default NodeFunnelIdGenerator wraps `crypto.randomUUID()`;
131
- * MemoryFunnelIdGenerator emits `<prefix>-1, <prefix>-2, ...` for deterministic tests.
132
- */
133
- declare abstract class FunnelIdGenerator {
134
- abstract generate(): string;
135
- }
136
- //#endregion
137
- //#region lib/engine/settings/settings-schema.d.ts
138
- /**
139
- * Routing mode when multiple WS clients are subscribed to the same channel.
140
- *
141
- * - `fanout` (default): every connected client receives every event. Right when each
142
- * subscriber has its own job (e.g., TUI mirrors, distinct Claude profiles each running
143
- * their own pipeline against the same source).
144
- * - `exclusive`: each event is delivered to exactly one connected client, picked
145
- * round-robin per channel. Right when subscribers are interchangeable workers and you
146
- * want each event handled once. Tap=all clients (TUI dashboard) always receive,
147
- * regardless of mode, so they can passively observe.
148
- */
149
- declare const channelDeliveryModeSchema: z.ZodEnum<{
150
- fanout: "fanout";
151
- exclusive: "exclusive";
152
- }>;
153
- type ChannelDeliveryMode = z.infer<typeof channelDeliveryModeSchema>;
154
- declare const channelConfigSchema: z.ZodObject<{
155
- id: z.ZodString;
156
- name: z.ZodString;
157
- delivery: z.ZodDefault<z.ZodEnum<{
158
- fanout: "fanout";
159
- exclusive: "exclusive";
160
- }>>;
161
- connectors: z.ZodDefault<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
162
- id: z.ZodString;
163
- name: z.ZodString;
164
- type: z.ZodLiteral<"slack">;
165
- botToken: z.ZodOptional<z.ZodString>;
166
- appToken: z.ZodOptional<z.ZodString>;
167
- botTokenEnv: z.ZodOptional<z.ZodString>;
168
- appTokenEnv: z.ZodOptional<z.ZodString>;
169
- minify: z.ZodDefault<z.ZodBoolean>;
170
- createdAt: z.ZodOptional<z.ZodString>;
171
- updatedAt: z.ZodOptional<z.ZodString>;
172
- }, z.core.$strip>, z.ZodObject<{
173
- id: z.ZodString;
174
- name: z.ZodString;
175
- type: z.ZodLiteral<"gh">;
176
- pollInterval: z.ZodOptional<z.ZodNumber>;
177
- createdAt: z.ZodOptional<z.ZodString>;
178
- updatedAt: z.ZodOptional<z.ZodString>;
179
- }, z.core.$strip>, z.ZodObject<{
180
- id: z.ZodString;
181
- name: z.ZodString;
182
- type: z.ZodLiteral<"discord">;
183
- botToken: z.ZodOptional<z.ZodString>;
184
- botTokenEnv: z.ZodOptional<z.ZodString>;
185
- createdAt: z.ZodOptional<z.ZodString>;
186
- updatedAt: z.ZodOptional<z.ZodString>;
187
- }, z.core.$strip>, z.ZodObject<{
188
- id: z.ZodString;
189
- name: z.ZodString;
190
- type: z.ZodLiteral<"schedule">;
191
- entries: z.ZodDefault<z.ZodArray<z.ZodObject<{
192
- id: z.ZodString;
193
- cron: z.ZodString;
194
- prompt: z.ZodString;
195
- enabled: z.ZodDefault<z.ZodBoolean>;
196
- catchupPolicy: z.ZodDefault<z.ZodEnum<{
197
- latest: "latest";
198
- all: "all";
199
- skip: "skip";
200
- }>>;
201
- }, z.core.$strip>>>;
202
- createdAt: z.ZodOptional<z.ZodString>;
203
- updatedAt: z.ZodOptional<z.ZodString>;
204
- }, z.core.$strip>], "type">>>;
205
- }, z.core.$strip>;
206
- type ChannelConfig = z.infer<typeof channelConfigSchema>;
207
- declare const profileConfigSchema: z.ZodObject<{
208
- id: z.ZodString;
209
- name: z.ZodString;
210
- path: z.ZodString;
211
- channelId: z.ZodString;
212
- options: z.ZodDefault<z.ZodArray<z.ZodString>>;
213
- env: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
214
- resume: z.ZodDefault<z.ZodBoolean>;
215
- sessionId: z.ZodOptional<z.ZodString>;
216
- }, z.core.$strip>;
217
- type ProfileConfig = z.infer<typeof profileConfigSchema>;
218
- declare const SETTINGS_VERSION = 1;
219
- declare const settingsSchema: z.ZodObject<{
220
- version: z.ZodDefault<z.ZodLiteral<1>>;
221
- channels: z.ZodDefault<z.ZodArray<z.ZodObject<{
222
- id: z.ZodString;
223
- name: z.ZodString;
224
- delivery: z.ZodDefault<z.ZodEnum<{
225
- fanout: "fanout";
226
- exclusive: "exclusive";
227
- }>>;
228
- connectors: z.ZodDefault<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
229
- id: z.ZodString;
230
- name: z.ZodString;
231
- type: z.ZodLiteral<"slack">;
232
- botToken: z.ZodOptional<z.ZodString>;
233
- appToken: z.ZodOptional<z.ZodString>;
234
- botTokenEnv: z.ZodOptional<z.ZodString>;
235
- appTokenEnv: z.ZodOptional<z.ZodString>;
236
- minify: z.ZodDefault<z.ZodBoolean>;
237
- createdAt: z.ZodOptional<z.ZodString>;
238
- updatedAt: z.ZodOptional<z.ZodString>;
239
- }, z.core.$strip>, z.ZodObject<{
240
- id: z.ZodString;
241
- name: z.ZodString;
242
- type: z.ZodLiteral<"gh">;
243
- pollInterval: z.ZodOptional<z.ZodNumber>;
244
- createdAt: z.ZodOptional<z.ZodString>;
245
- updatedAt: z.ZodOptional<z.ZodString>;
246
- }, z.core.$strip>, z.ZodObject<{
247
- id: z.ZodString;
248
- name: z.ZodString;
249
- type: z.ZodLiteral<"discord">;
250
- botToken: z.ZodOptional<z.ZodString>;
251
- botTokenEnv: z.ZodOptional<z.ZodString>;
252
- createdAt: z.ZodOptional<z.ZodString>;
253
- updatedAt: z.ZodOptional<z.ZodString>;
254
- }, z.core.$strip>, z.ZodObject<{
255
- id: z.ZodString;
256
- name: z.ZodString;
257
- type: z.ZodLiteral<"schedule">;
258
- entries: z.ZodDefault<z.ZodArray<z.ZodObject<{
259
- id: z.ZodString;
260
- cron: z.ZodString;
261
- prompt: z.ZodString;
262
- enabled: z.ZodDefault<z.ZodBoolean>;
263
- catchupPolicy: z.ZodDefault<z.ZodEnum<{
264
- latest: "latest";
265
- all: "all";
266
- skip: "skip";
267
- }>>;
268
- }, z.core.$strip>>>;
269
- createdAt: z.ZodOptional<z.ZodString>;
270
- updatedAt: z.ZodOptional<z.ZodString>;
271
- }, z.core.$strip>], "type">>>;
272
- }, z.core.$strip>>>;
273
- profiles: z.ZodDefault<z.ZodArray<z.ZodObject<{
274
- id: z.ZodString;
275
- name: z.ZodString;
276
- path: z.ZodString;
277
- channelId: z.ZodString;
278
- options: z.ZodDefault<z.ZodArray<z.ZodString>>;
279
- env: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
280
- resume: z.ZodDefault<z.ZodBoolean>;
281
- sessionId: z.ZodOptional<z.ZodString>;
282
- }, z.core.$strip>>>;
283
- }, z.core.$strip>;
284
- type Settings = z.infer<typeof settingsSchema>;
285
- //#endregion
286
- //#region lib/engine/settings/settings-reader.d.ts
287
- declare abstract class FunnelSettingsReader {
288
- abstract read(): Settings;
289
- abstract write(settings: Settings): void;
290
- }
291
- //#endregion
292
- //#region lib/engine/channels/channels.d.ts
293
- type Deps$14 = {
294
- store: FunnelSettingsReader;
295
- factory: FunnelConnectorFactory;
296
- profileChecker: ProfileChannelChecker;
297
- clock?: FunnelClock;
298
- idGenerator?: FunnelIdGenerator;
299
- };
300
- type ChannelConnectorView = ConnectorConfig & {
301
- channelId: string;
302
- channelName: string;
303
- };
304
- type AddConnectorInput = {
305
- type: "slack";
306
- name: string;
307
- botToken?: string;
308
- appToken?: string;
309
- botTokenEnv?: string;
310
- appTokenEnv?: string;
311
- minify?: boolean;
312
- } | {
313
- type: "gh";
314
- name: string;
315
- pollInterval?: number;
316
- } | {
317
- type: "discord";
318
- name: string;
319
- botToken?: string;
320
- botTokenEnv?: string;
321
- } | {
322
- type: "schedule";
323
- name: string;
324
- entries?: ScheduleEntry[];
325
- };
326
- /**
327
- * Channels own their connectors. Each channel has a stable id (UUID); the
328
- * `name` is the human-facing label used by the CLI. Connectors live nested
329
- * inside `channel.connectors[]`, so add/remove/rename are channel-scoped — no
330
- * global connector namespace exists. Token uniqueness is enforced across all
331
- * channels at add/update time so the same Slack/Discord credentials cannot
332
- * be registered twice.
333
- */
334
- declare class FunnelChannels {
335
- private readonly store;
336
- private readonly factory;
337
- private readonly profileChecker;
338
- private readonly clock;
339
- private readonly idGenerator;
340
- constructor(deps: Deps$14);
341
- list(): ChannelConfig[];
342
- get(name: string): ChannelConfig | null;
343
- getById(id: string): ChannelConfig | null;
344
- add(input: {
345
- name: string;
346
- delivery?: ChannelDeliveryMode;
347
- }): ChannelConfig;
348
- setDelivery(name: string, delivery: ChannelDeliveryMode): void;
349
- remove(name: string): void;
350
- rename(oldName: string, newName: string): void;
351
- listConnectors(channelName: string): ConnectorConfig[];
352
- getConnector(channelName: string, connectorName: string): ConnectorConfig | null;
353
- listAllConnectors(): ChannelConnectorView[];
354
- addConnector(channelName: string, input: AddConnectorInput): ConnectorConfig;
355
- private fromInput;
356
- removeConnector(channelName: string, connectorName: string): void;
357
- renameConnector(channelName: string, oldName: string, newName: string): void;
358
- updateSlackConnector(channelName: string, connectorName: string, fields: {
359
- botToken?: string;
360
- appToken?: string;
361
- botTokenEnv?: string;
362
- appTokenEnv?: string;
363
- }): void;
364
- updateGhConnector(channelName: string, connectorName: string, fields: {
365
- pollInterval?: number;
366
- }): void;
367
- updateDiscordConnector(channelName: string, connectorName: string, fields: {
368
- botToken?: string;
369
- botTokenEnv?: string;
370
- }): void;
371
- listScheduleEntries(channelName: string, connectorName: string): ScheduleEntry[];
372
- addScheduleEntry(channelName: string, connectorName: string, entry: Pick<ScheduleEntry, "cron" | "prompt"> & Partial<Pick<ScheduleEntry, "id" | "enabled" | "catchupPolicy">>): ScheduleEntry;
373
- removeScheduleEntry(channelName: string, connectorName: string, id: string): void;
374
- call(channelName: string, connectorName: string, input: CallInput): Promise<unknown>;
375
- createListener(channelName: string, connectorName: string): {
376
- config: ConnectorConfig;
377
- channelId: string;
378
- listener: FunnelConnectorListener;
379
- } | null;
380
- createAllListeners(): {
381
- config: ConnectorConfig;
382
- channelId: string;
383
- channelName: string;
384
- listener: FunnelConnectorListener;
385
- }[];
386
- private requireChannel;
387
- private replaceConnector;
388
- private assertNoTokenCollision;
389
- }
390
- //#endregion
391
- //#region lib/engine/error/on-funnel-error.d.ts
392
- /**
393
- * Host integration hook called when Funnel catches an exception that would
394
- * otherwise be silently swallowed (subscriber throw, listener start failure,
395
- * MCP forward failure, etc.). Pass `Sentry.captureException` from the host to
396
- * pipe these into your error reporter. Defaults to a no-op when omitted.
397
- *
398
- * `context` carries the component name and any extra metadata the caller had
399
- * at the catch site (channel / connector / subscriber id when available).
400
- */
401
- type OnFunnelError = (error: Error, context?: Record<string, unknown>) => void;
402
- //#endregion
403
- //#region lib/gateway/broadcaster.d.ts
404
- type ClientData = {
405
- /** Stable channel id (uuid) that the WS client subscribed to. */channel: string; /** Human-facing channel name resolved at upgrade time, kept for log readability. */
406
- channelName?: string | null; /** Connector names belonging to that channel; used by tap-all replay filtering. */
407
- connectors: string[];
408
- tapAll?: boolean; /** Routing mode resolved from channel config at upgrade time. Defaults to fanout. */
409
- delivery?: "fanout" | "exclusive";
410
- /**
411
- * Opaque per-client id declared at upgrade time (`?id=<subscriberId>`). When an
412
- * event carries `meta.target`, only the client whose `subscriberId` equals it
413
- * receives the event among that channel's regular subscribers. Targeted delivery
414
- * is how a publisher addresses one specific instance (e.g. a single agent
415
- * session) without every subscriber having to receive and discard it.
416
- */
417
- subscriberId?: string;
418
- };
419
- type BroadcastEvent = {
420
- content: string;
421
- meta?: Record<string, string>;
422
- };
423
- type ReplayableEvent = BroadcastEvent & {
424
- offset: number;
425
- };
426
- type BroadcastSubscriber = (event: ReplayableEvent) => void;
427
- /**
428
- * Optional persistent replay source. Wired in by the gateway-server with a
429
- * `FunnelEventLog` (SQLite-backed by default) so reconnects across daemon
430
- * restarts can recover events older than the in-memory buffer via an indexed
431
- * `seq > since` range scan.
432
- */
433
- type ReplaySource = {
434
- loadSince(since: number): ReplayableEvent[];
435
- };
436
- type Deps$13 = {
437
- logger?: FunnelLogger; /** Host hook for surfacing subscriber-throw exceptions. Defaults to no-op. */
438
- onError?: OnFunnelError;
439
- maxBufferedBytes?: number;
440
- now?: () => number; /** Number of recent events kept in the in-memory replay buffer. */
441
- replayBufferSize?: number; /** Hard byte cap on replay buffer payloads. Older events are evicted FIFO until under this cap. */
442
- replayBufferMaxBytes?: number; /** Persistent replay source consulted when the in-memory buffer cannot satisfy `since`. */
443
- persistentReplay?: ReplaySource;
444
- };
445
- type BroadcasterMetrics = {
446
- clients: number;
447
- subscribers: number;
448
- eventsBroadcast: number;
449
- droppedSlowClients: number;
450
- lastBroadcastAt: string | null; /** Latest emitted offset. Clients can `?since=<offset>` to ask for events strictly after this point. */
451
- latestOffset: number; /** Oldest offset still held in the replay buffer. Older values cannot be replayed and trigger a full resync. */
452
- oldestReplayableOffset: number | null;
453
- };
454
- /**
455
- * In-process pub/sub for connector events.
456
- *
457
- * Two outbound paths:
458
- * - WS clients connected via the gateway's `/ws` endpoint, scoped per channel
459
- * - In-process subscribers registered via `subscribe()` (programmable API)
460
- *
461
- * Backpressure: if a WS client's `bufferedAmount` exceeds `maxBufferedBytes`
462
- * (default 1 MiB), the client is closed with code 1009 and dropped from the
463
- * registry to keep one slow consumer from blocking the daemon.
464
- *
465
- * Replay: every emitted event gets a strictly increasing `offset`. The latest
466
- * `replayBufferSize` events are kept in memory; reconnecting WS clients can
467
- * pass `?since=<offset>` and the broadcaster resends matching events before
468
- * resuming the live stream. The in-memory ring covers short reconnects;
469
- * older history is served from the event log wired in as `persistentReplay`.
470
- */
471
- declare class FunnelBroadcaster {
472
- private readonly clients;
473
- private readonly subscribers;
474
- private readonly logger;
475
- private readonly onError;
476
- private readonly maxBufferedBytes;
477
- private readonly now;
478
- private readonly replayBufferSize;
479
- private readonly replayBufferMaxBytes;
480
- private readonly replayBuffer;
481
- private readonly persistentReplay;
482
- private readonly exclusiveCursor;
483
- private replayBufferBytes;
484
- private eventsBroadcast;
485
- private droppedSlowClients;
486
- private lastBroadcastAt;
487
- private latestOffset;
488
- constructor(deps?: Deps$13);
489
- getMetrics(): BroadcasterMetrics;
490
- /**
491
- * Returns events with offset > since, filtered by the connector subscription
492
- * rules of `data`. Used at WS upgrade time when the client passes `?since=<offset>`.
493
- *
494
- * Two-tier lookup:
495
- * 1. The in-memory ring buffer (covers short reconnects, last `replayBufferSize` events).
496
- * 2. If `since` predates the oldest in-memory entry and a persistent replay source
497
- * is wired in (SQLite by default), the gap is filled from it. This covers reconnects
498
- * across daemon restarts where the in-memory buffer was lost.
499
- *
500
- * Result is sorted ascending by offset and de-duplicated against the in-memory buffer.
501
- */
502
- replaySince(since: number, data: ClientData): ReplayableEvent[];
503
- private matchesClient;
504
- /**
505
- * Returns the list of WS clients that should receive `event`. Tap=all clients always
506
- * receive (passive observation). For each per-channel group:
507
- * - fanout → every matching client receives
508
- * - exclusive → exactly one client receives, picked round-robin per channel
509
- *
510
- * `meta.target` narrows the regular (non-tap) recipient set first via
511
- * `matchesClient`: only the subscriber whose `subscriberId` equals `target`
512
- * stays in the running, so a targeted event reaches one named instance while
513
- * still being observable by tap=all clients.
514
- */
515
- private pickRecipients;
516
- addClient(ws: ServerWebSocket<unknown>, data: ClientData): void;
517
- removeClient(ws: ServerWebSocket<unknown>): void;
518
- getClientCount(): number;
519
- listChannels(): {
520
- channel: string;
521
- connectors: string[];
522
- }[];
523
- subscribe(handler: BroadcastSubscriber): () => void;
524
- broadcast(content: string, meta?: Record<string, string>): ReplayableEvent;
525
- /** Forward-seed the offset counter (used at startup from the persisted event store). */
526
- seedLatestOffset(offset: number): void;
527
- }
528
- //#endregion
529
- //#region lib/gateway/listener-supervisor.d.ts
530
- type ConnectorRegistry = {
531
- listAllConnectors(): ChannelConnectorView[];
532
- createListener(channelName: string, connectorName: string): {
533
- config: ConnectorConfig;
534
- channelId: string;
535
- listener: FunnelConnectorListener;
536
- } | null;
537
- };
538
- type SupervisorNotify = (channelName: string, connectorName: string, content: string, meta?: Record<string, string>) => Promise<void>;
539
- type Deps$12 = {
540
- channels: ConnectorRegistry;
541
- notify: SupervisorNotify;
542
- logger?: FunnelLogger; /** Host hook for surfacing listener lifecycle exceptions. Defaults to no-op. */
543
- onError?: OnFunnelError;
544
- healthCheckIntervalMs?: number;
545
- maxBackoffMs?: number;
546
- sleep?: (ms: number) => Promise<void>;
547
- now?: () => number;
548
- };
549
- type ListenerEntryStatus = {
550
- channelName: string;
551
- channelId: string;
552
- name: string;
553
- type: ConnectorConfig["type"];
554
- alive: boolean;
555
- events: number;
556
- errors: number;
557
- failureCount: number;
558
- lastEventAt: string | null;
559
- };
560
- /**
561
- * Owns the running listener instances and their lifecycle.
562
- *
563
- * Lives in the gateway process and is the only place that calls
564
- * `listener.start()` / `listener.stop()`. Each entry is keyed by
565
- * `${channelName}/${connectorName}` so the same connector name can exist in
566
- * multiple channels without colliding.
567
- *
568
- * Periodically polls each running listener's `isAlive()` and auto-restarts
569
- * dead listeners with exponential backoff (1s, 2s, 4s, ... capped). Resets
570
- * the backoff counter on successful restart.
571
- */
572
- declare class FunnelListenerSupervisor {
573
- private readonly channels;
574
- private readonly notify;
575
- private readonly logger;
576
- private readonly onError;
577
- private readonly running;
578
- private readonly failureCounts;
579
- private readonly stats;
580
- private readonly healthCheckIntervalMs;
581
- private readonly maxBackoffMs;
582
- private readonly sleep;
583
- private readonly now;
584
- private healthCheckTimer;
585
- private healthCheckInFlight;
586
- constructor(deps: Deps$12);
587
- static keyOf(channelName: string, connectorName: string): string;
588
- isRunning(channelName: string, connectorName: string): boolean;
589
- list(): ListenerEntryStatus[];
590
- start(channelName: string, connectorName: string): Promise<{
591
- ok: boolean;
592
- reason?: string;
593
- }>;
594
- stop(channelName: string, connectorName: string): Promise<{
595
- ok: boolean;
596
- reason?: string;
597
- }>;
598
- restart(channelName: string, connectorName: string): Promise<{
599
- ok: boolean;
600
- reason?: string;
601
- }>;
602
- startAll(): Promise<void>;
603
- stopAll(): Promise<void>;
604
- private ensureStats;
605
- private recordEvent;
606
- private recordError;
607
- private startHealthCheck;
608
- private stopHealthCheck;
609
- private runHealthCheck;
610
- private recoverDead;
611
- }
612
- //#endregion
613
- //#region lib/gateway/routes/route-deps.d.ts
614
- type GatewayEmitInput = {
615
- channel: string;
616
- connector?: string;
617
- content: string;
618
- meta?: Record<string, string>;
619
- };
620
- type GatewayRouteDeps = {
621
- selfPid: number;
622
- broadcaster: FunnelBroadcaster;
623
- supervisor: FunnelListenerSupervisor;
624
- channels: FunnelChannels;
625
- uptimeMs: () => number;
626
- emit: (input: GatewayEmitInput) => {
627
- offset: number;
628
- };
629
- };
630
- //#endregion
631
- //#region lib/gateway/factory.d.ts
632
- type Env$1 = {
633
- Variables: {
634
- deps: GatewayRouteDeps;
635
- };
636
- };
637
- //#endregion
638
- //#region lib/gateway/routes/index.d.ts
639
- /**
640
- * Top-level Hono app for the gateway daemon. Mounts every HTTP endpoint flat
641
- * (the WebSocket /ws upgrade is handled directly by `Bun.serve`). Deps come
642
- * from the `deps` variable set by `FunnelGatewayServer`'s middleware — same
643
- * shape as CLI's `c.var.funnel`.
644
- */
645
- type GatewayApp = ReturnType<typeof buildGatewayRoutes>;
646
- declare function buildGatewayRoutes(): _$hono_hono_base0.HonoBase<Env$1, {
647
- "/health": {
648
- $get: {
649
- input: {};
650
- output: {
651
- ok: true;
652
- pid: number;
653
- clients: number;
654
- listeners: {
655
- channelName: string;
656
- channelId: string;
657
- name: string;
658
- type: ConnectorConfig["type"];
659
- alive: boolean;
660
- events: number;
661
- errors: number;
662
- failureCount: number;
663
- lastEventAt: string | null;
664
- }[];
665
- };
666
- outputFormat: "json";
667
- status: _$hono_utils_http_status0.ContentfulStatusCode;
668
- };
669
- };
670
- } & {
671
- "/status": {
672
- $get: {
673
- input: {};
674
- output: {
675
- ok: true;
676
- pid: number;
677
- uptimeMs: number;
678
- clients: {
679
- channel: string;
680
- connectors: string[];
681
- }[];
682
- listeners: {
683
- channelName: string;
684
- channelId: string;
685
- name: string;
686
- type: ConnectorConfig["type"];
687
- alive: boolean;
688
- events: number;
689
- errors: number;
690
- failureCount: number;
691
- lastEventAt: string | null;
692
- }[];
693
- broadcaster: {
694
- clients: number;
695
- subscribers: number;
696
- eventsBroadcast: number;
697
- droppedSlowClients: number;
698
- lastBroadcastAt: string | null;
699
- latestOffset: number;
700
- oldestReplayableOffset: number | null;
701
- };
702
- };
703
- outputFormat: "json";
704
- status: _$hono_utils_http_status0.ContentfulStatusCode;
705
- };
706
- };
707
- } & {
708
- "/debug": {
709
- $get: {
710
- input: {};
711
- output: {
712
- pid: number;
713
- uptimeMs: number;
714
- eventsBroadcast: number;
715
- channels: {
716
- id: string;
717
- name: string;
718
- connectors: string[];
719
- listener: {
720
- alive: boolean;
721
- events: number;
722
- errors: number;
723
- lastEventAt: string | null;
724
- } | null;
725
- claudeClients: number;
726
- recentEvents: {
727
- seq: number | null;
728
- ts: number | null;
729
- type: string;
730
- outcome: string;
731
- payload: string | null;
732
- payloadParsed: {
733
- [x: string]: _$hono_utils_types0.JSONValue;
734
- } | null;
735
- preview: string | null;
736
- }[];
737
- connectionErrors: {
738
- ts: number | null;
739
- type: string;
740
- status: string;
741
- detail: string | null;
742
- }[];
743
- diagnosis: {
744
- status: "ok" | "warn" | "error";
745
- message: string;
746
- nextActions: string[];
747
- rootCause: string | null;
748
- };
749
- }[];
750
- };
751
- outputFormat: "json";
752
- status: _$hono_utils_http_status0.ContentfulStatusCode;
753
- };
754
- };
755
- } & {
756
- "/listeners": {
757
- $get: {
758
- input: {};
759
- output: {
760
- listeners: {
761
- channelName: string;
762
- channelId: string;
763
- name: string;
764
- type: ConnectorConfig["type"];
765
- alive: boolean;
766
- events: number;
767
- errors: number;
768
- failureCount: number;
769
- lastEventAt: string | null;
770
- }[];
771
- };
772
- outputFormat: "json";
773
- status: _$hono_utils_http_status0.ContentfulStatusCode;
774
- };
775
- };
776
- } & {
777
- "/listeners/:channel/:connector/start": {
778
- $post: {
779
- input: {
780
- param: {
781
- channel: string;
782
- connector: string;
783
- };
784
- };
785
- output: {
786
- ok: boolean;
787
- reason: string;
788
- };
789
- outputFormat: "json";
790
- status: 400;
791
- } | {
792
- input: {
793
- param: {
794
- channel: string;
795
- connector: string;
796
- };
797
- };
798
- output: {
799
- ok: boolean;
800
- reason?: string | undefined;
801
- };
802
- outputFormat: "json";
803
- status: 200 | 400;
804
- };
805
- };
806
- } & {
807
- "/listeners/:channel/:connector": {
808
- $delete: {
809
- input: {
810
- param: {
811
- channel: string;
812
- connector: string;
813
- };
814
- };
815
- output: {
816
- ok: boolean;
817
- reason: string;
818
- };
819
- outputFormat: "json";
820
- status: 400;
821
- } | {
822
- input: {
823
- param: {
824
- channel: string;
825
- connector: string;
826
- };
827
- };
828
- output: {
829
- ok: boolean;
830
- reason?: string | undefined;
831
- };
832
- outputFormat: "json";
833
- status: 200 | 400;
834
- };
835
- };
836
- } & {
837
- "/listeners/:channel/:connector/restart": {
838
- $post: {
839
- input: {
840
- param: {
841
- channel: string;
842
- connector: string;
843
- };
844
- };
845
- output: {
846
- ok: boolean;
847
- reason: string;
848
- };
849
- outputFormat: "json";
850
- status: 400;
851
- } | {
852
- input: {
853
- param: {
854
- channel: string;
855
- connector: string;
856
- };
857
- };
858
- output: {
859
- ok: boolean;
860
- reason?: string | undefined;
861
- };
862
- outputFormat: "json";
863
- status: 200 | 400;
864
- };
865
- };
866
- } & {
867
- "/channels/:channel/connectors/:connector/call": {
868
- $post: {
869
- input: {
870
- param: {
871
- channel: string;
872
- connector: string;
873
- };
874
- };
875
- output: {
876
- ok: boolean;
877
- reason: string;
878
- };
879
- outputFormat: "json";
880
- status: 400;
881
- } | {
882
- input: {
883
- param: {
884
- channel: string;
885
- connector: string;
886
- };
887
- };
888
- output: {
889
- ok: true;
890
- result: _$hono_utils_types0.JSONValue;
891
- };
892
- outputFormat: "json";
893
- status: _$hono_utils_http_status0.ContentfulStatusCode;
894
- };
895
- };
896
- } & {
897
- "/channels/:channel/publish": {
898
- $post: {
899
- input: {
900
- param: {
901
- channel: string;
902
- };
903
- } & {
904
- json: {
905
- content: string;
906
- meta?: Record<string, string> | undefined;
907
- connector?: string | undefined;
908
- target?: string | undefined;
909
- };
910
- };
911
- output: {
912
- ok: boolean;
913
- reason: string;
914
- };
915
- outputFormat: "json";
916
- status: 400;
917
- } | {
918
- input: {
919
- param: {
920
- channel: string;
921
- };
922
- } & {
923
- json: {
924
- content: string;
925
- meta?: Record<string, string> | undefined;
926
- connector?: string | undefined;
927
- target?: string | undefined;
928
- };
929
- };
930
- output: {
931
- ok: boolean;
932
- reason: string;
933
- };
934
- outputFormat: "json";
935
- status: 400;
936
- } | {
937
- input: {
938
- param: {
939
- channel: string;
940
- };
941
- } & {
942
- json: {
943
- content: string;
944
- meta?: Record<string, string> | undefined;
945
- connector?: string | undefined;
946
- target?: string | undefined;
947
- };
948
- };
949
- output: {
950
- ok: true;
951
- offset: number;
952
- };
953
- outputFormat: "json";
954
- status: _$hono_utils_http_status0.ContentfulStatusCode;
955
- };
956
- };
957
- }, "/", "/channels/:channel/publish">;
958
- //#endregion
959
- //#region lib/engine/claude/gateway-controller.d.ts
960
- type GatewayController = {
961
- isRunning(): boolean;
962
- start(options?: {
963
- caffeinate?: boolean;
964
- }): Promise<boolean>;
965
- };
966
- //#endregion
967
- //#region lib/engine/mcp/mcp.d.ts
968
- declare const FUNNEL_MCP_COMMAND = "bun";
969
- declare const FUNNEL_MCP_ARGS: string[];
970
- declare const FUNNEL_MCP_NAME = "funnel";
971
- type Deps$11 = {
972
- fs?: FunnelFileSystem;
973
- };
974
- /**
975
- * Installs/uninstalls the funnel MCP entry into a target repository's
976
- * `.mcp.json`. Detects an existing entry by command match so renaming is
977
- * preserved across re-installs.
978
- */
979
- declare class FunnelMcp {
980
- private readonly fs;
981
- constructor(deps?: Deps$11);
982
- install(repoPath: string): void;
983
- uninstall(repoPath: string): void;
984
- findInstalledName(cwd: string): string | null;
985
- private findServerName;
986
- private isFunnelEntry;
987
- private readConfig;
988
- private writeConfig;
989
- }
990
- //#endregion
991
- //#region lib/engine/profiles/profiles.d.ts
992
- type Deps$10 = {
993
- store: FunnelSettingsReader;
994
- idGenerator: FunnelIdGenerator;
995
- };
996
- /**
997
- * Named launch presets for `fnl claude`. Each profile bundles a working
998
- * directory, the channel id its Claude instance subscribes to, and the launch
999
- * recipe (`options` prepended to the claude argv, `env` layered under the
1000
- * process, `resume` toggling session reuse). Implements ProfileChannelChecker
1001
- * so FunnelChannels can refuse to remove a channel that is still referenced.
1002
- *
1003
- * Each profile has a stable `id` (uuid) minted at `add`. That id is the unit
1004
- * everything internal keys on — the PID file, the resumable session id — so a
1005
- * rename never strands either. `name` is purely the CLI/TUI handle; the CRUD
1006
- * methods here take it because that is what the user types, but resolve to the
1007
- * id before touching id-keyed state. The first array entry is the default
1008
- * profile; `asDefault` reorders to put one first.
1009
- *
1010
- * `channelId` always stores the channel's stable id (uuid). CLI surfaces
1011
- * resolve channel name → id before calling `add`/`update` here.
1012
- */
1013
- declare class FunnelProfiles {
1014
- private readonly store;
1015
- private readonly idGenerator;
1016
- constructor(deps: Deps$10);
1017
- list(): ProfileConfig[];
1018
- get(name: string): ProfileConfig | null;
1019
- getById(id: string): ProfileConfig | null;
1020
- getDefault(): ProfileConfig | null;
1021
- add(input: {
1022
- name: string;
1023
- path: string;
1024
- channelId: string;
1025
- options?: string[];
1026
- env?: Record<string, string>;
1027
- resume?: boolean;
1028
- }): void;
1029
- remove(name: string): void;
1030
- rename(oldName: string, newName: string): void;
1031
- asDefault(name: string): void;
1032
- hasChannelRef(channelId: string): boolean;
1033
- /** Resumable claude session id last launched by this profile (by id), or null. */
1034
- getSessionId(id: string): string | null;
1035
- /** Records the claude session id this profile launched, overwriting any prior one. */
1036
- setSessionId(id: string, sessionId: string): void;
1037
- update(name: string, fields: Partial<Omit<ProfileConfig, "name">>): void;
1038
- }
1039
- //#endregion
1040
- //#region lib/engine/claude/claude.d.ts
1041
- type LaunchOptions = {
1042
- channel: string;
1043
- cwd?: string;
1044
- userArgs?: string[];
1045
- /** Stable id of the launching profile (uuid). Keys the singleton PID file and
1046
- * the resumable session. Absent for a profile-less launch (raw `--channel`),
1047
- * which never enforces singleton-ness and never resumes. */
1048
- profileId?: string; /** Args prepended to the claude argv (typically a profile's recipe). Defaults to none. */
1049
- options?: string[]; /** Env vars layered under the launched claude process. process.env wins on collision. */
1050
- env?: Record<string, string>;
1051
- /** Whether to inject a `--session-id`/`--resume` for this profile.
1052
- * Defaults to false: resuming is opt-in and only meaningful for a profile,
1053
- * since the persisted session is owned by the profile (by id). A launch
1054
- * without a profile always starts a fresh session regardless of this flag. */
1055
- resume?: boolean;
1056
- /** Invoked synchronously after the child claude process has been spawned, with its PID.
1057
- * Useful for hosts that need to register the spawned process before it exits
1058
- * (e.g. multi-session registries that track per-claude liveness). */
1059
- onSpawned?: (pid: number) => void;
1060
- /** Whether to install the funnel MCP entry into `.mcp.json` (default: true).
1061
- * Set to false when the host already provides its own MCP server entry and
1062
- * does not need the funnel binary as an MCP endpoint. */
1063
- installMcp?: boolean;
1064
- };
1065
- type Deps$9 = {
1066
- channels: FunnelChannels;
1067
- mcp: FunnelMcp;
1068
- gateway: GatewayController;
1069
- profiles: FunnelProfiles;
1070
- process?: FunnelProcessRunner;
1071
- fs?: FunnelFileSystem;
1072
- idGenerator?: FunnelIdGenerator;
1073
- logger?: FunnelLogger;
1074
- dir?: string;
1075
- };
1076
- /**
1077
- * Launches Claude Code with funnel pre-wired: ensures the gateway is running,
1078
- * installs the funnel MCP into the target repo's `.mcp.json` if missing,
1079
- * injects `FUNNEL_CHANNEL_ID` into the child env, and writes a per-profile
1080
- * PID file to enforce singleton launches.
1081
- */
1082
- declare class FunnelClaude {
1083
- private readonly channels;
1084
- private readonly mcp;
1085
- private readonly gateway;
1086
- private readonly profiles;
1087
- private readonly process;
1088
- private readonly fs;
1089
- private readonly idGenerator;
1090
- private readonly logger;
1091
- private readonly pidDir;
1092
- constructor(deps: Deps$9);
1093
- launch(options: LaunchOptions): Promise<number>;
1094
- isRunning(profileId: string): boolean;
1095
- private pidPath;
1096
- private readPid;
1097
- private writePidFile;
1098
- private removePidFile;
1099
- private installCleanup;
1100
- private isProcessAlive;
1101
- private buildArgs;
1102
- /**
1103
- * Decides whether funnel should resume an existing claude session or start
1104
- * a freshly minted one. Backs off when the user already passed a
1105
- * session-shaping flag, since combining them would either confuse claude
1106
- * or override the explicit user intent.
1107
- *
1108
- * The session is owned by the profile (by id), not by cwd: two profiles
1109
- * pointing at the same repo each keep their own conversation, and a launch
1110
- * with no profile never resumes — so an unrelated session in the same repo
1111
- * can't bleed in. The channel never enters into it; sessions belong to the
1112
- * launch layer (profiles), keeping the transport layer ignorant of them.
1113
- *
1114
- * A persisted id is only resumed when its session jsonl still exists on
1115
- * disk. claude errors out on `--resume <id>` for a missing conversation, and
1116
- * a persisted id can outlive its jsonl (claude pruned it, or the very first
1117
- * launch was aborted after the id was written but before the jsonl
1118
- * appeared). When the file is gone we mint a fresh session instead, which
1119
- * overwrites the dangling entry — so the store self-heals.
1120
- */
1121
- private resolveSession;
1122
- /**
1123
- * Mirrors claude's session storage path
1124
- * (`<config-dir>/projects/<cwd-with-slashes-as-dashes>/<id>.jsonl`) to check
1125
- * whether a recorded session still exists AND is non-empty. Reads the same
1126
- * `CLAUDE_CONFIG_DIR` the child will run under so the check matches reality; a
1127
- * wrong guess can only ever produce a false negative (start fresh), never a
1128
- * bad resume.
1129
- */
1130
- private sessionFileExists;
1131
- private buildEnv;
1132
- }
1133
- //#endregion
1134
- //#region lib/engine/local-config/local-config-schema.d.ts
1135
- declare const connectorSpecSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
1136
- type: z.ZodLiteral<"slack">;
1137
- name: z.ZodString;
1138
- minify: z.ZodOptional<z.ZodBoolean>;
1139
- }, z.core.$strip>, z.ZodObject<{
1140
- type: z.ZodLiteral<"discord">;
1141
- name: z.ZodString;
1142
- }, z.core.$strip>, z.ZodObject<{
1143
- type: z.ZodLiteral<"gh">;
1144
- name: z.ZodString;
1145
- pollInterval: z.ZodOptional<z.ZodNumber>;
1146
- }, z.core.$strip>, z.ZodObject<{
1147
- type: z.ZodLiteral<"schedule">;
1148
- name: z.ZodString;
1149
- }, z.core.$strip>], "type">;
1150
- type ConnectorSpec = z.infer<typeof connectorSpecSchema>;
1151
- declare const channelSpecSchema: z.ZodObject<{
1152
- name: z.ZodString;
1153
- connectors: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
1154
- type: z.ZodLiteral<"slack">;
1155
- name: z.ZodString;
1156
- minify: z.ZodOptional<z.ZodBoolean>;
1157
- }, z.core.$strip>, z.ZodObject<{
1158
- type: z.ZodLiteral<"discord">;
1159
- name: z.ZodString;
1160
- }, z.core.$strip>, z.ZodObject<{
1161
- type: z.ZodLiteral<"gh">;
1162
- name: z.ZodString;
1163
- pollInterval: z.ZodOptional<z.ZodNumber>;
1164
- }, z.core.$strip>, z.ZodObject<{
1165
- type: z.ZodLiteral<"schedule">;
1166
- name: z.ZodString;
1167
- }, z.core.$strip>], "type">>>;
1168
- }, z.core.$strip>;
1169
- type ChannelSpec = z.infer<typeof channelSpecSchema>;
1170
- declare const profileSpecSchema: z.ZodObject<{
1171
- name: z.ZodString;
1172
- channel: z.ZodString;
1173
- options: z.ZodOptional<z.ZodArray<z.ZodString>>;
1174
- env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
1175
- resume: z.ZodOptional<z.ZodBoolean>;
1176
- }, z.core.$strip>;
1177
- type ProfileSpec = z.infer<typeof profileSpecSchema>;
1178
- declare const localConfigSchema: z.ZodObject<{
1179
- $schema: z.ZodOptional<z.ZodString>;
1180
- id: z.ZodOptional<z.ZodString>;
1181
- channels: z.ZodArray<z.ZodObject<{
1182
- name: z.ZodString;
1183
- connectors: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
1184
- type: z.ZodLiteral<"slack">;
1185
- name: z.ZodString;
1186
- minify: z.ZodOptional<z.ZodBoolean>;
1187
- }, z.core.$strip>, z.ZodObject<{
1188
- type: z.ZodLiteral<"discord">;
1189
- name: z.ZodString;
1190
- }, z.core.$strip>, z.ZodObject<{
1191
- type: z.ZodLiteral<"gh">;
1192
- name: z.ZodString;
1193
- pollInterval: z.ZodOptional<z.ZodNumber>;
1194
- }, z.core.$strip>, z.ZodObject<{
1195
- type: z.ZodLiteral<"schedule">;
1196
- name: z.ZodString;
1197
- }, z.core.$strip>], "type">>>;
1198
- }, z.core.$strip>>;
1199
- profiles: z.ZodOptional<z.ZodArray<z.ZodObject<{
1200
- name: z.ZodString;
1201
- channel: z.ZodString;
1202
- options: z.ZodOptional<z.ZodArray<z.ZodString>>;
1203
- env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
1204
- resume: z.ZodOptional<z.ZodBoolean>;
1205
- }, z.core.$strip>>>;
1206
- }, z.core.$strip>;
1207
- type LocalConfig = z.infer<typeof localConfigSchema>;
1208
- declare const LOCAL_CONFIG_FILENAME = "funnel.json";
1209
- //#endregion
1210
- //#region lib/engine/local-config/local-config.d.ts
1211
- type Deps$8 = {
1212
- fs: FunnelFileSystem;
1213
- };
1214
- /**
1215
- * Reads `funnel.json` from a directory. Returns `null` when the file is
1216
- * absent so callers can fall through to other resolution paths (default
1217
- * profile, help). Throws on present-but-invalid files so misconfiguration
1218
- * surfaces loudly instead of silently launching the wrong channel.
1219
- */
1220
- declare class FunnelLocalConfig {
1221
- private readonly fs;
1222
- constructor(deps: Deps$8);
1223
- read(cwd: string): LocalConfig | null;
1224
- private assertProfilesValid;
1225
- }
1226
- //#endregion
1227
- //#region lib/engine/token-prompter/token-prompter.d.ts
1228
- /**
1229
- * Asks the user for a secret value on stdin. Used as a last resort when a
1230
- * funnel.json token field is absent and not present in `~/.funnel`. The Node
1231
- * implementation refuses to prompt when stdin is not a TTY so non-interactive
1232
- * launches (CI, agent spawning agent, daemons) fail fast instead of hanging.
1233
- */
1234
- declare abstract class FunnelTokenPrompter {
1235
- abstract promptSecret(label: string): Promise<string>;
1236
- }
1237
- //#endregion
1238
- //#region lib/engine/local-config/local-config-sync.d.ts
1239
- type Deps$7 = {
1240
- channels: FunnelChannels;
1241
- prompter: FunnelTokenPrompter;
1242
- };
1243
- type ConnectorSyncOutcome = {
1244
- name: string;
1245
- changed: boolean;
1246
- };
1247
- type LocalConfigSyncResult = {
1248
- touched: ConnectorSyncOutcome[];
1249
- removed: string[];
1250
- };
1251
- /**
1252
- * Reconciles a single funnel.json channel spec with `~/.funnel/settings.json`.
1253
- * The spec is the source of truth for the channel it declares:
1254
- *
1255
- * - missing channel → created
1256
- * - declared connector matched by name → tokens reconciled
1257
- * - declared connector matched by token in the same channel under a
1258
- * different name → renamed in place (then tokens reconciled)
1259
- * - declared connector with no match → added
1260
- * - any connector left in the channel that the spec did not touch → removed
1261
- *
1262
- * Removal only fires when the channel spec has a `connectors` field. An
1263
- * absent field means "do not manage connectors from here" and leaves
1264
- * everything in `~/.funnel` alone. Other channels in funnel.json (not
1265
- * passed to this call) are untouched.
1266
- *
1267
- * Returns the per-connector change set so callers (e.g. the claude launcher)
1268
- * can drive listener hot-reload on the gateway after settings are written.
1269
- */
1270
- declare class FunnelLocalConfigSync {
1271
- private readonly channels;
1272
- private readonly prompter;
1273
- constructor(deps: Deps$7);
1274
- ensure(channel: ChannelSpec): Promise<LocalConfigSyncResult>;
1275
- private ensureConnector;
1276
- private ensureSlack;
1277
- private ensureDiscord;
1278
- private ensureGh;
1279
- private ensureSchedule;
1280
- private findExistingSlack;
1281
- private findExistingDiscord;
1282
- private removeExtras;
1283
- /**
1284
- * Decides how a single token slot is stored in settings.json. funnel.json
1285
- * never carries tokens, so the only sources are a value already in
1286
- * settings.json (carried over verbatim, whichever form it was — literal or an
1287
- * `env`-var reference set via the CLI) or, on first sync, a TTY prompt for a
1288
- * literal (throws when stdin is not a TTY). Either way the secret lands in the
1289
- * repo-scoped settings, never in the repo itself.
1290
- */
1291
- private resolveSlot;
1292
- }
1293
- //#endregion
1294
- //#region lib/engine/local-config/local-config-writer.d.ts
1295
- type Deps$6 = {
1296
- fs: FunnelFileSystem;
1297
- };
1298
- /**
1299
- * The one path that mutates the repo-committed funnel.json, and it only ever
1300
- * inserts `id`. On first launch a repo has no `id`; funnel generates one and
1301
- * writes it back here so future launches resolve the same `~/.funnel/projects/<id>/`.
1302
- * Idempotent — a no-op once `id` is present. Kept separate from the read-only
1303
- * FunnelLocalConfig so reads stay side-effect free.
1304
- */
1305
- declare class FunnelLocalConfigWriter {
1306
- private readonly fs;
1307
- constructor(deps: Deps$6);
1308
- ensureId(cwd: string, id: string): void;
1309
- }
1310
- //#endregion
1311
- //#region lib/gateway/publish-schema.d.ts
1312
- /**
1313
- * Shared schema for `POST /channels/:channel/publish` — used by both the
1314
- * gateway route handler (input validation) and the CLI / programmable client
1315
- * (request shape). The route resolves `channel` from the path; this body
1316
- * covers everything else.
1317
- */
1318
- declare const publishRequestSchema: z.ZodObject<{
1319
- content: z.ZodString;
1320
- meta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
1321
- connector: z.ZodOptional<z.ZodString>;
1322
- target: z.ZodOptional<z.ZodString>;
1323
- }, z.core.$strip>;
1324
- type PublishRequest = z.infer<typeof publishRequestSchema>;
1325
- declare const publishResponseSchema: z.ZodObject<{
1326
- ok: z.ZodLiteral<true>;
1327
- offset: z.ZodNumber;
1328
- }, z.core.$strip>;
1329
- type PublishResponse = z.infer<typeof publishResponseSchema>;
1330
- type PublishResult = {
1331
- state: "ok";
1332
- offset: number;
1333
- } | {
1334
- state: "offline";
1335
- } | {
1336
- state: "error";
1337
- reason: string;
1338
- };
1339
- //#endregion
1340
- //#region lib/gateway/channel-publisher.d.ts
1341
- type Deps$5 = {
1342
- port: number;
1343
- isDaemonRunning: () => boolean; /** Returns the daemon's gateway token, or null if unavailable. Sent as `Authorization: Bearer`. */
1344
- getToken?: () => string | null;
1345
- };
1346
- /**
1347
- * HTTP client for `POST /channels/:channel/publish` on a running gateway
1348
- * daemon. Returns `{ state: "offline" }` when the daemon isn't up so callers
1349
- * can branch without exceptions, mirroring `FunnelListenersClient`.
1350
- */
1351
- declare class FunnelChannelPublisher {
1352
- private readonly port;
1353
- private readonly isDaemonRunning;
1354
- private readonly getToken;
1355
- constructor(deps: Deps$5);
1356
- publish(channelName: string, request: PublishRequest): Promise<PublishResult>;
1357
- private authHeaders;
1358
- }
1359
- //#endregion
1360
- //#region lib/gateway/funnel-event-log.d.ts
1361
- /**
1362
- * Replayable event payload persisted by the gateway. Domain events the
1363
- * broadcaster emits to WS clients land here so reconnects across daemon
1364
- * restarts can be served from disk. System events (gateway start, channel
1365
- * connected, etc.) are routed to `FunnelLogger` instead — they never go
1366
- * through this log, which keeps the offset space clean for replay.
1367
- */
1368
- declare const funnelEventSchema: z.ZodObject<{
1369
- type: z.ZodString;
1370
- content: z.ZodString;
1371
- channel_id: z.ZodNullable<z.ZodString>;
1372
- connector_id: z.ZodNullable<z.ZodString>;
1373
- meta: z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodString>>;
1374
- }, z.core.$strip>;
1375
- type FunnelEvent = z.infer<typeof funnelEventSchema>;
1376
- /** One broadcast event to persist, carrying the offset the broadcaster assigned. */
1377
- type FunnelEventRecord = {
1378
- content: string;
1379
- channelId: string | null;
1380
- connectorId: string | null;
1381
- meta: Record<string, string> | null;
1382
- offset: number;
1383
- };
1384
- /**
1385
- * Durable, append-only log of broadcaster events keyed by the offset the
1386
- * broadcaster assigns. The gateway persists every domain event here, and
1387
- * across restarts it both seeds the broadcaster's offset counter
1388
- * (`findMaxOffset`) and serves reconnect replay (`loadSince`) from it.
1389
- *
1390
- * `loadSince` is the only method the broadcaster itself needs, which makes
1391
- * any implementation assignable to the broadcaster's narrow `ReplaySource`.
1392
- *
1393
- * Implementations:
1394
- * - `SqliteFunnelEventLog` — the default; durable across daemon restarts.
1395
- * - `MemoryFunnelEventLog` — an in-process double for tests and embedders
1396
- * that do not need durability (replay is lost when the process exits).
1397
- */
1398
- declare abstract class FunnelEventLog {
1399
- abstract record(record: FunnelEventRecord): void;
1400
- abstract loadSince(since: number): ReplayableEvent[];
1401
- abstract findMaxOffset(): number;
1402
- /** Drop every stored event and reclaim the file. The broadcaster's in-memory
1403
- * offset counter is unaffected, so offsets keep increasing after a clear. */
1404
- abstract clear(): void;
1405
- abstract close(): void;
1406
- }
1407
- //#endregion
1408
- //#region lib/gateway/gateway.d.ts
1409
- type Deps$4 = {
1410
- process?: FunnelProcessRunner;
1411
- fs?: FunnelFileSystem;
1412
- clock?: FunnelClock;
1413
- dir?: string;
1414
- tmpDir?: string;
1415
- port?: number;
1416
- sleep?: (ms: number) => Promise<void>;
1417
- };
1418
- /**
1419
- * Manages the gateway daemon as a separate process via PID file.
1420
- * Use `start()` to spawn `bun daemon.ts` in the background and `stop()` to
1421
- * terminate it. For an in-process gateway, use `Funnel.gatewayServer` instead.
1422
- */
1423
- declare class FunnelGateway {
1424
- private readonly process;
1425
- private readonly fs;
1426
- private readonly clock;
1427
- private readonly dir;
1428
- private readonly pidFile;
1429
- private readonly gatewayLog;
1430
- private readonly tmpDir;
1431
- private readonly port;
1432
- private readonly sleep;
1433
- constructor(deps?: Deps$4);
1434
- isRunning(): boolean;
1435
- getStatus(): {
1436
- running: boolean;
1437
- pid: number | null;
1438
- port: number;
1439
- };
1440
- start(options?: {
1441
- caffeinate?: boolean;
1442
- }): Promise<boolean>;
1443
- buildStartCommand(gatewayScript: string, options?: {
1444
- caffeinate?: boolean;
1445
- }): string[];
1446
- stop(): Promise<boolean>;
1447
- restart(options?: {
1448
- onlyIfRunning?: boolean;
1449
- caffeinate?: boolean;
1450
- }): Promise<{
1451
- ok: boolean;
1452
- wasRunning: boolean;
1453
- stopped: boolean;
1454
- started: boolean;
1455
- }>;
1456
- getGatewayLog(): string;
1457
- getPort(): number;
1458
- private readPid;
1459
- private removePid;
1460
- private isProcessAlive;
1461
- }
1462
- //#endregion
1463
- //#region lib/gateway/gateway-server.d.ts
1464
- type Deps$3 = {
1465
- channels: FunnelChannels;
1466
- settings: FunnelSettingsReader;
1467
- port?: number; /** Bind address for `Bun.serve`. Defaults to `127.0.0.1` (loopback only). Set to `0.0.0.0` to expose on the network. */
1468
- hostname?: string; /** SQLite event store file path. Parent directory is created on demand. Defaults to `<os.tmpdir()>/funnel/events.db`. Ignored when `eventLog` is supplied. */
1469
- dbPath?: string; /** Durable replay log. Defaults to a `SqliteFunnelEventLog` at `dbPath`. Inject a `MemoryFunnelEventLog` (or any `FunnelEventLog`) to swap or disable persistence. */
1470
- eventLog?: FunnelEventLog;
1471
- process?: FunnelProcessRunner;
1472
- clock?: FunnelClock;
1473
- logger?: FunnelLogger; /** Host hook for surfacing internal exceptions (broadcaster / supervisor). Defaults to no-op. */
1474
- onError?: OnFunnelError;
1475
- selfPid?: number; /** Funnel home dir, used to scope kill-competing to daemons rooted at the same dir. Defaults to FUNNEL_DIR. */
1476
- dir?: string;
1477
- killCompetingSlack?: boolean; /** Bearer token required for `/listeners*`, `/status`, and `/ws`. Empty string disables auth (tests only). */
1478
- token?: string;
1479
- /**
1480
- * Additional hono app mounted before the built-in gateway routes.
1481
- * Use to embed host-specific endpoints (e.g. an MCP route, custom `/api/*`).
1482
- * Host routes are mounted first; built-in `/listeners`, `/status`,
1483
- * `/channels`, `/health` are mounted after and take precedence on conflict.
1484
- */
1485
- extraRoutes?: Hono<Env$1>;
1486
- };
1487
- type WsData = {
1488
- /** Stable channel id (uuid) the client subscribed to. "" for tap-all clients. */channel: string; /** Resolved channel name (for log readability). null for tap-all or unknown. */
1489
- channelName: string | null; /** Connector names belonging to that channel; used by tap-all replay filtering. */
1490
- connectors: string[];
1491
- tapAll?: boolean; /** Routing mode for this channel; resolved at upgrade time from settings. */
1492
- delivery: "fanout" | "exclusive"; /** Opaque client id from `?id=<subscriberId>`; lets publishers target this client via `meta.target`. */
1493
- subscriberId?: string; /** Replay any events with offset strictly greater than this on open, then resume the live stream. */
1494
- since?: number;
1495
- };
1496
- /**
1497
- * In-process gateway: runs `Bun.serve` (HTTP + WebSocket /ws), boots connector
1498
- * listeners through `FunnelListenerSupervisor`, fans events out via
1499
- * `FunnelBroadcaster`, and persists them via a `FunnelEventLog` (SQLite by default).
1500
- * System events (gateway lifecycle, connect/disconnect) flow to `FunnelLogger`
1501
- * instead — keeping the SQLite seq space exclusive to broadcaster traffic so
1502
- * the broadcaster's offset counter and `getMaxSeq()` stay aligned without
1503
- * per-event coordination. Exposes `/listeners` HTTP for runtime
1504
- * start/stop/restart of individual connectors.
1505
- */
1506
- declare class FunnelGatewayServer {
1507
- private readonly channels;
1508
- private readonly settings;
1509
- private readonly port;
1510
- private readonly hostname;
1511
- private readonly dbPath;
1512
- private readonly process?;
1513
- private readonly logger;
1514
- private readonly onError;
1515
- private readonly selfPid;
1516
- private readonly dir;
1517
- private readonly killCompetingSlack;
1518
- private readonly token;
1519
- private readonly broadcaster;
1520
- private readonly eventLog;
1521
- private readonly supervisor;
1522
- private readonly nowMs;
1523
- private readonly extraRoutes;
1524
- private startedAt;
1525
- private server;
1526
- constructor(deps: Deps$3);
1527
- start(): Promise<Server<WsData>>;
1528
- stop(): Promise<void>;
1529
- getStatus(): {
1530
- clients: number;
1531
- channels: {
1532
- channel: string;
1533
- connectors: string[];
1534
- }[];
1535
- };
1536
- getBroadcaster(): FunnelBroadcaster;
1537
- getSupervisor(): FunnelListenerSupervisor;
1538
- getEventLog(): FunnelEventLog;
1539
- /**
1540
- * Register an in-process observer for every broadcast event. Fires after
1541
- * the event is fanned out to WS clients and recorded in the event log.
1542
- * Returns an unsubscribe function. Only meaningful in-process (embedded
1543
- * hosts / `new Funnel(...)` running their own gateway-server); a separate
1544
- * daemon process cannot be observed this way — use a WS client for that.
1545
- */
1546
- onEvent(handler: BroadcastSubscriber): () => void;
1547
- private handleFetch;
1548
- private handleWsOpen;
1549
- private handleWsClose;
1550
- private logServerStarted;
1551
- private buildApp;
1552
- /**
1553
- * Reads the bearer token from the WebSocket upgrade request. Accepts:
1554
- * - `Sec-WebSocket-Protocol: funnel.token.<value>` (preferred — header, never logged in URLs)
1555
- * - `Authorization: Bearer <value>` (also header-based)
1556
- * Returns true on a constant-time match against the daemon token.
1557
- */
1558
- private tokenMatchesUpgrade;
1559
- private resolveChannel;
1560
- private bootListeners;
1561
- /**
1562
- * Broadcast `content` to subscribers of `channel`, persisting the event in
1563
- * the SQLite store and stamping `meta.channel{,Id}` / `meta.connector{,Id}`
1564
- * when they resolve. Used by both the connector-listener path (via the
1565
- * supervisor's `notify` callback) and the public `/channels/:channel/publish`
1566
- * route. Returns the assigned event offset.
1567
- */
1568
- emit(input: {
1569
- channel: string;
1570
- connector?: string;
1571
- content: string;
1572
- meta?: Record<string, string>;
1573
- }): {
1574
- offset: number;
1575
- };
1576
- private lookupChannelId;
1577
- private lookupConnectorId;
1578
- }
1579
- //#endregion
1580
- //#region lib/gateway/gateway-token.d.ts
1581
- type Deps$2 = {
1582
- fs?: FunnelFileSystem;
1583
- dir?: string;
1584
- generate?: () => string;
1585
- };
1586
- /**
1587
- * Reads / generates the gateway daemon token used to authenticate
1588
- * `/listeners*`, `/status`, and `/ws` connections.
1589
- *
1590
- * Token file: `<dir>/gateway.token` (default `~/.funnel/gateway.token`),
1591
- * written with mode 0600. Clients on the same machine as the daemon read
1592
- * the file directly; the token never leaves the user's home directory.
1593
- */
1594
- declare class FunnelGatewayToken {
1595
- private readonly fs;
1596
- private readonly path;
1597
- private readonly generate;
1598
- constructor(deps?: Deps$2);
1599
- read(): string | null;
1600
- /**
1601
- * Returns the existing token or, if missing, generates one and writes it with mode 0600.
1602
- *
1603
- * NOTE: not atomic — two concurrent `ensure()` calls (e.g., `fnl gateway start` racing
1604
- * itself before the PID lock is acquired) could each generate independent tokens. The
1605
- * gateway PID file makes this practically a non-issue; if you need stronger guarantees,
1606
- * take a file lock around this call externally.
1607
- */
1608
- ensure(): string;
1609
- getPath(): string;
1610
- }
1611
- declare const DEFAULT_GATEWAY_TOKEN_PATH: string;
1612
- //#endregion
1613
- //#region lib/gateway/listeners-client.d.ts
1614
- type Deps$1 = {
1615
- port: number;
1616
- isDaemonRunning: () => boolean; /** Returns the daemon's gateway token, or null if unavailable. Sent as `Authorization: Bearer`. */
1617
- getToken?: () => string | null;
1618
- };
1619
- declare const listenerEntrySchema: z.ZodObject<{
1620
- channelName: z.ZodString;
1621
- channelId: z.ZodString;
1622
- name: z.ZodString;
1623
- type: z.ZodString;
1624
- alive: z.ZodBoolean;
1625
- }, z.core.$strip>;
1626
- type ListenerEntry = z.infer<typeof listenerEntrySchema>;
1627
- type ListenerOpResult = {
1628
- state: "ok";
1629
- } | {
1630
- state: "offline";
1631
- } | {
1632
- state: "error";
1633
- reason: string;
1634
- };
1635
- type ListListenersResult = {
1636
- state: "ok";
1637
- listeners: ListenerEntry[];
1638
- } | {
1639
- state: "offline";
1640
- } | {
1641
- state: "error";
1642
- reason: string;
1643
- };
1644
- /**
1645
- * HTTP client for listener operations on a running gateway daemon.
1646
- *
1647
- * Returns `{ state: "offline" }` when the daemon isn't running so callers
1648
- * (CLI hot-reload paths) can treat that as a no-op without parsing strings.
1649
- * Pair this with `FunnelGateway` (process control) for the full picture.
1650
- */
1651
- declare class FunnelListenersClient {
1652
- private readonly port;
1653
- private readonly isDaemonRunning;
1654
- private readonly getToken;
1655
- constructor(deps: Deps$1);
1656
- list(): Promise<ListListenersResult>;
1657
- start(channelName: string, connectorName: string): Promise<ListenerOpResult>;
1658
- stop(channelName: string, connectorName: string): Promise<ListenerOpResult>;
1659
- restart(channelName: string, connectorName: string): Promise<ListenerOpResult>;
1660
- private path;
1661
- private authHeaders;
1662
- private call;
1663
- }
1664
- //#endregion
1665
- //#region lib/gateway/funnel-debug.d.ts
1666
- type FunnelDebugReport = {
1667
- gateway: {
1668
- running: boolean;
1669
- pid: number | null;
1670
- port: number | null;
1671
- uptimeMs: number | null;
1672
- };
1673
- channels: Array<{
1674
- name: string;
1675
- connectors: string[];
1676
- listener: {
1677
- alive: boolean;
1678
- events: number;
1679
- errors: number;
1680
- lastEventAt: string | null;
1681
- } | null;
1682
- claudeConnected: boolean;
1683
- claudeClientCount: number;
1684
- }>;
1685
- recentEvents: Array<{
1686
- ts: number;
1687
- outcome: string;
1688
- payload: string | null;
1689
- preview: string | null;
1690
- }> | null;
1691
- };
1692
- //#endregion
1693
- //#region lib/funnel.d.ts
1694
- type Props$8 = {
1695
- /** Settings persistence (channels with nested connectors / profiles). Defaults to a FunnelSettingsStore rooted at `dir`. */store?: FunnelSettingsReader; /** Filesystem boundary. Replace with MemoryFunnelFileSystem to sandbox all disk I/O. */
1696
- fs?: FunnelFileSystem; /** Process runner used by gateway / claude / gh listener. Replace with MemoryFunnelProcessRunner for tests. */
1697
- process?: FunnelProcessRunner; /** Logger flowed into every facet. Replace with MemoryFunnelLogger or NoopFunnelLogger to silence/inspect. */
1698
- logger?: FunnelLogger; /** Clock used by schedule listener, gh poll watermarks, and gateway timeouts. */
1699
- clock?: FunnelClock; /** ID generator for channel and connector ids. Use MemoryFunnelIdGenerator for deterministic tests. */
1700
- idGenerator?: FunnelIdGenerator; /** Prompter used by FunnelLocalConfigSync when funnel.json omits a token. Defaults to a TTY-only stdin prompter. */
1701
- tokenPrompter?: FunnelTokenPrompter; /** Funnel home directory (settings.json + per-channel/per-connector dirs). Defaults to ~/.funnel. */
1702
- dir?: string; /** Temp / runtime directory (gateway logs and PID adjacent files). Defaults to `<os.tmpdir()>/funnel`. */
1703
- tmpDir?: string;
1704
- /**
1705
- * Host integration hooks for Slack listeners — `onAppCreated` for attaching
1706
- * Bolt `app.action` handlers, `preprocessEvent` for transforming/dropping
1707
- * raw Slack events before the built-in processor sees them.
1708
- */
1709
- slackListenerOptions?: SlackListenerOptions;
1710
- /**
1711
- * Host integration hooks for Schedule listeners — `onFired` is invoked after
1712
- * each successful fire, useful for dropping one-shot entries.
1713
- */
1714
- scheduleListenerOptions?: ScheduleListenerOptions;
1715
- /**
1716
- * Diagnostic log of inbound connector traffic (raw events before filtering
1717
- * and the processor's verdict after). Threaded into listeners that record
1718
- * it. Only the gateway daemon injects a `SqliteConnectorDiagnosticLog`; everywhere
1719
- * else this stays absent and recording is a no-op.
1720
- */
1721
- diagnosticLog?: ConnectorDiagnosticLog;
1722
- /**
1723
- * Called when Funnel catches an exception that would otherwise be silently
1724
- * swallowed (subscriber throw, listener start/stop failure, etc.). Pass
1725
- * `Sentry.captureException` from the host to surface these. Defaults to no-op.
1726
- */
1727
- onError?: OnFunnelError;
1728
- /**
1729
- * Gateway daemon port. Passed directly to FunnelGateway so hosts can override
1730
- * the default (9742) without setting FUNNEL_PORT in the environment.
1731
- */
1732
- port?: number;
1733
- };
1734
- /**
1735
- * Facade exposing every funnel facet as a getter.
1736
- *
1737
- * The same `Funnel` is used by the CLI and as a programmable library.
1738
- * All side-effecting boundaries (filesystem, process, logger, clock, id, paths) are
1739
- * injectable via `Props` — passing memory implementations gives a fully sandboxed
1740
- * Funnel that touches no real disk, processes, or wall-clock time.
1741
- *
1742
- * Connectors live nested inside their owning channel (channels[].connectors[]),
1743
- * so connector CRUD is reached via `funnel.channels.addConnector(...)` etc.
1744
- *
1745
- * @example
1746
- * ```ts
1747
- * const funnel = new Funnel({})
1748
- * const channel = funnel.channels.add({ name: "inbox" })
1749
- * funnel.channels.addConnector("inbox", { type: "slack", name: "ops", botToken, appToken })
1750
- * await funnel.gatewayServer({ port: 9742 }).start()
1751
- * ```
1752
- */
1753
- declare class Funnel {
1754
- private readonly props;
1755
- private readonly memos;
1756
- constructor(props?: Props$8);
1757
- /**
1758
- * Sandboxed Funnel wired with in-memory implementations for every IO boundary.
1759
- * Touches no real disk, processes, wall-clock time, or UUIDs — safe for tests
1760
- * and ad-hoc experiments. Override individual fields by passing them in `props`.
1761
- */
1762
- static inMemory(props?: Props$8): Funnel;
1763
- /** Resolved on-disk paths the facade will read/write when methods are called. Pure compute, not memoized. */
1764
- get paths(): {
1765
- dir: string;
1766
- tmpDir: string;
1767
- settings: string;
1768
- };
1769
- /** Filesystem boundary. Defaults to NodeFunnelFileSystem. */
1770
- get fs(): FunnelFileSystem;
1771
- /** Process runner boundary. Defaults to NodeFunnelProcessRunner. */
1772
- get process(): FunnelProcessRunner;
1773
- /** Logger boundary. Optional — when no logger is injected, every facet's `this.logger?.x` call is a silent no-op. Production entry points (cli, daemon) inject a NodeFunnelLogger. */
1774
- get logger(): FunnelLogger | undefined;
1775
- /** Clock boundary. Defaults to NodeFunnelClock. */
1776
- get clock(): FunnelClock;
1777
- /**
1778
- * Error hook. Forwards Funnel-internal exceptions that would otherwise be
1779
- * swallowed. Defaults to a no-op when no host hook was passed.
1780
- */
1781
- get onError(): OnFunnelError;
1782
- /** ID generator boundary. Defaults to NodeFunnelIdGenerator. */
1783
- get idGenerator(): FunnelIdGenerator;
1784
- /** Settings reader. If not injected, a FunnelSettingsStore rooted at `dir` is created. */
1785
- get store(): FunnelSettingsReader;
1786
- /** Pure factory that constructs per-type listeners and adapters from connector configs. */
1787
- get factory(): FunnelConnectorFactory;
1788
- /** Channel CRUD + nested connector CRUD + schedule entries + listener/adapter dispatch. */
1789
- get channels(): FunnelChannels;
1790
- /** Launch profiles (named presets for `fnl claude`: path + sub-agent + channel id). */
1791
- get profiles(): FunnelProfiles;
1792
- /** Reads `funnel.json` from a cwd. `fnl claude` consults it before falling back to the default profile. */
1793
- get localConfig(): FunnelLocalConfig;
1794
- /** Writes the stable `id` into funnel.json on first launch so state can be scoped to `~/.funnel/projects/<id>/`. */
1795
- get localConfigWriter(): FunnelLocalConfigWriter;
1796
- /** Secret prompter. Defaults to a TTY-only stdin reader; tests inject MemoryFunnelTokenPrompter. */
1797
- get tokenPrompter(): FunnelTokenPrompter;
1798
- /** Reconciles funnel.json's channel + connectors with `~/.funnel/settings.json` on launch. */
1799
- get localConfigSync(): FunnelLocalConfigSync;
1800
- /** funnel MCP installer (writes/removes `.mcp.json` entries in target repos). */
1801
- get mcp(): FunnelMcp;
1802
- /** Launch Claude Code with a channel injected via env, MCP installed, gateway ensured. */
1803
- get claude(): FunnelClaude;
1804
- /** Gateway daemon controller (PID-file, start/stop the separate `bun daemon.ts` process). */
1805
- get gateway(): FunnelGateway;
1806
- /** Read / generate the daemon's gateway token (mode 0600 file under `dir`). */
1807
- get gatewayToken(): FunnelGatewayToken;
1808
- /**
1809
- * HTTP client for `POST /channels/:channel/publish` on the running gateway
1810
- * daemon. Use it to push arbitrary content into a channel from outside any
1811
- * connector. Returns `{ state: "offline" }` if the daemon isn't up.
1812
- */
1813
- get publisher(): FunnelChannelPublisher;
1814
- /**
1815
- * HTTP client for listener operations on the running gateway daemon.
1816
- * Returns `{ state: "offline" }` when the daemon is offline so hot-reload
1817
- * paths stay write-only without parsing strings.
1818
- */
1819
- get listeners(): FunnelListenersClient;
1820
- /**
1821
- * In-process gateway server. Unlike `gateway.start()` (which spawns a daemon),
1822
- * this returns a class that runs `Bun.serve` + listeners inside the current process —
1823
- * useful for tests, embedding, or custom hosts.
1824
- */
1825
- gatewayServer(options?: {
1826
- port?: number; /** Bind address. Defaults to `127.0.0.1` (loopback only). Set to `0.0.0.0` to expose on the network. */
1827
- hostname?: string;
1828
- dbPath?: string;
1829
- killCompetingSlack?: boolean; /** Override the auth token. Defaults to the persisted gateway.token. Pass "" to disable auth (tests). */
1830
- token?: string; /** Durable replay log. Defaults to a SqliteFunnelEventLog at dbPath; inject a MemoryFunnelEventLog (or any FunnelEventLog) to swap or disable persistence. */
1831
- eventLog?: FunnelEventLog;
1832
- /**
1833
- * Additional hono app mounted before the built-in gateway routes.
1834
- * Use to embed host-specific endpoints (e.g. an MCP route, custom `/api/*`).
1835
- * Host routes are mounted first; built-in `/listeners`, `/status`,
1836
- * `/channels`, `/health` are mounted after and take precedence on conflict.
1837
- */
1838
- extraRoutes?: Hono<Env$1>;
1839
- }): FunnelGatewayServer;
1840
- debug(channelName?: string): Promise<FunnelDebugReport>;
1841
- gatewayClient(): ReturnType<typeof hc<GatewayApp>>;
1842
- }
1843
- //#endregion
1844
- //#region lib/engine/mcp/channel-server.d.ts
1845
- type ChannelServerOptions = {
1846
- /** Funnel home directory (settings.json + gateway.token). Defaults to ~/.funnel. */dir?: string; /** Gateway base URL. Defaults to `$FUNNEL_GATEWAY_URL` or `http://127.0.0.1:<port>`. */
1847
- gatewayUrl?: string; /** Channel id to subscribe to. Defaults to `$FUNNEL_CHANNEL_ID`. */
1848
- channelId?: string; /** Auth token. Defaults to `$FUNNEL_GATEWAY_TOKEN` then `<dir>/gateway.token`. */
1849
- token?: string;
1850
- };
1851
- declare const startChannelServer: (options?: ChannelServerOptions) => Promise<void>;
1852
- //#endregion
1853
- //#region lib/engine/local-config/local-config-json-schema.d.ts
1854
- /**
1855
- * Generates the JSON Schema (draft 2020-12) for `funnel.json`. Useful for
1856
- * `$schema` references in committed `funnel.json` files so editors can give
1857
- * autocomplete and validation for channels[] (transport) and profiles[]
1858
- * (launch recipe) without anyone hand-maintaining a separate schema.
1859
- */
1860
- declare const funnelJsonSchema: () => Record<string, unknown>;
1861
- //#endregion
1862
- //#region lib/engine/settings/settings-store.d.ts
1863
- /**
1864
- * Resolves the funnel home dir. Defaults to `~/.funnel`, overridable via
1865
- * `FUNNEL_DIR` so a funnel.json-scoped launch can point everything (settings,
1866
- * gateway pid/token, claude pids) at a repo-local `<repo>/.funnel` and never
1867
- * touch the global home. Read at call time, not module load, so a daemon
1868
- * spawned with the env set resolves the override.
1869
- */
1870
- declare function resolveFunnelDir(): string;
1871
- declare const DEFAULT_GATEWAY_PORT = 9742;
1872
- /**
1873
- * Resolves the gateway port. Defaults to 9742 — the port a programmatically
1874
- * hosted gateway (`new Funnel().gatewayServer()`) uses. The `funnel` CLI entry
1875
- * sets `FUNNEL_PORT` to a distinct default so a CLI launch never collides with
1876
- * an embedding app's gateway on 9742. Read at call time so a daemon spawned
1877
- * with the env set resolves the override.
1878
- */
1879
- declare function resolveFunnelPort(): number;
1880
- declare const FUNNEL_DIR: string;
1881
- declare const SETTINGS_PATH: string;
1882
- type Deps = {
1883
- path?: string;
1884
- fs?: FunnelFileSystem;
1885
- idGenerator?: FunnelIdGenerator;
1886
- };
1887
- declare class FunnelSettingsStore extends FunnelSettingsReader {
1888
- private readonly path;
1889
- private readonly fs;
1890
- private readonly idGenerator;
1891
- constructor(deps?: Deps);
1892
- read(): Settings;
1893
- private looksLikeLegacy;
1894
- /**
1895
- * Non-destructive migration for profiles written before `id` existed. Mints a
1896
- * uuid for each profile lacking one and returns whether anything was minted, so
1897
- * `read` can persist it immediately — a profile id must be STABLE across reads,
1898
- * otherwise `setSessionId` (a second read) sees a different id and can't match
1899
- * the one the launch used. Mutates `parsed` in place (freshly JSON-parsed).
1900
- */
1901
- private backfillProfileIds;
1902
- write(settings: Settings): void;
1903
- }
1904
- //#endregion
1905
- //#region lib/engine/settings/mock-settings-reader.d.ts
1906
- declare const createSettings: (partial?: Partial<Settings>) => Settings;
1907
- declare class MockFunnelSettingsReader extends FunnelSettingsReader {
1908
- private state;
1909
- constructor(initial?: Partial<Settings>);
1910
- read(): Settings;
1911
- write(settings: Settings): void;
1912
- }
1913
- //#endregion
1914
- //#region lib/engine/fs/node-file-system.d.ts
1915
- declare class NodeFunnelFileSystem extends FunnelFileSystem {
1916
- constructor();
1917
- existsSync(path: string): boolean;
1918
- readFileSync(path: string): string;
1919
- writeFileSync(path: string, data: string): void;
1920
- writeSecretFileSync(path: string, data: string): void;
1921
- appendFileSync(path: string, data: string): void;
1922
- unlink(path: string): void;
1923
- mkdirSync(path: string, options?: {
1924
- recursive?: boolean;
1925
- }): void;
1926
- readdirSync(path: string): string[];
1927
- statSync(path: string): FileStat;
1928
- }
1929
- //#endregion
1930
- //#region lib/engine/fs/memory-file-system.d.ts
1931
- type Props$7 = {
1932
- dirs?: string[];
1933
- files?: Record<string, string>;
1934
- mtimes?: Record<string, number>;
1935
- modes?: Record<string, number>;
1936
- now?: () => number;
1937
- };
1938
- declare class MemoryFunnelFileSystem extends FunnelFileSystem {
1939
- private readonly dirs;
1940
- private readonly files;
1941
- private readonly mtimes;
1942
- private readonly modes;
1943
- private readonly now;
1944
- constructor(props?: Props$7);
1945
- existsSync(path: string): boolean;
1946
- readFileSync(path: string): string;
1947
- writeFileSync(path: string, data: string): void;
1948
- writeSecretFileSync(path: string, data: string): void;
1949
- appendFileSync(path: string, data: string): void;
1950
- unlink(path: string): void;
1951
- mkdirSync(path: string, options?: {
1952
- recursive?: boolean;
1953
- }): void;
1954
- readdirSync(path: string): string[];
1955
- statSync(path: string): FileStat;
1956
- setMtime(path: string, mtimeMs: number): void;
1957
- setMode(path: string, mode: number): void;
1958
- private touch;
1959
- }
1960
- //#endregion
1961
- //#region lib/engine/process/node-process-runner.d.ts
1962
- declare class NodeFunnelProcessRunner extends FunnelProcessRunner {
1963
- constructor();
1964
- runSync(command: string[]): RunResult;
1965
- run(command: string[], options?: RunOptions): Promise<RunResult>;
1966
- attach(command: string[], options?: AttachOptions): Promise<number>;
1967
- detach(command: string[], options?: DetachOptions): void;
1968
- kill(pid: number, signal?: string): void;
1969
- isAlive(pid: number): boolean;
1970
- listProcessesContaining(marker: string): ProcessSnapshot[];
1971
- private isAlivePosix;
1972
- private isAliveWindows;
1973
- private listProcessesContainingPosix;
1974
- private listProcessesContainingWindows;
1975
- }
1976
- //#endregion
1977
- //#region lib/engine/process/memory-process-runner.d.ts
1978
- type MemoryProcessResponse = {
1979
- exitCode?: number;
1980
- stdout?: string;
1981
- stderr?: string;
1982
- };
1983
- type MemoryProcessHandler = (command: string[]) => MemoryProcessResponse | Promise<MemoryProcessResponse>;
1984
- type MemoryProcessSyncHandler = (command: string[]) => MemoryProcessResponse;
1985
- type MemoryProcessCall = {
1986
- kind: "run";
1987
- command: string[];
1988
- options: RunOptions;
1989
- } | {
1990
- kind: "runSync";
1991
- command: string[];
1992
- } | {
1993
- kind: "attach";
1994
- command: string[];
1995
- options: AttachOptions;
1996
- } | {
1997
- kind: "detach";
1998
- command: string[];
1999
- options: DetachOptions;
2000
- } | {
2001
- kind: "kill";
2002
- command: string[];
2003
- };
2004
- type AliveStub = (pid: number) => boolean;
2005
- type ProcessListStub = (marker: string) => ProcessSnapshot[];
2006
- declare class MemoryFunnelProcessRunner extends FunnelProcessRunner {
2007
- readonly calls: MemoryProcessCall[];
2008
- readonly killed: {
2009
- pid: number;
2010
- signal: string;
2011
- }[];
2012
- private handler;
2013
- private syncHandler;
2014
- private aliveStub;
2015
- private listStub;
2016
- on(handler: MemoryProcessHandler): this;
2017
- onSync(handler: MemoryProcessSyncHandler): this;
2018
- onIsAlive(stub: AliveStub): this;
2019
- onListProcessesContaining(stub: ProcessListStub): this;
2020
- run(command: string[], options?: RunOptions): Promise<RunResult>;
2021
- runSync(command: string[]): RunResult;
2022
- attach(command: string[], options?: AttachOptions): Promise<number>;
2023
- detach(command: string[], options?: DetachOptions): void;
2024
- kill(pid: number, signal?: string): void;
2025
- isAlive(pid: number): boolean;
2026
- listProcessesContaining(marker: string): ProcessSnapshot[];
2027
- }
2028
- //#endregion
2029
- //#region lib/engine/logger/node-logger.d.ts
2030
- type Props$6 = {
2031
- file?: string;
2032
- now?: () => Date;
2033
- };
2034
- declare class NodeFunnelLogger extends FunnelLogger {
2035
- readonly file: string;
2036
- private readonly now;
2037
- constructor(props?: Props$6);
2038
- info(message: string, meta?: Record<string, unknown>): void;
2039
- warn(message: string, meta?: Record<string, unknown>): void;
2040
- error(message: string, meta?: Record<string, unknown>): void;
2041
- private write;
2042
- }
2043
- //#endregion
2044
- //#region lib/engine/logger/memory-logger.d.ts
2045
- type LogEntry = {
2046
- level: "info" | "warn" | "error";
2047
- message: string;
2048
- meta?: Record<string, unknown>;
2049
- };
2050
- declare class MemoryFunnelLogger extends FunnelLogger {
2051
- readonly file: null;
2052
- readonly entries: LogEntry[];
2053
- info(message: string, meta?: Record<string, unknown>): void;
2054
- warn(message: string, meta?: Record<string, unknown>): void;
2055
- error(message: string, meta?: Record<string, unknown>): void;
2056
- clear(): void;
2057
- }
2058
- //#endregion
2059
- //#region lib/engine/logger/noop-logger.d.ts
2060
- declare class NoopFunnelLogger extends FunnelLogger {
2061
- readonly file: null;
2062
- info(): void;
2063
- warn(): void;
2064
- error(): void;
2065
- }
2066
- //#endregion
2067
- //#region lib/engine/time/node-clock.d.ts
2068
- declare class NodeFunnelClock extends FunnelClock {
2069
- now(): Date;
2070
- }
2071
- //#endregion
2072
- //#region lib/engine/time/memory-clock.d.ts
2073
- type Props$5 = {
2074
- start?: Date;
2075
- };
2076
- declare class MemoryFunnelClock extends FunnelClock {
2077
- private current;
2078
- constructor(props?: Props$5);
2079
- now(): Date;
2080
- set(date: Date): void;
2081
- advance(ms: number): void;
2082
- }
2083
- //#endregion
2084
- //#region lib/engine/id/node-id-generator.d.ts
2085
- declare class NodeFunnelIdGenerator extends FunnelIdGenerator {
2086
- generate(): string;
2087
- }
2088
- //#endregion
2089
- //#region lib/engine/id/memory-id-generator.d.ts
2090
- type Props$4 = {
2091
- prefix?: string;
2092
- };
2093
- declare class MemoryFunnelIdGenerator extends FunnelIdGenerator {
2094
- private counter;
2095
- private readonly prefix;
2096
- constructor(props?: Props$4);
2097
- generate(): string;
2098
- }
2099
- //#endregion
2100
- //#region lib/engine/token-prompter/node-token-prompter.d.ts
2101
- /**
2102
- * Reads a secret from stdin in raw mode. Echoes a `*` per byte so the user
2103
- * can see progress without exposing the token. Refuses to prompt when stdin
2104
- * is not a TTY — callers should surface the resulting error with a hint
2105
- * pointing at the corresponding env var or CLI command.
2106
- */
2107
- declare class NodeFunnelTokenPrompter extends FunnelTokenPrompter {
2108
- promptSecret(label: string): Promise<string>;
2109
- private readSecret;
2110
- }
2111
- //#endregion
2112
- //#region lib/engine/token-prompter/memory-token-prompter.d.ts
2113
- type Props$3 = {
2114
- answers?: Record<string, string>;
2115
- };
2116
- /**
2117
- * Pre-seeded answers keyed by prompt label. Tests configure the map up front;
2118
- * unmapped labels throw so the test surfaces unexpected prompts loudly.
2119
- */
2120
- declare class MemoryFunnelTokenPrompter extends FunnelTokenPrompter {
2121
- private readonly answers;
2122
- readonly asked: string[];
2123
- constructor(props?: Props$3);
2124
- promptSecret(label: string): Promise<string>;
2125
- }
2126
- //#endregion
2127
- //#region lib/gateway/sqlite-funnel-event-log.d.ts
2128
- type Props$2 = {
2129
- /** SQLite database file path. Created on first write. ":memory:" for tests. */path: string; /** Override for tests. Defaults to `Date.now`. */
2130
- now?: () => number; /** Optional row cap. Pruned on every insert. */
2131
- maxRows?: number; /** Optional age cap in ms. Pruned on every insert. */
2132
- maxAgeMs?: number; /** Optional on-disk byte cap. Checked periodically; on overflow the oldest rows are dropped toward targetBytes and the file is VACUUMed. */
2133
- maxBytes?: number; /** Shrink target when maxBytes is exceeded. Defaults to maxBytes/4. */
2134
- targetBytes?: number;
2135
- };
2136
- /**
2137
- * SQLite-backed `FunnelEventLog`. One indexed table holds every broadcaster
2138
- * event with `channel_id` and `connector_id` as dedicated columns, so
2139
- * per-channel and per-connector replay is an indexed range scan.
2140
- *
2141
- * Concurrency: `seq` is `INTEGER PRIMARY KEY`, so SQLite assigns it
2142
- * atomically. The broadcaster owns its own offset counter at runtime
2143
- * (seeded from `findMaxOffset()` at startup); each broadcaster event
2144
- * flows in here via `record()` with that pre-assigned offset, which the
2145
- * sink stores via `write()` — PK uniqueness catches double-emit bugs.
2146
- *
2147
- * System events (gateway lifecycle, channel connect/disconnect, etc.) do
2148
- * NOT go through this store. They are diagnostic only and live in
2149
- * `FunnelLogger`'s file so the seq space here stays exclusive to
2150
- * broadcaster traffic. This is what makes the broadcaster's seq seeding
2151
- * (`getMaxSeq()` at startup) correct without per-event coordination.
2152
- */
2153
- declare class SqliteFunnelEventLog extends FunnelEventLog {
2154
- private readonly sink;
2155
- private readonly now;
2156
- constructor(props: Props$2);
2157
- /**
2158
- * Persist a broadcaster-driven event with its assigned offset. Caller
2159
- * (the gateway-server) supplies the offset from `broadcaster.broadcast()`
2160
- * so this store and the broadcaster's in-memory ring stay aligned.
2161
- */
2162
- record(record: FunnelEventRecord): void;
2163
- /**
2164
- * Returns events with offset > since. Filtering by channel/connector is
2165
- * the broadcaster's responsibility (it knows the client's subscription),
2166
- * so this returns the full slice and lets the caller filter.
2167
- */
2168
- loadSince(since: number): ReplayableEvent[];
2169
- /**
2170
- * Returns events for one channel (and optionally one connector). Used
2171
- * by the gateway logs CLI for scoped queries. Channel/connector filters
2172
- * are indexed columns, so this is an indexed range scan.
2173
- */
2174
- loadForChannel(props: {
2175
- channelId: string;
2176
- connectorId?: string;
2177
- sinceSeq?: number;
2178
- limit?: number;
2179
- }): ReplayableEvent[];
2180
- findMaxOffset(): number;
2181
- clear(): void;
2182
- close(): void;
2183
- }
2184
- //#endregion
2185
- //#region lib/gateway/memory-funnel-event-log.d.ts
2186
- /**
2187
- * In-process `FunnelEventLog` backed by a plain array. Used by tests and by
2188
- * embedders that do not need durability — replay works within the process
2189
- * lifetime but is lost when the process exits. Unlike the SQLite log it does
2190
- * not truncate content or prune, so it is not meant for unbounded production
2191
- * traffic.
2192
- */
2193
- declare class MemoryFunnelEventLog extends FunnelEventLog {
2194
- private readonly events;
2195
- constructor();
2196
- record(record: FunnelEventRecord): void;
2197
- loadSince(since: number): ReplayableEvent[];
2198
- findMaxOffset(): number;
2199
- clear(): void;
2200
- close(): void;
2201
- }
2202
- //#endregion
2203
- //#region lib/gateway/sqlite-connector-diagnostic-log.d.ts
2204
- type Props$1 = {
2205
- /** SQLite file for the raw (pre-filter) table. ":memory:" for tests. */rawPath: string; /** SQLite file for the processed (verdict) table. ":memory:" for tests. */
2206
- processedPath: string; /** SQLite file for the connection (lifecycle) table. ":memory:" for tests. */
2207
- connectionPath: string;
2208
- now?: () => number; /** Row cap for the processed and connection tables. Pruned on every insert. */
2209
- maxRows?: number;
2210
- /**
2211
- * Row cap for the raw table specifically. Raw rows can each hold up to
2212
- * `RAW_PAYLOAD_CAP` bytes, so they want a tighter cap than the small
2213
- * processed/connection verdict rows. Defaults to `maxRows` when unset.
2214
- */
2215
- rawMaxRows?: number; /** Age cap in ms for all tables — bounds how long untouched payloads (with PII) live. Pruned on every insert. */
2216
- maxAgeMs?: number; /** When set, `insert()` errors (disk full, WAL lock) are logged instead of silently dropped. */
2217
- logger?: FunnelLogger;
2218
- };
2219
- /**
2220
- * Default `ConnectorDiagnosticLog`: three independent `LeucoLoggerSqliteSink`s, one
2221
- * per table (raw / processed / connection), in separate files. Each sink
2222
- * indexes the columns its queries filter on — `event_id` / `connector_id` /
2223
- * `channel_id` for raw, plus `outcome` for processed and `status` for
2224
- * connection — so those lookups are indexed scans (`type` is a fixed column
2225
- * the sink extracts separately, not an index, so filtering by it is a scan).
2226
- *
2227
- * The raw table offloads any payload over `RAW_PAYLOAD_CAP`: rather than
2228
- * truncating mid-string (which yields unparseable JSON), it replaces the
2229
- * body with a small JSON object that keeps the diagnostic essentials and
2230
- * records the dropped size under `_funnel_oversized`. Every stored payload
2231
- * therefore stays valid JSON.
2232
- */
2233
- declare class SqliteConnectorDiagnosticLog extends ConnectorDiagnosticLog {
2234
- private readonly raw;
2235
- private readonly processed;
2236
- private readonly connection;
2237
- private readonly now;
2238
- private readonly logger;
2239
- constructor(props: Props$1);
2240
- recordRaw(record: ConnectorRawRecord): void;
2241
- recordProcessed(record: ConnectorProcessedRecord): void;
2242
- recordConnection(record: ConnectorConnectionRecord): void;
2243
- private report;
2244
- queryRaw(query: ConnectorRawQuery): StoredRawEvent[];
2245
- queryProcessed(query: ConnectorProcessedQuery): StoredProcessedEvent[];
2246
- queryConnection(query: ConnectorConnectionQuery): StoredConnectionEvent[];
2247
- clear(): void;
2248
- close(): void;
2249
- }
2250
- //#endregion
2251
- //#region lib/gateway/memory-connector-diagnostic-log.d.ts
2252
- /**
2253
- * In-process `ConnectorDiagnosticLog` backed by one array per table. Used by tests
2254
- * and embedders that do not need durability. Like the SQLite log it keeps
2255
- * `seq` per-table (each array's 1-based position) and returns the most recent
2256
- * `limit` rows oldest-first; unlike it, it never prunes and never offloads
2257
- * oversized payloads — it keeps whatever the caller hands it, which is fine
2258
- * for the bounded volumes a test produces. Payload-validity is therefore a
2259
- * SQLite-only guarantee; do not write a test that leans on this double
2260
- * rejecting a malformed payload.
2261
- */
2262
- declare class MemoryConnectorDiagnosticLog extends ConnectorDiagnosticLog {
2263
- private readonly now;
2264
- private readonly raws;
2265
- private readonly processeds;
2266
- private readonly connections;
2267
- constructor(now?: () => number);
2268
- recordRaw(record: ConnectorRawRecord): void;
2269
- recordProcessed(record: ConnectorProcessedRecord): void;
2270
- recordConnection(record: ConnectorConnectionRecord): void;
2271
- queryRaw(query: ConnectorRawQuery): StoredRawEvent[];
2272
- queryProcessed(query: ConnectorProcessedQuery): StoredProcessedEvent[];
2273
- queryConnection(query: ConnectorConnectionQuery): StoredConnectionEvent[];
2274
- clear(): void;
2275
- close(): void;
2276
- }
2277
- //#endregion
2278
- //#region lib/gateway/connector-diagnostic-sql-reader.d.ts
2279
- type Props = {
2280
- /** SQLite file holding the raw (pre-filter) table. */rawPath: string; /** SQLite file holding the processed (verdict) table. */
2281
- processedPath: string; /** SQLite file holding the connection (lifecycle) table. */
2282
- connectionPath: string;
2283
- };
2284
- type Row = Record<string, unknown>;
2285
- /**
2286
- * Read-only SQL surface over the three diagnostic tables, for Claude to query
2287
- * the log with arbitrary `SELECT`s. It opens all files read-only and exposes
2288
- * three views — `raw`, `processed`, `connection` — that hide the storage
2289
- * details (the physical table is `leuco_log` and each row's columns live
2290
- * inside a JSON `event` blob): the views surface the columns as plain fields,
2291
- * with `payload` already pulled out of the nested JSON.
2292
- *
2293
- * The tables are separate files. `raw` and `processed` share an `event_id`,
2294
- * so a `JOIN` answers "the event arrived, but what verdict did it get?";
2295
- * `connection` answers the other half — "did the listener ever connect at
2296
- * all?". Writes are impossible: the connection is read-only and `query`
2297
- * rejects anything but a single `SELECT`.
2298
- */
2299
- declare class ConnectorDiagnosticSqlReader {
2300
- private readonly db;
2301
- constructor(props: Props);
2302
- /**
2303
- * Run one read-only `SELECT` and return the rows. Returns an `Error` (rather
2304
- * than throwing) for a non-SELECT statement or a SQL error, so the caller
2305
- * can surface the message without a stack trace.
2306
- */
2307
- query(sql: string, params?: (string | number | null)[]): Row[] | Error;
2308
- close(): void;
2309
- }
2310
- //#endregion
2311
- //#region lib/cli/factory.d.ts
2312
- type Env = {
2313
- Bindings: {
2314
- funnel: Funnel;
2315
- };
2316
- };
2317
- declare const factory: _$hono_factory0.Factory<Env, string>;
2318
- //#endregion
2319
- //#region lib/cli/router/to-request.d.ts
2320
- declare const toRequest: (args: string[]) => {
2321
- method: string;
2322
- path: string;
2323
- url: string;
2324
- };
2325
- //#endregion
2326
- //#region lib/cli/router/query-to-cli-args.d.ts
2327
- declare const queryToCliArgs: (url: string, reservedKeys?: string[]) => string[];
2328
- //#endregion
2329
- //#region lib/cli/routes/index.d.ts
2330
- declare const routes: _$hono_hono_base0.HonoBase<Env, {
2331
- "/claude": {
2332
- $get: {
2333
- input: {
2334
- query: {
2335
- [x: string]: string | string[];
2336
- profile?: string | undefined;
2337
- channel?: string | undefined;
2338
- };
2339
- };
2340
- output: string;
2341
- outputFormat: "text";
2342
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2343
- } | {
2344
- input: {
2345
- query: {
2346
- [x: string]: string | string[];
2347
- profile?: string | undefined;
2348
- channel?: string | undefined;
2349
- };
2350
- };
2351
- output: "funnel claude — launch Claude Code\n\nusage:\n funnel claude launch the first channel from funnel.json, or the default profile\n funnel claude --channel <name> with funnel.json: select that channel; without: raw launch\n funnel claude -p <name> launch a named profile\n funnel claude --profile <name> (long form)\n funnel claude [...] any other argument is forwarded to the claude CLI\n\nresolution order:\n 1. --help print this help\n 2. --profile <name> named profile (ignores funnel.json)\n 3. ./funnel.json in the current directory + --channel selects (or first wins)\n 4. --channel <name> with no funnel.json → raw launch using an existing settings.json channel\n 5. the default profile (first entry in fnl profiles)\n\nfunnel-specific options (everything else passes through to claude verbatim):\n -p, --profile profile name to launch\n --channel channel name (selects from funnel.json, or raw-launches if no funnel.json)\n -h, --help show this help\n\nPositional args, unknown short flags (e.g. -c, -r), and claude's own flags\n(--agent, --resume, --model, --print, --output-format ...) are all forwarded.\nOn launch the FUNNEL_CHANNEL_ID env var is set and MCP connects to the gateway.";
2352
- outputFormat: "text";
2353
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2354
- };
2355
- };
2356
- } & {
2357
- "/channels": {
2358
- $get: {
2359
- input: {
2360
- query: {
2361
- json?: "" | "true" | "false" | undefined;
2362
- };
2363
- };
2364
- output: string;
2365
- outputFormat: "text";
2366
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2367
- } | {
2368
- input: {
2369
- query: {
2370
- json?: "" | "true" | "false" | undefined;
2371
- };
2372
- };
2373
- output: {
2374
- id: string;
2375
- name: string;
2376
- delivery: "fanout" | "exclusive";
2377
- connectors: {
2378
- id: string;
2379
- name: string;
2380
- type: "discord" | "slack" | "gh" | "schedule";
2381
- }[];
2382
- }[];
2383
- outputFormat: "json";
2384
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2385
- };
2386
- };
2387
- } & {
2388
- "/channels/add": {
2389
- $post: {
2390
- input: {};
2391
- output: "funnel channels add — add a channel\n\nusage: funnel channels add <name> [--delivery fanout|exclusive]\n\noptions:\n --delivery routing mode (default fanout):\n fanout every connected client receives every event\n exclusive each event delivered to exactly one client (round-robin)";
2392
- outputFormat: "text";
2393
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2394
- };
2395
- };
2396
- } & {
2397
- "/channels/add/:channel": {
2398
- $post: {
2399
- input: {
2400
- param: {
2401
- channel: string;
2402
- };
2403
- } & {
2404
- query: {
2405
- delivery?: "fanout" | "exclusive" | undefined;
2406
- };
2407
- };
2408
- output: string;
2409
- outputFormat: "text";
2410
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2411
- } | {
2412
- input: {
2413
- param: {
2414
- channel: string;
2415
- };
2416
- } & {
2417
- query: {
2418
- delivery?: "fanout" | "exclusive" | undefined;
2419
- };
2420
- };
2421
- output: `added channel "${string}" (id: ${string})`;
2422
- outputFormat: "text";
2423
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2424
- };
2425
- };
2426
- } & {
2427
- "/channels/remove": {
2428
- $post: {
2429
- input: {};
2430
- output: "funnel channels remove — remove a channel\n\nusage: funnel channels remove <name>";
2431
- outputFormat: "text";
2432
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2433
- };
2434
- };
2435
- } & {
2436
- "/channels/remove/:channel": {
2437
- $post: {
2438
- input: {
2439
- param: {
2440
- channel: string;
2441
- };
2442
- } & {
2443
- query: Record<string, never>;
2444
- };
2445
- output: string;
2446
- outputFormat: "text";
2447
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2448
- } | {
2449
- input: {
2450
- param: {
2451
- channel: string;
2452
- };
2453
- } & {
2454
- query: Record<string, never>;
2455
- };
2456
- output: `removed channel "${string}"`;
2457
- outputFormat: "text";
2458
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2459
- };
2460
- };
2461
- } & {
2462
- "/channels/rename/:channel/:newName": {
2463
- $post: {
2464
- input: {
2465
- param: {
2466
- channel: string;
2467
- newName: string;
2468
- };
2469
- } & {
2470
- query: Record<string, never>;
2471
- };
2472
- output: string;
2473
- outputFormat: "text";
2474
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2475
- } | {
2476
- input: {
2477
- param: {
2478
- channel: string;
2479
- newName: string;
2480
- };
2481
- } & {
2482
- query: Record<string, never>;
2483
- };
2484
- output: `renamed channel "${string}" to "${string}"`;
2485
- outputFormat: "text";
2486
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2487
- };
2488
- };
2489
- } & {
2490
- "/channels/:channel/rename/:newName": {
2491
- $post: {
2492
- input: {
2493
- param: {
2494
- channel: string;
2495
- newName: string;
2496
- };
2497
- } & {
2498
- query: Record<string, never>;
2499
- };
2500
- output: string;
2501
- outputFormat: "text";
2502
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2503
- } | {
2504
- input: {
2505
- param: {
2506
- channel: string;
2507
- newName: string;
2508
- };
2509
- } & {
2510
- query: Record<string, never>;
2511
- };
2512
- output: `renamed channel "${string}" to "${string}"`;
2513
- outputFormat: "text";
2514
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2515
- };
2516
- };
2517
- } & {
2518
- "/channels/rename": {
2519
- $post: {
2520
- input: {};
2521
- output: "funnel channels rename — rename a channel\n\nusage:\n funnel channels rename <old> <new>\n funnel channels <old> rename <new>";
2522
- outputFormat: "text";
2523
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2524
- };
2525
- };
2526
- } & {
2527
- "/channels/:channel/rename": {
2528
- $post: {
2529
- input: {
2530
- param: {
2531
- channel: string;
2532
- };
2533
- };
2534
- output: "funnel channels rename — rename a channel\n\nusage:\n funnel channels rename <old> <new>\n funnel channels <old> rename <new>";
2535
- outputFormat: "text";
2536
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2537
- };
2538
- };
2539
- } & {
2540
- "/channels/:channel/set/delivery/:mode": {
2541
- $post: {
2542
- input: {
2543
- param: {
2544
- channel: string;
2545
- mode: "fanout" | "exclusive";
2546
- };
2547
- };
2548
- output: string;
2549
- outputFormat: "text";
2550
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2551
- } | {
2552
- input: {
2553
- param: {
2554
- channel: string;
2555
- mode: "fanout" | "exclusive";
2556
- };
2557
- };
2558
- output: `channel "${string}" delivery set to fanout` | `channel "${string}" delivery set to exclusive`;
2559
- outputFormat: "text";
2560
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2561
- };
2562
- };
2563
- } & {
2564
- "/channels/publish": {
2565
- $post: {
2566
- input: {};
2567
- output: "funnel channels <channel> publish — push arbitrary content into a channel\n\nusage: funnel channels <channel> publish --content=\"<text>\" [--connector=<name>] [--meta-<key>=<value> ...]\n\noptions:\n --content Required. The event body delivered to subscribers.\n --connector Optional. Stamp the event with a connector name (resolved to id when found).\n --meta-<key> Optional. Repeatable. Added to meta. Example: --meta-source=cron";
2568
- outputFormat: "text";
2569
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2570
- };
2571
- };
2572
- } & {
2573
- "/channels/:channel/publish": {
2574
- $post: {
2575
- input: {
2576
- param: {
2577
- channel: string;
2578
- };
2579
- } & {
2580
- query: {
2581
- [x: string]: string | string[];
2582
- content: string | string[];
2583
- connector?: string | undefined;
2584
- };
2585
- };
2586
- output: string;
2587
- outputFormat: "text";
2588
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2589
- } | {
2590
- input: {
2591
- param: {
2592
- channel: string;
2593
- };
2594
- } & {
2595
- query: {
2596
- [x: string]: string | string[];
2597
- content: string | string[];
2598
- connector?: string | undefined;
2599
- };
2600
- };
2601
- output: `published (offset=${number})`;
2602
- outputFormat: "text";
2603
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2604
- };
2605
- };
2606
- } & {
2607
- "/channels/:channel/validate": {
2608
- $get: {
2609
- input: {
2610
- param: {
2611
- channel: string;
2612
- };
2613
- } & {
2614
- query: {
2615
- json?: "" | "true" | "false" | undefined;
2616
- };
2617
- };
2618
- output: string;
2619
- outputFormat: "text";
2620
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2621
- } | {
2622
- input: {
2623
- param: {
2624
- channel: string;
2625
- };
2626
- } & {
2627
- query: {
2628
- json?: "" | "true" | "false" | undefined;
2629
- };
2630
- };
2631
- output: {
2632
- channel: string;
2633
- valid: boolean;
2634
- issues: {
2635
- connector: string;
2636
- field: string;
2637
- message: string;
2638
- }[];
2639
- };
2640
- outputFormat: "json";
2641
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2642
- };
2643
- };
2644
- } & {
2645
- "/channels/validate": {
2646
- $get: {
2647
- input: {};
2648
- output: "funnel channels <channel> validate — check connector configuration\n\nusage: funnel channels <channel> validate [--json]\n\noptions:\n --json output as JSON\n\nChecks that each connector has the required tokens and fields set.\nDoes not make any network calls — static config check only.\n\nexamples:\n funnel channels open-karte validate\n funnel channels open-karte validate --json";
2649
- outputFormat: "text";
2650
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2651
- };
2652
- };
2653
- } & {
2654
- "/channels/:channel": {
2655
- $get: {
2656
- input: {
2657
- param: {
2658
- channel: string;
2659
- };
2660
- } & {
2661
- query: Record<string, never>;
2662
- };
2663
- output: string;
2664
- outputFormat: "text";
2665
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2666
- };
2667
- };
2668
- } & {
2669
- "/channels/:channel/connectors": {
2670
- $get: {
2671
- input: {
2672
- param: {
2673
- channel: string;
2674
- };
2675
- } & {
2676
- query: Record<string, never>;
2677
- };
2678
- output: string;
2679
- outputFormat: "text";
2680
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2681
- };
2682
- };
2683
- } & {
2684
- "/channels/:channel/connectors/add": {
2685
- $post: {
2686
- input: {
2687
- param: {
2688
- channel: string;
2689
- };
2690
- };
2691
- output: "funnel channels <channel> connectors add <connector> — add a connector to a channel\n\nusage:\n funnel channels <channel> connectors add <connector> --type=slack --bot-token=xoxb-... --app-token=xapp-...\n funnel channels <channel> connectors add <connector> --type=gh [--poll-interval=60]\n funnel channels <channel> connectors add <connector> --type=discord --bot-token=...\n funnel channels <channel> connectors add <connector> --type=schedule\n\nToken uniqueness is enforced across all channels.";
2692
- outputFormat: "text";
2693
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2694
- };
2695
- };
2696
- } & {
2697
- "/channels/:channel/connectors/add/:connector": {
2698
- $post: {
2699
- input: {
2700
- param: {
2701
- channel: string;
2702
- connector: string;
2703
- };
2704
- } & {
2705
- query: {
2706
- type: string | string[];
2707
- "bot-token": string | string[];
2708
- "app-token": string | string[];
2709
- } | {
2710
- type: string | string[];
2711
- "poll-interval"?: string | string[] | undefined;
2712
- } | {
2713
- type: string | string[];
2714
- "bot-token": string | string[];
2715
- } | {
2716
- type: string | string[];
2717
- };
2718
- };
2719
- output: string;
2720
- outputFormat: "text";
2721
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2722
- } | {
2723
- input: {
2724
- param: {
2725
- channel: string;
2726
- connector: string;
2727
- };
2728
- } & {
2729
- query: {
2730
- type: string | string[];
2731
- "bot-token": string | string[];
2732
- "app-token": string | string[];
2733
- } | {
2734
- type: string | string[];
2735
- "poll-interval"?: string | string[] | undefined;
2736
- } | {
2737
- type: string | string[];
2738
- "bot-token": string | string[];
2739
- } | {
2740
- type: string | string[];
2741
- };
2742
- };
2743
- output: `added slack connector "${string}" to channel "${string}"`;
2744
- outputFormat: "text";
2745
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2746
- } | {
2747
- input: {
2748
- param: {
2749
- channel: string;
2750
- connector: string;
2751
- };
2752
- } & {
2753
- query: {
2754
- type: string | string[];
2755
- "bot-token": string | string[];
2756
- "app-token": string | string[];
2757
- } | {
2758
- type: string | string[];
2759
- "poll-interval"?: string | string[] | undefined;
2760
- } | {
2761
- type: string | string[];
2762
- "bot-token": string | string[];
2763
- } | {
2764
- type: string | string[];
2765
- };
2766
- };
2767
- output: `added gh connector "${string}" to channel "${string}"`;
2768
- outputFormat: "text";
2769
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2770
- } | {
2771
- input: {
2772
- param: {
2773
- channel: string;
2774
- connector: string;
2775
- };
2776
- } & {
2777
- query: {
2778
- type: string | string[];
2779
- "bot-token": string | string[];
2780
- "app-token": string | string[];
2781
- } | {
2782
- type: string | string[];
2783
- "poll-interval"?: string | string[] | undefined;
2784
- } | {
2785
- type: string | string[];
2786
- "bot-token": string | string[];
2787
- } | {
2788
- type: string | string[];
2789
- };
2790
- };
2791
- output: `added discord connector "${string}" to channel "${string}"`;
2792
- outputFormat: "text";
2793
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2794
- } | {
2795
- input: {
2796
- param: {
2797
- channel: string;
2798
- connector: string;
2799
- };
2800
- } & {
2801
- query: {
2802
- type: string | string[];
2803
- "bot-token": string | string[];
2804
- "app-token": string | string[];
2805
- } | {
2806
- type: string | string[];
2807
- "poll-interval"?: string | string[] | undefined;
2808
- } | {
2809
- type: string | string[];
2810
- "bot-token": string | string[];
2811
- } | {
2812
- type: string | string[];
2813
- };
2814
- };
2815
- output: `added schedule connector "${string}" to channel "${string}"`;
2816
- outputFormat: "text";
2817
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2818
- };
2819
- };
2820
- } & {
2821
- "/channels/:channel/connectors/remove": {
2822
- $post: {
2823
- input: {
2824
- param: {
2825
- channel: string;
2826
- };
2827
- };
2828
- output: "funnel channels <channel> connectors remove <connector> — remove a connector\n\nusage: funnel channels <channel> connectors remove <connector>";
2829
- outputFormat: "text";
2830
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2831
- };
2832
- };
2833
- } & {
2834
- "/channels/:channel/connectors/remove/:connector": {
2835
- $post: {
2836
- input: {
2837
- param: {
2838
- channel: string;
2839
- connector: string;
2840
- };
2841
- } & {
2842
- query: Record<string, never>;
2843
- };
2844
- output: string;
2845
- outputFormat: "text";
2846
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2847
- } | {
2848
- input: {
2849
- param: {
2850
- channel: string;
2851
- connector: string;
2852
- };
2853
- } & {
2854
- query: Record<string, never>;
2855
- };
2856
- output: `removed connector "${string}" from channel "${string}"`;
2857
- outputFormat: "text";
2858
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2859
- };
2860
- };
2861
- } & {
2862
- "/channels/:channel/connectors/set": {
2863
- $post: {
2864
- input: {
2865
- param: {
2866
- channel: string;
2867
- };
2868
- };
2869
- output: "funnel channels <channel> connectors set <connector> — update connector fields\n\nusage:\n funnel channels <ch> connectors set <conn> [--bot-token=...] [--app-token=...] # slack\n funnel channels <ch> connectors set <conn> [--bot-token=...] # discord\n funnel channels <ch> connectors set <conn> [--poll-interval=N] # gh";
2870
- outputFormat: "text";
2871
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2872
- };
2873
- };
2874
- } & {
2875
- "/channels/:channel/connectors/set/:connector": {
2876
- $post: {
2877
- input: {
2878
- param: {
2879
- channel: string;
2880
- connector: string;
2881
- };
2882
- } & {
2883
- query: {
2884
- [x: string]: string | string[];
2885
- "bot-token"?: string | undefined;
2886
- "app-token"?: string | undefined;
2887
- "poll-interval"?: string | string[] | undefined;
2888
- };
2889
- };
2890
- output: string;
2891
- outputFormat: "text";
2892
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2893
- } | {
2894
- input: {
2895
- param: {
2896
- channel: string;
2897
- connector: string;
2898
- };
2899
- } & {
2900
- query: {
2901
- [x: string]: string | string[];
2902
- "bot-token"?: string | undefined;
2903
- "app-token"?: string | undefined;
2904
- "poll-interval"?: string | string[] | undefined;
2905
- };
2906
- };
2907
- output: `updated connector "${string}" in channel "${string}"`;
2908
- outputFormat: "text";
2909
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2910
- };
2911
- };
2912
- } & {
2913
- "/channels/:channel/connectors/rename/:connector/:newName": {
2914
- $post: {
2915
- input: {
2916
- param: {
2917
- channel: string;
2918
- connector: string;
2919
- newName: string;
2920
- };
2921
- } & {
2922
- query: Record<string, never>;
2923
- };
2924
- output: string;
2925
- outputFormat: "text";
2926
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2927
- } | {
2928
- input: {
2929
- param: {
2930
- channel: string;
2931
- connector: string;
2932
- newName: string;
2933
- };
2934
- } & {
2935
- query: Record<string, never>;
2936
- };
2937
- output: `renamed connector "${string}" to "${string}"`;
2938
- outputFormat: "text";
2939
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2940
- };
2941
- };
2942
- } & {
2943
- "/channels/:channel/connectors/:connector/rename/:newName": {
2944
- $post: {
2945
- input: {
2946
- param: {
2947
- channel: string;
2948
- connector: string;
2949
- newName: string;
2950
- };
2951
- } & {
2952
- query: Record<string, never>;
2953
- };
2954
- output: string;
2955
- outputFormat: "text";
2956
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2957
- } | {
2958
- input: {
2959
- param: {
2960
- channel: string;
2961
- connector: string;
2962
- newName: string;
2963
- };
2964
- } & {
2965
- query: Record<string, never>;
2966
- };
2967
- output: `renamed connector "${string}" to "${string}"`;
2968
- outputFormat: "text";
2969
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2970
- };
2971
- };
2972
- } & {
2973
- "/channels/:channel/connectors/rename": {
2974
- $post: {
2975
- input: {
2976
- param: {
2977
- channel: string;
2978
- };
2979
- };
2980
- output: "funnel channels <channel> connectors rename <connector> <new-name>\n\nusage: funnel channels <channel> connectors rename <connector> <new-name>";
2981
- outputFormat: "text";
2982
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2983
- };
2984
- };
2985
- } & {
2986
- "/channels/:channel/connectors/:connector/rename": {
2987
- $post: {
2988
- input: {
2989
- param: {
2990
- channel: string;
2991
- } & {
2992
- connector: string;
2993
- };
2994
- };
2995
- output: "funnel channels <channel> connectors rename <connector> <new-name>\n\nusage: funnel channels <channel> connectors rename <connector> <new-name>";
2996
- outputFormat: "text";
2997
- status: _$hono_utils_http_status0.ContentfulStatusCode;
2998
- };
2999
- };
3000
- } & {
3001
- "/channels/:channel/connectors/:connector/request": {
3002
- $post: {
3003
- input: {
3004
- param: {
3005
- channel: string;
3006
- connector: string;
3007
- };
3008
- } & {
3009
- query: {
3010
- [x: string]: string | string[];
3011
- method: string | string[];
3012
- };
3013
- };
3014
- output: string;
3015
- outputFormat: "text";
3016
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3017
- };
3018
- };
3019
- } & {
3020
- "/channels/:channel/connectors/:connector": {
3021
- $get: {
3022
- input: {
3023
- param: {
3024
- channel: string;
3025
- connector: string;
3026
- };
3027
- } & {
3028
- query: Record<string, never>;
3029
- };
3030
- output: string;
3031
- outputFormat: "text";
3032
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3033
- };
3034
- };
3035
- } & {
3036
- "/channels/:channel/connectors/:connector/schedules": {
3037
- $get: {
3038
- input: {
3039
- param: {
3040
- channel: string;
3041
- connector: string;
3042
- };
3043
- } & {
3044
- query: Record<string, never>;
3045
- };
3046
- output: string;
3047
- outputFormat: "text";
3048
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3049
- };
3050
- };
3051
- } & {
3052
- "/channels/:channel/connectors/:connector/schedules/add": {
3053
- $post: {
3054
- input: {
3055
- param: {
3056
- channel: string;
3057
- } & {
3058
- connector: string;
3059
- };
3060
- };
3061
- output: "funnel channels <ch> connectors <conn> schedules add <id> — add a schedule entry\n\nusage: funnel channels <ch> connectors <conn> schedules add <id> --cron=\"*/5 * * * *\" --prompt=\"...\" [--enabled=true] [--catchup-policy=latest|all|skip]";
3062
- outputFormat: "text";
3063
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3064
- };
3065
- };
3066
- } & {
3067
- "/channels/:channel/connectors/:connector/schedules/add/:id": {
3068
- $post: {
3069
- input: {
3070
- param: {
3071
- channel: string;
3072
- connector: string;
3073
- id: string;
3074
- };
3075
- } & {
3076
- query: {
3077
- cron: string | string[];
3078
- prompt: string | string[];
3079
- enabled?: string | string[] | undefined;
3080
- "catchup-policy"?: "latest" | "all" | "skip" | undefined;
3081
- };
3082
- };
3083
- output: string;
3084
- outputFormat: "text";
3085
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3086
- } | {
3087
- input: {
3088
- param: {
3089
- channel: string;
3090
- connector: string;
3091
- id: string;
3092
- };
3093
- } & {
3094
- query: {
3095
- cron: string | string[];
3096
- prompt: string | string[];
3097
- enabled?: string | string[] | undefined;
3098
- "catchup-policy"?: "latest" | "all" | "skip" | undefined;
3099
- };
3100
- };
3101
- output: `added schedule entry "${string}"`;
3102
- outputFormat: "text";
3103
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3104
- };
3105
- };
3106
- } & {
3107
- "/channels/:channel/connectors/:connector/schedules/remove": {
3108
- $post: {
3109
- input: {
3110
- param: {
3111
- channel: string;
3112
- } & {
3113
- connector: string;
3114
- };
3115
- };
3116
- output: "funnel channels <ch> connectors <conn> schedules remove <id>\n\nusage: funnel channels <ch> connectors <conn> schedules remove <id>";
3117
- outputFormat: "text";
3118
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3119
- };
3120
- };
3121
- } & {
3122
- "/channels/:channel/connectors/:connector/schedules/remove/:id": {
3123
- $post: {
3124
- input: {
3125
- param: {
3126
- channel: string;
3127
- connector: string;
3128
- id: string;
3129
- };
3130
- } & {
3131
- query: Record<string, never>;
3132
- };
3133
- output: string;
3134
- outputFormat: "text";
3135
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3136
- } | {
3137
- input: {
3138
- param: {
3139
- channel: string;
3140
- connector: string;
3141
- id: string;
3142
- };
3143
- } & {
3144
- query: Record<string, never>;
3145
- };
3146
- output: `removed schedule entry "${string}"`;
3147
- outputFormat: "text";
3148
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3149
- };
3150
- };
3151
- } & {
3152
- "/profiles": {
3153
- $get: {
3154
- input: {
3155
- query: Record<string, never>;
3156
- };
3157
- output: string;
3158
- outputFormat: "text";
3159
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3160
- };
3161
- };
3162
- } & {
3163
- "/profiles/add": {
3164
- $post: {
3165
- input: {};
3166
- output: "funnel profiles add — add a profile\n\nusage: funnel profiles add <name> --path <path> --channel <channel-name> [recipe]\n\noptions:\n --path working directory passed to claude as cwd\n --channel channel name (resolved to channel id internally)\n --agent sub-agent name, prepended to the launch argv as --agent <name>\n --options extra launch argv as one whitespace-split string (e.g. \"--brief\")\n --env env vars layered under the process, as \"KEY=VAL,KEY2=VAL2\"\n --no-resume start a fresh claude session every launch (default resumes)\n\nThe launch recipe (--agent / --options / --env / --resume) lives on the\nprofile; the channel only declares transport (connectors / delivery).";
3167
- outputFormat: "text";
3168
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3169
- };
3170
- };
3171
- } & {
3172
- "/profiles/add/:profile": {
3173
- $post: {
3174
- input: {
3175
- param: {
3176
- profile: string;
3177
- };
3178
- } & {
3179
- query: {
3180
- path: string;
3181
- channel: string;
3182
- agent?: string | undefined;
3183
- options?: string | undefined;
3184
- env?: string | undefined;
3185
- resume?: string | undefined;
3186
- "no-resume"?: string | undefined;
3187
- };
3188
- };
3189
- output: string;
3190
- outputFormat: "text";
3191
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3192
- } | {
3193
- input: {
3194
- param: {
3195
- profile: string;
3196
- };
3197
- } & {
3198
- query: {
3199
- path: string;
3200
- channel: string;
3201
- agent?: string | undefined;
3202
- options?: string | undefined;
3203
- env?: string | undefined;
3204
- resume?: string | undefined;
3205
- "no-resume"?: string | undefined;
3206
- };
3207
- };
3208
- output: `added profile "${string}"`;
3209
- outputFormat: "text";
3210
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3211
- };
3212
- };
3213
- } & {
3214
- "/profiles/set": {
3215
- $post: {
3216
- input: {};
3217
- output: "funnel profiles <name> set — update a profile\n\nusage: funnel profiles <name> set [--path <path>] [--channel <channel-name>] [recipe]\n\noptions:\n --path working directory passed to claude as cwd\n --channel channel name (resolved to channel id internally)\n --agent sub-agent name, prepended to the launch argv as --agent <name>\n --options extra launch argv as one whitespace-split string (e.g. \"--brief\")\n --env env vars layered under the process, as \"KEY=VAL,KEY2=VAL2\"\n --resume / --no-resume toggle claude session reuse\n\nOnly the flags you pass are changed; --agent and --options together replace\nthe profile's whole options list.";
3218
- outputFormat: "text";
3219
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3220
- };
3221
- };
3222
- } & {
3223
- "/profiles/set/:profile": {
3224
- $post: {
3225
- input: {
3226
- param: {
3227
- profile: string;
3228
- };
3229
- } & {
3230
- query: {
3231
- path?: string | undefined;
3232
- channel?: string | undefined;
3233
- agent?: string | undefined;
3234
- options?: string | undefined;
3235
- env?: string | undefined;
3236
- resume?: string | undefined;
3237
- "no-resume"?: string | undefined;
3238
- };
3239
- };
3240
- output: string;
3241
- outputFormat: "text";
3242
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3243
- } | {
3244
- input: {
3245
- param: {
3246
- profile: string;
3247
- };
3248
- } & {
3249
- query: {
3250
- path?: string | undefined;
3251
- channel?: string | undefined;
3252
- agent?: string | undefined;
3253
- options?: string | undefined;
3254
- env?: string | undefined;
3255
- resume?: string | undefined;
3256
- "no-resume"?: string | undefined;
3257
- };
3258
- };
3259
- output: `updated profile "${string}"`;
3260
- outputFormat: "text";
3261
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3262
- };
3263
- };
3264
- } & {
3265
- "/profiles/remove": {
3266
- $post: {
3267
- input: {};
3268
- output: "funnel profiles remove — remove a profile\n\nusage: funnel profiles remove <name>";
3269
- outputFormat: "text";
3270
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3271
- };
3272
- };
3273
- } & {
3274
- "/profiles/remove/:profile": {
3275
- $post: {
3276
- input: {
3277
- param: {
3278
- profile: string;
3279
- };
3280
- } & {
3281
- query: Record<string, never>;
3282
- };
3283
- output: string;
3284
- outputFormat: "text";
3285
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3286
- } | {
3287
- input: {
3288
- param: {
3289
- profile: string;
3290
- };
3291
- } & {
3292
- query: Record<string, never>;
3293
- };
3294
- output: `removed profile "${string}"`;
3295
- outputFormat: "text";
3296
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3297
- };
3298
- };
3299
- } & {
3300
- "/profiles/rename/:profile/:newName": {
3301
- $post: {
3302
- input: {
3303
- param: {
3304
- profile: string;
3305
- newName: string;
3306
- };
3307
- } & {
3308
- query: Record<string, never>;
3309
- };
3310
- output: string;
3311
- outputFormat: "text";
3312
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3313
- } | {
3314
- input: {
3315
- param: {
3316
- profile: string;
3317
- newName: string;
3318
- };
3319
- } & {
3320
- query: Record<string, never>;
3321
- };
3322
- output: `renamed profile "${string}" to "${string}"`;
3323
- outputFormat: "text";
3324
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3325
- };
3326
- };
3327
- } & {
3328
- "/profiles/:profile/rename/:newName": {
3329
- $post: {
3330
- input: {
3331
- param: {
3332
- profile: string;
3333
- newName: string;
3334
- };
3335
- } & {
3336
- query: Record<string, never>;
3337
- };
3338
- output: string;
3339
- outputFormat: "text";
3340
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3341
- } | {
3342
- input: {
3343
- param: {
3344
- profile: string;
3345
- newName: string;
3346
- };
3347
- } & {
3348
- query: Record<string, never>;
3349
- };
3350
- output: `renamed profile "${string}" to "${string}"`;
3351
- outputFormat: "text";
3352
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3353
- };
3354
- };
3355
- } & {
3356
- "/profiles/rename": {
3357
- $post: {
3358
- input: {};
3359
- output: "funnel profiles rename — rename a profile\n\nusage:\n funnel profiles rename <old> <new>\n funnel profiles <old> rename <new>";
3360
- outputFormat: "text";
3361
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3362
- };
3363
- };
3364
- } & {
3365
- "/profiles/:profile/rename": {
3366
- $post: {
3367
- input: {
3368
- param: {
3369
- profile: string;
3370
- };
3371
- };
3372
- output: "funnel profiles rename — rename a profile\n\nusage:\n funnel profiles rename <old> <new>\n funnel profiles <old> rename <new>";
3373
- outputFormat: "text";
3374
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3375
- };
3376
- };
3377
- } & {
3378
- "/profiles/:profile/as-default": {
3379
- $post: {
3380
- input: {
3381
- param: {
3382
- profile: string;
3383
- };
3384
- } & {
3385
- query: Record<string, never>;
3386
- };
3387
- output: string;
3388
- outputFormat: "text";
3389
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3390
- } | {
3391
- input: {
3392
- param: {
3393
- profile: string;
3394
- };
3395
- } & {
3396
- query: Record<string, never>;
3397
- };
3398
- output: `profile "${string}" is now the default`;
3399
- outputFormat: "text";
3400
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3401
- };
3402
- };
3403
- } & {
3404
- "/profiles/:profile/run": {
3405
- $get: {
3406
- input: {
3407
- param: {
3408
- profile: string;
3409
- };
3410
- } & {
3411
- query: {
3412
- [x: string]: string | string[];
3413
- };
3414
- };
3415
- output: string;
3416
- outputFormat: "text";
3417
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3418
- } | {
3419
- input: {
3420
- param: {
3421
- profile: string;
3422
- };
3423
- } & {
3424
- query: {
3425
- [x: string]: string | string[];
3426
- };
3427
- };
3428
- output: Promise<never>;
3429
- outputFormat: "json";
3430
- status: _$hono_utils_http_status0.StatusCode;
3431
- };
3432
- };
3433
- } & {
3434
- "/profiles/:profile": {
3435
- $get: {
3436
- input: {
3437
- param: {
3438
- profile: string;
3439
- };
3440
- } & {
3441
- query: {
3442
- [x: string]: string | string[];
3443
- };
3444
- };
3445
- output: string;
3446
- outputFormat: "text";
3447
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3448
- } | {
3449
- input: {
3450
- param: {
3451
- profile: string;
3452
- };
3453
- } & {
3454
- query: {
3455
- [x: string]: string | string[];
3456
- };
3457
- };
3458
- output: Promise<never>;
3459
- outputFormat: "json";
3460
- status: _$hono_utils_http_status0.StatusCode;
3461
- };
3462
- };
3463
- } & {
3464
- "/gateway": {
3465
- $get: {
3466
- input: {};
3467
- output: string;
3468
- outputFormat: "text";
3469
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3470
- };
3471
- };
3472
- } & {
3473
- "/gateway/status": {
3474
- $get: {
3475
- input: {
3476
- query: {
3477
- json?: "" | "true" | "false" | undefined;
3478
- };
3479
- };
3480
- output: string;
3481
- outputFormat: "text";
3482
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3483
- } | {
3484
- input: {
3485
- query: {
3486
- json?: "" | "true" | "false" | undefined;
3487
- };
3488
- };
3489
- output: {
3490
- running: true;
3491
- port: number;
3492
- };
3493
- outputFormat: "json";
3494
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3495
- };
3496
- };
3497
- } & {
3498
- "/gateway/start": {
3499
- $get: {
3500
- input: {
3501
- query: {
3502
- "no-caffeine"?: string | undefined;
3503
- };
3504
- };
3505
- output: string;
3506
- outputFormat: "text";
3507
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3508
- } | {
3509
- input: {
3510
- query: {
3511
- "no-caffeine"?: string | undefined;
3512
- };
3513
- };
3514
- output: "funnel gateway: already running (pid null)" | `funnel gateway: already running (pid ${number})`;
3515
- outputFormat: "text";
3516
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3517
- } | {
3518
- input: {
3519
- query: {
3520
- "no-caffeine"?: string | undefined;
3521
- };
3522
- };
3523
- output: "funnel gateway: started";
3524
- outputFormat: "text";
3525
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3526
- };
3527
- };
3528
- } & {
3529
- "/gateway/stop": {
3530
- $get: {
3531
- input: {
3532
- query: Record<string, never>;
3533
- };
3534
- output: string;
3535
- outputFormat: "text";
3536
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3537
- } | {
3538
- input: {
3539
- query: Record<string, never>;
3540
- };
3541
- output: "funnel gateway: no running process";
3542
- outputFormat: "text";
3543
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3544
- } | {
3545
- input: {
3546
- query: Record<string, never>;
3547
- };
3548
- output: "funnel gateway: stopped";
3549
- outputFormat: "text";
3550
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3551
- };
3552
- };
3553
- } & {
3554
- "/gateway/restart": {
3555
- $get: {
3556
- input: {
3557
- query: {
3558
- "no-caffeine"?: string | undefined;
3559
- };
3560
- };
3561
- output: string;
3562
- outputFormat: "text";
3563
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3564
- };
3565
- };
3566
- } & {
3567
- "/gateway/run": {
3568
- $get: {
3569
- input: {
3570
- query: {
3571
- "no-caffeine"?: string | undefined;
3572
- };
3573
- };
3574
- output: string;
3575
- outputFormat: "text";
3576
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3577
- } | {
3578
- input: {
3579
- query: {
3580
- "no-caffeine"?: string | undefined;
3581
- };
3582
- };
3583
- output: Promise<never>;
3584
- outputFormat: "json";
3585
- status: _$hono_utils_http_status0.StatusCode;
3586
- };
3587
- };
3588
- } & {
3589
- "/gateway/logs": {
3590
- $get: {
3591
- input: {
3592
- query: {
3593
- n?: string | undefined;
3594
- format?: "json" | "plain" | undefined;
3595
- };
3596
- };
3597
- output: string;
3598
- outputFormat: "text";
3599
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3600
- } | {
3601
- input: {
3602
- query: {
3603
- n?: string | undefined;
3604
- format?: "json" | "plain" | undefined;
3605
- };
3606
- };
3607
- output: "no logs";
3608
- outputFormat: "text";
3609
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3610
- };
3611
- };
3612
- } & {
3613
- "/gateway/sql": {
3614
- $get: {
3615
- input: {
3616
- query: {
3617
- query?: string | undefined;
3618
- preset?: string | undefined;
3619
- channel?: string | undefined;
3620
- limit?: string | undefined;
3621
- };
3622
- };
3623
- output: string;
3624
- outputFormat: "text";
3625
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3626
- };
3627
- };
3628
- } & {
3629
- "/gateway/listeners": {
3630
- $get: {
3631
- input: {
3632
- query: Record<string, never>;
3633
- };
3634
- output: string;
3635
- outputFormat: "text";
3636
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3637
- } | {
3638
- input: {
3639
- query: Record<string, never>;
3640
- };
3641
- output: "funnel gateway: no running listeners";
3642
- outputFormat: "text";
3643
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3644
- } | {
3645
- input: {
3646
- query: Record<string, never>;
3647
- };
3648
- output: `funnel gateway: running listeners
3649
- ${string}`;
3650
- outputFormat: "text";
3651
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3652
- };
3653
- };
3654
- } & {
3655
- "/debug": {
3656
- $get: {
3657
- input: {
3658
- query: {
3659
- channel?: string | undefined;
3660
- all?: "" | "true" | "false" | undefined;
3661
- json?: "" | "true" | "false" | undefined;
3662
- limit?: string | undefined;
3663
- };
3664
- };
3665
- output: string;
3666
- outputFormat: "text";
3667
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3668
- } | {
3669
- input: {
3670
- query: {
3671
- channel?: string | undefined;
3672
- all?: "" | "true" | "false" | undefined;
3673
- json?: "" | "true" | "false" | undefined;
3674
- limit?: string | undefined;
3675
- };
3676
- };
3677
- output: {
3678
- error: string;
3679
- nextAction: string;
3680
- };
3681
- outputFormat: "json";
3682
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3683
- } | {
3684
- input: {
3685
- query: {
3686
- channel?: string | undefined;
3687
- all?: "" | "true" | "false" | undefined;
3688
- json?: "" | "true" | "false" | undefined;
3689
- limit?: string | undefined;
3690
- };
3691
- };
3692
- output: {
3693
- summary: {
3694
- total: number;
3695
- ok: number;
3696
- warn: number;
3697
- error: number;
3698
- criticalChannels: string[];
3699
- warnChannels: string[];
3700
- suggestedActions: string[];
3701
- };
3702
- channels: {
3703
- channel: string;
3704
- gateway: {
3705
- running: boolean;
3706
- pid: number | null;
3707
- port: number | null;
3708
- uptimeMs: number | null;
3709
- };
3710
- listeners: {
3711
- name: string;
3712
- type: string;
3713
- alive: boolean;
3714
- events: number;
3715
- errors: number;
3716
- lastEventAt: string | null;
3717
- }[];
3718
- claudeClients: number;
3719
- channelId: string;
3720
- recentEvents: {
3721
- seq: number | null;
3722
- ts: number | null;
3723
- type: string;
3724
- outcome: string;
3725
- eventId: string | null;
3726
- payload: string | null;
3727
- payloadParsed: {
3728
- [x: string]: _$hono_utils_types0.JSONValue;
3729
- } | null;
3730
- preview: string | null;
3731
- }[];
3732
- connectionErrors: {
3733
- seq: number | null;
3734
- ts: number | null;
3735
- type: string;
3736
- status: string;
3737
- detail: string | null;
3738
- }[];
3739
- diagnosis: {
3740
- status: "ok" | "warn" | "error";
3741
- message: string;
3742
- nextActions: string[];
3743
- rootCause: string | null;
3744
- };
3745
- }[];
3746
- };
3747
- outputFormat: "json";
3748
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3749
- } | {
3750
- input: {
3751
- query: {
3752
- channel?: string | undefined;
3753
- all?: "" | "true" | "false" | undefined;
3754
- json?: "" | "true" | "false" | undefined;
3755
- limit?: string | undefined;
3756
- };
3757
- };
3758
- output: {
3759
- error: string;
3760
- availableChannels: string[];
3761
- };
3762
- outputFormat: "json";
3763
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3764
- } | {
3765
- input: {
3766
- query: {
3767
- channel?: string | undefined;
3768
- all?: "" | "true" | "false" | undefined;
3769
- json?: "" | "true" | "false" | undefined;
3770
- limit?: string | undefined;
3771
- };
3772
- };
3773
- output: {
3774
- error: string;
3775
- channels: string[];
3776
- hint: string;
3777
- };
3778
- outputFormat: "json";
3779
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3780
- } | {
3781
- input: {
3782
- query: {
3783
- channel?: string | undefined;
3784
- all?: "" | "true" | "false" | undefined;
3785
- json?: "" | "true" | "false" | undefined;
3786
- limit?: string | undefined;
3787
- };
3788
- };
3789
- output: {
3790
- channel: string;
3791
- gateway: {
3792
- running: boolean;
3793
- pid: number | null;
3794
- port: number | null;
3795
- uptimeMs: number | null;
3796
- };
3797
- listeners: {
3798
- name: string;
3799
- type: string;
3800
- alive: boolean;
3801
- events: number;
3802
- errors: number;
3803
- lastEventAt: string | null;
3804
- }[];
3805
- claudeClients: number;
3806
- channelId: string;
3807
- recentEvents: {
3808
- seq: number | null;
3809
- ts: number | null;
3810
- type: string;
3811
- outcome: string;
3812
- eventId: string | null;
3813
- payload: string | null;
3814
- payloadParsed: {
3815
- [x: string]: _$hono_utils_types0.JSONValue;
3816
- } | null;
3817
- preview: string | null;
3818
- }[];
3819
- connectionErrors: {
3820
- seq: number | null;
3821
- ts: number | null;
3822
- type: string;
3823
- status: string;
3824
- detail: string | null;
3825
- }[];
3826
- diagnosis: {
3827
- status: "ok" | "warn" | "error";
3828
- message: string;
3829
- nextActions: string[];
3830
- rootCause: string | null;
3831
- };
3832
- };
3833
- outputFormat: "json";
3834
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3835
- };
3836
- };
3837
- } & {
3838
- "/debug/events": {
3839
- $get: {
3840
- input: {
3841
- query: {
3842
- channel?: string | undefined;
3843
- limit?: string | undefined;
3844
- json?: "" | "true" | "false" | undefined;
3845
- };
3846
- };
3847
- output: string;
3848
- outputFormat: "text";
3849
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3850
- } | {
3851
- input: {
3852
- query: {
3853
- channel?: string | undefined;
3854
- limit?: string | undefined;
3855
- json?: "" | "true" | "false" | undefined;
3856
- };
3857
- };
3858
- output: {
3859
- error: string;
3860
- availableChannels: string[];
3861
- };
3862
- outputFormat: "json";
3863
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3864
- } | {
3865
- input: {
3866
- query: {
3867
- channel?: string | undefined;
3868
- limit?: string | undefined;
3869
- json?: "" | "true" | "false" | undefined;
3870
- };
3871
- };
3872
- output: {
3873
- error: string;
3874
- channels: string[];
3875
- };
3876
- outputFormat: "json";
3877
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3878
- } | {
3879
- input: {
3880
- query: {
3881
- channel?: string | undefined;
3882
- limit?: string | undefined;
3883
- json?: "" | "true" | "false" | undefined;
3884
- };
3885
- };
3886
- output: {
3887
- seq: number | null;
3888
- ts: number | null;
3889
- type: string;
3890
- outcome: string;
3891
- eventId: string | null;
3892
- payload: string | null;
3893
- payloadParsed: {
3894
- [x: string]: _$hono_utils_types0.JSONValue;
3895
- } | null;
3896
- preview: string | null;
3897
- }[];
3898
- outputFormat: "json";
3899
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3900
- };
3901
- };
3902
- } & {
3903
- "/debug/dropped": {
3904
- $get: {
3905
- input: {
3906
- query: {
3907
- channel?: string | undefined;
3908
- limit?: string | undefined;
3909
- json?: "" | "true" | "false" | undefined;
3910
- };
3911
- };
3912
- output: string;
3913
- outputFormat: "text";
3914
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3915
- } | {
3916
- input: {
3917
- query: {
3918
- channel?: string | undefined;
3919
- limit?: string | undefined;
3920
- json?: "" | "true" | "false" | undefined;
3921
- };
3922
- };
3923
- output: {
3924
- seq: number | null;
3925
- ts: number | null;
3926
- type: string;
3927
- outcome: string;
3928
- eventId: string | null;
3929
- payload: string | null;
3930
- payloadParsed: {
3931
- [x: string]: _$hono_utils_types0.JSONValue;
3932
- } | null;
3933
- preview: string | null;
3934
- }[];
3935
- outputFormat: "json";
3936
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3937
- } | {
3938
- input: {
3939
- query: {
3940
- channel?: string | undefined;
3941
- limit?: string | undefined;
3942
- json?: "" | "true" | "false" | undefined;
3943
- };
3944
- };
3945
- output: {
3946
- error: string;
3947
- availableChannels: string[];
3948
- };
3949
- outputFormat: "json";
3950
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3951
- } | {
3952
- input: {
3953
- query: {
3954
- channel?: string | undefined;
3955
- limit?: string | undefined;
3956
- json?: "" | "true" | "false" | undefined;
3957
- };
3958
- };
3959
- output: {
3960
- error: string;
3961
- channels: string[];
3962
- };
3963
- outputFormat: "json";
3964
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3965
- };
3966
- };
3967
- } & {
3968
- "/debug/errors": {
3969
- $get: {
3970
- input: {
3971
- query: {
3972
- channel?: string | undefined;
3973
- limit?: string | undefined;
3974
- json?: "" | "true" | "false" | undefined;
3975
- };
3976
- };
3977
- output: string;
3978
- outputFormat: "text";
3979
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3980
- } | {
3981
- input: {
3982
- query: {
3983
- channel?: string | undefined;
3984
- limit?: string | undefined;
3985
- json?: "" | "true" | "false" | undefined;
3986
- };
3987
- };
3988
- output: {
3989
- error: string;
3990
- availableChannels: string[];
3991
- };
3992
- outputFormat: "json";
3993
- status: _$hono_utils_http_status0.ContentfulStatusCode;
3994
- } | {
3995
- input: {
3996
- query: {
3997
- channel?: string | undefined;
3998
- limit?: string | undefined;
3999
- json?: "" | "true" | "false" | undefined;
4000
- };
4001
- };
4002
- output: {
4003
- error: string;
4004
- channels: string[];
4005
- };
4006
- outputFormat: "json";
4007
- status: _$hono_utils_http_status0.ContentfulStatusCode;
4008
- } | {
4009
- input: {
4010
- query: {
4011
- channel?: string | undefined;
4012
- limit?: string | undefined;
4013
- json?: "" | "true" | "false" | undefined;
4014
- };
4015
- };
4016
- output: {
4017
- seq: number | null;
4018
- ts: number | null;
4019
- type: string;
4020
- status: string;
4021
- detail: string | null;
4022
- }[];
4023
- outputFormat: "json";
4024
- status: _$hono_utils_http_status0.ContentfulStatusCode;
4025
- };
4026
- };
4027
- } & {
4028
- "/debug/replay": {
4029
- $get: {
4030
- input: {
4031
- query: {
4032
- channel?: string | undefined;
4033
- seq?: string | undefined;
4034
- json?: "" | "true" | "false" | undefined;
4035
- };
4036
- };
4037
- output: string;
4038
- outputFormat: "text";
4039
- status: _$hono_utils_http_status0.ContentfulStatusCode;
4040
- } | {
4041
- input: {
4042
- query: {
4043
- channel?: string | undefined;
4044
- seq?: string | undefined;
4045
- json?: "" | "true" | "false" | undefined;
4046
- };
4047
- };
4048
- output: `error: ${string}`;
4049
- outputFormat: "text";
4050
- status: _$hono_utils_http_status0.ContentfulStatusCode;
4051
- } | {
4052
- input: {
4053
- query: {
4054
- channel?: string | undefined;
4055
- seq?: string | undefined;
4056
- json?: "" | "true" | "false" | undefined;
4057
- };
4058
- };
4059
- output: `channel not found: ${string}`;
4060
- outputFormat: "text";
4061
- status: _$hono_utils_http_status0.ContentfulStatusCode;
4062
- } | {
4063
- input: {
4064
- query: {
4065
- channel?: string | undefined;
4066
- seq?: string | undefined;
4067
- json?: "" | "true" | "false" | undefined;
4068
- };
4069
- };
4070
- output: "no diagnostic store yet (start the gateway first)";
4071
- outputFormat: "text";
4072
- status: _$hono_utils_http_status0.ContentfulStatusCode;
4073
- } | {
4074
- input: {
4075
- query: {
4076
- channel?: string | undefined;
4077
- seq?: string | undefined;
4078
- json?: "" | "true" | "false" | undefined;
4079
- };
4080
- };
4081
- output: `multiple channels \u2014 specify one with --channel:
4082
- ${string}`;
4083
- outputFormat: "text";
4084
- status: _$hono_utils_http_status0.ContentfulStatusCode;
4085
- } | {
4086
- input: {
4087
- query: {
4088
- channel?: string | undefined;
4089
- seq?: string | undefined;
4090
- json?: "" | "true" | "false" | undefined;
4091
- };
4092
- };
4093
- output: "no channels configured";
4094
- outputFormat: "text";
4095
- status: _$hono_utils_http_status0.ContentfulStatusCode;
4096
- } | {
4097
- input: {
4098
- query: {
4099
- channel?: string | undefined;
4100
- seq?: string | undefined;
4101
- json?: "" | "true" | "false" | undefined;
4102
- };
4103
- };
4104
- output: {
4105
- error: string;
4106
- };
4107
- outputFormat: "json";
4108
- status: _$hono_utils_http_status0.ContentfulStatusCode;
4109
- } | {
4110
- input: {
4111
- query: {
4112
- channel?: string | undefined;
4113
- seq?: string | undefined;
4114
- json?: "" | "true" | "false" | undefined;
4115
- };
4116
- };
4117
- output: "no matching event found";
4118
- outputFormat: "text";
4119
- status: _$hono_utils_http_status0.ContentfulStatusCode;
4120
- } | {
4121
- input: {
4122
- query: {
4123
- channel?: string | undefined;
4124
- seq?: string | undefined;
4125
- json?: "" | "true" | "false" | undefined;
4126
- };
4127
- };
4128
- output: "event has no payload to replay";
4129
- outputFormat: "text";
4130
- status: _$hono_utils_http_status0.ContentfulStatusCode;
4131
- } | {
4132
- input: {
4133
- query: {
4134
- channel?: string | undefined;
4135
- seq?: string | undefined;
4136
- json?: "" | "true" | "false" | undefined;
4137
- };
4138
- };
4139
- output: {
4140
- replayed: true;
4141
- seq: number | null;
4142
- offset: number;
4143
- preview: string | null;
4144
- };
4145
- outputFormat: "json";
4146
- status: _$hono_utils_http_status0.ContentfulStatusCode;
4147
- } | {
4148
- input: {
4149
- query: {
4150
- channel?: string | undefined;
4151
- seq?: string | undefined;
4152
- json?: "" | "true" | "false" | undefined;
4153
- };
4154
- };
4155
- output: `replayed seq=${number} \u2192 offset=${number}${string}` | `replayed seq=? \u2192 offset=${number}${string}`;
4156
- outputFormat: "text";
4157
- status: _$hono_utils_http_status0.ContentfulStatusCode;
4158
- };
4159
- };
4160
- } & {
4161
- "/schema": {
4162
- $get: {
4163
- input: {
4164
- query: Record<string, never>;
4165
- };
4166
- output: string;
4167
- outputFormat: "text";
4168
- status: _$hono_utils_http_status0.ContentfulStatusCode;
4169
- } | {
4170
- input: {
4171
- query: Record<string, never>;
4172
- };
4173
- output: `${string}
4174
- `;
4175
- outputFormat: "text";
4176
- status: _$hono_utils_http_status0.ContentfulStatusCode;
4177
- };
4178
- };
4179
- } & {
4180
- "/status": {
4181
- $get: {
4182
- input: {
4183
- query: {
4184
- watch?: "" | "true" | "false" | undefined;
4185
- interval?: string | undefined;
4186
- };
4187
- };
4188
- output: string;
4189
- outputFormat: "text";
4190
- status: _$hono_utils_http_status0.ContentfulStatusCode;
4191
- };
4192
- };
4193
- } & {
4194
- "/update": {
4195
- $get: {
4196
- input: {
4197
- query: Record<string, never>;
4198
- };
4199
- output: string;
4200
- outputFormat: "text";
4201
- status: _$hono_utils_http_status0.ContentfulStatusCode;
4202
- } | {
4203
- input: {
4204
- query: Record<string, never>;
4205
- };
4206
- output: "updated @interactive-inc/claude-funnel";
4207
- outputFormat: "text";
4208
- status: _$hono_utils_http_status0.ContentfulStatusCode;
4209
- };
4210
- };
4211
- }, "/", "/update">;
4212
- type CliApp = typeof routes;
4213
- //#endregion
4214
- export { AliveStub, AttachOptions, BroadcastEvent, BroadcastSubscriber, CONNECTOR_CONNECTION_STATUSES, ChannelConfig, ChannelConnectorView, ChannelDeliveryMode, ChannelServerOptions, ChannelSpec, type CliApp, ConnectorConfig, ConnectorConnectionEvent, ConnectorConnectionQuery, ConnectorConnectionRecord, ConnectorConnectionStatus, ConnectorDiagnosticLog, ConnectorDiagnosticSqlReader, ConnectorProcessedEvent, ConnectorProcessedQuery, ConnectorProcessedRecord, ConnectorQuery, ConnectorRawEvent, ConnectorRawQuery, ConnectorRawRecord, ConnectorSpec, ConnectorSyncOutcome, ConnectorType, DEFAULT_GATEWAY_PORT, DEFAULT_GATEWAY_TOKEN_PATH, DetachOptions, DiscordConnectorConfig, Env, FUNNEL_DIR, FUNNEL_MCP_ARGS, FUNNEL_MCP_COMMAND, FUNNEL_MCP_NAME, FileStat, Funnel, FunnelBroadcaster, FunnelChannelPublisher, FunnelChannels, FunnelClaude, FunnelClock, FunnelConnectorFactory, FunnelConnectorListener, type FunnelDebugReport, FunnelEvent, FunnelEventLog, FunnelEventRecord, FunnelFileSystem, FunnelGateway, FunnelGatewayServer, FunnelGatewayToken, FunnelIdGenerator, FunnelListenerSupervisor, FunnelListenersClient, FunnelLocalConfig, FunnelLocalConfigSync, FunnelLocalConfigWriter, FunnelLogger, FunnelMcp, FunnelProcessRunner, FunnelProfiles, FunnelSettingsReader, FunnelSettingsStore, FunnelSlackEventProcessor, FunnelTokenPrompter, type GatewayApp, type GatewayEmitInput, type GatewayRouteDeps, type Env$1 as GatewayServerEnv, GhConnectorConfig, LOCAL_CONFIG_FILENAME, LaunchOptions, ListListenersResult, ListenerEntry, ListenerOpResult, LocalConfig, LocalConfigSyncResult, LogEntry, MemoryConnectorDiagnosticLog, MemoryFunnelClock, MemoryFunnelEventLog, MemoryFunnelFileSystem, MemoryFunnelIdGenerator, MemoryFunnelLogger, MemoryFunnelProcessRunner, MemoryFunnelTokenPrompter, MemoryProcessCall, MemoryProcessHandler, MemoryProcessResponse, MemoryProcessSyncHandler, MockFunnelSettingsReader, NodeFunnelClock, NodeFunnelFileSystem, NodeFunnelIdGenerator, NodeFunnelLogger, NodeFunnelProcessRunner, NodeFunnelTokenPrompter, NoopFunnelLogger, NotifyFn, OnFunnelError, ProcessListStub, ProcessSnapshot, ProfileConfig, ProfileSpec, PublishRequest, PublishResponse, PublishResult, ReplayableEvent, RunOptions, RunResult, SETTINGS_PATH, SETTINGS_VERSION, ScheduleCatchupPolicy, ScheduleConnectorConfig, ScheduleEntry, ScheduleListenerOptions, Settings, SlackConnectorConfig, SlackListenerOptions, SlackProcessed, SlackProcessedEmit, SlackProcessedSkip, SlackRawEvent, SlackSkipReason, SqliteConnectorDiagnosticLog, SqliteFunnelEventLog, StoredConnectionEvent, StoredProcessedEvent, StoredRawEvent, channelConfigSchema, channelDeliveryModeSchema, channelSpecSchema, routes as cliRoutes, connectorConfigSchema, connectorConnectionEventSchema, connectorProcessedEventSchema, connectorRawEventSchema, connectorSpecSchema, createSettings, discordConnectorSchema, factory, funnelEventSchema, funnelJsonSchema, ghConnectorSchema, localConfigSchema, profileConfigSchema, profileSpecSchema, publishRequestSchema, publishResponseSchema, queryToCliArgs, resolveFunnelDir, resolveFunnelPort, scheduleCatchupPolicySchema, scheduleConnectorSchema, scheduleEntrySchema, settingsSchema, slackConnectorSchema, startChannelServer, toRequest };
1
+ import { a as ProfileConfig, c as channelConfigSchema, d as settingsSchema, i as ChannelDeliveryMode, l as channelDeliveryModeSchema, n as FunnelIdGenerator, o as SETTINGS_VERSION, r as ChannelConfig, s as Settings, t as FunnelSettingsReader, u as profileConfigSchema } from "./settings-reader-BSU6JyvM.js";
2
+ import { S as FunnelLogger, _ as connectorConnectionEventSchema, a as ConnectorConnectionStatus, b as FunnelConnectorListener, c as ConnectorProcessedQuery, d as ConnectorRawEvent, f as ConnectorRawQuery, g as StoredRawEvent, h as StoredProcessedEvent, i as ConnectorConnectionRecord, l as ConnectorProcessedRecord, m as StoredConnectionEvent, n as ConnectorConnectionEvent, o as ConnectorDiagnosticLog, p as ConnectorRawRecord, r as ConnectorConnectionQuery, s as ConnectorProcessedEvent, t as CONNECTOR_CONNECTION_STATUSES, u as ConnectorQuery, v as connectorProcessedEventSchema, x as NotifyFn, y as connectorRawEventSchema } from "./connector-diagnostic-log-yTOojKUR.js";
3
+ import { a as RunOptions, i as ProcessSnapshot, n as DetachOptions, o as RunResult, r as FunnelProcessRunner, t as AttachOptions } from "./process-runner-DfniuWVU.js";
4
+ import { n as FunnelFileSystem, t as FileStat } from "./file-system-BeOKXjlV.js";
5
+ import { a as ChannelConnectorView, c as FunnelConnectorFactory, d as ConnectorConfig, f as ConnectorType, l as ScheduleListenerOptions, o as FunnelChannels, p as connectorConfigSchema, s as FunnelClock, u as SlackListenerOptions } from "./local-config-sync-BdsrDZOu.js";
6
+ import { a as ScheduleEntry, c as scheduleEntrySchema, i as ScheduleConnectorConfig, o as scheduleCatchupPolicySchema, r as ScheduleCatchupPolicy, s as scheduleConnectorSchema } from "./schedule-listener-CUyUFFR1.js";
7
+ import { a as slackConnectorSchema, c as SlackProcessedEmit, d as SlackSkipReason, i as SlackConnectorConfig, l as SlackProcessedSkip, o as FunnelSlackEventProcessor, s as SlackProcessed, u as SlackRawEvent } from "./slack-listener-Bv5xI9gC.js";
8
+ import { n as discordConnectorSchema, t as DiscordConnectorConfig } from "./discord-connector-schema-R0Uu-3ns.js";
9
+ import { n as ghConnectorSchema, t as GhConnectorConfig } from "./gh-connector-schema-eoTtHbY6.js";
10
+ import { $ as FunnelGatewayToken, A as FUNNEL_DIR, B as ListenerOpResult, C as ProcessListStub, D as MockFunnelSettingsReader, E as NodeFunnelFileSystem, F as Funnel, G as SqliteFunnelEventLog, H as MemoryConnectorDiagnosticLog, I as FunnelDebugReport, J as PublishResponse, K as FunnelChannelPublisher, L as FunnelListenersClient, M as SETTINGS_PATH, N as resolveFunnelDir, O as createSettings, P as resolveFunnelPort, Q as DEFAULT_GATEWAY_TOKEN_PATH, R as ListListenersResult, S as MemoryProcessSyncHandler, T as MemoryFunnelFileSystem, U as SqliteConnectorDiagnosticLog, V as FunnelGateway, W as MemoryFunnelEventLog, X as publishRequestSchema, Y as PublishResult, Z as publishResponseSchema, _ as AliveStub, a as toRequest, at as Env$1, b as MemoryProcessHandler, c as ConnectorDiagnosticSqlReader, ct as FunnelListenerSupervisor, d as MemoryFunnelClock, dt as FunnelBroadcaster, et as FunnelGatewayServer, f as NodeFunnelClock, ft as ReplayableEvent, g as NodeFunnelLogger, h as MemoryFunnelLogger, i as queryToCliArgs, it as funnelEventSchema, j as FunnelSettingsStore, k as DEFAULT_GATEWAY_PORT, l as MemoryFunnelIdGenerator, lt as BroadcastEvent, m as LogEntry, n as CliApp, nt as FunnelEventLog, o as Env, ot as GatewayEmitInput, p as NoopFunnelLogger, pt as OnFunnelError, q as PublishRequest, r as routes, rt as FunnelEventRecord, s as factory, st as GatewayRouteDeps, t as GatewayApp, tt as FunnelEvent, u as NodeFunnelIdGenerator, ut as BroadcastSubscriber, v as MemoryFunnelProcessRunner, w as NodeFunnelProcessRunner, x as MemoryProcessResponse, y as MemoryProcessCall, z as ListenerEntry } from "./index-ChomoTZ5.js";
11
+ export { AliveStub, AttachOptions, BroadcastEvent, BroadcastSubscriber, CONNECTOR_CONNECTION_STATUSES, ChannelConfig, ChannelConnectorView, ChannelDeliveryMode, CliApp, ConnectorConfig, ConnectorConnectionEvent, ConnectorConnectionQuery, ConnectorConnectionRecord, ConnectorConnectionStatus, ConnectorDiagnosticLog, ConnectorDiagnosticSqlReader, ConnectorProcessedEvent, ConnectorProcessedQuery, ConnectorProcessedRecord, ConnectorQuery, ConnectorRawEvent, ConnectorRawQuery, ConnectorRawRecord, ConnectorType, DEFAULT_GATEWAY_PORT, DEFAULT_GATEWAY_TOKEN_PATH, DetachOptions, DiscordConnectorConfig, Env, FUNNEL_DIR, FileStat, Funnel, FunnelBroadcaster, FunnelChannelPublisher, FunnelChannels, FunnelClock, FunnelConnectorFactory, FunnelConnectorListener, FunnelDebugReport, FunnelEvent, FunnelEventLog, FunnelEventRecord, FunnelFileSystem, FunnelGateway, FunnelGatewayServer, FunnelGatewayToken, FunnelIdGenerator, FunnelListenerSupervisor, FunnelListenersClient, FunnelLogger, FunnelProcessRunner, FunnelSettingsReader, FunnelSettingsStore, FunnelSlackEventProcessor, GatewayApp, GatewayEmitInput, GatewayRouteDeps, Env$1 as GatewayServerEnv, GhConnectorConfig, ListListenersResult, ListenerEntry, ListenerOpResult, LogEntry, MemoryConnectorDiagnosticLog, MemoryFunnelClock, MemoryFunnelEventLog, MemoryFunnelFileSystem, MemoryFunnelIdGenerator, MemoryFunnelLogger, MemoryFunnelProcessRunner, MemoryProcessCall, MemoryProcessHandler, MemoryProcessResponse, MemoryProcessSyncHandler, MockFunnelSettingsReader, NodeFunnelClock, NodeFunnelFileSystem, NodeFunnelIdGenerator, NodeFunnelLogger, NodeFunnelProcessRunner, NoopFunnelLogger, NotifyFn, OnFunnelError, ProcessListStub, ProcessSnapshot, ProfileConfig, PublishRequest, PublishResponse, PublishResult, ReplayableEvent, RunOptions, RunResult, SETTINGS_PATH, SETTINGS_VERSION, ScheduleCatchupPolicy, ScheduleConnectorConfig, ScheduleEntry, ScheduleListenerOptions, Settings, SlackConnectorConfig, SlackListenerOptions, SlackProcessed, SlackProcessedEmit, SlackProcessedSkip, SlackRawEvent, SlackSkipReason, SqliteConnectorDiagnosticLog, SqliteFunnelEventLog, StoredConnectionEvent, StoredProcessedEvent, StoredRawEvent, channelConfigSchema, channelDeliveryModeSchema, routes as cliRoutes, connectorConfigSchema, connectorConnectionEventSchema, connectorProcessedEventSchema, connectorRawEventSchema, createSettings, discordConnectorSchema, factory, funnelEventSchema, ghConnectorSchema, profileConfigSchema, publishRequestSchema, publishResponseSchema, queryToCliArgs, resolveFunnelDir, resolveFunnelPort, scheduleCatchupPolicySchema, scheduleConnectorSchema, scheduleEntrySchema, settingsSchema, slackConnectorSchema, toRequest };