@interactive-inc/claude-funnel 0.10.1 → 0.15.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -2,10 +2,11 @@ import { n as FunnelConnectorAdapter, t as CallInput } from "./connector-adapter
2
2
  import { n as discordConnectorSchema, t as DiscordConnectorConfig } from "./discord-connector-schema-Dww2I4zH.js";
3
3
  import { n as FunnelConnectorListener, r as NotifyFn, t as FunnelLogger } from "./logger-CTlXs7z4.js";
4
4
  import { a as FunnelProcessRunner, i as DetachOptions, n as ghConnectorSchema, o as RunOptions, r as AttachOptions, s as RunResult, t as GhConnectorConfig } from "./gh-connector-schema-BZFAS-p-.js";
5
- import { a as ScheduleEntry, c as scheduleEntrySchema, i as ScheduleConnectorConfig, n as FunnelFileSystem, o as scheduleCatchupPolicySchema, r as ScheduleCatchupPolicy, s as scheduleConnectorSchema, t as FileStat } from "./file-system-Co60LrmR.js";
6
- import { a as SlackRawEvent, i as SlackProcessedSkip, n as SlackProcessed, o as SlackConnectorConfig, r as SlackProcessedEmit, s as slackConnectorSchema, t as FunnelSlackEventProcessor } from "./slack-event-processor-CS-bAit9.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-BPodvbld.js";
6
+ import { a as SlackProcessed, c as SlackRawEvent, i as FunnelSlackEventProcessor, l as SlackConnectorConfig, n as SlackOnAppCreated, o as SlackProcessedEmit, r as SlackPreprocessEvent, s as SlackProcessedSkip, u as slackConnectorSchema } from "./slack-listener-CHj6uMY-.js";
7
7
  import { z } from "zod";
8
8
  import * as _$hono_factory0 from "hono/factory";
9
+ import { Hono } from "hono";
9
10
  import { Server, ServerWebSocket } from "bun";
10
11
  import * as _$hono_utils_http_status0 from "hono/utils/http-status";
11
12
  import * as _$hono_hono_base0 from "hono/hono-base";
@@ -55,11 +56,20 @@ type ConnectorConfig = z.infer<typeof connectorConfigSchema>;
55
56
  type ConnectorType = ConnectorConfig["type"];
56
57
  //#endregion
57
58
  //#region lib/connectors/connector-factory.d.ts
58
- type Deps$12 = {
59
+ type SlackListenerOptions = {
60
+ onAppCreated?: SlackOnAppCreated;
61
+ preprocessEvent?: SlackPreprocessEvent;
62
+ };
63
+ type ScheduleListenerOptions = {
64
+ onFired?: ScheduleOnFired;
65
+ };
66
+ type Deps$15 = {
59
67
  fs?: FunnelFileSystem;
60
68
  process?: FunnelProcessRunner;
61
69
  logger?: FunnelLogger;
62
- dir?: string;
70
+ dir?: string; /** Per-listener hooks for the slack connector type. Threaded into every Slack listener built by this factory. */
71
+ slackListenerOptions?: SlackListenerOptions; /** Per-listener hooks for the schedule connector type. Threaded into every Schedule listener built by this factory. */
72
+ scheduleListenerOptions?: ScheduleListenerOptions;
63
73
  };
64
74
  /**
65
75
  * Pure factory for per-type listeners and adapters. The factory has no CRUD
@@ -68,13 +78,19 @@ type Deps$12 = {
68
78
  *
69
79
  * `dir` is the funnel home (defaults to ~/.funnel); per-connector state files
70
80
  * land at `<dir>/channels/<channel-id>/connectors/<connector-id>/state.json`.
81
+ *
82
+ * Host integrations can supply per-type listener hooks via
83
+ * `slackListenerOptions` / `scheduleListenerOptions` — e.g. to attach a
84
+ * Bolt `app.action` handler or to drop one-shot schedule entries on fire.
71
85
  */
72
86
  declare class FunnelConnectorFactory {
73
87
  private readonly fs;
74
88
  private readonly process;
75
89
  private readonly logger;
76
90
  private readonly dir;
77
- constructor(deps?: Deps$12);
91
+ private readonly slackListenerOptions;
92
+ private readonly scheduleListenerOptions;
93
+ constructor(deps?: Deps$15);
78
94
  createListener(channelId: string, config: ConnectorConfig): FunnelConnectorListener;
79
95
  createAdapter(config: ConnectorConfig): FunnelConnectorAdapter | null;
80
96
  connectorDir(channelId: string, connectorId: string): string;
@@ -252,7 +268,7 @@ declare abstract class FunnelSettingsReader {
252
268
  }
253
269
  //#endregion
254
270
  //#region lib/engine/channels/channels.d.ts
255
- type Deps$11 = {
271
+ type Deps$14 = {
256
272
  store: FunnelSettingsReader;
257
273
  factory: FunnelConnectorFactory;
258
274
  profileChecker: ProfileChannelChecker;
@@ -295,7 +311,7 @@ declare class FunnelChannels {
295
311
  private readonly profileChecker;
296
312
  private readonly clock;
297
313
  private readonly idGenerator;
298
- constructor(deps: Deps$11);
314
+ constructor(deps: Deps$14);
299
315
  list(): ChannelConfig[];
300
316
  get(name: string): ChannelConfig | null;
301
317
  getById(id: string): ChannelConfig | null;
@@ -353,7 +369,7 @@ type GatewayController = {
353
369
  //#region lib/engine/mcp/mcp.d.ts
354
370
  declare const FUNNEL_MCP_COMMAND = "funnel";
355
371
  declare const FUNNEL_MCP_NAME = "funnel";
356
- type Deps$10 = {
372
+ type Deps$13 = {
357
373
  fs?: FunnelFileSystem;
358
374
  };
359
375
  /**
@@ -363,7 +379,7 @@ type Deps$10 = {
363
379
  */
364
380
  declare class FunnelMcp {
365
381
  private readonly fs;
366
- constructor(deps?: Deps$10);
382
+ constructor(deps?: Deps$13);
367
383
  install(repoPath: string): void;
368
384
  uninstall(repoPath: string): void;
369
385
  findInstalledName(cwd: string): string | null;
@@ -379,9 +395,10 @@ type LaunchOptions = {
379
395
  subAgent?: string;
380
396
  userArgs?: string[];
381
397
  profileName?: string; /** Forward `--brief` to claude on launch (enables the SendUserMessage tool). */
382
- brief?: boolean;
398
+ brief?: boolean; /** Extra env vars merged under process.env (process.env wins on collision). */
399
+ extraEnv?: Record<string, string>;
383
400
  };
384
- type Deps$9 = {
401
+ type Deps$12 = {
385
402
  channels: FunnelChannels;
386
403
  mcp: FunnelMcp;
387
404
  gateway: GatewayController;
@@ -404,7 +421,7 @@ declare class FunnelClaude {
404
421
  private readonly fs;
405
422
  private readonly logger;
406
423
  private readonly pidDir;
407
- constructor(deps: Deps$9);
424
+ constructor(deps: Deps$12);
408
425
  launch(options: LaunchOptions): Promise<number>;
409
426
  isRunning(profileName: string): boolean;
410
427
  private pidPath;
@@ -417,6 +434,151 @@ declare class FunnelClaude {
417
434
  private buildEnv;
418
435
  }
419
436
  //#endregion
437
+ //#region lib/engine/local-config/dotenv-reader.d.ts
438
+ type Deps$11 = {
439
+ fs: FunnelFileSystem;
440
+ };
441
+ /**
442
+ * Minimal `.env.local` parser. Supports `KEY=value` lines, blank lines, and
443
+ * `#` comments. Strips matching surrounding single or double quotes. No
444
+ * interpolation, no `export` prefix — anything fancier should live in a real
445
+ * env file loaded by the shell.
446
+ */
447
+ declare class FunnelDotenvReader {
448
+ private readonly fs;
449
+ constructor(deps: Deps$11);
450
+ read(cwd: string): Record<string, string>;
451
+ }
452
+ //#endregion
453
+ //#region lib/engine/local-config/local-config-schema.d.ts
454
+ declare const connectorSpecSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
455
+ type: z.ZodLiteral<"slack">;
456
+ name: z.ZodString;
457
+ botToken: z.ZodOptional<z.ZodString>;
458
+ appToken: z.ZodOptional<z.ZodString>;
459
+ env: z.ZodOptional<z.ZodObject<{
460
+ botToken: z.ZodOptional<z.ZodString>;
461
+ appToken: z.ZodOptional<z.ZodString>;
462
+ }, z.core.$strip>>;
463
+ }, z.core.$strip>, z.ZodObject<{
464
+ type: z.ZodLiteral<"discord">;
465
+ name: z.ZodString;
466
+ botToken: z.ZodOptional<z.ZodString>;
467
+ env: z.ZodOptional<z.ZodObject<{
468
+ botToken: z.ZodOptional<z.ZodString>;
469
+ }, z.core.$strip>>;
470
+ }, z.core.$strip>, z.ZodObject<{
471
+ type: z.ZodLiteral<"gh">;
472
+ name: z.ZodString;
473
+ pollInterval: z.ZodOptional<z.ZodNumber>;
474
+ }, z.core.$strip>, z.ZodObject<{
475
+ type: z.ZodLiteral<"schedule">;
476
+ name: z.ZodString;
477
+ }, z.core.$strip>], "type">;
478
+ type ConnectorSpec = z.infer<typeof connectorSpecSchema>;
479
+ declare const localConfigSchema: z.ZodObject<{
480
+ $schema: z.ZodOptional<z.ZodString>;
481
+ channel: z.ZodString;
482
+ options: z.ZodOptional<z.ZodArray<z.ZodString>>;
483
+ env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
484
+ connectors: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
485
+ type: z.ZodLiteral<"slack">;
486
+ name: z.ZodString;
487
+ botToken: z.ZodOptional<z.ZodString>;
488
+ appToken: z.ZodOptional<z.ZodString>;
489
+ env: z.ZodOptional<z.ZodObject<{
490
+ botToken: z.ZodOptional<z.ZodString>;
491
+ appToken: z.ZodOptional<z.ZodString>;
492
+ }, z.core.$strip>>;
493
+ }, z.core.$strip>, z.ZodObject<{
494
+ type: z.ZodLiteral<"discord">;
495
+ name: z.ZodString;
496
+ botToken: z.ZodOptional<z.ZodString>;
497
+ env: z.ZodOptional<z.ZodObject<{
498
+ botToken: z.ZodOptional<z.ZodString>;
499
+ }, z.core.$strip>>;
500
+ }, z.core.$strip>, z.ZodObject<{
501
+ type: z.ZodLiteral<"gh">;
502
+ name: z.ZodString;
503
+ pollInterval: z.ZodOptional<z.ZodNumber>;
504
+ }, z.core.$strip>, z.ZodObject<{
505
+ type: z.ZodLiteral<"schedule">;
506
+ name: z.ZodString;
507
+ }, z.core.$strip>], "type">>>;
508
+ }, z.core.$strip>;
509
+ type LocalConfig = z.infer<typeof localConfigSchema>;
510
+ declare const LOCAL_CONFIG_FILENAME = "funnel.json";
511
+ declare const LOCAL_ENV_FILENAME = ".env.local";
512
+ //#endregion
513
+ //#region lib/engine/local-config/local-config.d.ts
514
+ type Deps$10 = {
515
+ fs: FunnelFileSystem;
516
+ };
517
+ /**
518
+ * Reads `funnel.json` from a directory. Returns `null` when the file is
519
+ * absent so callers can fall through to other resolution paths (default
520
+ * profile, help). Throws on present-but-invalid files so misconfiguration
521
+ * surfaces loudly instead of silently launching the wrong channel.
522
+ */
523
+ declare class FunnelLocalConfig {
524
+ private readonly fs;
525
+ constructor(deps: Deps$10);
526
+ read(cwd: string): LocalConfig | null;
527
+ }
528
+ //#endregion
529
+ //#region lib/engine/token-prompter/token-prompter.d.ts
530
+ /**
531
+ * Asks the user for a secret value on stdin. Used as a last resort when a
532
+ * funnel.json token field is absent and not present in `~/.funnel`. The Node
533
+ * implementation refuses to prompt when stdin is not a TTY so non-interactive
534
+ * launches (CI, agent spawning agent, daemons) fail fast instead of hanging.
535
+ */
536
+ declare abstract class FunnelTokenPrompter {
537
+ abstract promptSecret(label: string): Promise<string>;
538
+ }
539
+ //#endregion
540
+ //#region lib/engine/local-config/local-config-sync.d.ts
541
+ type Deps$9 = {
542
+ channels: FunnelChannels;
543
+ dotenv: FunnelDotenvReader;
544
+ prompter: FunnelTokenPrompter;
545
+ env?: NodeJS.ProcessEnv;
546
+ };
547
+ /**
548
+ * Reconciles a `funnel.json` spec with `~/.funnel/settings.json`. The spec
549
+ * is the source of truth for the channel it declares:
550
+ *
551
+ * - missing channel → created
552
+ * - declared connector matched by name → tokens reconciled
553
+ * - declared connector matched by token in the same channel under a
554
+ * different name → renamed in place (then tokens reconciled)
555
+ * - declared connector with no match → added
556
+ * - any connector left in the channel that the spec did not touch → removed
557
+ *
558
+ * Removal only fires when funnel.json has a `connectors` field. An absent
559
+ * field means "do not manage connectors from here" and leaves everything in
560
+ * `~/.funnel` alone.
561
+ */
562
+ declare class FunnelLocalConfigSync {
563
+ private readonly channels;
564
+ private readonly dotenv;
565
+ private readonly prompter;
566
+ private readonly env;
567
+ constructor(deps: Deps$9);
568
+ ensure(local: LocalConfig, cwd: string): Promise<void>;
569
+ private ensureConnector;
570
+ private ensureSlack;
571
+ private ensureDiscord;
572
+ private ensureGh;
573
+ private ensureSchedule;
574
+ private findExistingSlack;
575
+ private findExistingDiscord;
576
+ private findSlackByToken;
577
+ private findDiscordByToken;
578
+ private removeExtras;
579
+ private resolveField;
580
+ }
581
+ //#endregion
420
582
  //#region lib/engine/profiles/profiles.d.ts
421
583
  type Deps$8 = {
422
584
  store: FunnelSettingsReader;
@@ -495,62 +657,6 @@ declare class FunnelChannelPublisher {
495
657
  private authHeaders;
496
658
  }
497
659
  //#endregion
498
- //#region lib/gateway/gateway.d.ts
499
- type Deps$6 = {
500
- process?: FunnelProcessRunner;
501
- fs?: FunnelFileSystem;
502
- clock?: FunnelClock;
503
- dir?: string;
504
- tmpDir?: string;
505
- port?: number;
506
- sleep?: (ms: number) => Promise<void>;
507
- };
508
- /**
509
- * Manages the gateway daemon as a separate process via PID file.
510
- * Use `start()` to spawn `bun daemon.ts` in the background and `stop()` to
511
- * terminate it. For an in-process gateway, use `Funnel.gatewayServer` instead.
512
- */
513
- declare class FunnelGateway {
514
- private readonly process;
515
- private readonly fs;
516
- private readonly clock;
517
- private readonly pidFile;
518
- private readonly logDir;
519
- private readonly gatewayLog;
520
- private readonly tmpDir;
521
- private readonly port;
522
- private readonly sleep;
523
- constructor(deps?: Deps$6);
524
- isRunning(): boolean;
525
- getStatus(): {
526
- running: boolean;
527
- pid: number | null;
528
- port: number;
529
- };
530
- start(options?: {
531
- caffeinate?: boolean;
532
- }): Promise<boolean>;
533
- buildStartCommand(gatewayScript: string, options?: {
534
- caffeinate?: boolean;
535
- }): string;
536
- stop(): Promise<boolean>;
537
- restart(options?: {
538
- onlyIfRunning?: boolean;
539
- caffeinate?: boolean;
540
- }): Promise<{
541
- ok: boolean;
542
- wasRunning: boolean;
543
- stopped: boolean;
544
- started: boolean;
545
- }>;
546
- getLogDir(): string;
547
- getGatewayLog(): string;
548
- getPort(): number;
549
- private readPid;
550
- private removePid;
551
- private isProcessAlive;
552
- }
553
- //#endregion
554
660
  //#region lib/gateway/broadcaster.d.ts
555
661
  type ClientData = {
556
662
  /** Stable channel id (uuid) that the WS client subscribed to. */channel: string; /** Human-facing channel name resolved at upgrade time, kept for log readability. */
@@ -576,7 +682,7 @@ type BroadcastSubscriber = (event: ReplayableEvent) => void;
576
682
  type ReplaySource = {
577
683
  loadSince(since: number): ReplayableEvent[];
578
684
  };
579
- type Deps$5 = {
685
+ type Deps$6 = {
580
686
  logger?: FunnelLogger;
581
687
  maxBufferedBytes?: number;
582
688
  now?: () => number; /** Number of recent events kept in the in-memory replay buffer. */
@@ -627,7 +733,7 @@ declare class FunnelBroadcaster {
627
733
  private droppedSlowClients;
628
734
  private lastBroadcastAt;
629
735
  private latestOffset;
630
- constructor(deps?: Deps$5);
736
+ constructor(deps?: Deps$6);
631
737
  getMetrics(): BroadcasterMetrics;
632
738
  /**
633
739
  * Returns events with offset > since, filtered by the connector subscription
@@ -663,82 +769,6 @@ declare class FunnelBroadcaster {
663
769
  seedLatestOffset(offset: number): void;
664
770
  }
665
771
  //#endregion
666
- //#region lib/gateway/funnel-event-store.d.ts
667
- /**
668
- * Replayable event payload persisted by the gateway. Domain events the
669
- * broadcaster emits to WS clients land here so reconnects across daemon
670
- * restarts can be served from disk. System events (gateway start, channel
671
- * connected, etc.) are routed to `FunnelLogger` instead — they never go
672
- * through this store, which keeps the seq space clean for replay.
673
- */
674
- declare const funnelEventSchema: z.ZodObject<{
675
- type: z.ZodString;
676
- content: z.ZodString;
677
- channel_id: z.ZodNullable<z.ZodString>;
678
- connector_id: z.ZodNullable<z.ZodString>;
679
- meta: z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodString>>;
680
- }, z.core.$strip>;
681
- type FunnelEvent = z.infer<typeof funnelEventSchema>;
682
- type Props$5 = {
683
- /** SQLite database file path. Created on first write. ":memory:" for tests. */path: string; /** Override for tests. Defaults to `Date.now`. */
684
- now?: () => number; /** Optional row cap. Pruned on every insert. */
685
- maxRows?: number; /** Optional age cap in ms. Pruned on every insert. */
686
- maxAgeMs?: number;
687
- };
688
- /**
689
- * SQLite-backed event store. One indexed table holds every broadcaster
690
- * event with `channel_id` and `connector_id` as dedicated columns, so
691
- * per-channel and per-connector replay is an indexed range scan.
692
- *
693
- * Concurrency: `seq` is `INTEGER PRIMARY KEY`, so SQLite assigns it
694
- * atomically. The broadcaster owns its own offset counter at runtime
695
- * (seeded from `findMaxOffset()` at startup); each broadcaster event
696
- * flows in here via `record()` with that pre-assigned offset, which the
697
- * sink stores via `write()` — PK uniqueness catches double-emit bugs.
698
- *
699
- * System events (gateway lifecycle, channel connect/disconnect, etc.) do
700
- * NOT go through this store. They are diagnostic only and live in
701
- * `FunnelLogger`'s file so the seq space here stays exclusive to
702
- * broadcaster traffic. This is what makes the broadcaster's seq seeding
703
- * (`getMaxSeq()` at startup) correct without per-event coordination.
704
- */
705
- declare class FunnelEventStore {
706
- private readonly sink;
707
- private readonly now;
708
- constructor(props: Props$5);
709
- /**
710
- * Persist a broadcaster-driven event with its assigned offset. Caller
711
- * (the gateway-server) supplies the offset from `broadcaster.broadcast()`
712
- * so this store and the broadcaster's in-memory ring stay aligned.
713
- */
714
- record(props: {
715
- content: string;
716
- channelId: string | null;
717
- connectorId: string | null;
718
- meta: Record<string, string> | null;
719
- offset: number;
720
- }): void;
721
- /**
722
- * Returns events with offset > since. Filtering by channel/connector is
723
- * the broadcaster's responsibility (it knows the client's subscription),
724
- * so this returns the full slice and lets the caller filter.
725
- */
726
- loadSince(since: number): ReplayableEvent[];
727
- /**
728
- * Returns events for one channel (and optionally one connector). Used
729
- * by the gateway logs CLI for scoped queries. Channel/connector filters
730
- * are indexed columns, so this is an indexed range scan.
731
- */
732
- loadForChannel(props: {
733
- channelId: string;
734
- connectorId?: string;
735
- sinceSeq?: number;
736
- limit?: number;
737
- }): ReplayableEvent[];
738
- findMaxOffset(): number;
739
- close(): void;
740
- }
741
- //#endregion
742
772
  //#region lib/gateway/listener-supervisor.d.ts
743
773
  type ConnectorRegistry = {
744
774
  listAllConnectors(): ChannelConnectorView[];
@@ -749,7 +779,7 @@ type ConnectorRegistry = {
749
779
  } | null;
750
780
  };
751
781
  type SupervisorNotify = (channelName: string, connectorName: string, content: string, meta?: Record<string, string>) => Promise<void>;
752
- type Deps$4 = {
782
+ type Deps$5 = {
753
783
  channels: ConnectorRegistry;
754
784
  notify: SupervisorNotify;
755
785
  logger?: FunnelLogger;
@@ -794,7 +824,7 @@ declare class FunnelListenerSupervisor {
794
824
  private readonly now;
795
825
  private healthCheckTimer;
796
826
  private healthCheckInFlight;
797
- constructor(deps: Deps$4);
827
+ constructor(deps: Deps$5);
798
828
  static keyOf(channelName: string, connectorName: string): string;
799
829
  isRunning(channelName: string, connectorName: string): boolean;
800
830
  list(): ListenerEntryStatus[];
@@ -821,6 +851,164 @@ declare class FunnelListenerSupervisor {
821
851
  private recoverDead;
822
852
  }
823
853
  //#endregion
854
+ //#region lib/gateway/routes/route-deps.d.ts
855
+ type GatewayEmitInput = {
856
+ channel: string;
857
+ connector?: string;
858
+ content: string;
859
+ meta?: Record<string, string>;
860
+ };
861
+ type GatewayRouteDeps = {
862
+ selfPid: number;
863
+ broadcaster: FunnelBroadcaster;
864
+ supervisor: FunnelListenerSupervisor;
865
+ channels: FunnelChannels;
866
+ uptimeMs: () => number;
867
+ emit: (input: GatewayEmitInput) => {
868
+ offset: number;
869
+ };
870
+ };
871
+ //#endregion
872
+ //#region lib/gateway/factory.d.ts
873
+ type Env$1 = {
874
+ Variables: {
875
+ deps: GatewayRouteDeps;
876
+ };
877
+ };
878
+ //#endregion
879
+ //#region lib/gateway/gateway.d.ts
880
+ type Deps$4 = {
881
+ process?: FunnelProcessRunner;
882
+ fs?: FunnelFileSystem;
883
+ clock?: FunnelClock;
884
+ dir?: string;
885
+ tmpDir?: string;
886
+ port?: number;
887
+ sleep?: (ms: number) => Promise<void>;
888
+ };
889
+ /**
890
+ * Manages the gateway daemon as a separate process via PID file.
891
+ * Use `start()` to spawn `bun daemon.ts` in the background and `stop()` to
892
+ * terminate it. For an in-process gateway, use `Funnel.gatewayServer` instead.
893
+ */
894
+ declare class FunnelGateway {
895
+ private readonly process;
896
+ private readonly fs;
897
+ private readonly clock;
898
+ private readonly dir;
899
+ private readonly pidFile;
900
+ private readonly logDir;
901
+ private readonly gatewayLog;
902
+ private readonly tmpDir;
903
+ private readonly port;
904
+ private readonly sleep;
905
+ constructor(deps?: Deps$4);
906
+ isRunning(): boolean;
907
+ getStatus(): {
908
+ running: boolean;
909
+ pid: number | null;
910
+ port: number;
911
+ };
912
+ start(options?: {
913
+ caffeinate?: boolean;
914
+ }): Promise<boolean>;
915
+ buildStartCommand(gatewayScript: string, options?: {
916
+ caffeinate?: boolean;
917
+ }): string;
918
+ stop(): Promise<boolean>;
919
+ restart(options?: {
920
+ onlyIfRunning?: boolean;
921
+ caffeinate?: boolean;
922
+ }): Promise<{
923
+ ok: boolean;
924
+ wasRunning: boolean;
925
+ stopped: boolean;
926
+ started: boolean;
927
+ }>;
928
+ getLogDir(): string;
929
+ getGatewayLog(): string;
930
+ getPort(): number;
931
+ private readPid;
932
+ private removePid;
933
+ private isProcessAlive;
934
+ }
935
+ //#endregion
936
+ //#region lib/gateway/funnel-event-store.d.ts
937
+ /**
938
+ * Replayable event payload persisted by the gateway. Domain events the
939
+ * broadcaster emits to WS clients land here so reconnects across daemon
940
+ * restarts can be served from disk. System events (gateway start, channel
941
+ * connected, etc.) are routed to `FunnelLogger` instead — they never go
942
+ * through this store, which keeps the seq space clean for replay.
943
+ */
944
+ declare const funnelEventSchema: z.ZodObject<{
945
+ type: z.ZodString;
946
+ content: z.ZodString;
947
+ channel_id: z.ZodNullable<z.ZodString>;
948
+ connector_id: z.ZodNullable<z.ZodString>;
949
+ meta: z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodString>>;
950
+ }, z.core.$strip>;
951
+ type FunnelEvent = z.infer<typeof funnelEventSchema>;
952
+ type Props$6 = {
953
+ /** SQLite database file path. Created on first write. ":memory:" for tests. */path: string; /** Override for tests. Defaults to `Date.now`. */
954
+ now?: () => number; /** Optional row cap. Pruned on every insert. */
955
+ maxRows?: number; /** Optional age cap in ms. Pruned on every insert. */
956
+ maxAgeMs?: number;
957
+ };
958
+ /**
959
+ * SQLite-backed event store. One indexed table holds every broadcaster
960
+ * event with `channel_id` and `connector_id` as dedicated columns, so
961
+ * per-channel and per-connector replay is an indexed range scan.
962
+ *
963
+ * Concurrency: `seq` is `INTEGER PRIMARY KEY`, so SQLite assigns it
964
+ * atomically. The broadcaster owns its own offset counter at runtime
965
+ * (seeded from `findMaxOffset()` at startup); each broadcaster event
966
+ * flows in here via `record()` with that pre-assigned offset, which the
967
+ * sink stores via `write()` — PK uniqueness catches double-emit bugs.
968
+ *
969
+ * System events (gateway lifecycle, channel connect/disconnect, etc.) do
970
+ * NOT go through this store. They are diagnostic only and live in
971
+ * `FunnelLogger`'s file so the seq space here stays exclusive to
972
+ * broadcaster traffic. This is what makes the broadcaster's seq seeding
973
+ * (`getMaxSeq()` at startup) correct without per-event coordination.
974
+ */
975
+ declare class FunnelEventStore {
976
+ private readonly sink;
977
+ private readonly now;
978
+ constructor(props: Props$6);
979
+ /**
980
+ * Persist a broadcaster-driven event with its assigned offset. Caller
981
+ * (the gateway-server) supplies the offset from `broadcaster.broadcast()`
982
+ * so this store and the broadcaster's in-memory ring stay aligned.
983
+ */
984
+ record(props: {
985
+ content: string;
986
+ channelId: string | null;
987
+ connectorId: string | null;
988
+ meta: Record<string, string> | null;
989
+ offset: number;
990
+ }): void;
991
+ /**
992
+ * Returns events with offset > since. Filtering by channel/connector is
993
+ * the broadcaster's responsibility (it knows the client's subscription),
994
+ * so this returns the full slice and lets the caller filter.
995
+ */
996
+ loadSince(since: number): ReplayableEvent[];
997
+ /**
998
+ * Returns events for one channel (and optionally one connector). Used
999
+ * by the gateway logs CLI for scoped queries. Channel/connector filters
1000
+ * are indexed columns, so this is an indexed range scan.
1001
+ */
1002
+ loadForChannel(props: {
1003
+ channelId: string;
1004
+ connectorId?: string;
1005
+ sinceSeq?: number;
1006
+ limit?: number;
1007
+ }): ReplayableEvent[];
1008
+ findMaxOffset(): number;
1009
+ close(): void;
1010
+ }
1011
+ //#endregion
824
1012
  //#region lib/gateway/gateway-server.d.ts
825
1013
  type Deps$3 = {
826
1014
  channels: FunnelChannels;
@@ -830,9 +1018,17 @@ type Deps$3 = {
830
1018
  process?: FunnelProcessRunner;
831
1019
  clock?: FunnelClock;
832
1020
  logger?: FunnelLogger;
833
- selfPid?: number;
1021
+ selfPid?: number; /** Funnel home dir, used to scope kill-competing to daemons rooted at the same dir. Defaults to FUNNEL_DIR. */
1022
+ dir?: string;
834
1023
  killCompetingSlack?: boolean; /** Bearer token required for `/listeners*`, `/status`, and `/ws`. Empty string disables auth (tests only). */
835
1024
  token?: string;
1025
+ /**
1026
+ * Additional hono app mounted before the built-in gateway routes.
1027
+ * Use to embed host-specific endpoints (e.g. an MCP route, custom `/api/*`).
1028
+ * Host routes are mounted first; built-in `/listeners`, `/status`,
1029
+ * `/channels`, `/health` are mounted after and take precedence on conflict.
1030
+ */
1031
+ extraRoutes?: Hono<Env$1>;
836
1032
  };
837
1033
  type WsData = {
838
1034
  /** 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. */
@@ -860,12 +1056,14 @@ declare class FunnelGatewayServer {
860
1056
  private readonly process?;
861
1057
  private readonly logger;
862
1058
  private readonly selfPid;
1059
+ private readonly dir;
863
1060
  private readonly killCompetingSlack;
864
1061
  private readonly token;
865
1062
  private readonly broadcaster;
866
1063
  private readonly eventStore;
867
1064
  private readonly supervisor;
868
1065
  private readonly nowMs;
1066
+ private readonly extraRoutes;
869
1067
  private startedAt;
870
1068
  private server;
871
1069
  constructor(deps: Deps$3);
@@ -1000,15 +1198,27 @@ declare class FunnelListenersClient {
1000
1198
  }
1001
1199
  //#endregion
1002
1200
  //#region lib/funnel.d.ts
1003
- type Props$4 = {
1201
+ type Props$5 = {
1004
1202
  /** 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. */
1005
1203
  fs?: FunnelFileSystem; /** Process runner used by gateway / claude / gh listener. Replace with MemoryFunnelProcessRunner for tests. */
1006
1204
  process?: FunnelProcessRunner; /** Logger flowed into every facet. Replace with MemoryFunnelLogger or NoopFunnelLogger to silence/inspect. */
1007
1205
  logger?: FunnelLogger; /** Clock used by schedule listener, gh poll watermarks, and gateway timeouts. */
1008
1206
  clock?: FunnelClock; /** ID generator for channel and connector ids. Use MemoryFunnelIdGenerator for deterministic tests. */
1009
- idGenerator?: FunnelIdGenerator; /** Funnel home directory (settings.json + per-channel/per-connector dirs). Defaults to ~/.funnel. */
1207
+ idGenerator?: FunnelIdGenerator; /** Prompter used by FunnelLocalConfigSync when funnel.json omits a token. Defaults to a TTY-only stdin prompter. */
1208
+ tokenPrompter?: FunnelTokenPrompter; /** Funnel home directory (settings.json + per-channel/per-connector dirs). Defaults to ~/.funnel. */
1010
1209
  dir?: string; /** Temp / runtime directory (gateway logs and PID adjacent files). Defaults to /tmp/funnel. */
1011
1210
  tmpDir?: string;
1211
+ /**
1212
+ * Host integration hooks for Slack listeners — `onAppCreated` for attaching
1213
+ * Bolt `app.action` handlers, `preprocessEvent` for transforming/dropping
1214
+ * raw Slack events before the built-in processor sees them.
1215
+ */
1216
+ slackListenerOptions?: SlackListenerOptions;
1217
+ /**
1218
+ * Host integration hooks for Schedule listeners — `onFired` is invoked after
1219
+ * each successful fire, useful for dropping one-shot entries.
1220
+ */
1221
+ scheduleListenerOptions?: ScheduleListenerOptions;
1012
1222
  };
1013
1223
  /**
1014
1224
  * Facade exposing every funnel facet as a getter.
@@ -1032,13 +1242,13 @@ type Props$4 = {
1032
1242
  declare class Funnel {
1033
1243
  private readonly props;
1034
1244
  private readonly memos;
1035
- constructor(props?: Props$4);
1245
+ constructor(props?: Props$5);
1036
1246
  /**
1037
1247
  * Sandboxed Funnel wired with in-memory implementations for every IO boundary.
1038
1248
  * Touches no real disk, processes, wall-clock time, or UUIDs — safe for tests
1039
1249
  * and ad-hoc experiments. Override individual fields by passing them in `props`.
1040
1250
  */
1041
- static inMemory(props?: Props$4): Funnel;
1251
+ static inMemory(props?: Props$5): Funnel;
1042
1252
  /** Resolved on-disk paths the facade will read/write when methods are called. Pure compute, not memoized. */
1043
1253
  get paths(): {
1044
1254
  dir: string;
@@ -1063,6 +1273,14 @@ declare class Funnel {
1063
1273
  get channels(): FunnelChannels;
1064
1274
  /** Launch profiles (named presets for `fnl claude`: path + sub-agent + channel id). */
1065
1275
  get profiles(): FunnelProfiles;
1276
+ /** Reads `funnel.json` from a cwd. `fnl claude` consults it before falling back to the default profile. */
1277
+ get localConfig(): FunnelLocalConfig;
1278
+ /** Parses `.env.local` from a cwd (used by sync to back $VAR references). */
1279
+ get dotenv(): FunnelDotenvReader;
1280
+ /** Secret prompter. Defaults to a TTY-only stdin reader; tests inject MemoryFunnelTokenPrompter. */
1281
+ get tokenPrompter(): FunnelTokenPrompter;
1282
+ /** Reconciles funnel.json's channel + connectors with `~/.funnel/settings.json` on launch. */
1283
+ get localConfigSync(): FunnelLocalConfigSync;
1066
1284
  /** funnel MCP installer (writes/removes `.mcp.json` entries in target repos). */
1067
1285
  get mcp(): FunnelMcp;
1068
1286
  /** Launch Claude Code with a channel injected via env, MCP installed, gateway ensured. */
@@ -1093,6 +1311,13 @@ declare class Funnel {
1093
1311
  logDir?: string;
1094
1312
  killCompetingSlack?: boolean; /** Override the auth token. Defaults to the persisted gateway.token. Pass "" to disable auth (tests). */
1095
1313
  token?: string;
1314
+ /**
1315
+ * Additional hono app mounted before the built-in gateway routes.
1316
+ * Use to embed host-specific endpoints (e.g. an MCP route, custom `/api/*`).
1317
+ * Host routes are mounted first; built-in `/listeners`, `/status`,
1318
+ * `/channels`, `/health` are mounted after and take precedence on conflict.
1319
+ */
1320
+ extraRoutes?: Hono<Env$1>;
1096
1321
  }): FunnelGatewayServer;
1097
1322
  }
1098
1323
  //#endregion
@@ -1105,6 +1330,15 @@ type ChannelServerOptions = {
1105
1330
  };
1106
1331
  declare const startChannelServer: (options?: ChannelServerOptions) => Promise<void>;
1107
1332
  //#endregion
1333
+ //#region lib/engine/local-config/local-config-json-schema.d.ts
1334
+ /**
1335
+ * Generates the JSON Schema (draft 2020-12) for `funnel.json`. Useful for
1336
+ * `$schema` references in committed `funnel.json` files so editors can give
1337
+ * autocomplete and validation for channel / subAgent / env / connectors[]
1338
+ * without anyone hand-maintaining a separate schema.
1339
+ */
1340
+ declare const funnelJsonSchema: () => Record<string, unknown>;
1341
+ //#endregion
1108
1342
  //#region lib/engine/settings/settings-store.d.ts
1109
1343
  declare const FUNNEL_DIR: string;
1110
1344
  declare const SETTINGS_PATH: string;
@@ -1147,7 +1381,7 @@ declare class NodeFunnelFileSystem extends FunnelFileSystem {
1147
1381
  }
1148
1382
  //#endregion
1149
1383
  //#region lib/engine/fs/memory-file-system.d.ts
1150
- type Props$3 = {
1384
+ type Props$4 = {
1151
1385
  dirs?: string[];
1152
1386
  files?: Record<string, string>;
1153
1387
  mtimes?: Record<string, number>;
@@ -1160,7 +1394,7 @@ declare class MemoryFunnelFileSystem extends FunnelFileSystem {
1160
1394
  private readonly mtimes;
1161
1395
  private readonly modes;
1162
1396
  private readonly now;
1163
- constructor(props?: Props$3);
1397
+ constructor(props?: Props$4);
1164
1398
  existsSync(path: string): boolean;
1165
1399
  readFileSync(path: string): string;
1166
1400
  writeFileSync(path: string, data: string): void;
@@ -1232,14 +1466,14 @@ declare class MemoryFunnelProcessRunner extends FunnelProcessRunner {
1232
1466
  }
1233
1467
  //#endregion
1234
1468
  //#region lib/engine/logger/node-logger.d.ts
1235
- type Props$2 = {
1469
+ type Props$3 = {
1236
1470
  file?: string;
1237
1471
  now?: () => Date;
1238
1472
  };
1239
1473
  declare class NodeFunnelLogger extends FunnelLogger {
1240
1474
  readonly file: string;
1241
1475
  private readonly now;
1242
- constructor(props?: Props$2);
1476
+ constructor(props?: Props$3);
1243
1477
  info(message: string, meta?: Record<string, unknown>): void;
1244
1478
  warn(message: string, meta?: Record<string, unknown>): void;
1245
1479
  error(message: string, meta?: Record<string, unknown>): void;
@@ -1275,12 +1509,12 @@ declare class NodeFunnelClock extends FunnelClock {
1275
1509
  }
1276
1510
  //#endregion
1277
1511
  //#region lib/engine/time/memory-clock.d.ts
1278
- type Props$1 = {
1512
+ type Props$2 = {
1279
1513
  start?: Date;
1280
1514
  };
1281
1515
  declare class MemoryFunnelClock extends FunnelClock {
1282
1516
  private current;
1283
- constructor(props?: Props$1);
1517
+ constructor(props?: Props$2);
1284
1518
  now(): Date;
1285
1519
  set(date: Date): void;
1286
1520
  advance(ms: number): void;
@@ -1292,16 +1526,43 @@ declare class NodeFunnelIdGenerator extends FunnelIdGenerator {
1292
1526
  }
1293
1527
  //#endregion
1294
1528
  //#region lib/engine/id/memory-id-generator.d.ts
1295
- type Props = {
1529
+ type Props$1 = {
1296
1530
  prefix?: string;
1297
1531
  };
1298
1532
  declare class MemoryFunnelIdGenerator extends FunnelIdGenerator {
1299
1533
  private counter;
1300
1534
  private readonly prefix;
1301
- constructor(props?: Props);
1535
+ constructor(props?: Props$1);
1302
1536
  generate(): string;
1303
1537
  }
1304
1538
  //#endregion
1539
+ //#region lib/engine/token-prompter/node-token-prompter.d.ts
1540
+ /**
1541
+ * Reads a secret from stdin in raw mode. Echoes a `*` per byte so the user
1542
+ * can see progress without exposing the token. Refuses to prompt when stdin
1543
+ * is not a TTY — callers should surface the resulting error with a hint
1544
+ * pointing at the corresponding env var or CLI command.
1545
+ */
1546
+ declare class NodeFunnelTokenPrompter extends FunnelTokenPrompter {
1547
+ promptSecret(label: string): Promise<string>;
1548
+ private readSecret;
1549
+ }
1550
+ //#endregion
1551
+ //#region lib/engine/token-prompter/memory-token-prompter.d.ts
1552
+ type Props = {
1553
+ answers?: Record<string, string>;
1554
+ };
1555
+ /**
1556
+ * Pre-seeded answers keyed by prompt label. Tests configure the map up front;
1557
+ * unmapped labels throw so the test surfaces unexpected prompts loudly.
1558
+ */
1559
+ declare class MemoryFunnelTokenPrompter extends FunnelTokenPrompter {
1560
+ private readonly answers;
1561
+ readonly asked: string[];
1562
+ constructor(props?: Props);
1563
+ promptSecret(label: string): Promise<string>;
1564
+ }
1565
+ //#endregion
1305
1566
  //#region lib/cli/factory.d.ts
1306
1567
  type Env = {
1307
1568
  Variables: {
@@ -1352,7 +1613,7 @@ declare const createCliApp: (funnel: Funnel) => _$hono_hono_base0.HonoBase<Env,
1352
1613
  channel?: string | undefined;
1353
1614
  };
1354
1615
  };
1355
- output: "funnel claude — launch Claude Code\n\nusage:\n funnel claude launch the default profile (first in the list)\n funnel claude -p <name> launch a named profile\n funnel claude --profile <name> (long form)\n funnel claude --channel <name> raw launch (no profile, cwd = current dir)\n\noptions:\n -p, --profile profile name to launch\n --channel channel name (raw launch, ignored when --profile is given)\n\nAny other arguments are forwarded to the claude CLI.\nOn launch the FUNNEL_CHANNEL_ID env var is set and MCP connects to the gateway.";
1616
+ output: "funnel claude — launch Claude Code\n\nusage:\n funnel claude launch using funnel.json in cwd, or the default profile\n funnel claude -p <name> launch a named profile\n funnel claude --profile <name> (long form)\n funnel claude --channel <name> raw launch (no profile, cwd = current dir)\n funnel claude [...] any other argument is forwarded to the claude CLI\n\nresolution order when no --profile / --channel is given:\n 1. ./funnel.json in the current directory\n 2. 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 (raw launch, ignored when --profile is given)\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.";
1356
1617
  outputFormat: "text";
1357
1618
  status: _$hono_utils_http_status0.ContentfulStatusCode;
1358
1619
  };
@@ -2572,6 +2833,25 @@ ${string}`;
2572
2833
  status: _$hono_utils_http_status0.ContentfulStatusCode;
2573
2834
  };
2574
2835
  };
2836
+ } & {
2837
+ "/schema": {
2838
+ $get: {
2839
+ input: {
2840
+ query: Record<string, never>;
2841
+ };
2842
+ output: string;
2843
+ outputFormat: "text";
2844
+ status: _$hono_utils_http_status0.ContentfulStatusCode;
2845
+ } | {
2846
+ input: {
2847
+ query: Record<string, never>;
2848
+ };
2849
+ output: `${string}
2850
+ `;
2851
+ outputFormat: "text";
2852
+ status: _$hono_utils_http_status0.ContentfulStatusCode;
2853
+ };
2854
+ };
2575
2855
  } & {
2576
2856
  "/status": {
2577
2857
  $get: {
@@ -2624,7 +2904,7 @@ declare const app: _$hono_hono_base0.HonoBase<Env, {
2624
2904
  channel?: string | undefined;
2625
2905
  };
2626
2906
  };
2627
- output: "funnel claude — launch Claude Code\n\nusage:\n funnel claude launch the default profile (first in the list)\n funnel claude -p <name> launch a named profile\n funnel claude --profile <name> (long form)\n funnel claude --channel <name> raw launch (no profile, cwd = current dir)\n\noptions:\n -p, --profile profile name to launch\n --channel channel name (raw launch, ignored when --profile is given)\n\nAny other arguments are forwarded to the claude CLI.\nOn launch the FUNNEL_CHANNEL_ID env var is set and MCP connects to the gateway.";
2907
+ output: "funnel claude — launch Claude Code\n\nusage:\n funnel claude launch using funnel.json in cwd, or the default profile\n funnel claude -p <name> launch a named profile\n funnel claude --profile <name> (long form)\n funnel claude --channel <name> raw launch (no profile, cwd = current dir)\n funnel claude [...] any other argument is forwarded to the claude CLI\n\nresolution order when no --profile / --channel is given:\n 1. ./funnel.json in the current directory\n 2. 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 (raw launch, ignored when --profile is given)\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.";
2628
2908
  outputFormat: "text";
2629
2909
  status: _$hono_utils_http_status0.ContentfulStatusCode;
2630
2910
  };
@@ -3844,6 +4124,25 @@ ${string}`;
3844
4124
  status: _$hono_utils_http_status0.ContentfulStatusCode;
3845
4125
  };
3846
4126
  };
4127
+ } & {
4128
+ "/schema": {
4129
+ $get: {
4130
+ input: {
4131
+ query: Record<string, never>;
4132
+ };
4133
+ output: string;
4134
+ outputFormat: "text";
4135
+ status: _$hono_utils_http_status0.ContentfulStatusCode;
4136
+ } | {
4137
+ input: {
4138
+ query: Record<string, never>;
4139
+ };
4140
+ output: `${string}
4141
+ `;
4142
+ outputFormat: "text";
4143
+ status: _$hono_utils_http_status0.ContentfulStatusCode;
4144
+ };
4145
+ };
3847
4146
  } & {
3848
4147
  "/status": {
3849
4148
  $get: {
@@ -3878,4 +4177,4 @@ ${string}`;
3878
4177
  //#region lib/tui/tui.d.ts
3879
4178
  declare function launchTui(funnel: Funnel): Promise<void>;
3880
4179
  //#endregion
3881
- export { AttachOptions, BroadcastEvent, BroadcastSubscriber, ChannelConfig, ChannelConnectorView, ChannelDeliveryMode, ChannelServerOptions, ConnectorConfig, ConnectorType, DEFAULT_GATEWAY_TOKEN_PATH, DetachOptions, DiscordConnectorConfig, Env, FUNNEL_DIR, FUNNEL_MCP_COMMAND, FUNNEL_MCP_NAME, FileStat, Funnel, FunnelBroadcaster, FunnelChannelPublisher, FunnelChannels, FunnelClaude, FunnelClock, FunnelConnectorFactory, FunnelConnectorListener, FunnelEvent, FunnelEventStore, FunnelFileSystem, FunnelGateway, FunnelGatewayServer, FunnelGatewayToken, FunnelIdGenerator, FunnelListenerSupervisor, FunnelListenersClient, FunnelLogger, FunnelMcp, FunnelProcessRunner, FunnelProfiles, FunnelSettingsReader, FunnelSettingsStore, FunnelSlackEventProcessor, GhConnectorConfig, LaunchOptions, ListListenersResult, ListenerEntry, ListenerOpResult, LogEntry, MemoryFunnelClock, MemoryFunnelFileSystem, MemoryFunnelIdGenerator, MemoryFunnelLogger, MemoryFunnelProcessRunner, MemoryProcessCall, MemoryProcessHandler, MemoryProcessResponse, MemoryProcessSyncHandler, MockFunnelSettingsReader, NodeFunnelClock, NodeFunnelFileSystem, NodeFunnelIdGenerator, NodeFunnelLogger, NodeFunnelProcessRunner, NoopFunnelLogger, NotifyFn, ProfileConfig, PublishRequest, PublishResponse, PublishResult, ReplayableEvent, RunOptions, RunResult, SETTINGS_PATH, SETTINGS_VERSION, ScheduleCatchupPolicy, ScheduleConnectorConfig, ScheduleEntry, Settings, SlackConnectorConfig, SlackProcessed, SlackProcessedEmit, SlackProcessedSkip, SlackRawEvent, channelConfigSchema, channelDeliveryModeSchema, app as cliApp, connectorConfigSchema, createCliApp, createSettings, discordConnectorSchema, factory, funnelEventSchema, ghConnectorSchema, launchTui, profileConfigSchema, publishRequestSchema, publishResponseSchema, queryToCliArgs, scheduleCatchupPolicySchema, scheduleConnectorSchema, scheduleEntrySchema, settingsSchema, slackConnectorSchema, startChannelServer, toRequest };
4180
+ export { AttachOptions, BroadcastEvent, BroadcastSubscriber, ChannelConfig, ChannelConnectorView, ChannelDeliveryMode, ChannelServerOptions, ConnectorConfig, ConnectorSpec, ConnectorType, DEFAULT_GATEWAY_TOKEN_PATH, DetachOptions, DiscordConnectorConfig, Env, FUNNEL_DIR, FUNNEL_MCP_COMMAND, FUNNEL_MCP_NAME, FileStat, Funnel, FunnelBroadcaster, FunnelChannelPublisher, FunnelChannels, FunnelClaude, FunnelClock, FunnelConnectorFactory, FunnelConnectorListener, FunnelDotenvReader, FunnelEvent, FunnelEventStore, FunnelFileSystem, FunnelGateway, FunnelGatewayServer, FunnelGatewayToken, FunnelIdGenerator, FunnelListenerSupervisor, FunnelListenersClient, FunnelLocalConfig, FunnelLocalConfigSync, FunnelLogger, FunnelMcp, FunnelProcessRunner, FunnelProfiles, FunnelSettingsReader, FunnelSettingsStore, FunnelSlackEventProcessor, FunnelTokenPrompter, GhConnectorConfig, LOCAL_CONFIG_FILENAME, LOCAL_ENV_FILENAME, LaunchOptions, ListListenersResult, ListenerEntry, ListenerOpResult, LocalConfig, LogEntry, MemoryFunnelClock, MemoryFunnelFileSystem, MemoryFunnelIdGenerator, MemoryFunnelLogger, MemoryFunnelProcessRunner, MemoryFunnelTokenPrompter, MemoryProcessCall, MemoryProcessHandler, MemoryProcessResponse, MemoryProcessSyncHandler, MockFunnelSettingsReader, NodeFunnelClock, NodeFunnelFileSystem, NodeFunnelIdGenerator, NodeFunnelLogger, NodeFunnelProcessRunner, NodeFunnelTokenPrompter, NoopFunnelLogger, NotifyFn, ProfileConfig, PublishRequest, PublishResponse, PublishResult, ReplayableEvent, RunOptions, RunResult, SETTINGS_PATH, SETTINGS_VERSION, ScheduleCatchupPolicy, ScheduleConnectorConfig, ScheduleEntry, ScheduleListenerOptions, Settings, SlackConnectorConfig, SlackListenerOptions, SlackProcessed, SlackProcessedEmit, SlackProcessedSkip, SlackRawEvent, channelConfigSchema, channelDeliveryModeSchema, app as cliApp, connectorConfigSchema, connectorSpecSchema, createCliApp, createSettings, discordConnectorSchema, factory, funnelEventSchema, funnelJsonSchema, ghConnectorSchema, launchTui, localConfigSchema, profileConfigSchema, publishRequestSchema, publishResponseSchema, queryToCliArgs, scheduleCatchupPolicySchema, scheduleConnectorSchema, scheduleEntrySchema, settingsSchema, slackConnectorSchema, startChannelServer, toRequest };