@interactive-inc/claude-funnel 0.21.1 → 0.22.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,14 +1,68 @@
1
1
  import { t as FunnelConnectorAdapter } from "./connector-adapter-D5Utumgz.js";
2
- import { r as FunnelConnectorListener, t as NodeFunnelLogger } from "./node-logger-DQz_BGOD.js";
2
+ import { i as FunnelConnectorListener, t as NodeFunnelLogger } from "./node-logger-B97ZiGwj.js";
3
+ import { openSync } from "node:fs";
3
4
  import { z } from "zod";
4
5
  //#region lib/engine/process/process-runner.ts
5
6
  /**
6
7
  * Process boundary covering one-shot runs, sync runs, foreground attach, and
7
8
  * detached background spawns. Default is NodeFunnelProcessRunner (Bun.spawn);
8
9
  * MemoryFunnelProcessRunner records calls and lets tests stub responses.
10
+ *
11
+ * Liveness and process-listing helpers absorb POSIX/Windows differences so
12
+ * callers do not branch on `process.platform`. `isAlive` checks whether a PID
13
+ * names a live (non-zombie) process; `listProcessesContaining` enumerates
14
+ * processes whose command line includes `marker`, used for funnel-gateway tag
15
+ * matching across daemons that share a home dir.
9
16
  */
10
17
  var FunnelProcessRunner = class {};
11
18
  //#endregion
19
+ //#region lib/engine/process/parse-csv-row.ts
20
+ /**
21
+ * Parse a single CSV row produced by Windows tools such as
22
+ * `ConvertTo-Csv -NoTypeInformation`. Returns the trimmed cell array.
23
+ * Supports embedded quotes via the `""` escape and quoted commas.
24
+ */
25
+ function parseCsvRow(line) {
26
+ const cells = [];
27
+ const chars = Array.from(line);
28
+ let current = "";
29
+ let inQuotes = false;
30
+ let cursor = 0;
31
+ while (cursor < chars.length) {
32
+ const char = chars[cursor] ?? "";
33
+ if (inQuotes) {
34
+ if (char === "\"" && chars[cursor + 1] === "\"") {
35
+ current += "\"";
36
+ cursor += 2;
37
+ continue;
38
+ }
39
+ if (char === "\"") {
40
+ inQuotes = false;
41
+ cursor += 1;
42
+ continue;
43
+ }
44
+ current += char;
45
+ cursor += 1;
46
+ continue;
47
+ }
48
+ if (char === "\"") {
49
+ inQuotes = true;
50
+ cursor += 1;
51
+ continue;
52
+ }
53
+ if (char === ",") {
54
+ cells.push(current);
55
+ current = "";
56
+ cursor += 1;
57
+ continue;
58
+ }
59
+ current += char;
60
+ cursor += 1;
61
+ }
62
+ cells.push(current);
63
+ return cells;
64
+ }
65
+ //#endregion
12
66
  //#region lib/engine/process/node-process-runner.ts
13
67
  const toEnv = (env) => {
14
68
  if (!env) return void 0;
@@ -17,6 +71,7 @@ const toEnv = (env) => {
17
71
  for (const [key, value] of Object.entries(env)) merged[key] = value;
18
72
  return merged;
19
73
  };
74
+ const isWindows = () => process.platform === "win32";
20
75
  var NodeFunnelProcessRunner = class extends FunnelProcessRunner {
21
76
  constructor() {
22
77
  super();
@@ -65,13 +120,16 @@ var NodeFunnelProcessRunner = class extends FunnelProcessRunner {
65
120
  return await proc.exited;
66
121
  }
67
122
  detach(command, options = {}) {
123
+ const stdoutTarget = options.stdoutFile ? openSync(options.stdoutFile, "a") : "ignore";
124
+ const stderrTarget = options.stderrFile ? options.stderrFile === options.stdoutFile && typeof stdoutTarget === "number" ? stdoutTarget : openSync(options.stderrFile, "a") : "ignore";
68
125
  Bun.spawn(command, {
69
126
  env: toEnv(options.env),
70
127
  stdio: [
71
128
  "ignore",
72
- "ignore",
73
- "ignore"
74
- ]
129
+ stdoutTarget,
130
+ stderrTarget
131
+ ],
132
+ windowsHide: true
75
133
  }).unref();
76
134
  }
77
135
  kill(pid, signal = "SIGTERM") {
@@ -79,6 +137,92 @@ var NodeFunnelProcessRunner = class extends FunnelProcessRunner {
79
137
  process.kill(pid, signal);
80
138
  } catch {}
81
139
  }
140
+ isAlive(pid) {
141
+ if (!Number.isInteger(pid) || pid <= 0) return false;
142
+ if (isWindows()) return this.isAliveWindows(pid);
143
+ return this.isAlivePosix(pid);
144
+ }
145
+ listProcessesContaining(marker) {
146
+ if (!marker) return [];
147
+ if (isWindows()) return this.listProcessesContainingWindows(marker);
148
+ return this.listProcessesContainingPosix(marker);
149
+ }
150
+ isAlivePosix(pid) {
151
+ const result = this.runSync([
152
+ "ps",
153
+ "-p",
154
+ String(pid),
155
+ "-o",
156
+ "state="
157
+ ]);
158
+ if (result.exitCode !== 0) return false;
159
+ const state = result.stdout.trim();
160
+ if (!state) return false;
161
+ return !state.startsWith("Z");
162
+ }
163
+ isAliveWindows(pid) {
164
+ const result = this.runSync([
165
+ "tasklist",
166
+ "/FI",
167
+ `PID eq ${pid}`,
168
+ "/NH",
169
+ "/FO",
170
+ "CSV"
171
+ ]);
172
+ if (result.exitCode !== 0) return false;
173
+ return result.stdout.includes(`"${pid}"`);
174
+ }
175
+ listProcessesContainingPosix(marker) {
176
+ const result = this.runSync([
177
+ "ps",
178
+ "-e",
179
+ "-o",
180
+ "pid=,args="
181
+ ]);
182
+ if (result.exitCode !== 0) return [];
183
+ const snapshots = [];
184
+ for (const raw of result.stdout.split("\n")) {
185
+ const line = raw.trim();
186
+ if (!line) continue;
187
+ const match = /^(\d+)\s+(.+)$/.exec(line);
188
+ if (!match) continue;
189
+ const pid = Number(match[1]);
190
+ const command = match[2] ?? "";
191
+ if (!Number.isInteger(pid) || pid <= 0) continue;
192
+ if (!command.includes(marker)) continue;
193
+ snapshots.push({
194
+ pid,
195
+ command
196
+ });
197
+ }
198
+ return snapshots;
199
+ }
200
+ listProcessesContainingWindows(marker) {
201
+ const result = this.runSync([
202
+ "powershell",
203
+ "-NoProfile",
204
+ "-Command",
205
+ "Get-CimInstance Win32_Process | Select-Object ProcessId,CommandLine | ConvertTo-Csv -NoTypeInformation"
206
+ ]);
207
+ if (result.exitCode !== 0) return [];
208
+ const snapshots = [];
209
+ const lines = result.stdout.split(/\r?\n/).slice(1);
210
+ for (const raw of lines) {
211
+ const line = raw.trim();
212
+ if (!line) continue;
213
+ const cells = parseCsvRow(line);
214
+ if (cells.length < 2) continue;
215
+ const pid = Number(cells[0]);
216
+ const command = cells[1] ?? "";
217
+ if (!Number.isInteger(pid) || pid <= 0) continue;
218
+ if (!command.includes(marker)) continue;
219
+ snapshots.push({
220
+ pid,
221
+ command
222
+ });
223
+ }
224
+ return snapshots;
225
+ }
82
226
  };
83
227
  //#endregion
84
228
  //#region lib/connectors/gh-adapter.ts
@@ -19,12 +19,24 @@ type AttachOptions = {
19
19
  onSpawned?: (pid: number) => void;
20
20
  };
21
21
  type DetachOptions = {
22
- env?: Record<string, string>;
22
+ env?: Record<string, string>; /** Append stdout to this file. Parent dir is the caller's responsibility. */
23
+ stdoutFile?: string; /** Append stderr to this file. Parent dir is the caller's responsibility. */
24
+ stderrFile?: string;
25
+ };
26
+ type ProcessSnapshot = {
27
+ pid: number;
28
+ command: string;
23
29
  };
24
30
  /**
25
31
  * Process boundary covering one-shot runs, sync runs, foreground attach, and
26
32
  * detached background spawns. Default is NodeFunnelProcessRunner (Bun.spawn);
27
33
  * MemoryFunnelProcessRunner records calls and lets tests stub responses.
34
+ *
35
+ * Liveness and process-listing helpers absorb POSIX/Windows differences so
36
+ * callers do not branch on `process.platform`. `isAlive` checks whether a PID
37
+ * names a live (non-zombie) process; `listProcessesContaining` enumerates
38
+ * processes whose command line includes `marker`, used for funnel-gateway tag
39
+ * matching across daemons that share a home dir.
28
40
  */
29
41
  declare abstract class FunnelProcessRunner {
30
42
  abstract run(command: string[], options?: RunOptions): Promise<RunResult>;
@@ -32,6 +44,8 @@ declare abstract class FunnelProcessRunner {
32
44
  abstract attach(command: string[], options?: AttachOptions): Promise<number>;
33
45
  abstract detach(command: string[], options?: DetachOptions): void;
34
46
  abstract kill(pid: number, signal?: string): void;
47
+ abstract isAlive(pid: number): boolean;
48
+ abstract listProcessesContaining(marker: string): ProcessSnapshot[];
35
49
  }
36
50
  //#endregion
37
51
  //#region lib/connectors/gh-connector-schema.d.ts
@@ -45,4 +59,4 @@ declare const ghConnectorSchema: z.ZodObject<{
45
59
  }, z.core.$strip>;
46
60
  type GhConnectorConfig = z.infer<typeof ghConnectorSchema>;
47
61
  //#endregion
48
- export { FunnelProcessRunner as a, DetachOptions as i, ghConnectorSchema as n, RunOptions as o, AttachOptions as r, RunResult as s, GhConnectorConfig as t };
62
+ export { FunnelProcessRunner as a, RunResult as c, DetachOptions as i, ghConnectorSchema as n, ProcessSnapshot as o, AttachOptions as r, RunOptions as s, GhConnectorConfig as t };
package/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import { n as FunnelConnectorAdapter, t as CallInput } from "./connector-adapter-CXB-q_XC.js";
2
2
  import { n as discordConnectorSchema, t as DiscordConnectorConfig } from "./discord-connector-schema-Dww2I4zH.js";
3
- import { n as FunnelConnectorListener, r as NotifyFn, t as FunnelLogger } from "./logger-CTlXs7z4.js";
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-BNyTaASt.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";
3
+ import { n as FunnelConnectorListener, r as NotifyFn, t as FunnelLogger } from "./logger-B3aXsVcX.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-Cmi57jvL.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-CBYF2bGZ.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-tQH7cXU7.js";
7
7
  import { z } from "zod";
8
8
  import * as _$hono_factory0 from "hono/factory";
9
9
  import { Hono } from "hono";
@@ -405,10 +405,15 @@ type Deps$13 = {
405
405
  /**
406
406
  * Per-channel persistent Claude Code session IDs, keyed by the cwd the
407
407
  * channel was launched from. The whole point is to give each (channel, cwd)
408
- * its own stable conversation: relaunching from the same path picks up the
409
- * previous claude session via `--session-id <uuid>`, while a different cwd
410
- * (or a different channel) gets an independent one — so sessions never
411
- * silently bleed across workspaces the way claude's `-c` does.
408
+ * its own stable conversation: relaunching from the same path resumes the
409
+ * previous claude session via `--resume <uuid>`, while a different cwd (or
410
+ * a different channel) gets an independent one — so sessions never silently
411
+ * bleed across workspaces the way claude's `-c` does.
412
+ *
413
+ * `get` and `create` are intentionally separate: claude's `--session-id`
414
+ * only accepts a fresh UUID (it errors if the session jsonl already
415
+ * exists), so callers must check `get` first and fall back to `create`
416
+ * only when there is nothing to resume.
412
417
  *
413
418
  * Storage lives under `<dir>/channels/<channel-id>/sessions.json` (channel
414
419
  * id, not name, so renames don't lose history). The file is a flat
@@ -419,10 +424,10 @@ declare class FunnelSessions {
419
424
  private readonly idGenerator;
420
425
  private readonly dir;
421
426
  constructor(deps: Deps$13);
422
- /** Returns the existing session id for (channelId, cwd) or generates and persists a new one. */
423
- getOrCreate(channelId: string, cwd: string): string;
424
427
  /** Returns the existing session id for (channelId, cwd) or null. */
425
428
  get(channelId: string, cwd: string): string | null;
429
+ /** Generates a new session id for (channelId, cwd) and persists it, overwriting any prior entry. */
430
+ create(channelId: string, cwd: string): string;
426
431
  /** Drops the recorded session id for (channelId, cwd). No-op if absent. */
427
432
  clear(channelId: string, cwd: string): void;
428
433
  /** Drops the whole session map for the channel (e.g. when the channel is deleted). */
@@ -484,11 +489,12 @@ declare class FunnelClaude {
484
489
  private isProcessAlive;
485
490
  private buildArgs;
486
491
  /**
487
- * Decides whether funnel should inject `--session-id`. We back off when
488
- * the user already passed a session-shaping flag, since combining them
489
- * would either confuse claude or override the explicit user intent.
492
+ * Decides whether funnel should resume an existing claude session or start
493
+ * a freshly minted one. Backs off when the user already passed a
494
+ * session-shaping flag, since combining them would either confuse claude
495
+ * or override the explicit user intent.
490
496
  */
491
- private resolveSessionId;
497
+ private resolveSession;
492
498
  private buildEnv;
493
499
  }
494
500
  //#endregion
@@ -1001,7 +1007,6 @@ declare class FunnelGateway {
1001
1007
  private readonly clock;
1002
1008
  private readonly dir;
1003
1009
  private readonly pidFile;
1004
- private readonly logDir;
1005
1010
  private readonly gatewayLog;
1006
1011
  private readonly tmpDir;
1007
1012
  private readonly port;
@@ -1018,7 +1023,7 @@ declare class FunnelGateway {
1018
1023
  }): Promise<boolean>;
1019
1024
  buildStartCommand(gatewayScript: string, options?: {
1020
1025
  caffeinate?: boolean;
1021
- }): string;
1026
+ }): string[];
1022
1027
  stop(): Promise<boolean>;
1023
1028
  restart(options?: {
1024
1029
  onlyIfRunning?: boolean;
@@ -1029,7 +1034,6 @@ declare class FunnelGateway {
1029
1034
  stopped: boolean;
1030
1035
  started: boolean;
1031
1036
  }>;
1032
- getLogDir(): string;
1033
1037
  getGatewayLog(): string;
1034
1038
  getPort(): number;
1035
1039
  private readPid;
@@ -1117,8 +1121,8 @@ declare class FunnelEventStore {
1117
1121
  type Deps$3 = {
1118
1122
  channels: FunnelChannels;
1119
1123
  settings: FunnelSettingsReader;
1120
- port?: number; /** Directory holding the SQLite event store. The DB file lives at `<logDir>/events.db`. */
1121
- logDir?: string;
1124
+ port?: number; /** SQLite event store file path. Parent directory is created on demand. Defaults to `<os.tmpdir()>/funnel/events.db`. */
1125
+ dbPath?: string;
1122
1126
  process?: FunnelProcessRunner;
1123
1127
  clock?: FunnelClock;
1124
1128
  logger?: FunnelLogger;
@@ -1156,7 +1160,7 @@ declare class FunnelGatewayServer {
1156
1160
  private readonly channels;
1157
1161
  private readonly settings;
1158
1162
  private readonly port;
1159
- private readonly logDir;
1163
+ private readonly dbPath;
1160
1164
  private readonly process?;
1161
1165
  private readonly logger;
1162
1166
  private readonly selfPid;
@@ -1310,7 +1314,7 @@ type Props$5 = {
1310
1314
  clock?: FunnelClock; /** ID generator for channel and connector ids. Use MemoryFunnelIdGenerator for deterministic tests. */
1311
1315
  idGenerator?: FunnelIdGenerator; /** Prompter used by FunnelLocalConfigSync when funnel.json omits a token. Defaults to a TTY-only stdin prompter. */
1312
1316
  tokenPrompter?: FunnelTokenPrompter; /** Funnel home directory (settings.json + per-channel/per-connector dirs). Defaults to ~/.funnel. */
1313
- dir?: string; /** Temp / runtime directory (gateway logs and PID adjacent files). Defaults to /tmp/funnel. */
1317
+ dir?: string; /** Temp / runtime directory (gateway logs and PID adjacent files). Defaults to `<os.tmpdir()>/funnel`. */
1314
1318
  tmpDir?: string;
1315
1319
  /**
1316
1320
  * Host integration hooks for Slack listeners — `onAppCreated` for attaching
@@ -1414,7 +1418,7 @@ declare class Funnel {
1414
1418
  */
1415
1419
  gatewayServer(options?: {
1416
1420
  port?: number;
1417
- logDir?: string;
1421
+ dbPath?: string;
1418
1422
  killCompetingSlack?: boolean; /** Override the auth token. Defaults to the persisted gateway.token. Pass "" to disable auth (tests). */
1419
1423
  token?: string;
1420
1424
  /**
@@ -1525,6 +1529,12 @@ declare class NodeFunnelProcessRunner extends FunnelProcessRunner {
1525
1529
  attach(command: string[], options?: AttachOptions): Promise<number>;
1526
1530
  detach(command: string[], options?: DetachOptions): void;
1527
1531
  kill(pid: number, signal?: string): void;
1532
+ isAlive(pid: number): boolean;
1533
+ listProcessesContaining(marker: string): ProcessSnapshot[];
1534
+ private isAlivePosix;
1535
+ private isAliveWindows;
1536
+ private listProcessesContainingPosix;
1537
+ private listProcessesContainingWindows;
1528
1538
  }
1529
1539
  //#endregion
1530
1540
  //#region lib/engine/process/memory-process-runner.d.ts
@@ -1554,6 +1564,8 @@ type MemoryProcessCall = {
1554
1564
  kind: "kill";
1555
1565
  command: string[];
1556
1566
  };
1567
+ type AliveStub = (pid: number) => boolean;
1568
+ type ProcessListStub = (marker: string) => ProcessSnapshot[];
1557
1569
  declare class MemoryFunnelProcessRunner extends FunnelProcessRunner {
1558
1570
  readonly calls: MemoryProcessCall[];
1559
1571
  readonly killed: {
@@ -1562,13 +1574,19 @@ declare class MemoryFunnelProcessRunner extends FunnelProcessRunner {
1562
1574
  }[];
1563
1575
  private handler;
1564
1576
  private syncHandler;
1577
+ private aliveStub;
1578
+ private listStub;
1565
1579
  on(handler: MemoryProcessHandler): this;
1566
1580
  onSync(handler: MemoryProcessSyncHandler): this;
1581
+ onIsAlive(stub: AliveStub): this;
1582
+ onListProcessesContaining(stub: ProcessListStub): this;
1567
1583
  run(command: string[], options?: RunOptions): Promise<RunResult>;
1568
1584
  runSync(command: string[]): RunResult;
1569
1585
  attach(command: string[], options?: AttachOptions): Promise<number>;
1570
1586
  detach(command: string[], options?: DetachOptions): void;
1571
1587
  kill(pid: number, signal?: string): void;
1588
+ isAlive(pid: number): boolean;
1589
+ listProcessesContaining(marker: string): ProcessSnapshot[];
1572
1590
  }
1573
1591
  //#endregion
1574
1592
  //#region lib/engine/logger/node-logger.d.ts
@@ -4263,4 +4281,4 @@ ${string}`;
4263
4281
  //#region lib/tui/tui.d.ts
4264
4282
  declare function launchTui(funnel: Funnel): Promise<void>;
4265
4283
  //#endregion
4266
- export { AttachOptions, BroadcastEvent, BroadcastSubscriber, ChannelConfig, ChannelConnectorView, ChannelDeliveryMode, ChannelServerOptions, ChannelSpec, ConnectorConfig, ConnectorSpec, ConnectorSyncOutcome, 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, FunnelSessions, FunnelSettingsReader, FunnelSettingsStore, FunnelSlackEventProcessor, FunnelTokenPrompter, type GatewayEmitInput, type GatewayRouteDeps, type Env$1 as GatewayServerEnv, GhConnectorConfig, LOCAL_CONFIG_FILENAME, LOCAL_ENV_FILENAME, LaunchOptions, ListListenersResult, ListenerEntry, ListenerOpResult, LocalConfig, LocalConfigSyncResult, 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, channelSpecSchema, 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 };
4284
+ export { AliveStub, AttachOptions, BroadcastEvent, BroadcastSubscriber, ChannelConfig, ChannelConnectorView, ChannelDeliveryMode, ChannelServerOptions, ChannelSpec, ConnectorConfig, ConnectorSpec, ConnectorSyncOutcome, 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, FunnelSessions, FunnelSettingsReader, FunnelSettingsStore, FunnelSlackEventProcessor, FunnelTokenPrompter, type GatewayEmitInput, type GatewayRouteDeps, type Env$1 as GatewayServerEnv, GhConnectorConfig, LOCAL_CONFIG_FILENAME, LOCAL_ENV_FILENAME, LaunchOptions, ListListenersResult, ListenerEntry, ListenerOpResult, LocalConfig, LocalConfigSyncResult, LogEntry, MemoryFunnelClock, MemoryFunnelFileSystem, MemoryFunnelIdGenerator, MemoryFunnelLogger, MemoryFunnelProcessRunner, MemoryFunnelTokenPrompter, MemoryProcessCall, MemoryProcessHandler, MemoryProcessResponse, MemoryProcessSyncHandler, MockFunnelSettingsReader, NodeFunnelClock, NodeFunnelFileSystem, NodeFunnelIdGenerator, NodeFunnelLogger, NodeFunnelProcessRunner, NodeFunnelTokenPrompter, NoopFunnelLogger, NotifyFn, ProcessListStub, ProcessSnapshot, ProfileConfig, PublishRequest, PublishResponse, PublishResult, ReplayableEvent, RunOptions, RunResult, SETTINGS_PATH, SETTINGS_VERSION, ScheduleCatchupPolicy, ScheduleConnectorConfig, ScheduleEntry, ScheduleListenerOptions, Settings, SlackConnectorConfig, SlackListenerOptions, SlackProcessed, SlackProcessedEmit, SlackProcessedSkip, SlackRawEvent, channelConfigSchema, channelDeliveryModeSchema, channelSpecSchema, 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 };