@interactive-inc/claude-funnel 0.60.1 → 0.64.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 (88) hide show
  1. package/README.md +2 -2
  2. package/dist/bin.js +428 -761
  3. package/dist/{channels-2g_BU1N0.d.ts → channels-CRGb6B5_.d.ts} +17 -16
  4. package/dist/claude.d.ts +5 -7
  5. package/dist/claude.js +143 -36
  6. package/dist/{connector-descriptor-6SXJoszo.d.ts → connector-descriptor-BFIhyTfa.d.ts} +49 -10
  7. package/dist/connector-diagnostics-recorder-COtNEmUp.js +42 -0
  8. package/dist/connectors/discord.d.ts +31 -37
  9. package/dist/connectors/discord.js +3 -3
  10. package/dist/connectors/gh.d.ts +37 -33
  11. package/dist/connectors/gh.js +3 -3
  12. package/dist/connectors/schedule.d.ts +9 -57
  13. package/dist/connectors/schedule.js +3 -3
  14. package/dist/connectors/slack.d.ts +106 -132
  15. package/dist/connectors/slack.js +4 -3
  16. package/dist/diagnostics.d.ts +1 -1
  17. package/dist/diagnostics.js +1 -1
  18. package/dist/discord-connector-DIFkYBbi.js +250 -0
  19. package/dist/discord-connector-schema-D-bOVAKt.d.ts +22 -0
  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/{file-process-guard-C_PLxfUX.d.ts → file-process-guard-tVcgckH6.d.ts} +6 -6
  24. package/dist/{file-system-o51IsM0W.d.ts → file-system-VhwwXZbm.d.ts} +8 -0
  25. package/dist/flume-source-listener-BNyAII7N.d.ts +133 -0
  26. package/dist/{funnel-diagnostics-CSiJmPlZ.js → funnel-diagnostics-Cvk6Sk4x.js} +193 -43
  27. package/dist/{funnel-diagnostics-DpXOsCty.d.ts → funnel-diagnostics-b9ar0Ing.d.ts} +67 -5
  28. package/dist/{funnel-docs-BxXZ9Ksx.js → funnel-docs-C-ge0MuB.js} +42 -6
  29. package/dist/{funnel-doctor-CZf_0Luq.d.ts → funnel-doctor-CnRQi4kM.d.ts} +2 -2
  30. package/dist/{funnel-doctor-DiJCjHsg.js → funnel-doctor-XrI2GBH8.js} +1 -1
  31. package/dist/funnel-error-0t1MK1R6.js +75 -0
  32. package/dist/{funnel-recovery-DnLrdWO9.d.ts → funnel-recovery-CMhY8Jfk.d.ts} +1 -1
  33. package/dist/gateway/daemon.js +167 -527
  34. package/dist/gateway.d.ts +3 -3
  35. package/dist/gateway.js +3 -3
  36. package/dist/gh-connector-BUGCOEWS.js +187 -0
  37. package/dist/{gh-connector-schema-Rzwc1c1N.js → gh-connector-schema-CAqIhzGr.js} +7 -0
  38. package/dist/gh-connector-schema-DWQaB6gX.d.ts +16 -0
  39. package/dist/{index-CgY8NdMz.d.ts → index-Ds6sHhA-.d.ts} +37 -19
  40. package/dist/index.d.ts +182 -22
  41. package/dist/index.js +363 -173
  42. package/dist/{local-config-json-schema-JyLqOQNX.js → local-config-json-schema-DexV8vX3.js} +24 -4
  43. package/dist/local-config.d.ts +39 -2
  44. package/dist/local-config.js +53 -2
  45. package/dist/logger.js +1 -1
  46. package/dist/loopback-fetch-CVNuN3YZ.js +40 -0
  47. package/dist/{local-config-sync-Dh1Croqe.d.ts → memory-token-prompter-BoV8Hf-n.d.ts} +30 -3
  48. package/dist/node-file-system-BOXIHW_Q.js +174 -0
  49. package/dist/{profiles-DSzTeKQw.js → profiles-ZHLONml4.js} +49 -49
  50. package/dist/{profiles-Cy5wXQ0L.d.ts → profiles-cVZQkM69.d.ts} +3 -3
  51. package/dist/profiles.d.ts +1 -1
  52. package/dist/profiles.js +1 -1
  53. package/dist/recovery.d.ts +1 -1
  54. package/dist/recovery.js +1 -1
  55. package/dist/resolve-connector-token-DxDG9mhf.js +22 -0
  56. package/dist/{schedule-connector-L4uzg5M8.js → schedule-connector-9k3gOIgl.js} +54 -55
  57. package/dist/schedule-connector-schema-Z0RXLgPI.d.ts +49 -0
  58. package/dist/settings-reader-BNxjsxCB.d.ts +27 -0
  59. package/dist/{settings-store-CUKSeTXC.js → settings-store-C2QdOH-t.js} +23 -4
  60. package/dist/slack-connector-CxpWagbT.js +388 -0
  61. package/dist/slack-event-processor-BhCf5Wiy.d.ts +95 -0
  62. package/dist/slack-event-processor-xFDG3US0.js +176 -0
  63. package/dist/slot-fields-D-pvMgTK.js +249 -0
  64. package/dist/{memory-diagnostic-log-CI60kNfB.js → sqlite-diagnostic-log-DOTPW-tG.js} +373 -249
  65. package/dist/{yaml-render-93pX7EF7.js → yaml-render--J1_3BSA.js} +25 -21
  66. package/package.json +2 -4
  67. package/dist/discord-connector-BL36yvbL.js +0 -250
  68. package/dist/gateway-base-url-Dy4Ykuoh.js +0 -14
  69. package/dist/gh-connector-DpiixfQZ.js +0 -226
  70. package/dist/http-client-oICicjuO.d.ts +0 -18
  71. package/dist/memory-token-prompter-B4sjyaAq.d.ts +0 -57
  72. package/dist/memory-token-prompter-CZde7e6y.js +0 -61
  73. package/dist/node-file-system-Blr8pAir.js +0 -48
  74. package/dist/settings-reader-BIFB_j2f.d.ts +0 -18
  75. package/dist/slack-connector-DQIFPdBF.js +0 -484
  76. package/dist/slot-fields-CMoRpwuy.js +0 -45
  77. /package/dist/{connector-adapter-DU9Rvyec.js → connector-adapter-Dvs8N7ew.js} +0 -0
  78. /package/dist/{connector-listener-DR3aKOuK.js → connector-listener-mPGZYa8e.js} +0 -0
  79. /package/dist/{diagnostic-sql-reader-C9zR-Csp.js → diagnostic-sql-reader-oXZnWFf_.js} +0 -0
  80. /package/dist/{discord-connector-schema-B_N6IXLz.js → discord-connector-schema-B4YpWpR3.js} +0 -0
  81. /package/dist/{error-message-of-Byi4y0Uf.js → error-message-of-ColuYmAk.js} +0 -0
  82. /package/dist/{funnel-log-sqlite-sink-kqJbx2H7.js → funnel-log-sqlite-sink-DLYkY0pZ.js} +0 -0
  83. /package/dist/{funnel-recovery-BFdPjL6Z.js → funnel-recovery-DKnEutUS.js} +0 -0
  84. /package/dist/{node-http-client-lowp60Oa.js → node-http-client-u00atiKx.js} +0 -0
  85. /package/dist/{schedule-connector-schema-CfyuMCMh.js → schedule-connector-schema-DKEPZnVv.js} +0 -0
  86. /package/dist/{settings-reader-CtQ-Ix8_.js → settings-reader-9FcX3qS1.js} +0 -0
  87. /package/dist/{settings-schema-D1xcOqRu.d.ts → settings-schema-BL_c2Udm.d.ts} +0 -0
  88. /package/dist/{slack-connector-schema-C1zEf4TG.js → slack-connector-schema-Dem8to4P.js} +0 -0
@@ -0,0 +1,249 @@
1
+ import { t as errorMessageOf } from "./error-message-of-ColuYmAk.js";
2
+ import { t as FunnelConnectorListener } from "./connector-listener-mPGZYa8e.js";
3
+ import { t as FunnelConnectorDiagnosticsRecorder } from "./connector-diagnostics-recorder-COtNEmUp.js";
4
+ import { Flume, createFlumeDefaultDeps } from "@interactive-inc/flume";
5
+ //#region lib/engine/connectors/flume-deps.ts
6
+ /**
7
+ * Builds the merged runtime deps Flume listeners pass to a source. Spreads the
8
+ * default IO over any partial test override and returns `undefined` when no
9
+ * override exists so Flume gets to use its own internal default and there is
10
+ * one less degree of freedom to debug.
11
+ */
12
+ const resolveFlumeDeps = (override) => {
13
+ if (!override || Object.keys(override).length === 0) return void 0;
14
+ return {
15
+ ...createFlumeDefaultDeps(),
16
+ ...override
17
+ };
18
+ };
19
+ /**
20
+ * Bridges a `FunnelLogger` into Flume's structured log stream. Returns
21
+ * `undefined` when no logger is wired so Flume's option stays cleanly absent
22
+ * instead of carrying a no-op handler.
23
+ *
24
+ * Forwards everything Flume produces: `detail` (reconnect counters, HTTP codes,
25
+ * parse offsets) is merged into the logger meta, and on errors the full stack
26
+ * is preserved — the leaf message alone is rarely enough to pinpoint a socket
27
+ * close or parse failure. Debug entries are dropped because FunnelLogger has no
28
+ * debug level and routing them to info would drown the operator log in
29
+ * heartbeats.
30
+ */
31
+ const flumeLogHandler = (logger) => {
32
+ if (!logger) return void 0;
33
+ return (log) => {
34
+ if (log.level === "debug") return;
35
+ const line = `${log.source}/${log.action}: ${log.message}`;
36
+ const meta = buildMeta(log);
37
+ if (log.level === "error") {
38
+ logger.error(line, meta);
39
+ return;
40
+ }
41
+ if (log.level === "warn") {
42
+ logger.warn(line, meta);
43
+ return;
44
+ }
45
+ logger.info(line, meta);
46
+ };
47
+ };
48
+ const buildMeta = (log) => {
49
+ const meta = { ...log.detail ?? {} };
50
+ if (log.error) {
51
+ meta.error = log.error.message;
52
+ if (log.error.stack) meta.stack = log.error.stack;
53
+ if (log.error.name && log.error.name !== "Error") meta.errorName = log.error.name;
54
+ }
55
+ return Object.keys(meta).length > 0 ? meta : void 0;
56
+ };
57
+ //#endregion
58
+ //#region lib/engine/connectors/flume-source-listener.ts
59
+ /**
60
+ * Shared lifecycle for any listener whose transport is a `FlumeSource`. Owns
61
+ * the per-listener `Flume` instance + the `FlumeRunning` handle returned by
62
+ * `open()`, the connected/alive bit, the `FlumeStatus ↔
63
+ * ConnectorConnectionStatus` mapping, and the close sequence — every Flume
64
+ * subclass plugs in only its own token resolution, source construction, and
65
+ * event dispatch around this skeleton.
66
+ *
67
+ * Flume 0.9 collapsed every observation channel into one firehose: events
68
+ * and all logs arrive through `onEvent` as a discriminated union
69
+ * (`{ kind: "event" } | { kind: "log" }`). This base class splits that back
70
+ * into the funnel-shaped trio (typed event handler, log forward, status
71
+ * mapping) so subclasses keep their per-protocol code unchanged.
72
+ */
73
+ var FunnelFlumeSourceListener = class extends FunnelConnectorListener {
74
+ logger;
75
+ diagnostics;
76
+ type;
77
+ running = null;
78
+ connected = false;
79
+ /**
80
+ * Flipped on by Flume's `reconnecting` status, off when the new socket
81
+ * lands on `connected` or the source gives up with `disconnected`. Used by
82
+ * `isAlive()` to treat a brief reconnect window as "still alive" so the
83
+ * supervisor does not preempt Flume's in-progress recovery with a heavier
84
+ * stop+start cycle (which would discard auth.test results and rebuild
85
+ * every per-listener state).
86
+ */
87
+ reconnecting = false;
88
+ /**
89
+ * Promise chain that serializes typed-event delivery. Flume's emitItem
90
+ * fire-and-forgets the onEvent callback (see flume.ts emitItem:
91
+ * `Promise.resolve(onEvent(item)).catch(() => {})`), so awaiting onEvent
92
+ * inside the handler does NOT pause flume's source queue — multiple event
93
+ * deliveries would race their microtask chains. Chaining each new event
94
+ * onto the previous promise's `.then(...)` guarantees per-listener
95
+ * end-to-end FIFO regardless of whether the notify path is sync or async.
96
+ */
97
+ deliveryChain = Promise.resolve();
98
+ constructor(props) {
99
+ super();
100
+ this.type = props.type;
101
+ this.logger = props.logger;
102
+ this.diagnostics = new FunnelConnectorDiagnosticsRecorder({
103
+ type: props.type,
104
+ connectorId: props.connectorId,
105
+ channelId: props.channelId,
106
+ log: props.diagnosticLog
107
+ });
108
+ }
109
+ /**
110
+ * Assemble a single-source Flume, open it, and store the `FlumeRunning`
111
+ * handle. Records `error` on any `Error` returned by `flume.open()` and
112
+ * rethrows so the supervisor sees the failure.
113
+ *
114
+ * The firehose handler routes:
115
+ * - `kind: "event"` → subclass's typed `onEvent`
116
+ * - `kind: "log"` with `action === "status"` → `handleStatus()`
117
+ * - `kind: "log"` (any) → optional `onLog` handler
118
+ */
119
+ async runStart(options) {
120
+ const reconnectOption = options.reconnect ?? true;
121
+ const flumeReconnect = reconnectOption === false ? void 0 : reconnectOption === true ? {} : reconnectOption;
122
+ const handleItem = (item) => {
123
+ if (item.kind === "event") {
124
+ this.deliveryChain = this.deliveryChain.catch(() => {}).then(() => Promise.resolve(options.onEvent(item.event)));
125
+ return;
126
+ }
127
+ const log = item.log;
128
+ const statusEvent = readStatusLog(log);
129
+ if (statusEvent) this.handleStatus(statusEvent);
130
+ options.onLog?.(log);
131
+ };
132
+ const flumeOptions = {
133
+ sources: [options.source],
134
+ onEvent: handleItem
135
+ };
136
+ if (options.deps) flumeOptions.deps = options.deps;
137
+ if (options.signal) flumeOptions.signal = options.signal;
138
+ if (flumeReconnect) flumeOptions.reconnect = flumeReconnect;
139
+ const result = await new Flume(flumeOptions).open();
140
+ if (result instanceof Error) {
141
+ this.diagnostics.recordConnection("error", errorMessageOf(result));
142
+ throw result;
143
+ }
144
+ this.running = result;
145
+ }
146
+ async stop() {
147
+ if (!this.running) return;
148
+ try {
149
+ await this.running.close();
150
+ this.diagnostics.recordConnection("disconnected", "");
151
+ } catch (error) {
152
+ this.diagnostics.recordConnection("error", errorMessageOf(error));
153
+ this.logger?.error(`${this.type} stop error`, { error: errorMessageOf(error) });
154
+ } finally {
155
+ this.running = null;
156
+ this.connected = false;
157
+ this.reconnecting = false;
158
+ this.deliveryChain = Promise.resolve();
159
+ this.onStop();
160
+ this.diagnostics.recordConnection("stopped", "");
161
+ }
162
+ }
163
+ isAlive() {
164
+ if (this.running === null) return false;
165
+ return this.connected || this.reconnecting;
166
+ }
167
+ /**
168
+ * Maps Flume's transport status to the connection table. `reconnecting`
169
+ * deliberately produces no row — Flume drives many transient reconnects per
170
+ * minute on a flaky network, and the row would drown the more meaningful
171
+ * `connected`/`disconnected` pair. The `reconnecting` flag still flips so
172
+ * `isAlive()` can surface it to the supervisor.
173
+ */
174
+ handleStatus(event) {
175
+ if (event.status === "connected") {
176
+ this.connected = true;
177
+ this.reconnecting = false;
178
+ this.diagnostics.recordConnection("connected", event.detail ?? "");
179
+ return;
180
+ }
181
+ if (event.status === "disconnected") {
182
+ this.connected = false;
183
+ this.reconnecting = false;
184
+ this.diagnostics.recordConnection("disconnected", event.detail ?? "");
185
+ return;
186
+ }
187
+ if (event.status === "reconnecting") {
188
+ this.connected = false;
189
+ this.reconnecting = true;
190
+ }
191
+ }
192
+ /**
193
+ * Hook for subclass-specific cleanup that has to run inside the stop()
194
+ * finally block (after the running handle is cleared, before the `stopped`
195
+ * row is recorded). Default is no-op.
196
+ */
197
+ onStop() {}
198
+ };
199
+ const STATUS_VALUES = [
200
+ "disconnected",
201
+ "connecting",
202
+ "connected",
203
+ "reconnecting"
204
+ ];
205
+ const isFlumeStatus = (value) => typeof value === "string" && STATUS_VALUES.includes(value);
206
+ /**
207
+ * Reconstructs the old `FlumeStatusEvent` shape from a `status` log entry.
208
+ * Returns `null` for anything else so the firehose pump is a single check.
209
+ * Flume 0.9 emits these as `log.action === "status"` with a structured
210
+ * `detail: { from, to, reason }` payload (see flume's FlumeStatusEmitter).
211
+ */
212
+ const readStatusLog = (log) => {
213
+ if (log.action !== "status") return null;
214
+ const detail = log.detail;
215
+ if (!detail) return null;
216
+ const to = detail.to;
217
+ if (!isFlumeStatus(to)) return null;
218
+ const reason = typeof detail.reason === "string" ? detail.reason : null;
219
+ return {
220
+ source: log.source,
221
+ status: to,
222
+ detail: reason
223
+ };
224
+ };
225
+ //#endregion
226
+ //#region lib/engine/connectors/slot-fields.ts
227
+ /**
228
+ * Resolves one token slot (e.g. botToken/botTokenEnv) for a connector update.
229
+ * The literal and the env-ref form are mutually exclusive: if `fields` supplies
230
+ * either, that form wins and the other key is omitted entirely; if it supplies
231
+ * neither, the connector's current slot is carried over unchanged. Returns a
232
+ * partial object spread into the rebuilt connector, so an omitted key is truly
233
+ * absent rather than set to undefined — switching a slot from literal to ref
234
+ * drops the stale literal instead of leaving both behind.
235
+ */
236
+ const slotFields = (literalKey, envKey, fields, current) => {
237
+ const literal = fields[literalKey];
238
+ if (typeof literal === "string") return { [literalKey]: literal };
239
+ const envVar = fields[envKey];
240
+ if (typeof envVar === "string") return { [envKey]: envVar };
241
+ const result = {};
242
+ const currentLiteral = current[literalKey];
243
+ const currentEnv = current[envKey];
244
+ if (typeof currentLiteral === "string") result[literalKey] = currentLiteral;
245
+ if (typeof currentEnv === "string") result[envKey] = currentEnv;
246
+ return result;
247
+ };
248
+ //#endregion
249
+ export { resolveFlumeDeps as i, FunnelFlumeSourceListener as n, flumeLogHandler as r, slotFields as t };