@interactive-inc/claude-funnel 0.25.1 → 0.26.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 +24 -14
- package/dist/bin.js +428 -429
- package/dist/connectors/discord.js +1 -1
- package/dist/connectors/gh.js +1 -1
- package/dist/connectors/schedule.js +1 -1
- package/dist/connectors/slack.js +1 -1
- package/dist/{discord-connector-schema-CR8RJ08_.js → discord-connector-schema-CpuI6rmE.js} +8 -9
- package/dist/gateway/daemon.js +181 -182
- package/dist/{gh-connector-schema-CAC24s0r.js → gh-connector-schema-CQRIvPpz.js} +5 -6
- package/dist/index.d.ts +245 -200
- package/dist/index.js +363 -248
- package/dist/logger-D1A3_JXV.js +27 -0
- package/dist/{schedule-connector-schema-BZpH6ZmR.js → schedule-connector-schema-CuCjP7z4.js} +4 -5
- package/dist/{slack-connector-schema-B0NyhxqQ.js → slack-connector-schema-BWL7dWlY.js} +8 -6
- package/funnel.schema.json +0 -4
- package/package.json +2 -3
- package/dist/node-logger-B97ZiGwj.js +0 -74
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
//#region lib/connectors/connector-listener.ts
|
|
2
|
+
/**
|
|
3
|
+
* Long-lived event source for one connector.
|
|
4
|
+
*
|
|
5
|
+
* `start()` opens the underlying connection (Slack Socket Mode, Discord
|
|
6
|
+
* Gateway, GH polling, schedule tick) and pushes events through `notify`.
|
|
7
|
+
* `stop()` releases the resources so the supervisor can recreate the listener
|
|
8
|
+
* with new config without restarting the whole gateway. `isAlive()` lets the
|
|
9
|
+
* supervisor periodically health-check and auto-restart dead listeners; the
|
|
10
|
+
* default optimistic implementation is fine for poll/tick-based listeners
|
|
11
|
+
* that self-heal.
|
|
12
|
+
*/
|
|
13
|
+
var FunnelConnectorListener = class {
|
|
14
|
+
isAlive() {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region lib/engine/logger/logger.ts
|
|
20
|
+
/**
|
|
21
|
+
* Structured logger with three levels and an optional log-file path.
|
|
22
|
+
* Defaults to NodeFunnelLogger (appends to `<os.tmpdir()>/funnel/funnel.log`);
|
|
23
|
+
* MemoryFunnelLogger captures entries in memory and NoopFunnelLogger silences output.
|
|
24
|
+
*/
|
|
25
|
+
var FunnelLogger = class {};
|
|
26
|
+
//#endregion
|
|
27
|
+
export { FunnelConnectorListener as n, FunnelLogger as t };
|
package/dist/{schedule-connector-schema-BZpH6ZmR.js → schedule-connector-schema-CuCjP7z4.js}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { n as FunnelConnectorListener } from "./logger-D1A3_JXV.js";
|
|
2
2
|
import { dirname } from "node:path";
|
|
3
3
|
import { appendFileSync, chmodSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { z } from "zod";
|
|
@@ -153,7 +153,6 @@ var ScheduleStateStore = class {
|
|
|
153
153
|
};
|
|
154
154
|
//#endregion
|
|
155
155
|
//#region lib/connectors/schedule-listener.ts
|
|
156
|
-
const defaultLogger = new NodeFunnelLogger();
|
|
157
156
|
const MAX_CATCHUP_MINUTES = 1440;
|
|
158
157
|
var FunnelScheduleListener = class extends FunnelConnectorListener {
|
|
159
158
|
config;
|
|
@@ -167,7 +166,7 @@ var FunnelScheduleListener = class extends FunnelConnectorListener {
|
|
|
167
166
|
super();
|
|
168
167
|
this.config = deps.config;
|
|
169
168
|
this.lastFiredStore = deps.lastFiredStore;
|
|
170
|
-
this.logger = deps.logger
|
|
169
|
+
this.logger = deps.logger;
|
|
171
170
|
this.now = deps.now ?? (() => /* @__PURE__ */ new Date());
|
|
172
171
|
this.onFired = deps.onFired ?? null;
|
|
173
172
|
}
|
|
@@ -248,7 +247,7 @@ var FunnelScheduleListener = class extends FunnelConnectorListener {
|
|
|
248
247
|
if (this.onFired) try {
|
|
249
248
|
await this.onFired(entry, firedAt);
|
|
250
249
|
} catch (error) {
|
|
251
|
-
this.logger
|
|
250
|
+
this.logger?.error("schedule onFired callback failed", {
|
|
252
251
|
connector: this.config.name,
|
|
253
252
|
id: entry.id,
|
|
254
253
|
error: error instanceof Error ? error.message : String(error)
|
|
@@ -290,7 +289,7 @@ var FunnelScheduleListener = class extends FunnelConnectorListener {
|
|
|
290
289
|
return matches;
|
|
291
290
|
}
|
|
292
291
|
logInvalidCron(entry, error) {
|
|
293
|
-
this.logger
|
|
292
|
+
this.logger?.error("invalid cron expression in schedule", {
|
|
294
293
|
connector: this.config.name,
|
|
295
294
|
id: entry.id,
|
|
296
295
|
cron: entry.cron,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as FunnelConnectorAdapter } from "./connector-adapter-D5Utumgz.js";
|
|
2
|
-
import {
|
|
2
|
+
import { n as FunnelConnectorListener } from "./logger-D1A3_JXV.js";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { WebClient } from "@slack/web-api";
|
|
5
5
|
import { App, LogLevel } from "@slack/bolt";
|
|
@@ -192,7 +192,6 @@ var FunnelSlackEventProcessor = class {
|
|
|
192
192
|
//#endregion
|
|
193
193
|
//#region lib/connectors/slack-listener.ts
|
|
194
194
|
const middlewareArgsSchema = z.object({ event: z.record(z.string(), z.unknown()).optional() });
|
|
195
|
-
const defaultLogger = new NodeFunnelLogger();
|
|
196
195
|
var FunnelSlackListener = class extends FunnelConnectorListener {
|
|
197
196
|
config;
|
|
198
197
|
logger;
|
|
@@ -202,7 +201,7 @@ var FunnelSlackListener = class extends FunnelConnectorListener {
|
|
|
202
201
|
constructor(deps) {
|
|
203
202
|
super();
|
|
204
203
|
this.config = deps.config;
|
|
205
|
-
this.logger = deps.logger
|
|
204
|
+
this.logger = deps.logger;
|
|
206
205
|
this.onAppCreated = deps.onAppCreated ?? null;
|
|
207
206
|
this.preprocessEvent = deps.preprocessEvent ?? null;
|
|
208
207
|
}
|
|
@@ -222,7 +221,10 @@ var FunnelSlackListener = class extends FunnelConnectorListener {
|
|
|
222
221
|
const preprocess = this.preprocessEvent;
|
|
223
222
|
app.use(async (args) => {
|
|
224
223
|
const parsed = middlewareArgsSchema.safeParse(args);
|
|
225
|
-
if (!parsed.success || !parsed.data.event)
|
|
224
|
+
if (!parsed.success || !parsed.data.event) {
|
|
225
|
+
await args.next();
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
226
228
|
const rawEvent = parsed.data.event;
|
|
227
229
|
const event = preprocess ? preprocess(rawEvent) : rawEvent;
|
|
228
230
|
if (event === null) return;
|
|
@@ -239,7 +241,7 @@ var FunnelSlackListener = class extends FunnelConnectorListener {
|
|
|
239
241
|
} catch {}
|
|
240
242
|
});
|
|
241
243
|
app.error(async (error) => {
|
|
242
|
-
this.logger
|
|
244
|
+
this.logger?.error("Slack error", { error: error instanceof Error ? error.message : String(error) });
|
|
243
245
|
});
|
|
244
246
|
if (this.onAppCreated) await this.onAppCreated(app);
|
|
245
247
|
await app.start();
|
|
@@ -250,7 +252,7 @@ var FunnelSlackListener = class extends FunnelConnectorListener {
|
|
|
250
252
|
try {
|
|
251
253
|
await this.app.stop();
|
|
252
254
|
} catch (error) {
|
|
253
|
-
this.logger
|
|
255
|
+
this.logger?.error("Slack stop error", { error: error instanceof Error ? error.message : String(error) });
|
|
254
256
|
} finally {
|
|
255
257
|
this.app = null;
|
|
256
258
|
}
|
package/funnel.schema.json
CHANGED
|
@@ -139,9 +139,6 @@
|
|
|
139
139
|
"items": {
|
|
140
140
|
"type": "object",
|
|
141
141
|
"properties": {
|
|
142
|
-
"name": {
|
|
143
|
-
"type": "string"
|
|
144
|
-
},
|
|
145
142
|
"channel": {
|
|
146
143
|
"type": "string"
|
|
147
144
|
},
|
|
@@ -165,7 +162,6 @@
|
|
|
165
162
|
}
|
|
166
163
|
},
|
|
167
164
|
"required": [
|
|
168
|
-
"name",
|
|
169
165
|
"channel"
|
|
170
166
|
],
|
|
171
167
|
"additionalProperties": false
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@interactive-inc/claude-funnel",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.0",
|
|
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",
|
|
@@ -85,8 +85,7 @@
|
|
|
85
85
|
"@types/bun": "^1.3.14",
|
|
86
86
|
"@types/react": "^19.2.14",
|
|
87
87
|
"@typescript/native-preview": "^7.0.0-dev.20260516.1",
|
|
88
|
-
"vite-plus": "^0.1.21"
|
|
89
|
-
"vitest": "^4.1.6"
|
|
88
|
+
"vite-plus": "^0.1.21"
|
|
90
89
|
},
|
|
91
90
|
"engines": {
|
|
92
91
|
"bun": ">=1.3.0"
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import { dirname, join } from "node:path";
|
|
2
|
-
import { appendFileSync, mkdirSync } from "node:fs";
|
|
3
|
-
import { tmpdir } from "node:os";
|
|
4
|
-
//#region lib/connectors/connector-listener.ts
|
|
5
|
-
/**
|
|
6
|
-
* Long-lived event source for one connector.
|
|
7
|
-
*
|
|
8
|
-
* `start()` opens the underlying connection (Slack Socket Mode, Discord
|
|
9
|
-
* Gateway, GH polling, schedule tick) and pushes events through `notify`.
|
|
10
|
-
* `stop()` releases the resources so the supervisor can recreate the listener
|
|
11
|
-
* with new config without restarting the whole gateway. `isAlive()` lets the
|
|
12
|
-
* supervisor periodically health-check and auto-restart dead listeners; the
|
|
13
|
-
* default optimistic implementation is fine for poll/tick-based listeners
|
|
14
|
-
* that self-heal.
|
|
15
|
-
*/
|
|
16
|
-
var FunnelConnectorListener = class {
|
|
17
|
-
isAlive() {
|
|
18
|
-
return true;
|
|
19
|
-
}
|
|
20
|
-
};
|
|
21
|
-
//#endregion
|
|
22
|
-
//#region lib/engine/logger/logger.ts
|
|
23
|
-
/**
|
|
24
|
-
* Structured logger with three levels and an optional log-file path.
|
|
25
|
-
* Defaults to NodeFunnelLogger (appends to `<os.tmpdir()>/funnel/funnel.log`);
|
|
26
|
-
* MemoryFunnelLogger captures entries in memory and NoopFunnelLogger silences output.
|
|
27
|
-
*/
|
|
28
|
-
var FunnelLogger = class {};
|
|
29
|
-
//#endregion
|
|
30
|
-
//#region lib/engine/settings/tmp-dir.ts
|
|
31
|
-
/**
|
|
32
|
-
* Resolves the funnel temp/log root for the current OS. Defaults to
|
|
33
|
-
* `<os.tmpdir()>/funnel` so Windows lands under `%TEMP%\funnel` and POSIX
|
|
34
|
-
* lands under `/tmp/funnel`. Callers may override via `FUNNEL_TMP_DIR`.
|
|
35
|
-
*/
|
|
36
|
-
function funnelTmpDir() {
|
|
37
|
-
const override = process.env.FUNNEL_TMP_DIR;
|
|
38
|
-
if (override && override.length > 0) return override;
|
|
39
|
-
return join(tmpdir(), "funnel");
|
|
40
|
-
}
|
|
41
|
-
//#endregion
|
|
42
|
-
//#region lib/engine/logger/node-logger.ts
|
|
43
|
-
const defaultLogFile = () => join(funnelTmpDir(), "funnel.log");
|
|
44
|
-
var NodeFunnelLogger = class extends FunnelLogger {
|
|
45
|
-
file;
|
|
46
|
-
now;
|
|
47
|
-
constructor(props = {}) {
|
|
48
|
-
super();
|
|
49
|
-
this.file = props.file ?? defaultLogFile();
|
|
50
|
-
this.now = props.now ?? (() => /* @__PURE__ */ new Date());
|
|
51
|
-
Object.freeze(this);
|
|
52
|
-
}
|
|
53
|
-
info(message, meta) {
|
|
54
|
-
this.write("info", message, meta);
|
|
55
|
-
}
|
|
56
|
-
warn(message, meta) {
|
|
57
|
-
this.write("warn", message, meta);
|
|
58
|
-
}
|
|
59
|
-
error(message, meta) {
|
|
60
|
-
this.write("error", message, meta);
|
|
61
|
-
}
|
|
62
|
-
write(level, message, meta) {
|
|
63
|
-
mkdirSync(dirname(this.file), { recursive: true });
|
|
64
|
-
const entry = {
|
|
65
|
-
time: this.now().toISOString(),
|
|
66
|
-
level,
|
|
67
|
-
message,
|
|
68
|
-
...meta ? { meta } : {}
|
|
69
|
-
};
|
|
70
|
-
appendFileSync(this.file, `${JSON.stringify(entry)}\n`);
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
|
-
//#endregion
|
|
74
|
-
export { FunnelConnectorListener as i, funnelTmpDir as n, FunnelLogger as r, NodeFunnelLogger as t };
|