@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.
- package/README.md +2 -2
- package/dist/bin.js +428 -761
- package/dist/{channels-2g_BU1N0.d.ts → channels-CRGb6B5_.d.ts} +17 -16
- package/dist/claude.d.ts +5 -7
- package/dist/claude.js +143 -36
- package/dist/{connector-descriptor-6SXJoszo.d.ts → connector-descriptor-BFIhyTfa.d.ts} +49 -10
- package/dist/connector-diagnostics-recorder-COtNEmUp.js +42 -0
- package/dist/connectors/discord.d.ts +31 -37
- package/dist/connectors/discord.js +3 -3
- package/dist/connectors/gh.d.ts +37 -33
- package/dist/connectors/gh.js +3 -3
- package/dist/connectors/schedule.d.ts +9 -57
- package/dist/connectors/schedule.js +3 -3
- package/dist/connectors/slack.d.ts +106 -132
- package/dist/connectors/slack.js +4 -3
- package/dist/diagnostics.d.ts +1 -1
- package/dist/diagnostics.js +1 -1
- package/dist/discord-connector-DIFkYBbi.js +250 -0
- package/dist/discord-connector-schema-D-bOVAKt.d.ts +22 -0
- package/dist/docs.js +1 -1
- package/dist/doctor.d.ts +1 -1
- package/dist/doctor.js +1 -1
- package/dist/{file-process-guard-C_PLxfUX.d.ts → file-process-guard-tVcgckH6.d.ts} +6 -6
- package/dist/{file-system-o51IsM0W.d.ts → file-system-VhwwXZbm.d.ts} +8 -0
- package/dist/flume-source-listener-BNyAII7N.d.ts +133 -0
- package/dist/{funnel-diagnostics-CSiJmPlZ.js → funnel-diagnostics-Cvk6Sk4x.js} +193 -43
- package/dist/{funnel-diagnostics-DpXOsCty.d.ts → funnel-diagnostics-b9ar0Ing.d.ts} +67 -5
- package/dist/{funnel-docs-BxXZ9Ksx.js → funnel-docs-C-ge0MuB.js} +42 -6
- package/dist/{funnel-doctor-CZf_0Luq.d.ts → funnel-doctor-CnRQi4kM.d.ts} +2 -2
- package/dist/{funnel-doctor-DiJCjHsg.js → funnel-doctor-XrI2GBH8.js} +1 -1
- package/dist/funnel-error-0t1MK1R6.js +75 -0
- package/dist/{funnel-recovery-DnLrdWO9.d.ts → funnel-recovery-CMhY8Jfk.d.ts} +1 -1
- package/dist/gateway/daemon.js +167 -527
- package/dist/gateway.d.ts +3 -3
- package/dist/gateway.js +3 -3
- package/dist/gh-connector-BUGCOEWS.js +187 -0
- package/dist/{gh-connector-schema-Rzwc1c1N.js → gh-connector-schema-CAqIhzGr.js} +7 -0
- package/dist/gh-connector-schema-DWQaB6gX.d.ts +16 -0
- package/dist/{index-CgY8NdMz.d.ts → index-Ds6sHhA-.d.ts} +37 -19
- package/dist/index.d.ts +182 -22
- package/dist/index.js +363 -173
- package/dist/{local-config-json-schema-JyLqOQNX.js → local-config-json-schema-DexV8vX3.js} +24 -4
- package/dist/local-config.d.ts +39 -2
- package/dist/local-config.js +53 -2
- package/dist/logger.js +1 -1
- package/dist/loopback-fetch-CVNuN3YZ.js +40 -0
- package/dist/{local-config-sync-Dh1Croqe.d.ts → memory-token-prompter-BoV8Hf-n.d.ts} +30 -3
- package/dist/node-file-system-BOXIHW_Q.js +174 -0
- package/dist/{profiles-DSzTeKQw.js → profiles-ZHLONml4.js} +49 -49
- package/dist/{profiles-Cy5wXQ0L.d.ts → profiles-cVZQkM69.d.ts} +3 -3
- package/dist/profiles.d.ts +1 -1
- package/dist/profiles.js +1 -1
- package/dist/recovery.d.ts +1 -1
- package/dist/recovery.js +1 -1
- package/dist/resolve-connector-token-DxDG9mhf.js +22 -0
- package/dist/{schedule-connector-L4uzg5M8.js → schedule-connector-9k3gOIgl.js} +54 -55
- package/dist/schedule-connector-schema-Z0RXLgPI.d.ts +49 -0
- package/dist/settings-reader-BNxjsxCB.d.ts +27 -0
- package/dist/{settings-store-CUKSeTXC.js → settings-store-C2QdOH-t.js} +23 -4
- package/dist/slack-connector-CxpWagbT.js +388 -0
- package/dist/slack-event-processor-BhCf5Wiy.d.ts +95 -0
- package/dist/slack-event-processor-xFDG3US0.js +176 -0
- package/dist/slot-fields-D-pvMgTK.js +249 -0
- package/dist/{memory-diagnostic-log-CI60kNfB.js → sqlite-diagnostic-log-DOTPW-tG.js} +373 -249
- package/dist/{yaml-render-93pX7EF7.js → yaml-render--J1_3BSA.js} +25 -21
- package/package.json +2 -4
- package/dist/discord-connector-BL36yvbL.js +0 -250
- package/dist/gateway-base-url-Dy4Ykuoh.js +0 -14
- package/dist/gh-connector-DpiixfQZ.js +0 -226
- package/dist/http-client-oICicjuO.d.ts +0 -18
- package/dist/memory-token-prompter-B4sjyaAq.d.ts +0 -57
- package/dist/memory-token-prompter-CZde7e6y.js +0 -61
- package/dist/node-file-system-Blr8pAir.js +0 -48
- package/dist/settings-reader-BIFB_j2f.d.ts +0 -18
- package/dist/slack-connector-DQIFPdBF.js +0 -484
- package/dist/slot-fields-CMoRpwuy.js +0 -45
- /package/dist/{connector-adapter-DU9Rvyec.js → connector-adapter-Dvs8N7ew.js} +0 -0
- /package/dist/{connector-listener-DR3aKOuK.js → connector-listener-mPGZYa8e.js} +0 -0
- /package/dist/{diagnostic-sql-reader-C9zR-Csp.js → diagnostic-sql-reader-oXZnWFf_.js} +0 -0
- /package/dist/{discord-connector-schema-B_N6IXLz.js → discord-connector-schema-B4YpWpR3.js} +0 -0
- /package/dist/{error-message-of-Byi4y0Uf.js → error-message-of-ColuYmAk.js} +0 -0
- /package/dist/{funnel-log-sqlite-sink-kqJbx2H7.js → funnel-log-sqlite-sink-DLYkY0pZ.js} +0 -0
- /package/dist/{funnel-recovery-BFdPjL6Z.js → funnel-recovery-DKnEutUS.js} +0 -0
- /package/dist/{node-http-client-lowp60Oa.js → node-http-client-u00atiKx.js} +0 -0
- /package/dist/{schedule-connector-schema-CfyuMCMh.js → schedule-connector-schema-DKEPZnVv.js} +0 -0
- /package/dist/{settings-reader-CtQ-Ix8_.js → settings-reader-9FcX3qS1.js} +0 -0
- /package/dist/{settings-schema-D1xcOqRu.d.ts → settings-schema-BL_c2Udm.d.ts} +0 -0
- /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 };
|