@interactive-inc/claude-funnel 0.59.1 → 0.60.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 +9 -3
- package/dist/bin.js +549 -487
- package/dist/channels-2g_BU1N0.d.ts +174 -0
- package/dist/claude.d.ts +9 -5
- package/dist/claude.js +54 -17
- package/dist/{diagnostic-log-Cb3v8P7p.d.ts → connector-descriptor-6SXJoszo.d.ts} +158 -2
- package/dist/connectors/discord.d.ts +30 -4
- package/dist/connectors/discord.js +2 -2
- package/dist/connectors/gh.d.ts +21 -5
- package/dist/connectors/gh.js +3 -3
- package/dist/connectors/schedule.d.ts +124 -2
- package/dist/connectors/schedule.js +3 -3
- package/dist/connectors/slack.d.ts +149 -5
- package/dist/connectors/slack.js +2 -2
- package/dist/{diagnostic-sql-reader-CzYgZpq2.js → diagnostic-sql-reader-C9zR-Csp.js} +5 -5
- package/dist/diagnostics.d.ts +1 -1
- package/dist/diagnostics.js +1 -1
- package/dist/{discord-listener-CKsZGTnH.js → discord-connector-BL36yvbL.js} +60 -37
- package/dist/docs.d.ts +1 -1
- package/dist/docs.js +1 -1
- package/dist/doctor.d.ts +1 -1
- package/dist/doctor.js +1 -1
- package/dist/error-message-of-Byi4y0Uf.js +9 -0
- package/dist/{file-process-guard-JhFpmHYo.d.ts → file-process-guard-DOlCr4GF.d.ts} +4 -5
- package/dist/{funnel-diagnostics-BpKYrMSu.js → funnel-diagnostics-CSiJmPlZ.js} +19 -2
- package/dist/{funnel-diagnostics-K-wON25Y.d.ts → funnel-diagnostics-DpXOsCty.d.ts} +3 -3
- package/dist/{funnel-docs-ng5K8w4j.js → funnel-docs-BxXZ9Ksx.js} +76 -3
- package/dist/{funnel-docs-DYBs1-H_.d.ts → funnel-docs-CNklHvbt.d.ts} +1 -1
- package/dist/{funnel-doctor-vxO96TCA.d.ts → funnel-doctor-CZf_0Luq.d.ts} +2 -2
- package/dist/{funnel-recovery-COExL9MD.d.ts → funnel-recovery-DnLrdWO9.d.ts} +1 -1
- package/dist/gateway/daemon.js +326 -266
- package/dist/gateway-base-url-Dy4Ykuoh.js +14 -0
- package/dist/gateway.d.ts +2 -2
- package/dist/gateway.js +2 -2
- package/dist/{gh-listener-B2I4s8qh.js → gh-connector-DpiixfQZ.js} +53 -5
- package/dist/gh-connector-schema-Rzwc1c1N.js +12 -0
- package/dist/http-client-oICicjuO.d.ts +18 -0
- package/dist/index-CgY8NdMz.d.ts +1057 -0
- package/dist/index.d.ts +1558 -17
- package/dist/index.js +374 -342
- package/dist/{local-config-json-schema-DE1zkMcb.js → local-config-json-schema-JyLqOQNX.js} +9 -5
- package/dist/local-config-sync-Dh1Croqe.d.ts +169 -0
- package/dist/local-config.d.ts +2 -2
- package/dist/local-config.js +2 -2
- package/dist/logger.js +1 -1
- package/dist/{memory-diagnostic-log-B9Us7X05.js → memory-diagnostic-log-CI60kNfB.js} +33 -18
- package/dist/{memory-token-prompter-CcShtF8B.d.ts → memory-token-prompter-B4sjyaAq.d.ts} +2 -2
- package/dist/{memory-token-prompter-C7vREzCL.js → memory-token-prompter-CZde7e6y.js} +1 -1
- package/dist/{node-file-system-BcrmWN9I.js → node-file-system-Blr8pAir.js} +1 -1
- package/dist/node-http-client-lowp60Oa.js +25 -0
- package/dist/{gh-connector-schema-ClPLSYD9.js → node-process-runner-DxTvycoK.js} +1 -12
- package/dist/{profiles-g2qGVOWv.d.ts → profiles-Cy5wXQ0L.d.ts} +3 -3
- package/dist/{profiles-MnXvYfZF.js → profiles-DSzTeKQw.js} +1 -1
- 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/{schedule-listener-DP9Jhc6U.js → schedule-connector-L4uzg5M8.js} +109 -9
- package/dist/{settings-reader-DPwqOVUm.d.ts → settings-reader-BIFB_j2f.d.ts} +1 -1
- package/dist/settings-schema-D1xcOqRu.d.ts +78 -0
- package/dist/{gateway-base-url-DxVjjDoW.js → settings-store-CUKSeTXC.js} +27 -29
- package/dist/{slack-listener-C4wlZaOq.js → slack-connector-DQIFPdBF.js} +67 -12
- package/dist/slot-fields-CMoRpwuy.js +45 -0
- package/dist/{yaml-render-cZu6CxkE.js → yaml-render-qW34NlYz.js} +4 -4
- package/package.json +1 -1
- package/dist/connector-adapter-DGacCppE.d.ts +0 -25
- package/dist/discord-connector-schema-CQyfDkLD.d.ts +0 -39
- package/dist/gh-connector-schema-CZzwzvqY.d.ts +0 -14
- package/dist/index-D7mjirUL.d.ts +0 -3602
- package/dist/local-config-sync-BGPAS9Be.d.ts +0 -401
- package/dist/process-runner-DIm1cy95.d.ts +0 -52
- package/dist/resolve-connector-token-CczqG_Ig.js +0 -22
- package/dist/schedule-listener-DoMPjHZj.d.ts +0 -112
- package/dist/settings-schema-1hh11jnN.d.ts +0 -152
- package/dist/slack-listener-Dj9NFbAJ.d.ts +0 -136
- /package/dist/{connector-adapter-qwXLjQId.js → connector-adapter-DU9Rvyec.js} +0 -0
- /package/dist/{connector-listener-CpHBecCj.js → connector-listener-DR3aKOuK.js} +0 -0
- /package/dist/{file-system-PWKKU7lA.js → file-system-Wvzc2ePY.js} +0 -0
- /package/dist/{file-system-DxpnnUVb.d.ts → file-system-o51IsM0W.d.ts} +0 -0
- /package/dist/{funnel-doctor-CApCezTq.js → funnel-doctor-DiJCjHsg.js} +0 -0
- /package/dist/{funnel-log-sqlite-sink-B_5_4ybn.js → funnel-log-sqlite-sink-kqJbx2H7.js} +0 -0
- /package/dist/{funnel-recovery-D9CxD5Zs.js → funnel-recovery-BFdPjL6Z.js} +0 -0
- /package/dist/{logger-BP6SisKt.js → logger-B6iyNbxM.js} +0 -0
- /package/dist/{schedule-connector-schema-B_xO5z5B.js → schedule-connector-schema-CfyuMCMh.js} +0 -0
- /package/dist/{settings-reader-DPqrpV7s.js → settings-reader-CtQ-Ix8_.js} +0 -0
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { B as FunnelLogger, D as FunnelConnectorListener, O as NotifyFn, p as ConnectorDiagnosticLog, r as ConnectorDescriptor } from "../connector-descriptor-6SXJoszo.js";
|
|
2
|
+
import { n as FunnelFileSystem } from "../file-system-o51IsM0W.js";
|
|
3
|
+
import { z } from "zod";
|
|
2
4
|
|
|
3
5
|
//#region lib/engine/connectors/match-cron.d.ts
|
|
4
6
|
/**
|
|
@@ -13,4 +15,124 @@ import { a as ScheduleEntry, c as scheduleEntrySchema, i as ScheduleConnectorCon
|
|
|
13
15
|
*/
|
|
14
16
|
declare const matchCron: (expr: string, date: Date) => boolean;
|
|
15
17
|
//#endregion
|
|
16
|
-
|
|
18
|
+
//#region lib/engine/connectors/schedule-state-store.d.ts
|
|
19
|
+
type Deps$1 = {
|
|
20
|
+
path: string;
|
|
21
|
+
fs?: FunnelFileSystem;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Per-connector lastFiredAt persistence for the schedule listener. The path is
|
|
25
|
+
* passed in by the schedule connector descriptor (via the registry's
|
|
26
|
+
* connectorDir) so this store does not know about the funnel directory layout
|
|
27
|
+
* (`channels/<id>/connectors/<id>/state.json` lives outside this class).
|
|
28
|
+
*/
|
|
29
|
+
declare class ScheduleStateStore {
|
|
30
|
+
private readonly path;
|
|
31
|
+
private readonly fs;
|
|
32
|
+
constructor(deps: Deps$1);
|
|
33
|
+
load(): Map<string, Date>;
|
|
34
|
+
save(state: Map<string, Date>): void;
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region lib/engine/connectors/schedule-connector-schema.d.ts
|
|
38
|
+
/**
|
|
39
|
+
* Catch-up behavior when the daemon was down past one or more matching minutes.
|
|
40
|
+
*
|
|
41
|
+
* - `latest`: fire once with the most recent missed match (default; preserves prior behavior).
|
|
42
|
+
* - `all`: fire once per missed minute, oldest first (capped at 24 h).
|
|
43
|
+
* - `skip`: never fire missed matches; only fire when the current minute matches.
|
|
44
|
+
*/
|
|
45
|
+
declare const scheduleCatchupPolicySchema: z.ZodEnum<{
|
|
46
|
+
latest: "latest";
|
|
47
|
+
all: "all";
|
|
48
|
+
skip: "skip";
|
|
49
|
+
}>;
|
|
50
|
+
type ScheduleCatchupPolicy = z.infer<typeof scheduleCatchupPolicySchema>;
|
|
51
|
+
declare const scheduleEntrySchema: z.ZodObject<{
|
|
52
|
+
id: z.ZodString;
|
|
53
|
+
cron: z.ZodString;
|
|
54
|
+
prompt: z.ZodString;
|
|
55
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
56
|
+
catchupPolicy: z.ZodDefault<z.ZodEnum<{
|
|
57
|
+
latest: "latest";
|
|
58
|
+
all: "all";
|
|
59
|
+
skip: "skip";
|
|
60
|
+
}>>;
|
|
61
|
+
}, z.core.$strip>;
|
|
62
|
+
type ScheduleEntry = z.infer<typeof scheduleEntrySchema>;
|
|
63
|
+
declare const scheduleConnectorSchema: z.ZodObject<{
|
|
64
|
+
id: z.ZodString;
|
|
65
|
+
name: z.ZodString;
|
|
66
|
+
type: z.ZodLiteral<"schedule">;
|
|
67
|
+
entries: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
68
|
+
id: z.ZodString;
|
|
69
|
+
cron: z.ZodString;
|
|
70
|
+
prompt: z.ZodString;
|
|
71
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
72
|
+
catchupPolicy: z.ZodDefault<z.ZodEnum<{
|
|
73
|
+
latest: "latest";
|
|
74
|
+
all: "all";
|
|
75
|
+
skip: "skip";
|
|
76
|
+
}>>;
|
|
77
|
+
}, z.core.$strip>>>;
|
|
78
|
+
createdAt: z.ZodOptional<z.ZodString>;
|
|
79
|
+
updatedAt: z.ZodOptional<z.ZodString>;
|
|
80
|
+
}, z.core.$strip>;
|
|
81
|
+
type ScheduleConnectorConfig = z.infer<typeof scheduleConnectorSchema>;
|
|
82
|
+
//#endregion
|
|
83
|
+
//#region lib/engine/connectors/schedule-listener.d.ts
|
|
84
|
+
type ScheduleOnFired = (entry: ScheduleEntry, firedAt: Date) => void | Promise<void>;
|
|
85
|
+
type Deps = {
|
|
86
|
+
config: ScheduleConnectorConfig;
|
|
87
|
+
lastFiredStore: ScheduleStateStore; /** Funnel channel uuid this connector lives under; stamped onto diagnostic-log rows. */
|
|
88
|
+
channelId?: string;
|
|
89
|
+
logger?: FunnelLogger; /** Diagnostic log of fired entries and lifecycle. No-op when absent. */
|
|
90
|
+
diagnosticLog?: ConnectorDiagnosticLog;
|
|
91
|
+
now?: () => Date;
|
|
92
|
+
/**
|
|
93
|
+
* Invoked after a schedule entry fires successfully. Use to remove one-shot
|
|
94
|
+
* entries from the connector config, or to log per-fire side effects.
|
|
95
|
+
* Errors from this callback are caught and logged; they do not abort the tick.
|
|
96
|
+
*/
|
|
97
|
+
onFired?: ScheduleOnFired;
|
|
98
|
+
};
|
|
99
|
+
declare class FunnelScheduleListener extends FunnelConnectorListener {
|
|
100
|
+
private readonly config;
|
|
101
|
+
private readonly lastFiredStore;
|
|
102
|
+
private readonly channelId;
|
|
103
|
+
private readonly logger;
|
|
104
|
+
private readonly diagnosticLog;
|
|
105
|
+
private readonly now;
|
|
106
|
+
private readonly onFired;
|
|
107
|
+
private timer;
|
|
108
|
+
private stopped;
|
|
109
|
+
constructor(deps: Deps);
|
|
110
|
+
start(notify: NotifyFn): Promise<void>;
|
|
111
|
+
stop(): Promise<void>;
|
|
112
|
+
isAlive(): boolean;
|
|
113
|
+
tick(notify: NotifyFn): Promise<void>;
|
|
114
|
+
private fireEntry;
|
|
115
|
+
private notifyOne;
|
|
116
|
+
private findMostRecentMatch;
|
|
117
|
+
private findAllMatches;
|
|
118
|
+
private logInvalidCron;
|
|
119
|
+
private truncateToMinute;
|
|
120
|
+
private recordRaw;
|
|
121
|
+
private recordProcessed;
|
|
122
|
+
private recordConnection;
|
|
123
|
+
}
|
|
124
|
+
//#endregion
|
|
125
|
+
//#region lib/engine/connectors/schedule-connector.d.ts
|
|
126
|
+
type ScheduleConnectorOptions = {
|
|
127
|
+
/** Invoked after a schedule entry fires successfully — e.g. to drop one-shot entries. */onFired?: ScheduleOnFired;
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* Schedule connector descriptor. Pass `scheduleConnector()` to
|
|
131
|
+
* `new Funnel({ connectors: [...] })` to enable the type. Schedule has no
|
|
132
|
+
* outbound adapter; its per-entry CRUD is exposed via `operations`
|
|
133
|
+
* (listEntries / addEntry / removeEntry) and reached through
|
|
134
|
+
* `funnel.channels.connectorOp(...)`.
|
|
135
|
+
*/
|
|
136
|
+
declare const scheduleConnector: (options?: ScheduleConnectorOptions) => ConnectorDescriptor;
|
|
137
|
+
//#endregion
|
|
138
|
+
export { FunnelScheduleListener, ScheduleCatchupPolicy, ScheduleConnectorConfig, ScheduleConnectorOptions, ScheduleEntry, ScheduleOnFired, ScheduleStateStore, matchCron, scheduleCatchupPolicySchema, scheduleConnector, scheduleConnectorSchema, scheduleEntrySchema };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { n as
|
|
2
|
-
import { n as
|
|
3
|
-
export { FunnelScheduleListener, ScheduleStateStore, matchCron, scheduleCatchupPolicySchema, scheduleConnectorSchema, scheduleEntrySchema };
|
|
1
|
+
import { n as scheduleConnectorSchema, r as scheduleEntrySchema, t as scheduleCatchupPolicySchema } from "../schedule-connector-schema-CfyuMCMh.js";
|
|
2
|
+
import { i as matchCron, n as FunnelScheduleListener, r as ScheduleStateStore, t as scheduleConnector } from "../schedule-connector-L4uzg5M8.js";
|
|
3
|
+
export { FunnelScheduleListener, ScheduleStateStore, matchCron, scheduleCatchupPolicySchema, scheduleConnector, scheduleConnectorSchema, scheduleEntrySchema };
|
|
@@ -1,18 +1,48 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { A as FunnelConnectorAdapter, B as FunnelLogger, D as FunnelConnectorListener, O as NotifyFn, k as CallInput, p as ConnectorDiagnosticLog, r as ConnectorDescriptor } from "../connector-descriptor-6SXJoszo.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { App } from "@slack/bolt";
|
|
3
4
|
|
|
5
|
+
//#region lib/engine/connectors/slack-connector-schema.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* A slack connector resolves its tokens one of two ways, set at sync time:
|
|
8
|
+
*
|
|
9
|
+
* - literal: `botToken` / `appToken` hold the real `xoxb-`/`xapp-` secret
|
|
10
|
+
* (set by a `fnl channels` command or a TTY prompt at launch).
|
|
11
|
+
* - by reference: `botTokenEnv` / `appTokenEnv` hold the *name* of an env var.
|
|
12
|
+
* The secret never lands in settings.json; the listener resolves it from
|
|
13
|
+
* `process.env` at start. This form is only set through the engine API
|
|
14
|
+
* (`new Funnel(...)`) — funnel.json and the `fnl` CLI produce literals.
|
|
15
|
+
*
|
|
16
|
+
* Both are optional at the schema level (a discriminated-union member can't
|
|
17
|
+
* carry a cross-field refine); the listener requires exactly one resolved
|
|
18
|
+
* token per slot and errors loudly otherwise.
|
|
19
|
+
*/
|
|
20
|
+
declare const slackConnectorSchema: z.ZodObject<{
|
|
21
|
+
id: z.ZodString;
|
|
22
|
+
name: z.ZodString;
|
|
23
|
+
type: z.ZodLiteral<"slack">;
|
|
24
|
+
botToken: z.ZodOptional<z.ZodString>;
|
|
25
|
+
appToken: z.ZodOptional<z.ZodString>;
|
|
26
|
+
botTokenEnv: z.ZodOptional<z.ZodString>;
|
|
27
|
+
appTokenEnv: z.ZodOptional<z.ZodString>;
|
|
28
|
+
minify: z.ZodDefault<z.ZodBoolean>;
|
|
29
|
+
createdAt: z.ZodOptional<z.ZodString>;
|
|
30
|
+
updatedAt: z.ZodOptional<z.ZodString>;
|
|
31
|
+
}, z.core.$strip>;
|
|
32
|
+
type SlackConnectorConfig = z.infer<typeof slackConnectorSchema>;
|
|
33
|
+
//#endregion
|
|
4
34
|
//#region lib/engine/connectors/slack-adapter.d.ts
|
|
5
35
|
type SlackWebClientLike = {
|
|
6
36
|
apiCall: (method: string, options?: Record<string, unknown>) => Promise<unknown>;
|
|
7
37
|
};
|
|
8
|
-
type Deps = {
|
|
38
|
+
type Deps$1 = {
|
|
9
39
|
config: SlackConnectorConfig; /** Environment used to resolve a `botTokenEnv` reference. Defaults to process.env. */
|
|
10
40
|
env?: NodeJS.ProcessEnv;
|
|
11
41
|
client?: SlackWebClientLike;
|
|
12
42
|
};
|
|
13
43
|
declare class FunnelSlackAdapter extends FunnelConnectorAdapter {
|
|
14
44
|
private readonly client;
|
|
15
|
-
constructor(deps: Deps);
|
|
45
|
+
constructor(deps: Deps$1);
|
|
16
46
|
call(input: CallInput): Promise<unknown>;
|
|
17
47
|
postMessage(props: {
|
|
18
48
|
channel: string;
|
|
@@ -31,4 +61,118 @@ declare class FunnelSlackAdapter extends FunnelConnectorAdapter {
|
|
|
31
61
|
}): Promise<unknown>;
|
|
32
62
|
}
|
|
33
63
|
//#endregion
|
|
34
|
-
|
|
64
|
+
//#region lib/engine/connectors/slack-event-types.d.ts
|
|
65
|
+
type SlackMessageEvent = {
|
|
66
|
+
kind: "message";
|
|
67
|
+
channel: string;
|
|
68
|
+
user: string;
|
|
69
|
+
rawText: string;
|
|
70
|
+
text: string;
|
|
71
|
+
threadTs: string;
|
|
72
|
+
ts: string;
|
|
73
|
+
isThreadRoot: boolean;
|
|
74
|
+
mentioned: boolean;
|
|
75
|
+
source: "app_mention" | "message";
|
|
76
|
+
};
|
|
77
|
+
type SlackReactionEvent = {
|
|
78
|
+
kind: "reaction_added" | "reaction_removed";
|
|
79
|
+
channel: string;
|
|
80
|
+
user: string;
|
|
81
|
+
emoji: string;
|
|
82
|
+
targetTs: string;
|
|
83
|
+
targetUser: string | null;
|
|
84
|
+
};
|
|
85
|
+
type SlackEvent = SlackMessageEvent | SlackReactionEvent;
|
|
86
|
+
//#endregion
|
|
87
|
+
//#region lib/engine/connectors/slack-event-processor.d.ts
|
|
88
|
+
type SlackRawEvent = Record<string, unknown>;
|
|
89
|
+
/**
|
|
90
|
+
* Why the processor dropped an event. Mirrored verbatim into the diagnostic
|
|
91
|
+
* log's processed `outcome` column so "Slack delivered it but no notification arrived" is
|
|
92
|
+
* traceable to the exact gate that dropped it. The listener may additionally
|
|
93
|
+
* record `skip:preprocess` for events a host preprocessor dropped before the
|
|
94
|
+
* processor ran — that gate is outside this type.
|
|
95
|
+
*/
|
|
96
|
+
type SlackSkipReason = "skip:type" | "skip:subtype" | "skip:dedup" | "skip:self-user" | "skip:self-bot";
|
|
97
|
+
type SlackProcessedSkip = {
|
|
98
|
+
skip: true;
|
|
99
|
+
reason: SlackSkipReason;
|
|
100
|
+
};
|
|
101
|
+
type SlackProcessedEmit = {
|
|
102
|
+
skip: false;
|
|
103
|
+
event: SlackEvent;
|
|
104
|
+
content: string;
|
|
105
|
+
meta: Record<string, string>;
|
|
106
|
+
shouldReact: boolean;
|
|
107
|
+
channel: string;
|
|
108
|
+
timestamp: string;
|
|
109
|
+
};
|
|
110
|
+
type SlackProcessed = SlackProcessedSkip | SlackProcessedEmit;
|
|
111
|
+
type Props = {
|
|
112
|
+
ownBotUserId: string;
|
|
113
|
+
ownBotId: string;
|
|
114
|
+
minify?: boolean;
|
|
115
|
+
now?: () => number;
|
|
116
|
+
};
|
|
117
|
+
declare class FunnelSlackEventProcessor {
|
|
118
|
+
private readonly ownBotUserId;
|
|
119
|
+
private readonly ownBotId;
|
|
120
|
+
private readonly minify;
|
|
121
|
+
private readonly now;
|
|
122
|
+
private readonly dedup;
|
|
123
|
+
constructor(props: Props);
|
|
124
|
+
process(event: SlackRawEvent): SlackProcessed;
|
|
125
|
+
}
|
|
126
|
+
//#endregion
|
|
127
|
+
//#region lib/engine/connectors/slack-listener.d.ts
|
|
128
|
+
type SlackOnAppCreated = (app: App) => void | Promise<void>;
|
|
129
|
+
type SlackPreprocessEvent = (event: SlackRawEvent) => SlackRawEvent | null;
|
|
130
|
+
type Deps = {
|
|
131
|
+
config: SlackConnectorConfig; /** Funnel channel uuid this connector lives under; stamped onto diagnostic-log rows. */
|
|
132
|
+
channelId?: string; /** Environment used to resolve `botTokenEnv`/`appTokenEnv` references. Defaults to process.env. */
|
|
133
|
+
env?: NodeJS.ProcessEnv;
|
|
134
|
+
logger?: FunnelLogger; /** Diagnostic log of inbound events, before and after processing. No-op when absent. */
|
|
135
|
+
diagnosticLog?: ConnectorDiagnosticLog;
|
|
136
|
+
/**
|
|
137
|
+
* Invoked after the Bolt App is constructed, before it starts.
|
|
138
|
+
* Use to attach app.action handlers, custom middleware, etc.
|
|
139
|
+
*/
|
|
140
|
+
onAppCreated?: SlackOnAppCreated;
|
|
141
|
+
/**
|
|
142
|
+
* Transform or drop the raw Slack event before the built-in processor sees it.
|
|
143
|
+
* Return null to drop the event entirely.
|
|
144
|
+
*/
|
|
145
|
+
preprocessEvent?: SlackPreprocessEvent;
|
|
146
|
+
};
|
|
147
|
+
declare class FunnelSlackListener extends FunnelConnectorListener {
|
|
148
|
+
private readonly config;
|
|
149
|
+
private readonly channelId;
|
|
150
|
+
private readonly env;
|
|
151
|
+
private readonly logger;
|
|
152
|
+
private readonly diagnosticLog;
|
|
153
|
+
private readonly onAppCreated;
|
|
154
|
+
private readonly preprocessEvent;
|
|
155
|
+
private app;
|
|
156
|
+
private connected;
|
|
157
|
+
constructor(deps: Deps);
|
|
158
|
+
start(notify: NotifyFn): Promise<void>;
|
|
159
|
+
stop(): Promise<void>;
|
|
160
|
+
isAlive(): boolean;
|
|
161
|
+
private recordRaw;
|
|
162
|
+
private recordProcessed;
|
|
163
|
+
private recordConnection;
|
|
164
|
+
}
|
|
165
|
+
//#endregion
|
|
166
|
+
//#region lib/engine/connectors/slack-connector.d.ts
|
|
167
|
+
type SlackConnectorOptions = {
|
|
168
|
+
/** Invoked after the Bolt App is constructed, before start — attach app.action handlers etc. */onAppCreated?: SlackOnAppCreated; /** Transform or drop a raw Slack event before the built-in processor sees it. */
|
|
169
|
+
preprocessEvent?: SlackPreprocessEvent;
|
|
170
|
+
};
|
|
171
|
+
/**
|
|
172
|
+
* Slack connector descriptor. Pass `slackConnector()` to
|
|
173
|
+
* `new Funnel({ connectors: [...] })` to enable the type. Host launch hooks are
|
|
174
|
+
* closed over here, so they need no Funnel-level option plumbing.
|
|
175
|
+
*/
|
|
176
|
+
declare const slackConnector: (options?: SlackConnectorOptions) => ConnectorDescriptor;
|
|
177
|
+
//#endregion
|
|
178
|
+
export { FunnelSlackAdapter, FunnelSlackEventProcessor, FunnelSlackListener, SlackConnectorConfig, SlackConnectorOptions, SlackEvent, SlackMessageEvent, SlackOnAppCreated, SlackPreprocessEvent, SlackProcessed, SlackProcessedEmit, SlackProcessedSkip, SlackRawEvent, SlackReactionEvent, SlackSkipReason, SlackWebClientLike, slackConnector, slackConnectorSchema };
|
package/dist/connectors/slack.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { n as FunnelSlackEventProcessor, r as FunnelSlackAdapter, t as FunnelSlackListener } from "../slack-listener-C4wlZaOq.js";
|
|
2
1
|
import { t as slackConnectorSchema } from "../slack-connector-schema-C1zEf4TG.js";
|
|
3
|
-
|
|
2
|
+
import { i as FunnelSlackAdapter, n as FunnelSlackListener, r as FunnelSlackEventProcessor, t as slackConnector } from "../slack-connector-DQIFPdBF.js";
|
|
3
|
+
export { FunnelSlackAdapter, FunnelSlackEventProcessor, FunnelSlackListener, slackConnector, slackConnectorSchema };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Database } from "bun:sqlite";
|
|
2
|
-
//#region lib/
|
|
2
|
+
//#region lib/engine/diagnostic-log/diagnostic-sql-reader.ts
|
|
3
3
|
/**
|
|
4
4
|
* Read-only SQL surface over the three diagnostic tables, for Claude to query
|
|
5
5
|
* the log with arbitrary `SELECT`s. It opens all files read-only and exposes
|
|
6
6
|
* three views — `raw`, `processed`, `connection` — that hide the storage
|
|
7
|
-
* details (the physical table is `
|
|
7
|
+
* details (the physical table is `logs` and each row's columns live
|
|
8
8
|
* inside a JSON `event` blob): the views surface the columns as plain fields,
|
|
9
9
|
* with `payload` already pulled out of the nested JSON.
|
|
10
10
|
*
|
|
@@ -59,7 +59,7 @@ const rawViewSql = `CREATE TEMP VIEW raw AS SELECT
|
|
|
59
59
|
json_extract(event, '$.connector_id') AS connector_id,
|
|
60
60
|
json_extract(event, '$.channel_id') AS channel_id,
|
|
61
61
|
json_extract(event, '$.payload') AS payload
|
|
62
|
-
FROM main.
|
|
62
|
+
FROM main.logs`;
|
|
63
63
|
const processedViewSql = `CREATE TEMP VIEW processed AS SELECT
|
|
64
64
|
seq,
|
|
65
65
|
ts,
|
|
@@ -69,7 +69,7 @@ const processedViewSql = `CREATE TEMP VIEW processed AS SELECT
|
|
|
69
69
|
json_extract(event, '$.channel_id') AS channel_id,
|
|
70
70
|
json_extract(event, '$.outcome') AS outcome,
|
|
71
71
|
json_extract(event, '$.payload') AS payload
|
|
72
|
-
FROM processeddb.
|
|
72
|
+
FROM processeddb.logs`;
|
|
73
73
|
const connectionViewSql = `CREATE TEMP VIEW connection AS SELECT
|
|
74
74
|
seq,
|
|
75
75
|
ts,
|
|
@@ -78,6 +78,6 @@ const connectionViewSql = `CREATE TEMP VIEW connection AS SELECT
|
|
|
78
78
|
json_extract(event, '$.channel_id') AS channel_id,
|
|
79
79
|
json_extract(event, '$.status') AS status,
|
|
80
80
|
json_extract(event, '$.detail') AS detail
|
|
81
|
-
FROM connectiondb.
|
|
81
|
+
FROM connectiondb.logs`;
|
|
82
82
|
//#endregion
|
|
83
83
|
export { ConnectorDiagnosticSqlReader as t };
|
package/dist/diagnostics.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as DiagnosticsGatewayProbe, c as FunnelDiagnostics, d as DiagnosticEvent, f as previewOf, h as toDiagnosticEvent, i as DiagnosticsChannelSource, l as ReplayResult, m as toDiagnosticConnectionError, n as DiagnoseAllReport, o as DiagnosticsPublisher, p as queryRows, r as DiagnosisStatus, s as DiagnosticsTokenReader, t as ChannelDiagnosis, u as DiagnosticConnectionError } from "./funnel-diagnostics-
|
|
1
|
+
import { a as DiagnosticsGatewayProbe, c as FunnelDiagnostics, d as DiagnosticEvent, f as previewOf, h as toDiagnosticEvent, i as DiagnosticsChannelSource, l as ReplayResult, m as toDiagnosticConnectionError, n as DiagnoseAllReport, o as DiagnosticsPublisher, p as queryRows, r as DiagnosisStatus, s as DiagnosticsTokenReader, t as ChannelDiagnosis, u as DiagnosticConnectionError } from "./funnel-diagnostics-DpXOsCty.js";
|
|
2
2
|
export { ChannelDiagnosis, DiagnoseAllReport, DiagnosisStatus, DiagnosticConnectionError, DiagnosticEvent, DiagnosticsChannelSource, DiagnosticsGatewayProbe, DiagnosticsPublisher, DiagnosticsTokenReader, FunnelDiagnostics, ReplayResult, previewOf, queryRows, toDiagnosticConnectionError, toDiagnosticEvent };
|
package/dist/diagnostics.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as toDiagnosticEvent, i as toDiagnosticConnectionError, n as previewOf, r as queryRows, t as FunnelDiagnostics } from "./funnel-diagnostics-
|
|
1
|
+
import { a as toDiagnosticEvent, i as toDiagnosticConnectionError, n as previewOf, r as queryRows, t as FunnelDiagnostics } from "./funnel-diagnostics-CSiJmPlZ.js";
|
|
2
2
|
export { FunnelDiagnostics, previewOf, queryRows, toDiagnosticConnectionError, toDiagnosticEvent };
|
|
@@ -1,31 +1,10 @@
|
|
|
1
|
-
import { t as
|
|
2
|
-
import { t as
|
|
3
|
-
import { t as
|
|
1
|
+
import { t as discordConnectorSchema } from "./discord-connector-schema-B_N6IXLz.js";
|
|
2
|
+
import { t as NodeFunnelHttpClient } from "./node-http-client-lowp60Oa.js";
|
|
3
|
+
import { t as FunnelConnectorAdapter } from "./connector-adapter-DU9Rvyec.js";
|
|
4
|
+
import { t as FunnelConnectorListener } from "./connector-listener-DR3aKOuK.js";
|
|
5
|
+
import { t as errorMessageOf } from "./error-message-of-Byi4y0Uf.js";
|
|
6
|
+
import { n as resolveConnectorToken, t as slotFields } from "./slot-fields-CMoRpwuy.js";
|
|
4
7
|
import { Client, GatewayIntentBits, Partials } from "discord.js";
|
|
5
|
-
//#region lib/engine/http/http-client.ts
|
|
6
|
-
var FunnelHttpClient = class {};
|
|
7
|
-
//#endregion
|
|
8
|
-
//#region lib/engine/http/node-http-client.ts
|
|
9
|
-
var NodeFunnelHttpClient = class extends FunnelHttpClient {
|
|
10
|
-
constructor() {
|
|
11
|
-
super();
|
|
12
|
-
Object.freeze(this);
|
|
13
|
-
}
|
|
14
|
-
async fetch(request) {
|
|
15
|
-
const res = await globalThis.fetch(request.url, {
|
|
16
|
-
method: request.method,
|
|
17
|
-
headers: request.headers,
|
|
18
|
-
body: request.body
|
|
19
|
-
});
|
|
20
|
-
return {
|
|
21
|
-
status: res.status,
|
|
22
|
-
ok: res.ok,
|
|
23
|
-
text: () => res.text(),
|
|
24
|
-
json: () => res.json()
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
//#endregion
|
|
29
8
|
//#region lib/engine/connectors/discord-adapter.ts
|
|
30
9
|
const DISCORD_API_BASE = "https://discord.com/api/v10";
|
|
31
10
|
const defaultHttp = new NodeFunnelHttpClient();
|
|
@@ -145,7 +124,7 @@ var FunnelDiscordListener = class extends FunnelConnectorListener {
|
|
|
145
124
|
await notify(result.content, result.meta);
|
|
146
125
|
} catch (error) {
|
|
147
126
|
this.recordProcessed(eventId, rawEvent, "emitted:delivery-failed", result.content);
|
|
148
|
-
this.logger?.error("discord notify error", { error:
|
|
127
|
+
this.logger?.error("discord notify error", { error: errorMessageOf(error) });
|
|
149
128
|
return;
|
|
150
129
|
}
|
|
151
130
|
this.recordProcessed(eventId, rawEvent, "emitted", result.content);
|
|
@@ -158,8 +137,8 @@ var FunnelDiscordListener = class extends FunnelConnectorListener {
|
|
|
158
137
|
});
|
|
159
138
|
});
|
|
160
139
|
client.on("error", (error) => {
|
|
161
|
-
this.recordConnection("error",
|
|
162
|
-
this.logger?.error("discord client error", { error:
|
|
140
|
+
this.recordConnection("error", errorMessageOf(error));
|
|
141
|
+
this.logger?.error("discord client error", { error: errorMessageOf(error) });
|
|
163
142
|
});
|
|
164
143
|
try {
|
|
165
144
|
await client.login(resolveConnectorToken({
|
|
@@ -169,7 +148,7 @@ var FunnelDiscordListener = class extends FunnelConnectorListener {
|
|
|
169
148
|
label: `${this.config.name}.botToken`
|
|
170
149
|
}));
|
|
171
150
|
} catch (error) {
|
|
172
|
-
this.recordConnection("error",
|
|
151
|
+
this.recordConnection("error", errorMessageOf(error));
|
|
173
152
|
throw error;
|
|
174
153
|
}
|
|
175
154
|
this.client = client;
|
|
@@ -181,8 +160,8 @@ var FunnelDiscordListener = class extends FunnelConnectorListener {
|
|
|
181
160
|
await this.client.destroy();
|
|
182
161
|
this.recordConnection("disconnected", "");
|
|
183
162
|
} catch (error) {
|
|
184
|
-
this.recordConnection("error",
|
|
185
|
-
this.logger?.error("discord stop error", { error:
|
|
163
|
+
this.recordConnection("error", errorMessageOf(error));
|
|
164
|
+
this.logger?.error("discord stop error", { error: errorMessageOf(error) });
|
|
186
165
|
} finally {
|
|
187
166
|
this.client = null;
|
|
188
167
|
this.recordConnection("stopped", "");
|
|
@@ -220,8 +199,52 @@ var FunnelDiscordListener = class extends FunnelConnectorListener {
|
|
|
220
199
|
});
|
|
221
200
|
}
|
|
222
201
|
};
|
|
223
|
-
const messageOf = (error) => {
|
|
224
|
-
return error instanceof Error ? error.message : String(error);
|
|
225
|
-
};
|
|
226
202
|
//#endregion
|
|
227
|
-
|
|
203
|
+
//#region lib/engine/connectors/discord-connector.ts
|
|
204
|
+
/**
|
|
205
|
+
* Discord connector descriptor. Pass `discordConnector()` to
|
|
206
|
+
* `new Funnel({ connectors: [...] })` to enable the type.
|
|
207
|
+
*/
|
|
208
|
+
const discordConnector = () => ({
|
|
209
|
+
type: "discord",
|
|
210
|
+
toolExposed: true,
|
|
211
|
+
createListener(config, deps) {
|
|
212
|
+
return new FunnelDiscordListener({
|
|
213
|
+
config: discordConnectorSchema.parse(config),
|
|
214
|
+
channelId: deps.channelId,
|
|
215
|
+
logger: deps.logger,
|
|
216
|
+
diagnosticLog: deps.diagnosticLog
|
|
217
|
+
});
|
|
218
|
+
},
|
|
219
|
+
createAdapter(config) {
|
|
220
|
+
return new FunnelDiscordAdapter({ config: discordConnectorSchema.parse(config) });
|
|
221
|
+
},
|
|
222
|
+
secretTokens(config) {
|
|
223
|
+
return [discordConnectorSchema.parse(config).botToken].filter((token) => token !== void 0);
|
|
224
|
+
},
|
|
225
|
+
buildConfig(input, context) {
|
|
226
|
+
return discordConnectorSchema.parse({
|
|
227
|
+
id: context.id,
|
|
228
|
+
type: "discord",
|
|
229
|
+
name: input.name,
|
|
230
|
+
...typeof input.botToken === "string" ? { botToken: input.botToken } : {},
|
|
231
|
+
...typeof input.botTokenEnv === "string" ? { botTokenEnv: input.botTokenEnv } : {},
|
|
232
|
+
createdAt: context.now,
|
|
233
|
+
updatedAt: context.now
|
|
234
|
+
});
|
|
235
|
+
},
|
|
236
|
+
applyUpdate(config, fields, context) {
|
|
237
|
+
const current = discordConnectorSchema.parse(config);
|
|
238
|
+
return discordConnectorSchema.parse({
|
|
239
|
+
id: current.id,
|
|
240
|
+
name: current.name,
|
|
241
|
+
type: "discord",
|
|
242
|
+
createdAt: current.createdAt,
|
|
243
|
+
updatedAt: context.now,
|
|
244
|
+
...slotFields("botToken", "botTokenEnv", fields, current)
|
|
245
|
+
});
|
|
246
|
+
},
|
|
247
|
+
operations: {}
|
|
248
|
+
});
|
|
249
|
+
//#endregion
|
|
250
|
+
export { FunnelDiscordAdapter as i, FunnelDiscordListener as n, FunnelDiscordEventProcessor as r, discordConnector as t };
|
package/dist/docs.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as FunnelDocs, t as DocsTopicListing } from "./funnel-docs-
|
|
1
|
+
import { n as FunnelDocs, t as DocsTopicListing } from "./funnel-docs-CNklHvbt.js";
|
|
2
2
|
export { DocsTopicListing, FunnelDocs };
|
package/dist/docs.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as FunnelDocs } from "./funnel-docs-
|
|
1
|
+
import { t as FunnelDocs } from "./funnel-docs-BxXZ9Ksx.js";
|
|
2
2
|
export { FunnelDocs };
|
package/dist/doctor.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as DoctorReport, r as FunnelDoctor, t as DoctorFixMode } from "./funnel-doctor-
|
|
1
|
+
import { n as DoctorReport, r as FunnelDoctor, t as DoctorFixMode } from "./funnel-doctor-CZf_0Luq.js";
|
|
2
2
|
export { DoctorFixMode, DoctorReport, FunnelDoctor };
|
package/dist/doctor.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as FunnelDoctor } from "./funnel-doctor-
|
|
1
|
+
import { t as FunnelDoctor } from "./funnel-doctor-DiJCjHsg.js";
|
|
2
2
|
export { FunnelDoctor };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
//#region lib/engine/error/error-message-of.ts
|
|
2
|
+
/**
|
|
3
|
+
* Normalize an unknown thrown value into a loggable message string.
|
|
4
|
+
*/
|
|
5
|
+
const errorMessageOf = (error) => {
|
|
6
|
+
return error instanceof Error ? error.message : String(error);
|
|
7
|
+
};
|
|
8
|
+
//#endregion
|
|
9
|
+
export { errorMessageOf as t };
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { t as ChannelConfig } from "./settings-schema-
|
|
2
|
-
import { n as FunnelIdGenerator } from "./settings-reader-
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { n as FunnelFileSystem } from "./file-system-DxpnnUVb.js";
|
|
1
|
+
import { t as ChannelConfig } from "./settings-schema-D1xcOqRu.js";
|
|
2
|
+
import { n as FunnelIdGenerator } from "./settings-reader-BIFB_j2f.js";
|
|
3
|
+
import { B as FunnelLogger, I as FunnelProcessRunner } from "./connector-descriptor-6SXJoszo.js";
|
|
4
|
+
import { n as FunnelFileSystem } from "./file-system-o51IsM0W.js";
|
|
6
5
|
|
|
7
6
|
//#region lib/engine/claude/channel-resolver.d.ts
|
|
8
7
|
type ChannelResolver = {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { t as
|
|
1
|
+
import { t as gatewayLoopbackUrl } from "./gateway-base-url-Dy4Ykuoh.js";
|
|
2
|
+
import { t as ConnectorDiagnosticSqlReader } from "./diagnostic-sql-reader-C9zR-Csp.js";
|
|
2
3
|
import { join } from "node:path";
|
|
3
4
|
import { existsSync } from "node:fs";
|
|
4
5
|
//#region lib/services/diagnostics/diagnostic-event.ts
|
|
@@ -103,6 +104,8 @@ const buildDiagnosis = (report) => {
|
|
|
103
104
|
nextActions: ["fnl gateway logs"],
|
|
104
105
|
rootCause
|
|
105
106
|
};
|
|
107
|
+
const slackEventGap = diagnoseSlackEventSubscriptionGap(report);
|
|
108
|
+
if (slackEventGap !== null) return slackEventGap;
|
|
106
109
|
return {
|
|
107
110
|
status: "ok",
|
|
108
111
|
message: "everything looks healthy",
|
|
@@ -110,6 +113,20 @@ const buildDiagnosis = (report) => {
|
|
|
110
113
|
rootCause: null
|
|
111
114
|
};
|
|
112
115
|
};
|
|
116
|
+
const diagnoseSlackEventSubscriptionGap = (report) => {
|
|
117
|
+
if (!report.listeners.some((listener) => listener.type === "slack") || report.recentEvents.length === 0) return null;
|
|
118
|
+
const slackEvents = report.recentEvents.filter((event) => event.type === "slack").map((event) => event.payloadParsed?.type);
|
|
119
|
+
if (slackEvents.length === 0) return null;
|
|
120
|
+
const sawAppMention = slackEvents.includes("app_mention");
|
|
121
|
+
const sawMessage = slackEvents.includes("message");
|
|
122
|
+
if (!sawAppMention || sawMessage) return null;
|
|
123
|
+
return {
|
|
124
|
+
status: "warn",
|
|
125
|
+
message: "Slack is only delivering app_mention events; unmentioned thread replies may not arrive",
|
|
126
|
+
nextActions: ["Add Slack bot events: message.channels, message.groups, message.im, message.mpim; reinstall the app; then restart the gateway"],
|
|
127
|
+
rootCause: "Slack Event Subscriptions likely omit message.* events"
|
|
128
|
+
};
|
|
129
|
+
};
|
|
113
130
|
/**
|
|
114
131
|
* Programmable diagnostics surface — used by both the CLI (fnl debug …) and
|
|
115
132
|
* the MCP tools (fnl_debug, fnl_recent_events, …). Pure read-side, no
|
|
@@ -247,7 +264,7 @@ var FunnelDiagnostics = class {
|
|
|
247
264
|
if (!gatewayStatus.running) return null;
|
|
248
265
|
const token = this.props.gatewayToken.read();
|
|
249
266
|
const headers = token ? { Authorization: `Bearer ${token}` } : {};
|
|
250
|
-
const res = await fetch(
|
|
267
|
+
const res = await fetch(`${gatewayLoopbackUrl(gatewayStatus.port)}/status`, { headers }).catch(() => null);
|
|
251
268
|
if (!res || !res.ok) return null;
|
|
252
269
|
const body = await res.json();
|
|
253
270
|
return isGatewayStatusResponse(body) ? body : null;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { t as ChannelConfig } from "./settings-schema-
|
|
1
|
+
import { t as ChannelConfig } from "./settings-schema-D1xcOqRu.js";
|
|
2
2
|
|
|
3
|
-
//#region lib/
|
|
3
|
+
//#region lib/engine/diagnostic-log/diagnostic-sql-reader.d.ts
|
|
4
4
|
type Props$1 = {
|
|
5
5
|
/** SQLite file holding the raw (pre-filter) table. */rawPath: string; /** SQLite file holding the processed (verdict) table. */
|
|
6
6
|
processedPath: string; /** SQLite file holding the connection (lifecycle) table. */
|
|
@@ -11,7 +11,7 @@ type Row = Record<string, unknown>;
|
|
|
11
11
|
* Read-only SQL surface over the three diagnostic tables, for Claude to query
|
|
12
12
|
* the log with arbitrary `SELECT`s. It opens all files read-only and exposes
|
|
13
13
|
* three views — `raw`, `processed`, `connection` — that hide the storage
|
|
14
|
-
* details (the physical table is `
|
|
14
|
+
* details (the physical table is `logs` and each row's columns live
|
|
15
15
|
* inside a JSON `event` blob): the views surface the columns as plain fields,
|
|
16
16
|
* with `payload` already pulled out of the nested JSON.
|
|
17
17
|
*
|