@interactive-inc/claude-funnel 0.66.0 → 0.68.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 (97) hide show
  1. package/README.md +31 -6
  2. package/dist/bin.js +292 -383
  3. package/dist/channel.d.ts +76 -52
  4. package/dist/channel.js +82 -47
  5. package/dist/{channels-DR90RmUP.d.ts → channels-B0cifCfw.d.ts} +6 -6
  6. package/dist/claude.d.ts +11 -8
  7. package/dist/claude.js +31 -15
  8. package/dist/connector-descriptor-D4XtEsH8.d.ts +215 -0
  9. package/dist/{connector-diagnostics-recorder-COtNEmUp.js → connector-diagnostics-recorder-BmOijU1p.js} +1 -0
  10. package/dist/connectors/discord.d.ts +11 -8
  11. package/dist/connectors/discord.js +2 -2
  12. package/dist/connectors/gh.d.ts +7 -6
  13. package/dist/connectors/gh.js +2 -2
  14. package/dist/connectors/schedule.d.ts +21 -17
  15. package/dist/connectors/schedule.js +3 -3
  16. package/dist/connectors/slack.d.ts +15 -10
  17. package/dist/connectors/slack.js +3 -3
  18. package/dist/diagnostic-event-CxMM5Bl2.js +78 -0
  19. package/dist/diagnostic-log-BsAg5qZK.d.ts +186 -0
  20. package/dist/diagnostics.d.ts +2 -2
  21. package/dist/diagnostics.js +3 -2
  22. package/dist/{discord-connector-DXARcO6w.js → discord-connector-CAcWifJn.js} +6 -6
  23. package/dist/{discord-connector-schema-D1dyxhXk.d.ts → discord-connector-schema-BaBZYHxK.d.ts} +0 -1
  24. package/dist/docs.d.ts +1 -1
  25. package/dist/docs.js +1 -1
  26. package/dist/doctor.d.ts +1 -1
  27. package/dist/doctor.js +1 -1
  28. package/dist/event-log.d.ts +2 -0
  29. package/dist/event-log.js +3 -0
  30. package/dist/{file-process-guard-CiBwXjzm.d.ts → file-process-guard-D-QatrwL.d.ts} +22 -18
  31. package/dist/{file-system-DHgbuTFb.d.ts → file-system-BNtl997T.d.ts} +2 -1
  32. package/dist/{flume-source-listener-FzR5lGpL.d.ts → flume-source-listener-Ba8_1Mg-.d.ts} +9 -6
  33. package/dist/{funnel-diagnostics-Cvk6Sk4x.js → funnel-diagnostics-CAG7hJP0.js} +85 -141
  34. package/dist/{funnel-diagnostics-kbd27d7I.d.ts → funnel-diagnostics-CDrZznTB.d.ts} +18 -18
  35. package/dist/{funnel-docs-C-ge0MuB.js → funnel-docs-CI4hMkhq.js} +12 -3
  36. package/dist/{funnel-doctor-CVTNUtDn.d.ts → funnel-doctor-CY4S5cnz.d.ts} +20 -9
  37. package/dist/{funnel-doctor-XrI2GBH8.js → funnel-doctor-Csw5qjcH.js} +1 -0
  38. package/dist/{funnel-error-0t1MK1R6.js → funnel-error-DoSBCogD.js} +13 -0
  39. package/dist/{funnel-recovery-D8MkiTpk.d.ts → funnel-recovery-BwcSNNSN.d.ts} +1 -2
  40. package/dist/{funnel-recovery-DKnEutUS.js → funnel-recovery-DYbSYGWC.js} +1 -0
  41. package/dist/gateway/daemon.js +60 -139
  42. package/dist/gateway.d.ts +2 -3
  43. package/dist/gateway.js +2 -2
  44. package/dist/{gh-connector-BUGCOEWS.js → gh-connector-DMwI6zJA.js} +5 -5
  45. package/dist/{gh-connector-schema-BCHEqpUg.d.ts → gh-connector-schema-BrNsCl1T.d.ts} +0 -1
  46. package/dist/{index-BU1TtuFy.d.ts → index-fHrKn4jm.d.ts} +210 -40
  47. package/dist/index.d.ts +125 -115
  48. package/dist/index.js +242 -57
  49. package/dist/{local-config-json-schema-DexV8vX3.js → local-config-json-schema-_-YVHX4c.js} +4 -4
  50. package/dist/local-config.d.ts +2 -3
  51. package/dist/local-config.js +1 -1
  52. package/dist/logger.d.ts +17 -265
  53. package/dist/logger.js +6 -141
  54. package/dist/memory-event-log-BY8XjFzi.js +147 -0
  55. package/dist/{memory-token-prompter-D0kIdhar.d.ts → memory-token-prompter-B20tl_aU.d.ts} +2 -3
  56. package/dist/{node-file-system-BOXIHW_Q.js → node-file-system-xJx7dymE.js} +11 -3
  57. package/dist/{profiles-M24JrcOh.d.ts → profiles-CePRnv3F.d.ts} +3 -4
  58. package/dist/{profiles-ZHLONml4.js → profiles-KpN7_gBw.js} +19 -5
  59. package/dist/profiles.d.ts +1 -1
  60. package/dist/profiles.js +1 -1
  61. package/dist/recovery.d.ts +1 -1
  62. package/dist/recovery.js +1 -1
  63. package/dist/{schedule-connector-9k3gOIgl.js → schedule-connector-BXUOYgwZ.js} +63 -99
  64. package/dist/schedule-connector-schema-CNV8PgWX.js +137 -0
  65. package/dist/schedule-connector-schema-Tq5kJul-.d.ts +127 -0
  66. package/dist/{settings-reader-BnKIbmsD.d.ts → settings-reader-CyTpbAre.d.ts} +1 -2
  67. package/dist/{settings-schema-IShSMm5G.d.ts → settings-schema-B-CKLuST.d.ts} +0 -1
  68. package/dist/{settings-store-ccv291GV.js → settings-store-ZFWBhOnp.js} +12 -3
  69. package/dist/{slack-connector-CxpWagbT.js → slack-connector-CC3V2VXQ.js} +10 -9
  70. package/dist/{slack-event-processor-xFDG3US0.js → slack-event-processor-Cs_YuI3w.js} +2 -2
  71. package/dist/{slack-event-processor-BDTr62cN.d.ts → slack-event-processor-DmAlq4cV.d.ts} +0 -1
  72. package/dist/{slot-fields-D-pvMgTK.js → slot-fields-eCWizJqS.js} +4 -4
  73. package/dist/{sqlite-diagnostic-log-CwhXE9Qh.js → sqlite-diagnostic-log-Qs4cf9I_.js} +92 -100
  74. package/dist/sqlite-event-log-BYgCFMxC.d.ts +284 -0
  75. package/dist/{funnel-log-sqlite-sink-DLYkY0pZ.js → sqlite-event-log-eZuXKszJ.js} +53 -12
  76. package/dist/{yaml-render-DVEtYuF1.js → yaml-render-DxxRQT-V.js} +3 -3
  77. package/package.json +25 -10
  78. package/dist/broadcaster-DVNcw00K.d.ts +0 -138
  79. package/dist/connector-descriptor-CmyHlEiT.d.ts +0 -380
  80. package/dist/diagnostic-sql-reader-oXZnWFf_.js +0 -83
  81. package/dist/file-system-Wvzc2ePY.js +0 -9
  82. package/dist/logger-B6iyNbxM.js +0 -9
  83. package/dist/schedule-connector-schema-D7ZEKvit.d.ts +0 -49
  84. package/dist/schedule-connector-schema-DKEPZnVv.js +0 -31
  85. package/dist/settings-reader-9FcX3qS1.js +0 -11
  86. /package/dist/{connector-adapter-Dvs8N7ew.js → connector-adapter-BL2ehMej.js} +0 -0
  87. /package/dist/{connector-listener-mPGZYa8e.js → connector-listener-BcQMzY6Q.js} +0 -0
  88. /package/dist/{discord-connector-schema-B4YpWpR3.js → discord-connector-schema-saAGuPmJ.js} +0 -0
  89. /package/dist/{error-message-of-ColuYmAk.js → error-message-of-BG4ezZ_s.js} +0 -0
  90. /package/dist/{funnel-docs-Cd66sKyV.d.ts → funnel-docs-BJWawfWI.d.ts} +0 -0
  91. /package/dist/{gh-connector-schema-CAqIhzGr.js → gh-connector-schema-DmZTrzUu.js} +0 -0
  92. /package/dist/{logger-Bc_Ooypb.d.ts → logger-mMZvblTx.d.ts} +0 -0
  93. /package/dist/{loopback-fetch-CVNuN3YZ.js → loopback-fetch-HP-bo9Kv.js} +0 -0
  94. /package/dist/{node-http-client-u00atiKx.js → node-http-client-SX3xFh4h.js} +0 -0
  95. /package/dist/{node-process-runner-DxTvycoK.js → node-process-runner-D4rzPl8Q.js} +0 -0
  96. /package/dist/{resolve-connector-token-DxDG9mhf.js → resolve-connector-token-BwiJCu82.js} +0 -0
  97. /package/dist/{slack-connector-schema-Dem8to4P.js → slack-connector-schema-EGVuuqSX.js} +0 -0
package/dist/index.js CHANGED
@@ -1,37 +1,43 @@
1
- import { n as gatewayLoopbackUrl, t as loopbackFetch } from "./loopback-fetch-CVNuN3YZ.js";
2
- import { t as FunnelFileSystem } from "./file-system-Wvzc2ePY.js";
3
- import { t as NodeFunnelFileSystem } from "./node-file-system-BOXIHW_Q.js";
4
- import { t as FunnelLogger } from "./logger-B6iyNbxM.js";
5
- import { n as FunnelProcessRunner, t as NodeFunnelProcessRunner } from "./node-process-runner-DxTvycoK.js";
6
- import { n as FunnelHttpClient, t as NodeFunnelHttpClient } from "./node-http-client-u00atiKx.js";
7
- import { n as FunnelIdGenerator, t as FunnelSettingsReader } from "./settings-reader-9FcX3qS1.js";
8
- import { a as expandHomeDir, c as SETTINGS_VERSION, d as profileConfigSchema, f as settingsSchema, i as SETTINGS_PATH, l as channelConfigSchema, m as NodeFunnelIdGenerator, n as FUNNEL_DIR, o as resolveFunnelDir, p as baseConnectorConfigSchema, r as FunnelSettingsStore, s as resolveFunnelPort, t as DEFAULT_GATEWAY_PORT, u as channelDeliveryModeSchema } from "./settings-store-ccv291GV.js";
9
- import { a as FunnelConnectorTypeMismatchError, c as FunnelTokenCollisionError, i as FunnelConnectorNotFoundError, n as FunnelChannelAlreadyExistsError, o as FunnelError, r as FunnelChannelNotFoundError, s as FunnelGatewayBindError, t as FunnelAuthFailedError } from "./funnel-error-0t1MK1R6.js";
10
- import { a as FunnelMcp, o as FunnelFileProcessGuard, s as FunnelClaude, t as renderYaml } from "./yaml-render-DVEtYuF1.js";
11
- import { a as toDiagnosticEvent, i as toDiagnosticConnectionError, n as previewOf, r as queryRows, t as FunnelDiagnostics } from "./funnel-diagnostics-Cvk6Sk4x.js";
12
- import { t as ConnectorDiagnosticSqlReader } from "./diagnostic-sql-reader-oXZnWFf_.js";
13
- import { t as FunnelDoctor } from "./funnel-doctor-XrI2GBH8.js";
14
- import { t as FunnelDocs } from "./funnel-docs-C-ge0MuB.js";
15
- import { a as FunnelTokenPrompter, i as FunnelLocalConfigSync, n as MemoryFunnelTokenPrompter, o as FunnelLocalConfig, r as NodeFunnelTokenPrompter, t as funnelJsonSchema } from "./local-config-json-schema-DexV8vX3.js";
16
- import { t as discordConnectorSchema } from "./discord-connector-schema-B4YpWpR3.js";
17
- import { t as ghConnectorSchema } from "./gh-connector-schema-CAqIhzGr.js";
18
- import { t as slackConnectorSchema } from "./slack-connector-schema-Dem8to4P.js";
19
- import { t as FunnelProfiles } from "./profiles-ZHLONml4.js";
20
- import { t as FunnelRecovery } from "./funnel-recovery-DKnEutUS.js";
21
- import { C as funnelTmpDir, S as connectorRawEventSchema, _ as MemoryConnectorDiagnosticLog, a as DEFAULT_GATEWAY_TOKEN_PATH, b as connectorConnectionEventSchema, c as FunnelListenerRegistry, d as funnelEventSchema, f as FunnelBroadcaster, g as publishResponseSchema, h as publishRequestSchema, i as channelWsUrl, l as SqliteFunnelEventLog, m as FunnelChannelPublisher, n as MemoryFunnelEventLog, o as FunnelGatewayToken, p as requireBearerToken, r as channelWsProtocols, s as FunnelGatewayServer, t as SqliteConnectorDiagnosticLog, u as FunnelEventLog, v as CONNECTOR_CONNECTION_STATUSES, x as connectorProcessedEventSchema, y as ConnectorDiagnosticLog } from "./sqlite-diagnostic-log-CwhXE9Qh.js";
22
- import { t as FunnelConnectorAdapter } from "./connector-adapter-Dvs8N7ew.js";
23
- import { t as FunnelConnectorListener } from "./connector-listener-mPGZYa8e.js";
24
- import { t as FunnelSlackEventProcessor } from "./slack-event-processor-xFDG3US0.js";
25
- import { n as scheduleConnectorSchema, r as scheduleEntrySchema, t as scheduleCatchupPolicySchema } from "./schedule-connector-schema-DKEPZnVv.js";
1
+ import { n as gatewayLoopbackUrl, t as loopbackFetch } from "./loopback-fetch-HP-bo9Kv.js";
2
+ import { n as FunnelFileSystem, t as NodeFunnelFileSystem } from "./node-file-system-xJx7dymE.js";
3
+ import { n as FunnelProcessRunner, t as NodeFunnelProcessRunner } from "./node-process-runner-D4rzPl8Q.js";
4
+ import { n as FunnelHttpClient, t as NodeFunnelHttpClient } from "./node-http-client-SX3xFh4h.js";
5
+ import { a as expandHomeDir, c as SETTINGS_VERSION, d as profileConfigSchema, f as settingsSchema, g as FunnelIdGenerator, h as NodeFunnelIdGenerator, i as SETTINGS_PATH, l as channelConfigSchema, m as FunnelSettingsReader, n as FUNNEL_DIR, o as resolveFunnelDir, p as baseConnectorConfigSchema, r as FunnelSettingsStore, s as resolveFunnelPort, t as DEFAULT_GATEWAY_PORT, u as channelDeliveryModeSchema } from "./settings-store-ZFWBhOnp.js";
6
+ import { a as FunnelConnectorTypeMismatchError, c as FunnelTokenCollisionError, i as FunnelConnectorNotFoundError, n as FunnelChannelAlreadyExistsError, o as FunnelError, r as FunnelChannelNotFoundError, s as FunnelGatewayBindError, t as FunnelAuthFailedError } from "./funnel-error-DoSBCogD.js";
7
+ import { a as FunnelMcp, o as FunnelFileProcessGuard, s as FunnelClaude, t as renderYaml } from "./yaml-render-DxxRQT-V.js";
8
+ import { n as sessionFileExists, t as FunnelProfiles } from "./profiles-KpN7_gBw.js";
9
+ import { a as queryRows, i as previewOf, n as diagnosticEventOfProcessed, o as toDiagnosticConnectionError, r as diagnosticEventOfRaw, s as toDiagnosticEvent, t as diagnosticConnectionEventOf } from "./diagnostic-event-CxMM5Bl2.js";
10
+ import { t as FunnelDiagnostics } from "./funnel-diagnostics-CAG7hJP0.js";
11
+ import { t as FunnelDoctor } from "./funnel-doctor-Csw5qjcH.js";
12
+ import { t as FunnelDocs } from "./funnel-docs-CI4hMkhq.js";
13
+ import { a as FunnelTokenPrompter, i as FunnelLocalConfigSync, n as MemoryFunnelTokenPrompter, o as FunnelLocalConfig, r as NodeFunnelTokenPrompter, t as funnelJsonSchema } from "./local-config-json-schema-_-YVHX4c.js";
14
+ import { t as discordConnectorSchema } from "./discord-connector-schema-saAGuPmJ.js";
15
+ import { t as ghConnectorSchema } from "./gh-connector-schema-DmZTrzUu.js";
16
+ import { t as slackConnectorSchema } from "./slack-connector-schema-EGVuuqSX.js";
17
+ import { t as FunnelRecovery } from "./funnel-recovery-DYbSYGWC.js";
18
+ import { C as funnelTmpDir, S as connectorRawEventSchema, _ as MemoryConnectorDiagnosticLog, a as DEFAULT_GATEWAY_TOKEN_PATH, b as connectorConnectionEventSchema, c as FunnelListenerRegistry, d as funnelEventSchema, f as FunnelBroadcaster, g as publishResponseSchema, h as publishRequestSchema, i as channelWsUrl, l as SqliteFunnelEventLog, m as FunnelChannelPublisher, n as MemoryFunnelEventLog, o as FunnelGatewayToken, p as requireBearerToken, r as channelWsProtocols, s as FunnelGatewayServer, t as SqliteConnectorDiagnosticLog, u as FunnelEventLog, v as CONNECTOR_CONNECTION_STATUSES, x as connectorProcessedEventSchema, y as ConnectorDiagnosticLog } from "./sqlite-diagnostic-log-Qs4cf9I_.js";
19
+ import { t as FunnelConnectorAdapter } from "./connector-adapter-BL2ehMej.js";
20
+ import { t as FunnelConnectorListener } from "./connector-listener-BcQMzY6Q.js";
21
+ import { t as FunnelSlackEventProcessor } from "./slack-event-processor-Cs_YuI3w.js";
22
+ import { a as scheduleConnectorSchema, i as scheduleCatchupPolicySchema, n as cronScheduleEntrySchema, o as scheduleEntryInputSchema, r as onceScheduleEntrySchema, s as scheduleEntrySchema, t as cronExpressionSchema } from "./schedule-connector-schema-CNV8PgWX.js";
26
23
  import { dirname, join, resolve } from "node:path";
27
24
  import { hc } from "hono/client";
28
25
  import { appendFileSync, existsSync, mkdirSync } from "node:fs";
29
26
  import { z } from "zod";
30
27
  import { fileURLToPath } from "node:url";
31
28
  import { createFactory } from "hono/factory";
29
+ import { Database } from "bun:sqlite";
32
30
  import { HTTPException } from "hono/http-exception";
33
31
  import { zValidator } from "@hono/zod-validator";
34
32
  import { Hono } from "hono";
33
+ //#region lib/engine/logger/logger.ts
34
+ /**
35
+ * Structured logger with three levels and an optional log-file path.
36
+ * Defaults to NodeFunnelLogger (appends to `<os.tmpdir()>/funnel/funnel.log`);
37
+ * MemoryFunnelLogger captures entries in memory and NoopFunnelLogger silences output.
38
+ */
39
+ var FunnelLogger = class {};
40
+ //#endregion
35
41
  //#region lib/engine/time/clock.ts
36
42
  /**
37
43
  * Time boundary. Default NodeFunnelClock returns `new Date()`; MemoryFunnelClock
@@ -371,6 +377,76 @@ var FunnelChannels = class {
371
377
  }
372
378
  };
373
379
  //#endregion
380
+ //#region lib/engine/claude/file-session-store.ts
381
+ const sessionIdsSchema = z.record(z.string(), z.string());
382
+ /**
383
+ * Session-id store for repo-local funnel.json profiles, isolated from the
384
+ * global profile list while remaining stable across launches.
385
+ */
386
+ var FunnelFileSessionStore = class {
387
+ fs;
388
+ path;
389
+ constructor(deps) {
390
+ this.fs = deps.fs;
391
+ this.path = join(deps.dir, "claude", "local-sessions.json");
392
+ Object.freeze(this);
393
+ }
394
+ getSessionId(profileId) {
395
+ this.fs.mkdirSync(dirname(this.path), { recursive: true });
396
+ return this.fs.withFileLock(`${this.path}.lock`, () => this.read()[profileId] ?? null);
397
+ }
398
+ setSessionId(profileId, sessionId) {
399
+ this.fs.mkdirSync(dirname(this.path), { recursive: true });
400
+ this.fs.withFileLock(`${this.path}.lock`, () => {
401
+ const sessionIds = this.read();
402
+ sessionIds[profileId] = sessionId;
403
+ this.fs.writeFileSync(this.path, `${JSON.stringify(sessionIds, null, 2)}\n`);
404
+ });
405
+ }
406
+ sessionFileExists(cwd, sessionId, env) {
407
+ return sessionFileExists({
408
+ fs: this.fs,
409
+ cwd,
410
+ sessionId,
411
+ env
412
+ });
413
+ }
414
+ read() {
415
+ if (!this.fs.existsSync(this.path)) return {};
416
+ const parsed = JSON.parse(this.fs.readFileSync(this.path));
417
+ const sessionIds = sessionIdsSchema.safeParse(parsed);
418
+ if (!sessionIds.success) throw new Error(`invalid local profile session store (${this.path})`);
419
+ return sessionIds.data;
420
+ }
421
+ };
422
+ //#endregion
423
+ //#region lib/engine/claude/routed-session-store.ts
424
+ /**
425
+ * Keeps repo-local profile execution state out of the global profile store.
426
+ * Local ids carry a reserved prefix generated by localProfileId().
427
+ */
428
+ var FunnelRoutedSessionStore = class {
429
+ global;
430
+ local;
431
+ constructor(deps) {
432
+ this.global = deps.global;
433
+ this.local = deps.local;
434
+ Object.freeze(this);
435
+ }
436
+ getSessionId(profileId) {
437
+ return this.storeFor(profileId).getSessionId(profileId);
438
+ }
439
+ setSessionId(profileId, sessionId) {
440
+ this.storeFor(profileId).setSessionId(profileId, sessionId);
441
+ }
442
+ sessionFileExists(cwd, sessionId, env) {
443
+ return this.global.sessionFileExists(cwd, sessionId, env);
444
+ }
445
+ storeFor(profileId) {
446
+ return profileId.startsWith("local-") ? this.local : this.global;
447
+ }
448
+ };
449
+ //#endregion
374
450
  //#region lib/engine/fs/memory-file-system.ts
375
451
  const SECRET_MODE = 384;
376
452
  var MemoryFunnelFileSystem = class extends FunnelFileSystem {
@@ -752,7 +828,11 @@ var FunnelGateway = class {
752
828
  const gatewayScript = resolveDaemonScript();
753
829
  const command = this.buildStartCommand(gatewayScript, options);
754
830
  this.process.detach(command, {
755
- env: { FUNNEL_DIR: this.dir },
831
+ env: {
832
+ FUNNEL_DIR: this.dir,
833
+ FUNNEL_PORT: String(this.port),
834
+ FUNNEL_TMP_DIR: this.tmpDir
835
+ },
756
836
  stdoutFile: this.gatewayLog,
757
837
  stderrFile: this.gatewayLog
758
838
  });
@@ -998,6 +1078,7 @@ var Funnel = class Funnel {
998
1078
  clock;
999
1079
  http;
1000
1080
  onError;
1081
+ diagnosticLog;
1001
1082
  constructor(props = {}) {
1002
1083
  const dir = props.dir ?? resolveFunnelDir();
1003
1084
  const tmpDir = props.tmpDir ?? funnelTmpDir();
@@ -1017,6 +1098,7 @@ var Funnel = class Funnel {
1017
1098
  this.clock = clock;
1018
1099
  this.http = http;
1019
1100
  this.onError = props.onError ?? noopOnError;
1101
+ this.diagnosticLog = props.diagnosticLog;
1020
1102
  const store = props.store ?? new FunnelSettingsStore({
1021
1103
  path: this.paths.settings,
1022
1104
  fs,
@@ -1029,7 +1111,7 @@ var Funnel = class Funnel {
1029
1111
  http,
1030
1112
  clock,
1031
1113
  logger: this.logger,
1032
- diagnosticLog: props.diagnosticLog,
1114
+ diagnosticLog: this.diagnosticLog,
1033
1115
  signal: props.signal,
1034
1116
  dir
1035
1117
  });
@@ -1073,11 +1155,18 @@ var Funnel = class Funnel {
1073
1155
  channels: this.channels,
1074
1156
  prompter: props.tokenPrompter ?? new NodeFunnelTokenPrompter()
1075
1157
  });
1158
+ const sessions = new FunnelRoutedSessionStore({
1159
+ global: this.profiles,
1160
+ local: new FunnelFileSessionStore({
1161
+ fs,
1162
+ dir
1163
+ })
1164
+ });
1076
1165
  this.claude = new FunnelClaude({
1077
1166
  channels: this.channels,
1078
1167
  mcp,
1079
1168
  gateway: this.gateway,
1080
- sessions: this.profiles,
1169
+ sessions,
1081
1170
  guard: new FunnelFileProcessGuard({
1082
1171
  fs,
1083
1172
  process,
@@ -1092,6 +1181,7 @@ var Funnel = class Funnel {
1092
1181
  gatewayToken: this.gatewayToken,
1093
1182
  channels: this.channels,
1094
1183
  publisher: this.publisher,
1184
+ diagnosticLog: this.diagnosticLog,
1095
1185
  tmpDir
1096
1186
  });
1097
1187
  this.recovery = new FunnelRecovery({
@@ -1154,10 +1244,12 @@ var Funnel = class Funnel {
1154
1244
  logger: this.logger,
1155
1245
  onError: this.onError,
1156
1246
  dir: this.paths.dir,
1247
+ tmpDir: this.paths.tmpDir,
1157
1248
  killCompetingSlack: options.killCompetingSlack,
1158
1249
  token: options.token ?? this.gatewayToken.ensure(),
1159
1250
  allowInsecureHost: options.allowInsecureHost,
1160
- extraRoutes: options.extraRoutes
1251
+ extraRoutes: options.extraRoutes,
1252
+ diagnosticLog: this.diagnosticLog
1161
1253
  });
1162
1254
  }
1163
1255
  /**
@@ -1184,7 +1276,11 @@ var Funnel = class Funnel {
1184
1276
  "bun",
1185
1277
  gatewayScript
1186
1278
  ] : ["bun", gatewayScript];
1187
- return this.process.attach(command);
1279
+ return this.process.attach(command, { env: {
1280
+ FUNNEL_DIR: this.paths.dir,
1281
+ FUNNEL_PORT: String(this.gateway.getPort()),
1282
+ FUNNEL_TMP_DIR: this.paths.tmpDir
1283
+ } });
1188
1284
  }
1189
1285
  gatewayClient() {
1190
1286
  const { port } = this.gateway.getStatus();
@@ -1254,6 +1350,87 @@ var NoopFunnelLogger = class extends FunnelLogger {
1254
1350
  error() {}
1255
1351
  };
1256
1352
  //#endregion
1353
+ //#region lib/engine/diagnostic-log/diagnostic-sql-reader.ts
1354
+ /**
1355
+ * Read-only SQL surface over the three diagnostic tables, for Claude to query
1356
+ * the log with arbitrary `SELECT`s. It opens all files read-only and exposes
1357
+ * three views — `raw`, `processed`, `connection` — that hide the storage
1358
+ * details (the physical table is `logs` and each row's columns live
1359
+ * inside a JSON `event` blob): the views surface the columns as plain fields,
1360
+ * with `payload` already pulled out of the nested JSON.
1361
+ *
1362
+ * The tables are separate files. `raw` and `processed` share an `event_id`,
1363
+ * so a `JOIN` answers "the event arrived, but what verdict did it get?";
1364
+ * `connection` answers the other half — "did the listener ever connect at
1365
+ * all?". Writes are impossible: the connection is read-only and `query`
1366
+ * rejects anything but a single `SELECT`.
1367
+ */
1368
+ var ConnectorDiagnosticSqlReader = class {
1369
+ db;
1370
+ constructor(props) {
1371
+ const db = new Database(props.rawPath, { readonly: true });
1372
+ try {
1373
+ db.run("PRAGMA busy_timeout = 500");
1374
+ db.prepare("ATTACH DATABASE ? AS processeddb").run(props.processedPath);
1375
+ db.prepare("ATTACH DATABASE ? AS connectiondb").run(props.connectionPath);
1376
+ db.run(rawViewSql);
1377
+ db.run(processedViewSql);
1378
+ db.run(connectionViewSql);
1379
+ } catch (error) {
1380
+ db.close();
1381
+ throw error;
1382
+ }
1383
+ this.db = db;
1384
+ Object.freeze(this);
1385
+ }
1386
+ /**
1387
+ * Run one read-only `SELECT` and return the rows. Returns an `Error` (rather
1388
+ * than throwing) for a non-SELECT statement or a SQL error, so the caller
1389
+ * can surface the message without a stack trace.
1390
+ */
1391
+ query(sql, params = []) {
1392
+ const trimmed = sql.trim().replace(/;$/, "").trim();
1393
+ if (!/^select\b/i.test(trimmed)) return /* @__PURE__ */ new Error("only a single SELECT statement is allowed");
1394
+ if (trimmed.includes(";")) return /* @__PURE__ */ new Error("only a single statement is allowed (remove the ';')");
1395
+ try {
1396
+ return this.db.prepare(trimmed).all(...params);
1397
+ } catch (error) {
1398
+ return error instanceof Error ? error : new Error(String(error));
1399
+ }
1400
+ }
1401
+ close() {
1402
+ this.db.close();
1403
+ }
1404
+ };
1405
+ const rawViewSql = `CREATE TEMP VIEW raw AS SELECT
1406
+ seq,
1407
+ ts,
1408
+ json_extract(event, '$.event_id') AS event_id,
1409
+ json_extract(event, '$.type') AS type,
1410
+ json_extract(event, '$.connector_id') AS connector_id,
1411
+ json_extract(event, '$.channel_id') AS channel_id,
1412
+ json_extract(event, '$.payload') AS payload
1413
+ FROM main.logs`;
1414
+ const processedViewSql = `CREATE TEMP VIEW processed AS SELECT
1415
+ seq,
1416
+ ts,
1417
+ json_extract(event, '$.event_id') AS event_id,
1418
+ json_extract(event, '$.type') AS type,
1419
+ json_extract(event, '$.connector_id') AS connector_id,
1420
+ json_extract(event, '$.channel_id') AS channel_id,
1421
+ json_extract(event, '$.outcome') AS outcome,
1422
+ json_extract(event, '$.payload') AS payload
1423
+ FROM processeddb.logs`;
1424
+ const connectionViewSql = `CREATE TEMP VIEW connection AS SELECT
1425
+ seq,
1426
+ ts,
1427
+ json_extract(event, '$.type') AS type,
1428
+ json_extract(event, '$.connector_id') AS connector_id,
1429
+ json_extract(event, '$.channel_id') AS channel_id,
1430
+ json_extract(event, '$.status') AS status,
1431
+ json_extract(event, '$.detail') AS detail
1432
+ FROM connectiondb.logs`;
1433
+ //#endregion
1257
1434
  //#region lib/gateway/service-routes.ts
1258
1435
  /**
1259
1436
  * Mountable Hono app that exposes the service layer (`FunnelDiagnostics` +
@@ -1374,7 +1551,7 @@ const SHORT_FLAGS = {
1374
1551
  n: "name",
1375
1552
  p: "profile"
1376
1553
  };
1377
- const METHOD_KEYWORDS = new Set([
1554
+ const METHOD_KEYWORDS = /* @__PURE__ */ new Set([
1378
1555
  "add",
1379
1556
  "set",
1380
1557
  "remove",
@@ -1383,7 +1560,7 @@ const METHOD_KEYWORDS = new Set([
1383
1560
  "request",
1384
1561
  "publish"
1385
1562
  ]);
1386
- const API_CALL_METHODS = new Set([
1563
+ const API_CALL_METHODS = /* @__PURE__ */ new Set([
1387
1564
  "get",
1388
1565
  "post",
1389
1566
  "put",
@@ -1474,9 +1651,9 @@ const toRequest = (args) => {
1474
1651
  };
1475
1652
  //#endregion
1476
1653
  //#region lib/cli/router/query-to-cli-args.ts
1477
- const BUILTIN_SKIP = new Set(["help"]);
1654
+ const BUILTIN_SKIP = /* @__PURE__ */ new Set(["help"]);
1478
1655
  const queryToCliArgs = (url, reservedKeys = []) => {
1479
- const skipped = new Set([...BUILTIN_SKIP, ...reservedKeys]);
1656
+ const skipped = /* @__PURE__ */ new Set([...BUILTIN_SKIP, ...reservedKeys]);
1480
1657
  const args = [];
1481
1658
  const searchParams = new URL(url).searchParams;
1482
1659
  for (const entry of searchParams.entries()) {
@@ -1842,22 +2019,26 @@ usage: funnel channels <ch> connectors <conn> schedules [subcommand]
1842
2019
 
1843
2020
  subcommands:
1844
2021
  (none) / list schedule entries
1845
- add <id> --cron=... --prompt=... [--enabled=true] [--catchup-policy=latest|all|skip] / add entry
2022
+ add <id> (--cron=... | --run-at=...) --prompt=... [--enabled=true] [--catchup-policy=latest|all|skip] / add entry
1846
2023
  remove <id> / remove entry`), (c) => {
1847
2024
  const param = c.req.valid("param");
1848
2025
  const funnel = c.env.funnel;
1849
2026
  const entries = z.array(scheduleEntrySchema).parse(funnel.channels.connectorOp(param.channel, param.connector, "listEntries", void 0));
1850
2027
  if (entries.length === 0) return c.text("no schedule entries");
1851
- return c.text(entries.map((e) => `${e.id}\t${e.cron}\t${e.enabled ? "on" : "off"}\t${e.prompt}`).join("\n"));
2028
+ return c.text(entries.map((entry) => {
2029
+ const schedule = entry.kind === "cron" ? entry.cron : `once:${entry.runAt}`;
2030
+ return `${entry.id}\t${schedule}\t${entry.enabled ? "on" : "off"}\t${entry.prompt}`;
2031
+ }).join("\n"));
1852
2032
  });
1853
2033
  //#endregion
1854
2034
  //#region lib/cli/routes/channels.$channel.connectors.$connector.schedules.add.ts
1855
2035
  const help$9 = `funnel channels <ch> connectors <conn> schedules add <id> — add a schedule entry
1856
2036
 
1857
- usage: funnel channels <ch> connectors <conn> schedules add <id> --cron="*/5 * * * *" --prompt="..." [--enabled|--enabled=false] [--catchup-policy=latest|all|skip]
2037
+ usage: funnel channels <ch> connectors <conn> schedules add <id> (--cron="*/5 * * * *" | --run-at="2026-08-01T09:00:00+09:00") --prompt="..." [--enabled|--enabled=false] [--catchup-policy=latest|all|skip]
1858
2038
 
1859
2039
  options:
1860
- --cron <expr> / 5-field cron expression (required)
2040
+ --cron <expr> / 5-field cron expression (exclusive with --run-at)
2041
+ --run-at <ISO datetime> / fire once at or after this instant (exclusive with --cron)
1861
2042
  --prompt <text> / prompt delivered on each fire (required)
1862
2043
  --enabled / fire on schedule (default: true; --enabled=false stores it disabled)
1863
2044
  --catchup-policy latest|all|skip / how missed fires are replayed after downtime (default: latest)`;
@@ -1885,17 +2066,23 @@ const channelsConnectorsSchedulesAddHandler = factory.createHandlers(zValidator$
1885
2066
  connector: z.string(),
1886
2067
  id: z.string()
1887
2068
  })), zValidator$1("query", z.object({
1888
- cron: z.string(),
2069
+ cron: cronExpressionSchema.optional(),
2070
+ "run-at": z.string().datetime({ offset: true }).optional(),
1889
2071
  prompt: z.string(),
1890
2072
  enabled: booleanFlag,
1891
2073
  "catchup-policy": scheduleCatchupPolicySchema.optional()
2074
+ }).superRefine((query, context) => {
2075
+ if (query.cron === void 0 === (query["run-at"] === void 0)) context.addIssue({
2076
+ code: "custom",
2077
+ message: "exactly one of --cron or --run-at is required"
2078
+ });
1892
2079
  })), async (c) => {
1893
2080
  const param = c.req.valid("param");
1894
2081
  const query = c.req.valid("query");
1895
2082
  const funnel = c.env.funnel;
1896
2083
  const entry = scheduleEntrySchema.parse(funnel.channels.connectorOp(param.channel, param.connector, "addEntry", {
1897
2084
  id: param.id,
1898
- cron: query.cron,
2085
+ ...query.cron !== void 0 ? { cron: query.cron } : { runAt: query["run-at"] },
1899
2086
  prompt: query.prompt,
1900
2087
  ...query.enabled !== void 0 ? { enabled: query.enabled } : {},
1901
2088
  ...query["catchup-policy"] !== void 0 ? { catchupPolicy: query["catchup-policy"] } : {}
@@ -2780,6 +2967,14 @@ const gatewayLogsHandler = factory.createHandlers(helpGuard(logsHelp), zValidato
2780
2967
  process.exit(0);
2781
2968
  });
2782
2969
  //#endregion
2970
+ //#region lib/engine/diagnostic-log/diagnostic-log-paths.ts
2971
+ /** Default on-disk layout used by the bundled CLI and gateway daemon. */
2972
+ const connectorDiagnosticLogPaths = (tmpDir) => ({
2973
+ rawPath: join(tmpDir, "connector-raw.db"),
2974
+ processedPath: join(tmpDir, "connector-processed.db"),
2975
+ connectionPath: join(tmpDir, "connector-connection.db")
2976
+ });
2977
+ //#endregion
2783
2978
  //#region lib/cli/routes/gateway.sql.ts
2784
2979
  const PRESETS = {
2785
2980
  recent: "SELECT seq, ts, type, outcome FROM processed ORDER BY seq DESC LIMIT 20",
@@ -2864,10 +3059,7 @@ const gatewaySqlHandler = factory.createHandlers(helpGuard(sqlHelp), zValidator$
2864
3059
  params = resolvedChannelId ? [resolvedChannelId] : [];
2865
3060
  } else if (query.query) sql = query.query;
2866
3061
  if (!sql) return c.text(sqlHelp);
2867
- const tmpDir = funnelTmpDir();
2868
- const rawPath = join(tmpDir, "connector-raw.db");
2869
- const processedPath = join(tmpDir, "connector-processed.db");
2870
- const connectionPath = join(tmpDir, "connector-connection.db");
3062
+ const { rawPath, processedPath, connectionPath } = connectorDiagnosticLogPaths(funnelTmpDir());
2871
3063
  if (!existsSync(rawPath) || !existsSync(processedPath) || !existsSync(connectionPath)) return c.text("no diagnostic store yet (the gateway has not initialized it)");
2872
3064
  const reader = new ConnectorDiagnosticSqlReader({
2873
3065
  rawPath,
@@ -3057,7 +3249,7 @@ const profilesAddHandler = factory.createHandlers(zValidator$1("param", z.object
3057
3249
  const param = c.req.valid("param");
3058
3250
  const query = c.req.valid("query");
3059
3251
  const funnel = c.env.funnel;
3060
- const { profiles, claude } = c.env;
3252
+ const profiles = c.env.profiles;
3061
3253
  const channel = funnel.channels.get(query.channel);
3062
3254
  if (!channel) throw new HTTPException(400, { message: notFoundMessage({
3063
3255
  kind: "channel",
@@ -3082,9 +3274,7 @@ usage: funnel profiles <name> as-default
3082
3274
 
3083
3275
  the first profile in the list is treated as the default for fnl claude.`), (c) => {
3084
3276
  const param = c.req.valid("param");
3085
- c.env.funnel;
3086
- const { profiles, claude } = c.env;
3087
- profiles.asDefault(param.profile);
3277
+ c.env.profiles.asDefault(param.profile);
3088
3278
  return c.text(`profile "${param.profile}" is now the default`);
3089
3279
  });
3090
3280
  //#endregion
@@ -3110,9 +3300,7 @@ const profilesRenameHandler = factory.createHandlers(zValidator$1("param", z.obj
3110
3300
  newName: z.string()
3111
3301
  })), zValidator$1("query", z.object({})), (c) => {
3112
3302
  const param = c.req.valid("param");
3113
- c.env.funnel;
3114
- const { profiles, claude } = c.env;
3115
- profiles.rename(param.profile, param.newName);
3303
+ c.env.profiles.rename(param.profile, param.newName);
3116
3304
  return c.text(`renamed profile "${param.profile}" to "${param.newName}"`);
3117
3305
  });
3118
3306
  //#endregion
@@ -3124,7 +3312,6 @@ usage: funnel profiles <name> run [additional claude args...]
3124
3312
  const RESERVED_KEYS = [];
3125
3313
  const profilesLaunchHandler = factory.createHandlers(zValidator$1("param", z.object({ profile: z.string() })), helpGuard(launchHelp), zValidator$1("query", z.object({}).loose()), async (c) => {
3126
3314
  const param = c.req.valid("param");
3127
- c.env.funnel;
3128
3315
  const { profiles, claude } = c.env;
3129
3316
  const profile = profiles.get(param.profile);
3130
3317
  if (!profile) throw new HTTPException(404, { message: notFoundMessage({
@@ -3154,9 +3341,7 @@ const profilesRemoveHelpHandler = factory.createHandlers((c) => c.text(help$1));
3154
3341
  //#region lib/cli/routes/profiles.remove.$profile.ts
3155
3342
  const profilesRemoveHandler = factory.createHandlers(zValidator$1("param", z.object({ profile: z.string() })), zValidator$1("query", z.object({})), (c) => {
3156
3343
  const param = c.req.valid("param");
3157
- c.env.funnel;
3158
- const { profiles, claude } = c.env;
3159
- profiles.remove(param.profile);
3344
+ c.env.profiles.remove(param.profile);
3160
3345
  return c.text(`removed profile "${param.profile}"`);
3161
3346
  });
3162
3347
  //#endregion
@@ -3190,7 +3375,7 @@ const profilesSetHandler = factory.createHandlers(zValidator$1("param", z.object
3190
3375
  const param = c.req.valid("param");
3191
3376
  const query = c.req.valid("query");
3192
3377
  const funnel = c.env.funnel;
3193
- const { profiles, claude } = c.env;
3378
+ const profiles = c.env.profiles;
3194
3379
  const channel = query.channel !== void 0 ? funnel.channels.get(query.channel) : null;
3195
3380
  if (query.channel !== void 0 && !channel) throw new HTTPException(400, { message: notFoundMessage({
3196
3381
  kind: "channel",
@@ -3408,4 +3593,4 @@ const routes = factory.createApp().onError((error, c) => {
3408
3593
  return c.text(`error: ${error instanceof Error ? error.message : String(error)}`, 400);
3409
3594
  }).get("/claude", ...claudeHandler).get("/channels", ...channelsGroupHandler).post("/channels/add", ...channelsAddHelpHandler).post("/channels/add/:channel", ...channelsAddHandler).post("/channels/remove", ...channelsRemoveHelpHandler).post("/channels/remove/:channel", ...channelsRemoveHandler).post("/channels/rename/:channel/:newName", ...channelsRenameHandler).post("/channels/:channel/rename/:newName", ...channelsRenameHandler).post("/channels/rename", ...channelsRenameHelpHandler).post("/channels/:channel/rename", ...channelsChannelRenameHelpHandler).post("/channels/:channel/set/delivery/:mode", ...channelsSetDeliveryHandler).post("/channels/publish", ...channelsPublishHelpHandler).post("/channels/:channel/publish", ...channelsPublishHandler).get("/channels/:channel/validate", ...channelsValidateHandler).get("/channels/validate", ...channelsValidateHelpHandler).get("/channels/:channel", ...channelsShowHandler).get("/channels/:channel/connectors", ...channelsConnectorsGroupHandler).post("/channels/:channel/connectors/add", ...channelsConnectorsAddHelpHandler).post("/channels/:channel/connectors/add/:connector", ...channelsConnectorsAddHandler).post("/channels/:channel/connectors/remove", ...channelsConnectorsRemoveHelpHandler).post("/channels/:channel/connectors/remove/:connector", ...channelsConnectorsRemoveHandler).post("/channels/:channel/connectors/set", ...channelsConnectorsSetHelpHandler).post("/channels/:channel/connectors/set/:connector", ...channelsConnectorsSetHandler).post("/channels/:channel/connectors/rename/:connector/:newName", ...channelsConnectorsRenameHandler).post("/channels/:channel/connectors/:connector/rename/:newName", ...channelsConnectorsRenameHandler).post("/channels/:channel/connectors/rename", ...channelsConnectorsRenameHelpHandler).post("/channels/:channel/connectors/:connector/rename", ...channelsConnectorRenameHelpHandler).post("/channels/:channel/connectors/:connector/request", ...channelsConnectorsRequestHandler).get("/channels/:channel/connectors/:connector", ...channelsConnectorsShowHandler).get("/channels/:channel/connectors/:connector/schedules", ...channelsConnectorsSchedulesGroupHandler).post("/channels/:channel/connectors/:connector/schedules/add", ...channelsConnectorSchedulesAddHelpHandler).post("/channels/:channel/connectors/:connector/schedules/add/:id", ...channelsConnectorsSchedulesAddHandler).post("/channels/:channel/connectors/:connector/schedules/remove", ...channelsConnectorSchedulesRemoveHelpHandler).post("/channels/:channel/connectors/:connector/schedules/remove/:id", ...channelsConnectorsSchedulesRemoveHandler).get("/profiles", ...profilesGroupHandler).post("/profiles/add", ...profilesAddHelpHandler).post("/profiles/add/:profile", ...profilesAddHandler).post("/profiles/set", ...profilesSetHelpHandler).post("/profiles/set/:profile", ...profilesSetHandler).post("/profiles/remove", ...profilesRemoveHelpHandler).post("/profiles/remove/:profile", ...profilesRemoveHandler).post("/profiles/rename/:profile/:newName", ...profilesRenameHandler).post("/profiles/:profile/rename/:newName", ...profilesRenameHandler).post("/profiles/rename", ...profilesRenameHelpHandler).post("/profiles/:profile/rename", ...profilesProfileRenameHelpHandler).post("/profiles/:profile/as-default", ...profilesAsDefaultHandler).get("/profiles/:profile/run", ...profilesLaunchHandler).get("/profiles/:profile", ...profilesLaunchHandler).get("/gateway", ...gatewayGroupHandler).get("/gateway/status", ...gatewayStatusHandler).get("/gateway/start", ...gatewayStartHandler).get("/gateway/stop", ...gatewayStopHandler).get("/gateway/restart", ...gatewayRestartHandler).get("/gateway/run", ...gatewayRunHandler).get("/gateway/logs", ...gatewayLogsHandler).get("/gateway/sql", ...gatewaySqlHandler).get("/gateway/listeners", ...gatewayListenersHandler).get("/debug", ...debugHandler).get("/debug/events", ...debugEventsHandler).get("/debug/dropped", ...debugDroppedHandler).get("/debug/errors", ...debugErrorsHandler).get("/debug/replay", ...debugReplayHandler).get("/debug/raw", ...debugRawHandler).get("/debug/connection", ...debugConnectionHandler).get("/debug/logs", ...debugLogsHandler).get("/docs", ...docsIndexHandler).get("/docs/:topic", ...docsTopicHandler).get("/doctor", ...doctorHandler).get("/schema", ...schemaHandler).get("/status", ...statusHandler).get("/update", ...updateHandler);
3410
3595
  //#endregion
3411
- export { CONNECTOR_CONNECTION_STATUSES, ConnectorDiagnosticLog, ConnectorDiagnosticSqlReader, DEFAULT_GATEWAY_PORT, DEFAULT_GATEWAY_TOKEN_PATH, FUNNEL_DIR, Funnel, FunnelAuthFailedError, FunnelBroadcaster, FunnelChannelAlreadyExistsError, FunnelChannelNotFoundError, FunnelChannelPublisher, FunnelChannels, FunnelClock, FunnelConnectorAdapter, FunnelConnectorListener, FunnelConnectorNotFoundError, FunnelConnectorRegistry, FunnelConnectorTypeMismatchError, FunnelDiagnostics, FunnelDocs, FunnelDoctor, FunnelError, FunnelEventLog, FunnelFileSystem, FunnelGateway, FunnelGatewayBindError, FunnelGatewayServer, FunnelGatewayToken, FunnelHttpClient, FunnelIdGenerator, FunnelListenerRegistry, FunnelListenersClient, FunnelLogger, FunnelProcessRunner, FunnelRecovery, FunnelSettingsReader, FunnelSettingsStore, FunnelSlackEventProcessor, FunnelTokenCollisionError, FunnelTokenPrompter, MemoryConnectorDiagnosticLog, MemoryFunnelClock, MemoryFunnelEventLog, MemoryFunnelFileSystem, MemoryFunnelHttpClient, MemoryFunnelIdGenerator, MemoryFunnelLogger, MemoryFunnelProcessRunner, MemoryFunnelTokenPrompter, MockFunnelSettingsReader, NodeFunnelClock, NodeFunnelFileSystem, NodeFunnelHttpClient, NodeFunnelIdGenerator, NodeFunnelLogger, NodeFunnelProcessRunner, NodeFunnelTokenPrompter, NoopFunnelLogger, SETTINGS_PATH, SETTINGS_VERSION, SqliteConnectorDiagnosticLog, SqliteFunnelEventLog, baseConnectorConfigSchema, buildServiceRoutes, channelConfigSchema, channelDeliveryModeSchema, channelWsProtocols, channelWsUrl, routes as cliRoutes, connectorConnectionEventSchema, connectorProcessedEventSchema, connectorRawEventSchema, createSettings, discordConnectorSchema, expandHomeDir, factory, funnelEventSchema, gatewayLoopbackUrl, ghConnectorSchema, previewOf, profileConfigSchema, publishRequestSchema, publishResponseSchema, queryRows, queryToCliArgs, resolveFunnelDir, resolveFunnelPort, scheduleCatchupPolicySchema, scheduleConnectorSchema, scheduleEntrySchema, settingsSchema, slackConnectorSchema, toDiagnosticConnectionError, toDiagnosticEvent, toRequest };
3596
+ export { CONNECTOR_CONNECTION_STATUSES, ConnectorDiagnosticLog, ConnectorDiagnosticSqlReader, DEFAULT_GATEWAY_PORT, DEFAULT_GATEWAY_TOKEN_PATH, FUNNEL_DIR, Funnel, FunnelAuthFailedError, FunnelBroadcaster, FunnelChannelAlreadyExistsError, FunnelChannelNotFoundError, FunnelChannelPublisher, FunnelChannels, FunnelClock, FunnelConnectorAdapter, FunnelConnectorListener, FunnelConnectorNotFoundError, FunnelConnectorRegistry, FunnelConnectorTypeMismatchError, FunnelDiagnostics, FunnelDocs, FunnelDoctor, FunnelError, FunnelEventLog, FunnelFileSystem, FunnelGateway, FunnelGatewayBindError, FunnelGatewayServer, FunnelGatewayToken, FunnelHttpClient, FunnelIdGenerator, FunnelListenerRegistry, FunnelListenersClient, FunnelLogger, FunnelProcessRunner, FunnelRecovery, FunnelSettingsReader, FunnelSettingsStore, FunnelSlackEventProcessor, FunnelTokenCollisionError, FunnelTokenPrompter, MemoryConnectorDiagnosticLog, MemoryFunnelClock, MemoryFunnelEventLog, MemoryFunnelFileSystem, MemoryFunnelHttpClient, MemoryFunnelIdGenerator, MemoryFunnelLogger, MemoryFunnelProcessRunner, MemoryFunnelTokenPrompter, MockFunnelSettingsReader, NodeFunnelClock, NodeFunnelFileSystem, NodeFunnelHttpClient, NodeFunnelIdGenerator, NodeFunnelLogger, NodeFunnelProcessRunner, NodeFunnelTokenPrompter, NoopFunnelLogger, SETTINGS_PATH, SETTINGS_VERSION, SqliteConnectorDiagnosticLog, SqliteFunnelEventLog, baseConnectorConfigSchema, buildServiceRoutes, channelConfigSchema, channelDeliveryModeSchema, channelWsProtocols, channelWsUrl, routes as cliRoutes, connectorConnectionEventSchema, connectorProcessedEventSchema, connectorRawEventSchema, createSettings, cronExpressionSchema, cronScheduleEntrySchema, diagnosticConnectionEventOf, diagnosticEventOfProcessed, diagnosticEventOfRaw, discordConnectorSchema, expandHomeDir, factory, funnelEventSchema, gatewayLoopbackUrl, ghConnectorSchema, onceScheduleEntrySchema, previewOf, profileConfigSchema, publishRequestSchema, publishResponseSchema, queryRows, queryToCliArgs, resolveFunnelDir, resolveFunnelPort, scheduleCatchupPolicySchema, scheduleConnectorSchema, scheduleEntryInputSchema, scheduleEntrySchema, settingsSchema, slackConnectorSchema, toDiagnosticConnectionError, toDiagnosticEvent, toRequest };
@@ -1,6 +1,6 @@
1
- import { t as discordConnectorSchema } from "./discord-connector-schema-B4YpWpR3.js";
2
- import { t as ghConnectorSchema } from "./gh-connector-schema-CAqIhzGr.js";
3
- import { t as slackConnectorSchema } from "./slack-connector-schema-Dem8to4P.js";
1
+ import { t as discordConnectorSchema } from "./discord-connector-schema-saAGuPmJ.js";
2
+ import { t as ghConnectorSchema } from "./gh-connector-schema-DmZTrzUu.js";
3
+ import { t as slackConnectorSchema } from "./slack-connector-schema-EGVuuqSX.js";
4
4
  import { join } from "node:path";
5
5
  import { z } from "zod";
6
6
  import { stderr, stdin } from "node:process";
@@ -60,7 +60,7 @@ const profileSpecSchema = z.object({
60
60
  /** Env vars layered under the launched claude process. process.env wins on collision. */
61
61
  env: z.record(z.string(), z.string()).optional(),
62
62
  /**
63
- * When true (the default), funnel injects `--session-id <uuid>` so that
63
+ * When true, funnel injects `--session-id <uuid>` so that
64
64
  * relaunching from the same cwd resumes the previous claude session
65
65
  * without bleeding into other channels or workspaces. Set to false for
66
66
  * profiles that should always start a fresh session.
@@ -1,6 +1,5 @@
1
- import { n as FunnelFileSystem } from "./file-system-DHgbuTFb.js";
2
- import { a as LocalConfigSyncResult, c as ChannelSpec, d as LocalConfig, f as ProfileSpec, g as profileSpecSchema, h as localConfigSchema, i as FunnelLocalConfigSync, l as ConnectorSpec, m as connectorSpecSchema, n as NodeFunnelTokenPrompter, o as FunnelTokenPrompter, p as channelSpecSchema, r as ConnectorSyncOutcome, s as FunnelLocalConfig, t as MemoryFunnelTokenPrompter, u as LOCAL_CONFIG_FILENAME } from "./memory-token-prompter-D0kIdhar.js";
3
-
1
+ import { n as FunnelFileSystem } from "./file-system-BNtl997T.js";
2
+ import { a as LocalConfigSyncResult, c as ChannelSpec, d as LocalConfig, f as ProfileSpec, g as profileSpecSchema, h as localConfigSchema, i as FunnelLocalConfigSync, l as ConnectorSpec, m as connectorSpecSchema, n as NodeFunnelTokenPrompter, o as FunnelTokenPrompter, p as channelSpecSchema, r as ConnectorSyncOutcome, s as FunnelLocalConfig, t as MemoryFunnelTokenPrompter, u as LOCAL_CONFIG_FILENAME } from "./memory-token-prompter-B20tl_aU.js";
4
3
  //#region lib/services/local-config/local-config-json-schema.d.ts
5
4
  /**
6
5
  * Generates the JSON Schema (draft 2020-12) for `funnel.json`. Useful for
@@ -1,4 +1,4 @@
1
- import { a as FunnelTokenPrompter, c as channelSpecSchema, d as profileSpecSchema, i as FunnelLocalConfigSync, l as connectorSpecSchema, n as MemoryFunnelTokenPrompter, o as FunnelLocalConfig, r as NodeFunnelTokenPrompter, s as LOCAL_CONFIG_FILENAME, t as funnelJsonSchema, u as localConfigSchema } from "./local-config-json-schema-DexV8vX3.js";
1
+ import { a as FunnelTokenPrompter, c as channelSpecSchema, d as profileSpecSchema, i as FunnelLocalConfigSync, l as connectorSpecSchema, n as MemoryFunnelTokenPrompter, o as FunnelLocalConfig, r as NodeFunnelTokenPrompter, s as LOCAL_CONFIG_FILENAME, t as funnelJsonSchema, u as localConfigSchema } from "./local-config-json-schema-_-YVHX4c.js";
2
2
  import { join } from "node:path";
3
3
  //#region lib/services/local-config/local-config-writer.ts
4
4
  const isRecord = (value) => {