@interactive-inc/claude-funnel 0.59.1 → 0.60.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.
Files changed (85) hide show
  1. package/README.md +9 -3
  2. package/dist/bin.js +549 -487
  3. package/dist/channels-2g_BU1N0.d.ts +174 -0
  4. package/dist/claude.d.ts +9 -5
  5. package/dist/claude.js +54 -17
  6. package/dist/{diagnostic-log-Cb3v8P7p.d.ts → connector-descriptor-6SXJoszo.d.ts} +158 -2
  7. package/dist/connectors/discord.d.ts +30 -4
  8. package/dist/connectors/discord.js +2 -2
  9. package/dist/connectors/gh.d.ts +21 -5
  10. package/dist/connectors/gh.js +3 -3
  11. package/dist/connectors/schedule.d.ts +124 -2
  12. package/dist/connectors/schedule.js +3 -3
  13. package/dist/connectors/slack.d.ts +149 -5
  14. package/dist/connectors/slack.js +2 -2
  15. package/dist/{diagnostic-sql-reader-CzYgZpq2.js → diagnostic-sql-reader-C9zR-Csp.js} +5 -5
  16. package/dist/diagnostics.d.ts +1 -1
  17. package/dist/diagnostics.js +1 -1
  18. package/dist/{discord-listener-CKsZGTnH.js → discord-connector-BL36yvbL.js} +60 -37
  19. package/dist/docs.d.ts +1 -1
  20. package/dist/docs.js +1 -1
  21. package/dist/doctor.d.ts +1 -1
  22. package/dist/doctor.js +1 -1
  23. package/dist/error-message-of-Byi4y0Uf.js +9 -0
  24. package/dist/{file-process-guard-JhFpmHYo.d.ts → file-process-guard-C_PLxfUX.d.ts} +6 -5
  25. package/dist/{funnel-diagnostics-BpKYrMSu.js → funnel-diagnostics-CSiJmPlZ.js} +19 -2
  26. package/dist/{funnel-diagnostics-K-wON25Y.d.ts → funnel-diagnostics-DpXOsCty.d.ts} +3 -3
  27. package/dist/{funnel-docs-ng5K8w4j.js → funnel-docs-BxXZ9Ksx.js} +76 -3
  28. package/dist/{funnel-docs-DYBs1-H_.d.ts → funnel-docs-CNklHvbt.d.ts} +1 -1
  29. package/dist/{funnel-doctor-vxO96TCA.d.ts → funnel-doctor-CZf_0Luq.d.ts} +2 -2
  30. package/dist/{funnel-recovery-COExL9MD.d.ts → funnel-recovery-DnLrdWO9.d.ts} +1 -1
  31. package/dist/gateway/daemon.js +326 -266
  32. package/dist/gateway-base-url-Dy4Ykuoh.js +14 -0
  33. package/dist/gateway.d.ts +2 -2
  34. package/dist/gateway.js +2 -2
  35. package/dist/{gh-listener-B2I4s8qh.js → gh-connector-DpiixfQZ.js} +53 -5
  36. package/dist/gh-connector-schema-Rzwc1c1N.js +12 -0
  37. package/dist/http-client-oICicjuO.d.ts +18 -0
  38. package/dist/index-CgY8NdMz.d.ts +1057 -0
  39. package/dist/index.d.ts +1558 -17
  40. package/dist/index.js +376 -343
  41. package/dist/{local-config-json-schema-DE1zkMcb.js → local-config-json-schema-JyLqOQNX.js} +9 -5
  42. package/dist/local-config-sync-Dh1Croqe.d.ts +169 -0
  43. package/dist/local-config.d.ts +2 -2
  44. package/dist/local-config.js +2 -2
  45. package/dist/logger.js +1 -1
  46. package/dist/{memory-diagnostic-log-B9Us7X05.js → memory-diagnostic-log-CI60kNfB.js} +33 -18
  47. package/dist/{memory-token-prompter-CcShtF8B.d.ts → memory-token-prompter-B4sjyaAq.d.ts} +2 -2
  48. package/dist/{memory-token-prompter-C7vREzCL.js → memory-token-prompter-CZde7e6y.js} +1 -1
  49. package/dist/{node-file-system-BcrmWN9I.js → node-file-system-Blr8pAir.js} +1 -1
  50. package/dist/node-http-client-lowp60Oa.js +25 -0
  51. package/dist/{gh-connector-schema-ClPLSYD9.js → node-process-runner-DxTvycoK.js} +1 -12
  52. package/dist/{profiles-g2qGVOWv.d.ts → profiles-Cy5wXQ0L.d.ts} +3 -3
  53. package/dist/{profiles-MnXvYfZF.js → profiles-DSzTeKQw.js} +1 -1
  54. package/dist/profiles.d.ts +1 -1
  55. package/dist/profiles.js +1 -1
  56. package/dist/recovery.d.ts +1 -1
  57. package/dist/recovery.js +1 -1
  58. package/dist/{schedule-listener-DP9Jhc6U.js → schedule-connector-L4uzg5M8.js} +109 -9
  59. package/dist/{settings-reader-DPwqOVUm.d.ts → settings-reader-BIFB_j2f.d.ts} +1 -1
  60. package/dist/settings-schema-D1xcOqRu.d.ts +78 -0
  61. package/dist/{gateway-base-url-DxVjjDoW.js → settings-store-CUKSeTXC.js} +27 -29
  62. package/dist/{slack-listener-C4wlZaOq.js → slack-connector-DQIFPdBF.js} +67 -12
  63. package/dist/slot-fields-CMoRpwuy.js +45 -0
  64. package/dist/{yaml-render-cZu6CxkE.js → yaml-render-93pX7EF7.js} +7 -4
  65. package/package.json +1 -1
  66. package/dist/connector-adapter-DGacCppE.d.ts +0 -25
  67. package/dist/discord-connector-schema-CQyfDkLD.d.ts +0 -39
  68. package/dist/gh-connector-schema-CZzwzvqY.d.ts +0 -14
  69. package/dist/index-D7mjirUL.d.ts +0 -3602
  70. package/dist/local-config-sync-BGPAS9Be.d.ts +0 -401
  71. package/dist/process-runner-DIm1cy95.d.ts +0 -52
  72. package/dist/resolve-connector-token-CczqG_Ig.js +0 -22
  73. package/dist/schedule-listener-DoMPjHZj.d.ts +0 -112
  74. package/dist/settings-schema-1hh11jnN.d.ts +0 -152
  75. package/dist/slack-listener-Dj9NFbAJ.d.ts +0 -136
  76. /package/dist/{connector-adapter-qwXLjQId.js → connector-adapter-DU9Rvyec.js} +0 -0
  77. /package/dist/{connector-listener-CpHBecCj.js → connector-listener-DR3aKOuK.js} +0 -0
  78. /package/dist/{file-system-PWKKU7lA.js → file-system-Wvzc2ePY.js} +0 -0
  79. /package/dist/{file-system-DxpnnUVb.d.ts → file-system-o51IsM0W.d.ts} +0 -0
  80. /package/dist/{funnel-doctor-CApCezTq.js → funnel-doctor-DiJCjHsg.js} +0 -0
  81. /package/dist/{funnel-log-sqlite-sink-B_5_4ybn.js → funnel-log-sqlite-sink-kqJbx2H7.js} +0 -0
  82. /package/dist/{funnel-recovery-D9CxD5Zs.js → funnel-recovery-BFdPjL6Z.js} +0 -0
  83. /package/dist/{logger-BP6SisKt.js → logger-B6iyNbxM.js} +0 -0
  84. /package/dist/{schedule-connector-schema-B_xO5z5B.js → schedule-connector-schema-CfyuMCMh.js} +0 -0
  85. /package/dist/{settings-reader-DPqrpV7s.js → settings-reader-CtQ-Ix8_.js} +0 -0
@@ -0,0 +1,78 @@
1
+ import { z } from "zod";
2
+
3
+ //#region lib/engine/settings/settings-schema.d.ts
4
+ /**
5
+ * Routing mode when multiple WS clients are subscribed to the same channel.
6
+ *
7
+ * - `fanout` (default): every connected client receives every event. Right when each
8
+ * subscriber has its own job (e.g., TUI mirrors, distinct Claude profiles each running
9
+ * their own pipeline against the same source).
10
+ * - `exclusive`: each event is delivered to exactly one connected client, picked
11
+ * round-robin per channel. Right when subscribers are interchangeable workers and you
12
+ * want each event handled once. Tap=all clients (TUI dashboard) always receive,
13
+ * regardless of mode, so they can passively observe.
14
+ */
15
+ declare const channelDeliveryModeSchema: z.ZodEnum<{
16
+ fanout: "fanout";
17
+ exclusive: "exclusive";
18
+ }>;
19
+ type ChannelDeliveryMode = z.infer<typeof channelDeliveryModeSchema>;
20
+ declare const channelConfigSchema: z.ZodObject<{
21
+ id: z.ZodString;
22
+ name: z.ZodString;
23
+ delivery: z.ZodDefault<z.ZodEnum<{
24
+ fanout: "fanout";
25
+ exclusive: "exclusive";
26
+ }>>;
27
+ connectors: z.ZodDefault<z.ZodArray<z.ZodObject<{
28
+ id: z.ZodString;
29
+ name: z.ZodString;
30
+ type: z.ZodString;
31
+ createdAt: z.ZodOptional<z.ZodString>;
32
+ updatedAt: z.ZodOptional<z.ZodString>;
33
+ }, z.core.$loose>>>;
34
+ }, z.core.$strip>;
35
+ type ChannelConfig = z.infer<typeof channelConfigSchema>;
36
+ declare const profileConfigSchema: z.ZodObject<{
37
+ id: z.ZodString;
38
+ name: z.ZodString;
39
+ path: z.ZodString;
40
+ channelId: z.ZodString;
41
+ options: z.ZodDefault<z.ZodArray<z.ZodString>>;
42
+ env: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
43
+ resume: z.ZodDefault<z.ZodBoolean>;
44
+ sessionId: z.ZodOptional<z.ZodString>;
45
+ }, z.core.$strip>;
46
+ type ProfileConfig = z.infer<typeof profileConfigSchema>;
47
+ declare const SETTINGS_VERSION = 1;
48
+ declare const settingsSchema: z.ZodObject<{
49
+ version: z.ZodDefault<z.ZodLiteral<1>>;
50
+ channels: z.ZodDefault<z.ZodArray<z.ZodObject<{
51
+ id: z.ZodString;
52
+ name: z.ZodString;
53
+ delivery: z.ZodDefault<z.ZodEnum<{
54
+ fanout: "fanout";
55
+ exclusive: "exclusive";
56
+ }>>;
57
+ connectors: z.ZodDefault<z.ZodArray<z.ZodObject<{
58
+ id: z.ZodString;
59
+ name: z.ZodString;
60
+ type: z.ZodString;
61
+ createdAt: z.ZodOptional<z.ZodString>;
62
+ updatedAt: z.ZodOptional<z.ZodString>;
63
+ }, z.core.$loose>>>;
64
+ }, z.core.$strip>>>;
65
+ profiles: z.ZodDefault<z.ZodArray<z.ZodObject<{
66
+ id: z.ZodString;
67
+ name: z.ZodString;
68
+ path: z.ZodString;
69
+ channelId: z.ZodString;
70
+ options: z.ZodDefault<z.ZodArray<z.ZodString>>;
71
+ env: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
72
+ resume: z.ZodDefault<z.ZodBoolean>;
73
+ sessionId: z.ZodOptional<z.ZodString>;
74
+ }, z.core.$strip>>>;
75
+ }, z.core.$strip>;
76
+ type Settings = z.infer<typeof settingsSchema>;
77
+ //#endregion
78
+ export { Settings as a, profileConfigSchema as c, SETTINGS_VERSION as i, settingsSchema as l, ChannelDeliveryMode as n, channelConfigSchema as o, ProfileConfig as r, channelDeliveryModeSchema as s, ChannelConfig as t };
@@ -1,12 +1,8 @@
1
- import { t as ghConnectorSchema } from "./gh-connector-schema-ClPLSYD9.js";
2
- import { t as NodeFunnelFileSystem } from "./node-file-system-BcrmWN9I.js";
3
- import { n as FunnelIdGenerator, t as FunnelSettingsReader } from "./settings-reader-DPqrpV7s.js";
4
- import { t as discordConnectorSchema } from "./discord-connector-schema-B_N6IXLz.js";
5
- import { n as scheduleConnectorSchema } from "./schedule-connector-schema-B_xO5z5B.js";
6
- import { t as slackConnectorSchema } from "./slack-connector-schema-C1zEf4TG.js";
1
+ import { t as NodeFunnelFileSystem } from "./node-file-system-Blr8pAir.js";
2
+ import { n as FunnelIdGenerator, t as FunnelSettingsReader } from "./settings-reader-CtQ-Ix8_.js";
7
3
  import { dirname, join } from "node:path";
8
- import { z } from "zod";
9
4
  import { homedir } from "node:os";
5
+ import { z } from "zod";
10
6
  //#region lib/engine/id/node-id-generator.ts
11
7
  var NodeFunnelIdGenerator = class extends FunnelIdGenerator {
12
8
  generate() {
@@ -14,16 +10,31 @@ var NodeFunnelIdGenerator = class extends FunnelIdGenerator {
14
10
  }
15
11
  };
16
12
  //#endregion
17
- //#region lib/engine/connectors/connector-config-schema.ts
18
- const connectorConfigSchema = z.discriminatedUnion("type", [
19
- slackConnectorSchema,
20
- ghConnectorSchema,
21
- discordConnectorSchema,
22
- scheduleConnectorSchema
23
- ]);
13
+ //#region lib/engine/connectors/base-connector-config.ts
14
+ /**
15
+ * Fields every connector config carries, regardless of type. The discriminated
16
+ * union of concrete connector configs no longer lives in core: each connector
17
+ * type owns its full schema inside its descriptor, and core handles connectors
18
+ * through this base shape plus the injected registry. `type` is an open string
19
+ * here on purpose — core does not enumerate the known connector types.
20
+ */
21
+ const baseConnectorConfigSchema = z.object({
22
+ id: z.string(),
23
+ name: z.string(),
24
+ type: z.string(),
25
+ createdAt: z.string().datetime().optional(),
26
+ updatedAt: z.string().datetime().optional()
27
+ });
24
28
  //#endregion
25
29
  //#region lib/engine/settings/settings-schema.ts
26
30
  /**
31
+ * Connectors are stored loosely here: settings validates only the common base
32
+ * fields and preserves every type-specific key verbatim (`.passthrough()`).
33
+ * Core does not enumerate connector types, so strict per-type validation happens
34
+ * at the registry/descriptor layer (CRUD time), not on every settings read.
35
+ */
36
+ const storedConnectorSchema = baseConnectorConfigSchema.passthrough();
37
+ /**
27
38
  * Routing mode when multiple WS clients are subscribed to the same channel.
28
39
  *
29
40
  * - `fanout` (default): every connected client receives every event. Right when each
@@ -39,7 +50,7 @@ const channelConfigSchema = z.object({
39
50
  id: z.string(),
40
51
  name: z.string(),
41
52
  delivery: channelDeliveryModeSchema.default("fanout"),
42
- connectors: z.array(connectorConfigSchema).default([])
53
+ connectors: z.array(storedConnectorSchema).default([])
43
54
  });
44
55
  const profileConfigSchema = z.object({
45
56
  /** Stable identity (uuid). The primary key everything internal resolves to;
@@ -183,17 +194,4 @@ var FunnelSettingsStore = class extends FunnelSettingsReader {
183
194
  }
184
195
  };
185
196
  //#endregion
186
- //#region lib/gateway/gateway-base-url.ts
187
- /**
188
- * The HTTP base URL of a gateway daemon on the loopback interface. The daemon
189
- * always binds 127.0.0.1 for its management API (only the WS `/ws` endpoint is
190
- * ever exposed off-box), so every in-process HTTP client — publisher, listeners
191
- * client, MCP channel server — talks to it here. Centralizing the construction
192
- * keeps the host/port shape in one place instead of re-spelling
193
- * `http://127.0.0.1:${port}` at each call site.
194
- */
195
- function gatewayLoopbackUrl(port) {
196
- return `http://127.0.0.1:${port}`;
197
- }
198
- //#endregion
199
- export { SETTINGS_PATH as a, SETTINGS_VERSION as c, profileConfigSchema as d, settingsSchema as f, FunnelSettingsStore as i, channelConfigSchema as l, NodeFunnelIdGenerator as m, DEFAULT_GATEWAY_PORT as n, resolveFunnelDir as o, connectorConfigSchema as p, FUNNEL_DIR as r, resolveFunnelPort as s, gatewayLoopbackUrl as t, channelDeliveryModeSchema as u };
197
+ export { resolveFunnelDir as a, channelConfigSchema as c, settingsSchema as d, baseConnectorConfigSchema as f, SETTINGS_PATH as i, channelDeliveryModeSchema as l, FUNNEL_DIR as n, resolveFunnelPort as o, NodeFunnelIdGenerator as p, FunnelSettingsStore as r, SETTINGS_VERSION as s, DEFAULT_GATEWAY_PORT as t, profileConfigSchema as u };
@@ -1,6 +1,8 @@
1
- import { t as FunnelConnectorAdapter } from "./connector-adapter-qwXLjQId.js";
2
- import { t as resolveConnectorToken } from "./resolve-connector-token-CczqG_Ig.js";
3
- import { t as FunnelConnectorListener } from "./connector-listener-CpHBecCj.js";
1
+ import { t as slackConnectorSchema } from "./slack-connector-schema-C1zEf4TG.js";
2
+ import { t as FunnelConnectorAdapter } from "./connector-adapter-DU9Rvyec.js";
3
+ import { t as FunnelConnectorListener } from "./connector-listener-DR3aKOuK.js";
4
+ import { t as errorMessageOf } from "./error-message-of-Byi4y0Uf.js";
5
+ import { n as resolveConnectorToken, t as slotFields } from "./slot-fields-CMoRpwuy.js";
4
6
  import { z } from "zod";
5
7
  import { WebClient } from "@slack/web-api";
6
8
  import { App, LogLevel, SocketModeReceiver } from "@slack/bolt";
@@ -316,7 +318,7 @@ var FunnelSlackListener = class extends FunnelConnectorListener {
316
318
  try {
317
319
  authResult = await app.client.auth.test({ token: botToken });
318
320
  } catch (error) {
319
- this.recordConnection("auth-failed", messageOf(error));
321
+ this.recordConnection("auth-failed", errorMessageOf(error));
320
322
  throw error;
321
323
  }
322
324
  const processor = new FunnelSlackEventProcessor({
@@ -361,7 +363,7 @@ var FunnelSlackListener = class extends FunnelConnectorListener {
361
363
  } catch {}
362
364
  });
363
365
  app.error(async (error) => {
364
- const message = messageOf(error);
366
+ const message = errorMessageOf(error);
365
367
  this.recordConnection("error", message);
366
368
  this.logger?.error("Slack error", { error: message });
367
369
  });
@@ -369,7 +371,7 @@ var FunnelSlackListener = class extends FunnelConnectorListener {
369
371
  try {
370
372
  await app.start();
371
373
  } catch (error) {
372
- this.recordConnection("error", messageOf(error));
374
+ this.recordConnection("error", errorMessageOf(error));
373
375
  throw error;
374
376
  }
375
377
  this.app = app;
@@ -382,8 +384,8 @@ var FunnelSlackListener = class extends FunnelConnectorListener {
382
384
  await this.app.stop();
383
385
  this.recordConnection("disconnected", "");
384
386
  } catch (error) {
385
- this.recordConnection("error", messageOf(error));
386
- this.logger?.error("Slack stop error", { error: messageOf(error) });
387
+ this.recordConnection("error", errorMessageOf(error));
388
+ this.logger?.error("Slack stop error", { error: errorMessageOf(error) });
387
389
  } finally {
388
390
  this.app = null;
389
391
  this.connected = false;
@@ -422,8 +424,61 @@ var FunnelSlackListener = class extends FunnelConnectorListener {
422
424
  });
423
425
  }
424
426
  };
425
- const messageOf = (error) => {
426
- return error instanceof Error ? error.message : String(error);
427
- };
428
427
  //#endregion
429
- export { FunnelSlackEventProcessor as n, FunnelSlackAdapter as r, FunnelSlackListener as t };
428
+ //#region lib/engine/connectors/slack-connector.ts
429
+ /**
430
+ * Slack connector descriptor. Pass `slackConnector()` to
431
+ * `new Funnel({ connectors: [...] })` to enable the type. Host launch hooks are
432
+ * closed over here, so they need no Funnel-level option plumbing.
433
+ */
434
+ const slackConnector = (options = {}) => ({
435
+ type: "slack",
436
+ toolExposed: true,
437
+ createListener(config, deps) {
438
+ return new FunnelSlackListener({
439
+ config: slackConnectorSchema.parse(config),
440
+ channelId: deps.channelId,
441
+ logger: deps.logger,
442
+ diagnosticLog: deps.diagnosticLog,
443
+ onAppCreated: options.onAppCreated,
444
+ preprocessEvent: options.preprocessEvent
445
+ });
446
+ },
447
+ createAdapter(config) {
448
+ return new FunnelSlackAdapter({ config: slackConnectorSchema.parse(config) });
449
+ },
450
+ secretTokens(config) {
451
+ const parsed = slackConnectorSchema.parse(config);
452
+ return [parsed.botToken, parsed.appToken].filter((token) => token !== void 0);
453
+ },
454
+ buildConfig(input, context) {
455
+ return slackConnectorSchema.parse({
456
+ id: context.id,
457
+ type: "slack",
458
+ name: input.name,
459
+ ...typeof input.botToken === "string" ? { botToken: input.botToken } : {},
460
+ ...typeof input.appToken === "string" ? { appToken: input.appToken } : {},
461
+ ...typeof input.botTokenEnv === "string" ? { botTokenEnv: input.botTokenEnv } : {},
462
+ ...typeof input.appTokenEnv === "string" ? { appTokenEnv: input.appTokenEnv } : {},
463
+ minify: typeof input.minify === "boolean" ? input.minify : true,
464
+ createdAt: context.now,
465
+ updatedAt: context.now
466
+ });
467
+ },
468
+ applyUpdate(config, fields, context) {
469
+ const current = slackConnectorSchema.parse(config);
470
+ return slackConnectorSchema.parse({
471
+ id: current.id,
472
+ name: current.name,
473
+ type: "slack",
474
+ minify: current.minify,
475
+ createdAt: current.createdAt,
476
+ updatedAt: context.now,
477
+ ...slotFields("botToken", "botTokenEnv", fields, current),
478
+ ...slotFields("appToken", "appTokenEnv", fields, current)
479
+ });
480
+ },
481
+ operations: {}
482
+ });
483
+ //#endregion
484
+ export { FunnelSlackAdapter as i, FunnelSlackListener as n, FunnelSlackEventProcessor as r, slackConnector as t };
@@ -0,0 +1,45 @@
1
+ //#region lib/engine/connectors/resolve-connector-token.ts
2
+ /**
3
+ * Resolves a connector token from either a literal value or the name of an env
4
+ * var. A connector config carries one or the other per slot (see
5
+ * slack-connector-schema): literals are inlined into settings.json, references
6
+ * keep the secret in `process.env` and out of settings.json.
7
+ *
8
+ * Errors loudly when neither yields a value — a misconfigured connector should
9
+ * fail at listener start, not connect with an empty token and silently never
10
+ * receive events.
11
+ */
12
+ const resolveConnectorToken = (props) => {
13
+ if (props.literal !== void 0 && props.literal !== "") return props.literal;
14
+ if (props.envVar !== void 0 && props.envVar !== "") {
15
+ const fromEnv = props.env[props.envVar];
16
+ if (fromEnv !== void 0 && fromEnv !== "") return fromEnv;
17
+ throw new Error(`${props.label} references env var "${props.envVar}" but it is not set in the environment`);
18
+ }
19
+ throw new Error(`${props.label} has neither a literal token nor an env var reference`);
20
+ };
21
+ //#endregion
22
+ //#region lib/engine/connectors/slot-fields.ts
23
+ /**
24
+ * Resolves one token slot (e.g. botToken/botTokenEnv) for a connector update.
25
+ * The literal and the env-ref form are mutually exclusive: if `fields` supplies
26
+ * either, that form wins and the other key is omitted entirely; if it supplies
27
+ * neither, the connector's current slot is carried over unchanged. Returns a
28
+ * partial object spread into the rebuilt connector, so an omitted key is truly
29
+ * absent rather than set to undefined — switching a slot from literal to ref
30
+ * drops the stale literal instead of leaving both behind.
31
+ */
32
+ const slotFields = (literalKey, envKey, fields, current) => {
33
+ const literal = fields[literalKey];
34
+ if (typeof literal === "string") return { [literalKey]: literal };
35
+ const envVar = fields[envKey];
36
+ if (typeof envVar === "string") return { [envKey]: envVar };
37
+ const result = {};
38
+ const currentLiteral = current[literalKey];
39
+ const currentEnv = current[envKey];
40
+ if (typeof currentLiteral === "string") result[literalKey] = currentLiteral;
41
+ if (typeof currentEnv === "string") result[envKey] = currentEnv;
42
+ return result;
43
+ };
44
+ //#endregion
45
+ export { resolveConnectorToken as n, slotFields as t };
@@ -1,6 +1,6 @@
1
- import { n as NodeFunnelProcessRunner } from "./gh-connector-schema-ClPLSYD9.js";
2
- import { t as NodeFunnelFileSystem } from "./node-file-system-BcrmWN9I.js";
3
- import { m as NodeFunnelIdGenerator, r as FUNNEL_DIR, s as resolveFunnelPort } from "./gateway-base-url-DxVjjDoW.js";
1
+ import { t as NodeFunnelFileSystem } from "./node-file-system-Blr8pAir.js";
2
+ import { t as NodeFunnelProcessRunner } from "./node-process-runner-DxTvycoK.js";
3
+ import { n as FUNNEL_DIR, o as resolveFunnelPort, p as NodeFunnelIdGenerator } from "./settings-store-CUKSeTXC.js";
4
4
  import { join } from "node:path";
5
5
  import { stringify } from "yaml";
6
6
  //#region lib/engine/claude/claude.ts
@@ -21,6 +21,7 @@ var FunnelClaude = class {
21
21
  process;
22
22
  idGenerator;
23
23
  logger;
24
+ dir;
24
25
  constructor(deps) {
25
26
  this.channels = deps.channels;
26
27
  this.mcp = deps.mcp;
@@ -30,6 +31,7 @@ var FunnelClaude = class {
30
31
  this.process = deps.process ?? defaultProcess$1;
31
32
  this.idGenerator = deps.idGenerator ?? defaultIdGenerator;
32
33
  this.logger = deps.logger;
34
+ this.dir = deps.dir;
33
35
  Object.freeze(this);
34
36
  }
35
37
  async launch(options) {
@@ -115,6 +117,7 @@ var FunnelClaude = class {
115
117
  for (const [key, value] of Object.entries(globalThis.process.env)) if (typeof value === "string") env[key] = value;
116
118
  env.FUNNEL_CHANNEL_ID = channelId;
117
119
  env.FUNNEL_PORT = String(resolveFunnelPort());
120
+ if (this.dir !== void 0) env.FUNNEL_DIR = this.dir;
118
121
  return env;
119
122
  }
120
123
  };
@@ -280,7 +283,7 @@ var FunnelMcp = class {
280
283
  }
281
284
  };
282
285
  //#endregion
283
- //#region lib/cli/yaml-render.ts
286
+ //#region lib/engine/yaml/yaml-render.ts
284
287
  /**
285
288
  * Render any value as a valid YAML document for CLI output.
286
289
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@interactive-inc/claude-funnel",
3
- "version": "0.59.1",
3
+ "version": "0.60.1",
4
4
  "description": "Hub CLI that routes external events (Slack / GitHub / Discord) to Claude Code agents through subscription channels over MCP.",
5
5
  "keywords": [
6
6
  "bun",
@@ -1,25 +0,0 @@
1
- //#region lib/engine/connectors/connector-adapter.d.ts
2
- /**
3
- * A JSON-serializable value. Connector call bodies are sent to external APIs as
4
- * JSON, so the body must be representable as JSON — `JsonValue` says exactly
5
- * that, replacing a bare `unknown` that let non-serializable values (functions,
6
- * symbols, class instances) slip through to `JSON.stringify`.
7
- */
8
- type JsonValue = string | number | boolean | null | JsonValue[] | {
9
- [key: string]: JsonValue;
10
- };
11
- type CallInput = {
12
- method: string;
13
- path: string; /** JSON request body. Omit for GET-like calls. */
14
- body?: JsonValue;
15
- };
16
- declare abstract class FunnelConnectorAdapter {
17
- /**
18
- * Dispatches one Claude → external call. The response is the external API's
19
- * raw payload, typed `unknown` because its shape is the provider's concern —
20
- * the caller (Claude, via MCP) interprets it.
21
- */
22
- abstract call(input: CallInput): Promise<unknown>;
23
- }
24
- //#endregion
25
- export { FunnelConnectorAdapter as n, JsonValue as r, CallInput as t };
@@ -1,39 +0,0 @@
1
- import { z } from "zod";
2
-
3
- //#region lib/engine/http/http-client.d.ts
4
- type HttpRequest = {
5
- method: string;
6
- url: string;
7
- headers?: Record<string, string>;
8
- body?: string;
9
- };
10
- type HttpResponse = {
11
- status: number;
12
- ok: boolean;
13
- text(): Promise<string>;
14
- json(): Promise<unknown>;
15
- };
16
- declare abstract class FunnelHttpClient {
17
- abstract fetch(request: HttpRequest): Promise<HttpResponse>;
18
- }
19
- //#endregion
20
- //#region lib/engine/connectors/discord-connector-schema.d.ts
21
- /**
22
- * Like slack, a discord connector holds either a literal `botToken` or a
23
- * `botTokenEnv` reference resolved from `process.env` at listener start. The
24
- * reference form keeps the secret out of settings.json, but is only set through
25
- * the engine API (`new Funnel(...)`); funnel.json and the `fnl` CLI produce
26
- * literals.
27
- */
28
- declare const discordConnectorSchema: z.ZodObject<{
29
- id: z.ZodString;
30
- name: z.ZodString;
31
- type: z.ZodLiteral<"discord">;
32
- botToken: z.ZodOptional<z.ZodString>;
33
- botTokenEnv: z.ZodOptional<z.ZodString>;
34
- createdAt: z.ZodOptional<z.ZodString>;
35
- updatedAt: z.ZodOptional<z.ZodString>;
36
- }, z.core.$strip>;
37
- type DiscordConnectorConfig = z.infer<typeof discordConnectorSchema>;
38
- //#endregion
39
- export { HttpResponse as a, HttpRequest as i, discordConnectorSchema as n, FunnelHttpClient as r, DiscordConnectorConfig as t };
@@ -1,14 +0,0 @@
1
- import { z } from "zod";
2
-
3
- //#region lib/engine/connectors/gh-connector-schema.d.ts
4
- declare const ghConnectorSchema: z.ZodObject<{
5
- id: z.ZodString;
6
- name: z.ZodString;
7
- type: z.ZodLiteral<"gh">;
8
- pollInterval: z.ZodOptional<z.ZodNumber>;
9
- createdAt: z.ZodOptional<z.ZodString>;
10
- updatedAt: z.ZodOptional<z.ZodString>;
11
- }, z.core.$strip>;
12
- type GhConnectorConfig = z.infer<typeof ghConnectorSchema>;
13
- //#endregion
14
- export { ghConnectorSchema as n, GhConnectorConfig as t };