@interactive-inc/claude-funnel 0.10.1 → 0.15.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.
- package/README.md +106 -56
- package/dist/bin.js +532 -505
- package/dist/connectors/schedule.d.ts +2 -49
- package/dist/connectors/schedule.js +1 -1
- package/dist/connectors/slack.d.ts +4 -20
- package/dist/connectors/slack.js +1 -1
- package/dist/gateway/daemon.js +214 -212
- package/dist/index.d.ts +463 -164
- package/dist/index.js +561 -36
- package/dist/{schedule-connector-schema-CkuIQ0JQ.js → schedule-connector-schema-FxP7LPlx.js} +11 -0
- package/dist/{file-system-Co60LrmR.d.ts → schedule-listener-BPodvbld.d.ts} +56 -1
- package/dist/{slack-connector-schema-Cd22WiHB.js → slack-connector-schema-B4hsf3AY.js} +10 -1
- package/dist/slack-listener-CHj6uMY-.d.ts +74 -0
- package/package.json +2 -1
- package/schemas/funnel.schema.json +144 -0
- package/dist/slack-event-processor-CS-bAit9.d.ts +0 -43
package/dist/{schedule-connector-schema-CkuIQ0JQ.js → schedule-connector-schema-FxP7LPlx.js}
RENAMED
|
@@ -160,6 +160,7 @@ var FunnelScheduleListener = class extends FunnelConnectorListener {
|
|
|
160
160
|
lastFiredStore;
|
|
161
161
|
logger;
|
|
162
162
|
now;
|
|
163
|
+
onFired;
|
|
163
164
|
timer = null;
|
|
164
165
|
stopped = false;
|
|
165
166
|
constructor(deps) {
|
|
@@ -168,6 +169,7 @@ var FunnelScheduleListener = class extends FunnelConnectorListener {
|
|
|
168
169
|
this.lastFiredStore = deps.lastFiredStore;
|
|
169
170
|
this.logger = deps.logger ?? defaultLogger;
|
|
170
171
|
this.now = deps.now ?? (() => /* @__PURE__ */ new Date());
|
|
172
|
+
this.onFired = deps.onFired ?? null;
|
|
171
173
|
}
|
|
172
174
|
async start(notify) {
|
|
173
175
|
this.stopped = false;
|
|
@@ -243,6 +245,15 @@ var FunnelScheduleListener = class extends FunnelConnectorListener {
|
|
|
243
245
|
};
|
|
244
246
|
if (catchup) meta.catchup = "true";
|
|
245
247
|
await notify(entry.prompt, meta);
|
|
248
|
+
if (this.onFired) try {
|
|
249
|
+
await this.onFired(entry, firedAt);
|
|
250
|
+
} catch (error) {
|
|
251
|
+
this.logger.error("schedule onFired callback failed", {
|
|
252
|
+
connector: this.config.name,
|
|
253
|
+
id: entry.id,
|
|
254
|
+
error: error instanceof Error ? error.message : String(error)
|
|
255
|
+
});
|
|
256
|
+
}
|
|
246
257
|
}
|
|
247
258
|
findMostRecentMatch(cron, from, until, entryId) {
|
|
248
259
|
const maxIterations = Math.min(MAX_CATCHUP_MINUTES, Math.floor((until.getTime() - from.getTime()) / 6e4) + 1);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { n as FunnelConnectorListener, r as NotifyFn, t as FunnelLogger } from "./logger-CTlXs7z4.js";
|
|
1
2
|
import { z } from "zod";
|
|
2
3
|
|
|
3
4
|
//#region lib/connectors/schedule-connector-schema.d.ts
|
|
@@ -71,4 +72,58 @@ declare abstract class FunnelFileSystem {
|
|
|
71
72
|
abstract statSync(path: string): FileStat;
|
|
72
73
|
}
|
|
73
74
|
//#endregion
|
|
74
|
-
|
|
75
|
+
//#region lib/connectors/schedule-state-store.d.ts
|
|
76
|
+
type Deps$1 = {
|
|
77
|
+
path: string;
|
|
78
|
+
fs?: FunnelFileSystem;
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Per-connector lastFiredAt persistence for the schedule listener. The path is
|
|
82
|
+
* passed in by FunnelConnectorFactory so this store does not know about the
|
|
83
|
+
* funnel directory layout (`channels/<id>/connectors/<id>/state.json` lives
|
|
84
|
+
* outside this class).
|
|
85
|
+
*/
|
|
86
|
+
declare class ScheduleStateStore {
|
|
87
|
+
private readonly path;
|
|
88
|
+
private readonly fs;
|
|
89
|
+
constructor(deps: Deps$1);
|
|
90
|
+
load(): Map<string, Date>;
|
|
91
|
+
save(state: Map<string, Date>): void;
|
|
92
|
+
}
|
|
93
|
+
//#endregion
|
|
94
|
+
//#region lib/connectors/schedule-listener.d.ts
|
|
95
|
+
type ScheduleOnFired = (entry: ScheduleEntry, firedAt: Date) => void | Promise<void>;
|
|
96
|
+
type Deps = {
|
|
97
|
+
config: ScheduleConnectorConfig;
|
|
98
|
+
lastFiredStore: ScheduleStateStore;
|
|
99
|
+
logger?: FunnelLogger;
|
|
100
|
+
now?: () => Date;
|
|
101
|
+
/**
|
|
102
|
+
* Invoked after a schedule entry fires successfully. Use to remove one-shot
|
|
103
|
+
* entries from the connector config, or to log per-fire side effects.
|
|
104
|
+
* Errors from this callback are caught and logged; they do not abort the tick.
|
|
105
|
+
*/
|
|
106
|
+
onFired?: ScheduleOnFired;
|
|
107
|
+
};
|
|
108
|
+
declare class FunnelScheduleListener extends FunnelConnectorListener {
|
|
109
|
+
private readonly config;
|
|
110
|
+
private readonly lastFiredStore;
|
|
111
|
+
private readonly logger;
|
|
112
|
+
private readonly now;
|
|
113
|
+
private readonly onFired;
|
|
114
|
+
private timer;
|
|
115
|
+
private stopped;
|
|
116
|
+
constructor(deps: Deps);
|
|
117
|
+
start(notify: NotifyFn): Promise<void>;
|
|
118
|
+
stop(): Promise<void>;
|
|
119
|
+
isAlive(): boolean;
|
|
120
|
+
tick(notify: NotifyFn): Promise<void>;
|
|
121
|
+
private fireEntry;
|
|
122
|
+
private notifyOne;
|
|
123
|
+
private findMostRecentMatch;
|
|
124
|
+
private findAllMatches;
|
|
125
|
+
private logInvalidCron;
|
|
126
|
+
private truncateToMinute;
|
|
127
|
+
}
|
|
128
|
+
//#endregion
|
|
129
|
+
export { FunnelFileSystem as a, ScheduleEntry as c, scheduleEntrySchema as d, FileStat as i, scheduleCatchupPolicySchema as l, ScheduleOnFired as n, ScheduleCatchupPolicy as o, ScheduleStateStore as r, ScheduleConnectorConfig as s, FunnelScheduleListener as t, scheduleConnectorSchema as u };
|
|
@@ -85,11 +85,15 @@ const defaultLogger = new NodeFunnelLogger();
|
|
|
85
85
|
var FunnelSlackListener = class extends FunnelConnectorListener {
|
|
86
86
|
config;
|
|
87
87
|
logger;
|
|
88
|
+
onAppCreated;
|
|
89
|
+
preprocessEvent;
|
|
88
90
|
app = null;
|
|
89
91
|
constructor(deps) {
|
|
90
92
|
super();
|
|
91
93
|
this.config = deps.config;
|
|
92
94
|
this.logger = deps.logger ?? defaultLogger;
|
|
95
|
+
this.onAppCreated = deps.onAppCreated ?? null;
|
|
96
|
+
this.preprocessEvent = deps.preprocessEvent ?? null;
|
|
93
97
|
}
|
|
94
98
|
async start(notify) {
|
|
95
99
|
const app = new App({
|
|
@@ -103,10 +107,14 @@ var FunnelSlackListener = class extends FunnelConnectorListener {
|
|
|
103
107
|
ownBotUserId: authResult.user_id ?? "",
|
|
104
108
|
ownBotId: authResult.bot_id ?? ""
|
|
105
109
|
});
|
|
110
|
+
const preprocess = this.preprocessEvent;
|
|
106
111
|
app.use(async (args) => {
|
|
107
112
|
const parsed = middlewareArgsSchema.safeParse(args);
|
|
108
113
|
if (!parsed.success || !parsed.data.event) return;
|
|
109
|
-
const
|
|
114
|
+
const rawEvent = parsed.data.event;
|
|
115
|
+
const event = preprocess ? preprocess(rawEvent) : rawEvent;
|
|
116
|
+
if (event === null) return;
|
|
117
|
+
const result = processor.process(event);
|
|
110
118
|
if (result.skip) return;
|
|
111
119
|
if (result.shouldReact) try {
|
|
112
120
|
await app.client.reactions.add({
|
|
@@ -121,6 +129,7 @@ var FunnelSlackListener = class extends FunnelConnectorListener {
|
|
|
121
129
|
app.error(async (error) => {
|
|
122
130
|
this.logger.error("Slack error", { error: error instanceof Error ? error.message : String(error) });
|
|
123
131
|
});
|
|
132
|
+
if (this.onAppCreated) await this.onAppCreated(app);
|
|
124
133
|
await app.start();
|
|
125
134
|
this.app = app;
|
|
126
135
|
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { n as FunnelConnectorListener, r as NotifyFn, t as FunnelLogger } from "./logger-CTlXs7z4.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { App } from "@slack/bolt";
|
|
4
|
+
|
|
5
|
+
//#region lib/connectors/slack-connector-schema.d.ts
|
|
6
|
+
declare const slackConnectorSchema: z.ZodObject<{
|
|
7
|
+
id: z.ZodString;
|
|
8
|
+
name: z.ZodString;
|
|
9
|
+
type: z.ZodLiteral<"slack">;
|
|
10
|
+
botToken: z.ZodString;
|
|
11
|
+
appToken: z.ZodString;
|
|
12
|
+
createdAt: z.ZodOptional<z.ZodString>;
|
|
13
|
+
updatedAt: z.ZodOptional<z.ZodString>;
|
|
14
|
+
}, z.core.$strip>;
|
|
15
|
+
type SlackConnectorConfig = z.infer<typeof slackConnectorSchema>;
|
|
16
|
+
//#endregion
|
|
17
|
+
//#region lib/connectors/slack-event-processor.d.ts
|
|
18
|
+
type SlackRawEvent = Record<string, unknown>;
|
|
19
|
+
type SlackProcessedSkip = {
|
|
20
|
+
skip: true;
|
|
21
|
+
};
|
|
22
|
+
type SlackProcessedEmit = {
|
|
23
|
+
skip: false;
|
|
24
|
+
content: string;
|
|
25
|
+
meta: Record<string, string>;
|
|
26
|
+
shouldReact: boolean;
|
|
27
|
+
channel: string;
|
|
28
|
+
timestamp: string;
|
|
29
|
+
};
|
|
30
|
+
type SlackProcessed = SlackProcessedSkip | SlackProcessedEmit;
|
|
31
|
+
type Props = {
|
|
32
|
+
ownBotUserId: string;
|
|
33
|
+
ownBotId: string;
|
|
34
|
+
now?: () => number;
|
|
35
|
+
};
|
|
36
|
+
declare class FunnelSlackEventProcessor {
|
|
37
|
+
private readonly ownBotUserId;
|
|
38
|
+
private readonly ownBotId;
|
|
39
|
+
private readonly now;
|
|
40
|
+
private readonly dedup;
|
|
41
|
+
constructor(props: Props);
|
|
42
|
+
process(event: SlackRawEvent): SlackProcessed;
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region lib/connectors/slack-listener.d.ts
|
|
46
|
+
type SlackOnAppCreated = (app: App) => void | Promise<void>;
|
|
47
|
+
type SlackPreprocessEvent = (event: SlackRawEvent) => SlackRawEvent | null;
|
|
48
|
+
type Deps = {
|
|
49
|
+
config: SlackConnectorConfig;
|
|
50
|
+
logger?: FunnelLogger;
|
|
51
|
+
/**
|
|
52
|
+
* Invoked after the Bolt App is constructed, before it starts.
|
|
53
|
+
* Use to attach app.action handlers, custom middleware, etc.
|
|
54
|
+
*/
|
|
55
|
+
onAppCreated?: SlackOnAppCreated;
|
|
56
|
+
/**
|
|
57
|
+
* Transform or drop the raw Slack event before the built-in processor sees it.
|
|
58
|
+
* Return null to drop the event entirely.
|
|
59
|
+
*/
|
|
60
|
+
preprocessEvent?: SlackPreprocessEvent;
|
|
61
|
+
};
|
|
62
|
+
declare class FunnelSlackListener extends FunnelConnectorListener {
|
|
63
|
+
private readonly config;
|
|
64
|
+
private readonly logger;
|
|
65
|
+
private readonly onAppCreated;
|
|
66
|
+
private readonly preprocessEvent;
|
|
67
|
+
private app;
|
|
68
|
+
constructor(deps: Deps);
|
|
69
|
+
start(notify: NotifyFn): Promise<void>;
|
|
70
|
+
stop(): Promise<void>;
|
|
71
|
+
isAlive(): boolean;
|
|
72
|
+
}
|
|
73
|
+
//#endregion
|
|
74
|
+
export { SlackProcessed as a, SlackRawEvent as c, FunnelSlackEventProcessor as i, SlackConnectorConfig as l, SlackOnAppCreated as n, SlackProcessedEmit as o, SlackPreprocessEvent as r, SlackProcessedSkip as s, FunnelSlackListener as t, slackConnectorSchema as u };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@interactive-inc/claude-funnel",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.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",
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
},
|
|
29
29
|
"files": [
|
|
30
30
|
"dist/**/*",
|
|
31
|
+
"schemas/**/*",
|
|
31
32
|
"README.md",
|
|
32
33
|
"LICENSE"
|
|
33
34
|
],
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"type": "object",
|
|
4
|
+
"properties": {
|
|
5
|
+
"$schema": {
|
|
6
|
+
"type": "string"
|
|
7
|
+
},
|
|
8
|
+
"channel": {
|
|
9
|
+
"type": "string"
|
|
10
|
+
},
|
|
11
|
+
"options": {
|
|
12
|
+
"type": "array",
|
|
13
|
+
"items": {
|
|
14
|
+
"type": "string"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"env": {
|
|
18
|
+
"type": "object",
|
|
19
|
+
"propertyNames": {
|
|
20
|
+
"type": "string"
|
|
21
|
+
},
|
|
22
|
+
"additionalProperties": {
|
|
23
|
+
"type": "string"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"connectors": {
|
|
27
|
+
"type": "array",
|
|
28
|
+
"items": {
|
|
29
|
+
"oneOf": [
|
|
30
|
+
{
|
|
31
|
+
"type": "object",
|
|
32
|
+
"properties": {
|
|
33
|
+
"type": {
|
|
34
|
+
"type": "string",
|
|
35
|
+
"const": "slack"
|
|
36
|
+
},
|
|
37
|
+
"name": {
|
|
38
|
+
"type": "string"
|
|
39
|
+
},
|
|
40
|
+
"botToken": {
|
|
41
|
+
"type": "string"
|
|
42
|
+
},
|
|
43
|
+
"appToken": {
|
|
44
|
+
"type": "string"
|
|
45
|
+
},
|
|
46
|
+
"env": {
|
|
47
|
+
"type": "object",
|
|
48
|
+
"properties": {
|
|
49
|
+
"botToken": {
|
|
50
|
+
"type": "string"
|
|
51
|
+
},
|
|
52
|
+
"appToken": {
|
|
53
|
+
"type": "string"
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"additionalProperties": false
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"required": [
|
|
60
|
+
"type",
|
|
61
|
+
"name"
|
|
62
|
+
],
|
|
63
|
+
"additionalProperties": false
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"type": "object",
|
|
67
|
+
"properties": {
|
|
68
|
+
"type": {
|
|
69
|
+
"type": "string",
|
|
70
|
+
"const": "discord"
|
|
71
|
+
},
|
|
72
|
+
"name": {
|
|
73
|
+
"type": "string"
|
|
74
|
+
},
|
|
75
|
+
"botToken": {
|
|
76
|
+
"type": "string"
|
|
77
|
+
},
|
|
78
|
+
"env": {
|
|
79
|
+
"type": "object",
|
|
80
|
+
"properties": {
|
|
81
|
+
"botToken": {
|
|
82
|
+
"type": "string"
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
"additionalProperties": false
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
"required": [
|
|
89
|
+
"type",
|
|
90
|
+
"name"
|
|
91
|
+
],
|
|
92
|
+
"additionalProperties": false
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"type": "object",
|
|
96
|
+
"properties": {
|
|
97
|
+
"type": {
|
|
98
|
+
"type": "string",
|
|
99
|
+
"const": "gh"
|
|
100
|
+
},
|
|
101
|
+
"name": {
|
|
102
|
+
"type": "string"
|
|
103
|
+
},
|
|
104
|
+
"pollInterval": {
|
|
105
|
+
"type": "integer",
|
|
106
|
+
"exclusiveMinimum": 0,
|
|
107
|
+
"maximum": 9007199254740991
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
"required": [
|
|
111
|
+
"type",
|
|
112
|
+
"name"
|
|
113
|
+
],
|
|
114
|
+
"additionalProperties": false
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"type": "object",
|
|
118
|
+
"properties": {
|
|
119
|
+
"type": {
|
|
120
|
+
"type": "string",
|
|
121
|
+
"const": "schedule"
|
|
122
|
+
},
|
|
123
|
+
"name": {
|
|
124
|
+
"type": "string"
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
"required": [
|
|
128
|
+
"type",
|
|
129
|
+
"name"
|
|
130
|
+
],
|
|
131
|
+
"additionalProperties": false
|
|
132
|
+
}
|
|
133
|
+
]
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
"required": [
|
|
138
|
+
"channel"
|
|
139
|
+
],
|
|
140
|
+
"additionalProperties": false,
|
|
141
|
+
"title": "Funnel per-repo launch config",
|
|
142
|
+
"description": "Used by `fnl claude` when no --profile / --channel is given. Declares the channel to subscribe to, optional sub-agent and brief flag, environment variables to layer under process.env, and optional connectors to materialize into ~/.funnel/settings.json on launch."
|
|
143
|
+
}
|
|
144
|
+
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
|
|
3
|
-
//#region lib/connectors/slack-connector-schema.d.ts
|
|
4
|
-
declare const slackConnectorSchema: z.ZodObject<{
|
|
5
|
-
id: z.ZodString;
|
|
6
|
-
name: z.ZodString;
|
|
7
|
-
type: z.ZodLiteral<"slack">;
|
|
8
|
-
botToken: z.ZodString;
|
|
9
|
-
appToken: z.ZodString;
|
|
10
|
-
createdAt: z.ZodOptional<z.ZodString>;
|
|
11
|
-
updatedAt: z.ZodOptional<z.ZodString>;
|
|
12
|
-
}, z.core.$strip>;
|
|
13
|
-
type SlackConnectorConfig = z.infer<typeof slackConnectorSchema>;
|
|
14
|
-
//#endregion
|
|
15
|
-
//#region lib/connectors/slack-event-processor.d.ts
|
|
16
|
-
type SlackRawEvent = Record<string, unknown>;
|
|
17
|
-
type SlackProcessedSkip = {
|
|
18
|
-
skip: true;
|
|
19
|
-
};
|
|
20
|
-
type SlackProcessedEmit = {
|
|
21
|
-
skip: false;
|
|
22
|
-
content: string;
|
|
23
|
-
meta: Record<string, string>;
|
|
24
|
-
shouldReact: boolean;
|
|
25
|
-
channel: string;
|
|
26
|
-
timestamp: string;
|
|
27
|
-
};
|
|
28
|
-
type SlackProcessed = SlackProcessedSkip | SlackProcessedEmit;
|
|
29
|
-
type Props = {
|
|
30
|
-
ownBotUserId: string;
|
|
31
|
-
ownBotId: string;
|
|
32
|
-
now?: () => number;
|
|
33
|
-
};
|
|
34
|
-
declare class FunnelSlackEventProcessor {
|
|
35
|
-
private readonly ownBotUserId;
|
|
36
|
-
private readonly ownBotId;
|
|
37
|
-
private readonly now;
|
|
38
|
-
private readonly dedup;
|
|
39
|
-
constructor(props: Props);
|
|
40
|
-
process(event: SlackRawEvent): SlackProcessed;
|
|
41
|
-
}
|
|
42
|
-
//#endregion
|
|
43
|
-
export { SlackRawEvent as a, SlackProcessedSkip as i, SlackProcessed as n, SlackConnectorConfig as o, SlackProcessedEmit as r, slackConnectorSchema as s, FunnelSlackEventProcessor as t };
|