@interactive-inc/claude-funnel 0.49.0 → 0.51.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/dist/bin.js +1 -1
- package/dist/claude-CB1WkV77.d.ts +115 -0
- package/dist/claude.d.ts +59 -0
- package/dist/claude.js +322 -0
- package/dist/{connector-diagnostic-log-OPpPi9V9.d.ts → connector-diagnostic-log-yTOojKUR.d.ts} +14 -14
- package/dist/{logger-Czli2OKh.js → connector-listener-DU54DN-f.js} +1 -9
- package/dist/connectors/discord.d.ts +3 -3
- package/dist/connectors/discord.js +2 -1
- package/dist/connectors/gh.d.ts +4 -3
- package/dist/connectors/gh.js +2 -1
- package/dist/connectors/schedule.d.ts +1 -1
- package/dist/connectors/schedule.js +2 -1
- package/dist/connectors/slack.d.ts +2 -2
- package/dist/connectors/slack.js +2 -1
- package/dist/discord-connector-schema-CBDyGdOI.js +21 -0
- package/dist/{discord-connector-schema-BeThExJp.js → discord-listener-_jSE3HsQ.js} +2 -22
- package/dist/file-system-BeOKXjlV.d.ts +26 -0
- package/dist/file-system-PWKKU7lA.js +9 -0
- package/dist/gateway.d.ts +3 -0
- package/dist/gateway.js +2 -0
- package/dist/gh-connector-schema-eoTtHbY6.d.ts +14 -0
- package/dist/{gh-connector-schema-eYE4g77K.js → gh-connector-schema-o3Q1-ojL.js} +1 -176
- package/dist/gh-listener-DH-fClQm.js +178 -0
- package/dist/index-BM0-f6KL.d.ts +3404 -0
- package/dist/index.d.ts +11 -4083
- package/dist/index.js +247 -3459
- package/dist/local-config-json-schema-8IHjS4Q7.js +439 -0
- package/dist/local-config-sync-BdsrDZOu.d.ts +381 -0
- package/dist/local-config.d.ts +3 -0
- package/dist/local-config.js +3 -0
- package/dist/logger-BP6SisKt.js +9 -0
- package/dist/mcp-Dr-nIBwN.js +253 -0
- package/dist/memory-connector-diagnostic-log-CrW1ltLM.js +2245 -0
- package/dist/memory-token-prompter-B5FFCsGP.d.ts +57 -0
- package/dist/memory-token-prompter-CLerGsgM.js +61 -0
- package/dist/node-file-system-BcrmWN9I.js +48 -0
- package/dist/{gh-connector-schema-CQmEWzdV.d.ts → process-runner-DfniuWVU.d.ts} +1 -14
- package/dist/profiles-f0mNmEyP.d.ts +64 -0
- package/dist/profiles-wMRnjSid.js +129 -0
- package/dist/profiles.d.ts +2 -0
- package/dist/profiles.js +2 -0
- package/dist/schedule-connector-schema-iCI61gzU.js +31 -0
- package/dist/{schedule-listener-3M6WkH1Y.d.ts → schedule-listener-CUyUFFR1.d.ts} +22 -46
- package/dist/{schedule-connector-schema-CM-sRkac.js → schedule-listener-ePAjians.js} +3 -86
- package/dist/settings-reader-BSU6JyvM.d.ts +167 -0
- package/dist/settings-reader-DPqrpV7s.js +11 -0
- package/dist/settings-store-D2XSXTyt.js +186 -0
- package/dist/slack-connector-schema-BCNWluHM.js +32 -0
- package/dist/{slack-listener-9UdAn_ui.d.ts → slack-listener-Bv5xI9gC.d.ts} +31 -31
- package/dist/{slack-connector-schema-DDbSGPZn.js → slack-listener-ClQuHhEF.js} +2 -32
- package/package.json +6 -1
- /package/dist/{connector-adapter-VA6undzc.d.ts → connector-adapter-DKgsVuMH.d.ts} +0 -0
- /package/dist/{discord-connector-schema-DF4pL3Sc.d.ts → discord-connector-schema-R0Uu-3ns.d.ts} +0 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
//#region lib/engine/settings/settings-schema.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Routing mode when multiple WS clients are subscribed to the same channel.
|
|
6
|
+
*
|
|
7
|
+
* - `fanout` (default): every connected client receives every event. Right when each
|
|
8
|
+
* subscriber has its own job (e.g., TUI mirrors, distinct Claude profiles each running
|
|
9
|
+
* their own pipeline against the same source).
|
|
10
|
+
* - `exclusive`: each event is delivered to exactly one connected client, picked
|
|
11
|
+
* round-robin per channel. Right when subscribers are interchangeable workers and you
|
|
12
|
+
* want each event handled once. Tap=all clients (TUI dashboard) always receive,
|
|
13
|
+
* regardless of mode, so they can passively observe.
|
|
14
|
+
*/
|
|
15
|
+
declare const channelDeliveryModeSchema: z.ZodEnum<{
|
|
16
|
+
fanout: "fanout";
|
|
17
|
+
exclusive: "exclusive";
|
|
18
|
+
}>;
|
|
19
|
+
type ChannelDeliveryMode = z.infer<typeof channelDeliveryModeSchema>;
|
|
20
|
+
declare const channelConfigSchema: z.ZodObject<{
|
|
21
|
+
id: z.ZodString;
|
|
22
|
+
name: z.ZodString;
|
|
23
|
+
delivery: z.ZodDefault<z.ZodEnum<{
|
|
24
|
+
fanout: "fanout";
|
|
25
|
+
exclusive: "exclusive";
|
|
26
|
+
}>>;
|
|
27
|
+
connectors: z.ZodDefault<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
28
|
+
id: z.ZodString;
|
|
29
|
+
name: z.ZodString;
|
|
30
|
+
type: z.ZodLiteral<"slack">;
|
|
31
|
+
botToken: z.ZodOptional<z.ZodString>;
|
|
32
|
+
appToken: z.ZodOptional<z.ZodString>;
|
|
33
|
+
botTokenEnv: z.ZodOptional<z.ZodString>;
|
|
34
|
+
appTokenEnv: z.ZodOptional<z.ZodString>;
|
|
35
|
+
minify: z.ZodDefault<z.ZodBoolean>;
|
|
36
|
+
createdAt: z.ZodOptional<z.ZodString>;
|
|
37
|
+
updatedAt: z.ZodOptional<z.ZodString>;
|
|
38
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
39
|
+
id: z.ZodString;
|
|
40
|
+
name: z.ZodString;
|
|
41
|
+
type: z.ZodLiteral<"gh">;
|
|
42
|
+
pollInterval: z.ZodOptional<z.ZodNumber>;
|
|
43
|
+
createdAt: z.ZodOptional<z.ZodString>;
|
|
44
|
+
updatedAt: z.ZodOptional<z.ZodString>;
|
|
45
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
46
|
+
id: z.ZodString;
|
|
47
|
+
name: z.ZodString;
|
|
48
|
+
type: z.ZodLiteral<"discord">;
|
|
49
|
+
botToken: z.ZodOptional<z.ZodString>;
|
|
50
|
+
botTokenEnv: z.ZodOptional<z.ZodString>;
|
|
51
|
+
createdAt: z.ZodOptional<z.ZodString>;
|
|
52
|
+
updatedAt: z.ZodOptional<z.ZodString>;
|
|
53
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
54
|
+
id: z.ZodString;
|
|
55
|
+
name: z.ZodString;
|
|
56
|
+
type: z.ZodLiteral<"schedule">;
|
|
57
|
+
entries: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
58
|
+
id: z.ZodString;
|
|
59
|
+
cron: z.ZodString;
|
|
60
|
+
prompt: z.ZodString;
|
|
61
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
62
|
+
catchupPolicy: z.ZodDefault<z.ZodEnum<{
|
|
63
|
+
latest: "latest";
|
|
64
|
+
all: "all";
|
|
65
|
+
skip: "skip";
|
|
66
|
+
}>>;
|
|
67
|
+
}, z.core.$strip>>>;
|
|
68
|
+
createdAt: z.ZodOptional<z.ZodString>;
|
|
69
|
+
updatedAt: z.ZodOptional<z.ZodString>;
|
|
70
|
+
}, z.core.$strip>], "type">>>;
|
|
71
|
+
}, z.core.$strip>;
|
|
72
|
+
type ChannelConfig = z.infer<typeof channelConfigSchema>;
|
|
73
|
+
declare const profileConfigSchema: z.ZodObject<{
|
|
74
|
+
id: z.ZodString;
|
|
75
|
+
name: z.ZodString;
|
|
76
|
+
path: z.ZodString;
|
|
77
|
+
channelId: z.ZodString;
|
|
78
|
+
options: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
79
|
+
env: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
80
|
+
resume: z.ZodDefault<z.ZodBoolean>;
|
|
81
|
+
sessionId: z.ZodOptional<z.ZodString>;
|
|
82
|
+
}, z.core.$strip>;
|
|
83
|
+
type ProfileConfig = z.infer<typeof profileConfigSchema>;
|
|
84
|
+
declare const SETTINGS_VERSION = 1;
|
|
85
|
+
declare const settingsSchema: z.ZodObject<{
|
|
86
|
+
version: z.ZodDefault<z.ZodLiteral<1>>;
|
|
87
|
+
channels: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
88
|
+
id: z.ZodString;
|
|
89
|
+
name: z.ZodString;
|
|
90
|
+
delivery: z.ZodDefault<z.ZodEnum<{
|
|
91
|
+
fanout: "fanout";
|
|
92
|
+
exclusive: "exclusive";
|
|
93
|
+
}>>;
|
|
94
|
+
connectors: z.ZodDefault<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
95
|
+
id: z.ZodString;
|
|
96
|
+
name: z.ZodString;
|
|
97
|
+
type: z.ZodLiteral<"slack">;
|
|
98
|
+
botToken: z.ZodOptional<z.ZodString>;
|
|
99
|
+
appToken: z.ZodOptional<z.ZodString>;
|
|
100
|
+
botTokenEnv: z.ZodOptional<z.ZodString>;
|
|
101
|
+
appTokenEnv: z.ZodOptional<z.ZodString>;
|
|
102
|
+
minify: z.ZodDefault<z.ZodBoolean>;
|
|
103
|
+
createdAt: z.ZodOptional<z.ZodString>;
|
|
104
|
+
updatedAt: z.ZodOptional<z.ZodString>;
|
|
105
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
106
|
+
id: z.ZodString;
|
|
107
|
+
name: z.ZodString;
|
|
108
|
+
type: z.ZodLiteral<"gh">;
|
|
109
|
+
pollInterval: z.ZodOptional<z.ZodNumber>;
|
|
110
|
+
createdAt: z.ZodOptional<z.ZodString>;
|
|
111
|
+
updatedAt: z.ZodOptional<z.ZodString>;
|
|
112
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
113
|
+
id: z.ZodString;
|
|
114
|
+
name: z.ZodString;
|
|
115
|
+
type: z.ZodLiteral<"discord">;
|
|
116
|
+
botToken: z.ZodOptional<z.ZodString>;
|
|
117
|
+
botTokenEnv: z.ZodOptional<z.ZodString>;
|
|
118
|
+
createdAt: z.ZodOptional<z.ZodString>;
|
|
119
|
+
updatedAt: z.ZodOptional<z.ZodString>;
|
|
120
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
121
|
+
id: z.ZodString;
|
|
122
|
+
name: z.ZodString;
|
|
123
|
+
type: z.ZodLiteral<"schedule">;
|
|
124
|
+
entries: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
125
|
+
id: z.ZodString;
|
|
126
|
+
cron: z.ZodString;
|
|
127
|
+
prompt: z.ZodString;
|
|
128
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
129
|
+
catchupPolicy: z.ZodDefault<z.ZodEnum<{
|
|
130
|
+
latest: "latest";
|
|
131
|
+
all: "all";
|
|
132
|
+
skip: "skip";
|
|
133
|
+
}>>;
|
|
134
|
+
}, z.core.$strip>>>;
|
|
135
|
+
createdAt: z.ZodOptional<z.ZodString>;
|
|
136
|
+
updatedAt: z.ZodOptional<z.ZodString>;
|
|
137
|
+
}, z.core.$strip>], "type">>>;
|
|
138
|
+
}, z.core.$strip>>>;
|
|
139
|
+
profiles: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
140
|
+
id: z.ZodString;
|
|
141
|
+
name: z.ZodString;
|
|
142
|
+
path: z.ZodString;
|
|
143
|
+
channelId: z.ZodString;
|
|
144
|
+
options: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
145
|
+
env: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
146
|
+
resume: z.ZodDefault<z.ZodBoolean>;
|
|
147
|
+
sessionId: z.ZodOptional<z.ZodString>;
|
|
148
|
+
}, z.core.$strip>>>;
|
|
149
|
+
}, z.core.$strip>;
|
|
150
|
+
type Settings = z.infer<typeof settingsSchema>;
|
|
151
|
+
//#endregion
|
|
152
|
+
//#region lib/engine/id/id-generator.d.ts
|
|
153
|
+
/**
|
|
154
|
+
* ID generator boundary. Default NodeFunnelIdGenerator wraps `crypto.randomUUID()`;
|
|
155
|
+
* MemoryFunnelIdGenerator emits `<prefix>-1, <prefix>-2, ...` for deterministic tests.
|
|
156
|
+
*/
|
|
157
|
+
declare abstract class FunnelIdGenerator {
|
|
158
|
+
abstract generate(): string;
|
|
159
|
+
}
|
|
160
|
+
//#endregion
|
|
161
|
+
//#region lib/engine/settings/settings-reader.d.ts
|
|
162
|
+
declare abstract class FunnelSettingsReader {
|
|
163
|
+
abstract read(): Settings;
|
|
164
|
+
abstract write(settings: Settings): void;
|
|
165
|
+
}
|
|
166
|
+
//#endregion
|
|
167
|
+
export { ProfileConfig as a, channelConfigSchema as c, settingsSchema as d, ChannelDeliveryMode as i, channelDeliveryModeSchema as l, FunnelIdGenerator as n, SETTINGS_VERSION as o, ChannelConfig as r, Settings as s, FunnelSettingsReader as t, profileConfigSchema as u };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region lib/engine/id/id-generator.ts
|
|
2
|
+
/**
|
|
3
|
+
* ID generator boundary. Default NodeFunnelIdGenerator wraps `crypto.randomUUID()`;
|
|
4
|
+
* MemoryFunnelIdGenerator emits `<prefix>-1, <prefix>-2, ...` for deterministic tests.
|
|
5
|
+
*/
|
|
6
|
+
var FunnelIdGenerator = class {};
|
|
7
|
+
//#endregion
|
|
8
|
+
//#region lib/engine/settings/settings-reader.ts
|
|
9
|
+
var FunnelSettingsReader = class {};
|
|
10
|
+
//#endregion
|
|
11
|
+
export { FunnelIdGenerator as n, FunnelSettingsReader as t };
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { t as ghConnectorSchema } from "./gh-connector-schema-o3Q1-ojL.js";
|
|
2
|
+
import { t as NodeFunnelFileSystem } from "./node-file-system-BcrmWN9I.js";
|
|
3
|
+
import { n as FunnelIdGenerator, t as FunnelSettingsReader } from "./settings-reader-DPqrpV7s.js";
|
|
4
|
+
import { t as discordConnectorSchema } from "./discord-connector-schema-CBDyGdOI.js";
|
|
5
|
+
import { n as scheduleConnectorSchema } from "./schedule-connector-schema-iCI61gzU.js";
|
|
6
|
+
import { t as slackConnectorSchema } from "./slack-connector-schema-BCNWluHM.js";
|
|
7
|
+
import { dirname, join } from "node:path";
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
import { homedir } from "node:os";
|
|
10
|
+
//#region lib/engine/id/node-id-generator.ts
|
|
11
|
+
var NodeFunnelIdGenerator = class extends FunnelIdGenerator {
|
|
12
|
+
generate() {
|
|
13
|
+
return crypto.randomUUID();
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
//#endregion
|
|
17
|
+
//#region lib/connectors/connector-config-schema.ts
|
|
18
|
+
const connectorConfigSchema = z.discriminatedUnion("type", [
|
|
19
|
+
slackConnectorSchema,
|
|
20
|
+
ghConnectorSchema,
|
|
21
|
+
discordConnectorSchema,
|
|
22
|
+
scheduleConnectorSchema
|
|
23
|
+
]);
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region lib/engine/settings/settings-schema.ts
|
|
26
|
+
/**
|
|
27
|
+
* Routing mode when multiple WS clients are subscribed to the same channel.
|
|
28
|
+
*
|
|
29
|
+
* - `fanout` (default): every connected client receives every event. Right when each
|
|
30
|
+
* subscriber has its own job (e.g., TUI mirrors, distinct Claude profiles each running
|
|
31
|
+
* their own pipeline against the same source).
|
|
32
|
+
* - `exclusive`: each event is delivered to exactly one connected client, picked
|
|
33
|
+
* round-robin per channel. Right when subscribers are interchangeable workers and you
|
|
34
|
+
* want each event handled once. Tap=all clients (TUI dashboard) always receive,
|
|
35
|
+
* regardless of mode, so they can passively observe.
|
|
36
|
+
*/
|
|
37
|
+
const channelDeliveryModeSchema = z.enum(["fanout", "exclusive"]);
|
|
38
|
+
const channelConfigSchema = z.object({
|
|
39
|
+
id: z.string(),
|
|
40
|
+
name: z.string(),
|
|
41
|
+
delivery: channelDeliveryModeSchema.default("fanout"),
|
|
42
|
+
connectors: z.array(connectorConfigSchema).default([])
|
|
43
|
+
});
|
|
44
|
+
const profileConfigSchema = z.object({
|
|
45
|
+
/** Stable identity (uuid). The primary key everything internal resolves to;
|
|
46
|
+
* survives renames. CLI surfaces still address profiles by `name`. */
|
|
47
|
+
id: z.string(),
|
|
48
|
+
/** Human-facing label used only at the CLI/TUI surface (`--profile <name>`).
|
|
49
|
+
* Renameable; never used as a storage key. */
|
|
50
|
+
name: z.string(),
|
|
51
|
+
path: z.string(),
|
|
52
|
+
channelId: z.string(),
|
|
53
|
+
/** Args prepended to the claude argv on every launch through this profile. */
|
|
54
|
+
options: z.array(z.string()).default([]),
|
|
55
|
+
/** Env vars layered under the launched claude process. process.env wins on collision. */
|
|
56
|
+
env: z.record(z.string(), z.string()).default({}),
|
|
57
|
+
/**
|
|
58
|
+
* When true (the default), funnel resumes this profile's previous claude
|
|
59
|
+
* session via `--session-id`/`--resume`. The id lives in `sessionId` below,
|
|
60
|
+
* scoped to this profile so an unrelated session in the same repo can't bleed
|
|
61
|
+
* in. Set to false for profiles that should always start fresh.
|
|
62
|
+
*/
|
|
63
|
+
resume: z.boolean().default(true),
|
|
64
|
+
/**
|
|
65
|
+
* Execution state, not config: the claude session id this profile last
|
|
66
|
+
* launched. Written by the launcher, read on the next resume. Absent until
|
|
67
|
+
* the first launch; kept inside the profile (rather than a separate file) so
|
|
68
|
+
* the session belongs to the profile by identity and the transport layer
|
|
69
|
+
* (channels) never has to know profiles exist.
|
|
70
|
+
*/
|
|
71
|
+
sessionId: z.string().optional()
|
|
72
|
+
});
|
|
73
|
+
const SETTINGS_VERSION = 1;
|
|
74
|
+
const settingsSchema = z.object({
|
|
75
|
+
/** Schema version. New files always write the current version; older files without one are read as v1. */
|
|
76
|
+
version: z.literal(1).default(1),
|
|
77
|
+
channels: z.array(channelConfigSchema).default([]),
|
|
78
|
+
profiles: z.array(profileConfigSchema).default([])
|
|
79
|
+
});
|
|
80
|
+
//#endregion
|
|
81
|
+
//#region lib/engine/settings/settings-store.ts
|
|
82
|
+
/**
|
|
83
|
+
* Resolves the funnel home dir. Defaults to `~/.funnel`, overridable via
|
|
84
|
+
* `FUNNEL_DIR` so a funnel.json-scoped launch can point everything (settings,
|
|
85
|
+
* gateway pid/token, claude pids) at a repo-local `<repo>/.funnel` and never
|
|
86
|
+
* touch the global home. Read at call time, not module load, so a daemon
|
|
87
|
+
* spawned with the env set resolves the override.
|
|
88
|
+
*/
|
|
89
|
+
function resolveFunnelDir() {
|
|
90
|
+
const override = process.env.FUNNEL_DIR;
|
|
91
|
+
if (override && override.length > 0) return override;
|
|
92
|
+
return join(homedir(), ".funnel");
|
|
93
|
+
}
|
|
94
|
+
const DEFAULT_GATEWAY_PORT = 9742;
|
|
95
|
+
/**
|
|
96
|
+
* Resolves the gateway port. Defaults to 9742 — the port a programmatically
|
|
97
|
+
* hosted gateway (`new Funnel().gatewayServer()`) uses. The `funnel` CLI entry
|
|
98
|
+
* sets `FUNNEL_PORT` to a distinct default so a CLI launch never collides with
|
|
99
|
+
* an embedding app's gateway on 9742. Read at call time so a daemon spawned
|
|
100
|
+
* with the env set resolves the override.
|
|
101
|
+
*/
|
|
102
|
+
function resolveFunnelPort() {
|
|
103
|
+
return Number(process.env.FUNNEL_PORT) || 9742;
|
|
104
|
+
}
|
|
105
|
+
const FUNNEL_DIR = join(homedir(), ".funnel");
|
|
106
|
+
const SETTINGS_PATH = join(FUNNEL_DIR, "settings.json");
|
|
107
|
+
const defaultFs = new NodeFunnelFileSystem();
|
|
108
|
+
const defaultIdGenerator = new NodeFunnelIdGenerator();
|
|
109
|
+
var FunnelSettingsStore = class extends FunnelSettingsReader {
|
|
110
|
+
path;
|
|
111
|
+
fs;
|
|
112
|
+
idGenerator;
|
|
113
|
+
constructor(deps = {}) {
|
|
114
|
+
super();
|
|
115
|
+
this.path = deps.path ?? SETTINGS_PATH;
|
|
116
|
+
this.fs = deps.fs ?? defaultFs;
|
|
117
|
+
this.idGenerator = deps.idGenerator ?? defaultIdGenerator;
|
|
118
|
+
Object.freeze(this);
|
|
119
|
+
}
|
|
120
|
+
read() {
|
|
121
|
+
if (!this.fs.existsSync(this.path)) return {
|
|
122
|
+
version: 1,
|
|
123
|
+
channels: [],
|
|
124
|
+
profiles: []
|
|
125
|
+
};
|
|
126
|
+
const content = this.fs.readFileSync(this.path);
|
|
127
|
+
const parsed = JSON.parse(content);
|
|
128
|
+
if (this.looksLikeLegacy(parsed)) throw new Error(`legacy settings.json detected at ${this.path}. The schema changed (channel.connectors are now nested objects with ids; profile fields renamed). Migration is intentionally not provided. Back up and remove the old file:\n mv ${this.path} ${this.path}.bak`);
|
|
129
|
+
if (parsed && typeof parsed === "object" && "version" in parsed && parsed.version !== 1) throw new Error(`unsupported settings.json version (${this.path}): expected 1, got ${String(parsed.version)}`);
|
|
130
|
+
const minted = this.backfillProfileIds(parsed);
|
|
131
|
+
const result = settingsSchema.safeParse(parsed);
|
|
132
|
+
if (!result.success) throw new Error(`invalid settings.json (${this.path}): ${result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join(", ")}`);
|
|
133
|
+
if (minted) this.write(result.data);
|
|
134
|
+
return result.data;
|
|
135
|
+
}
|
|
136
|
+
looksLikeLegacy(parsed) {
|
|
137
|
+
if (!parsed || typeof parsed !== "object") return false;
|
|
138
|
+
const obj = parsed;
|
|
139
|
+
if (Array.isArray(obj.channels)) for (const channel of obj.channels) {
|
|
140
|
+
if (!channel || typeof channel !== "object") continue;
|
|
141
|
+
const ch = channel;
|
|
142
|
+
if (Array.isArray(ch.connectors) && ch.connectors.some((x) => typeof x === "string")) return true;
|
|
143
|
+
if (!("id" in ch) && "name" in ch) return true;
|
|
144
|
+
}
|
|
145
|
+
if (Array.isArray(obj.connectors)) return true;
|
|
146
|
+
if (Array.isArray(obj.repositories)) return true;
|
|
147
|
+
if (Array.isArray(obj.profiles)) for (const profile of obj.profiles) {
|
|
148
|
+
if (!profile || typeof profile !== "object") continue;
|
|
149
|
+
const p = profile;
|
|
150
|
+
if ("repository" in p || "envFiles" in p || "channel" in p && !("channelId" in p)) return true;
|
|
151
|
+
}
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Non-destructive migration for profiles written before `id` existed. Mints a
|
|
156
|
+
* uuid for each profile lacking one and returns whether anything was minted, so
|
|
157
|
+
* `read` can persist it immediately — a profile id must be STABLE across reads,
|
|
158
|
+
* otherwise `setSessionId` (a second read) sees a different id and can't match
|
|
159
|
+
* the one the launch used. Mutates `parsed` in place (freshly JSON-parsed).
|
|
160
|
+
*/
|
|
161
|
+
backfillProfileIds(parsed) {
|
|
162
|
+
if (!parsed || typeof parsed !== "object") return false;
|
|
163
|
+
const obj = parsed;
|
|
164
|
+
if (!Array.isArray(obj.profiles)) return false;
|
|
165
|
+
let minted = false;
|
|
166
|
+
for (const profile of obj.profiles) {
|
|
167
|
+
if (!profile || typeof profile !== "object") continue;
|
|
168
|
+
const p = profile;
|
|
169
|
+
if (typeof p.id !== "string") {
|
|
170
|
+
p.id = this.idGenerator.generate();
|
|
171
|
+
minted = true;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return minted;
|
|
175
|
+
}
|
|
176
|
+
write(settings) {
|
|
177
|
+
this.fs.mkdirSync(dirname(this.path), { recursive: true });
|
|
178
|
+
const versioned = {
|
|
179
|
+
...settings,
|
|
180
|
+
version: 1
|
|
181
|
+
};
|
|
182
|
+
this.fs.writeSecretFileSync(this.path, `${JSON.stringify(versioned, null, 2)}\n`);
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
//#endregion
|
|
186
|
+
export { resolveFunnelDir as a, channelConfigSchema as c, settingsSchema as d, connectorConfigSchema as f, SETTINGS_PATH as i, channelDeliveryModeSchema as l, FUNNEL_DIR as n, resolveFunnelPort as o, NodeFunnelIdGenerator as p, FunnelSettingsStore as r, SETTINGS_VERSION as s, DEFAULT_GATEWAY_PORT as t, profileConfigSchema as u };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
//#region lib/connectors/slack-connector-schema.ts
|
|
3
|
+
/**
|
|
4
|
+
* A slack connector resolves its tokens one of two ways, set at sync time:
|
|
5
|
+
*
|
|
6
|
+
* - literal: `botToken` / `appToken` hold the real `xoxb-`/`xapp-` secret
|
|
7
|
+
* (set by a `fnl channels` command or a TTY prompt at launch).
|
|
8
|
+
* - by reference: `botTokenEnv` / `appTokenEnv` hold the *name* of an env var.
|
|
9
|
+
* The secret never lands in settings.json; the listener resolves it from
|
|
10
|
+
* `process.env` at start. This form is only set through the engine API
|
|
11
|
+
* (`new Funnel(...)`) — funnel.json and the `fnl` CLI produce literals.
|
|
12
|
+
*
|
|
13
|
+
* Both are optional at the schema level (a discriminated-union member can't
|
|
14
|
+
* carry a cross-field refine); the listener requires exactly one resolved
|
|
15
|
+
* token per slot and errors loudly otherwise.
|
|
16
|
+
*/
|
|
17
|
+
const slackConnectorSchema = z.object({
|
|
18
|
+
id: z.string(),
|
|
19
|
+
name: z.string(),
|
|
20
|
+
type: z.literal("slack"),
|
|
21
|
+
botToken: z.string().startsWith("xoxb-").optional(),
|
|
22
|
+
appToken: z.string().startsWith("xapp-").optional(),
|
|
23
|
+
/** Name of the env var holding the bot token, resolved at listener start. */
|
|
24
|
+
botTokenEnv: z.string().optional(),
|
|
25
|
+
/** Name of the env var holding the app token, resolved at listener start. */
|
|
26
|
+
appTokenEnv: z.string().optional(),
|
|
27
|
+
minify: z.boolean().default(true),
|
|
28
|
+
createdAt: z.string().datetime().optional(),
|
|
29
|
+
updatedAt: z.string().datetime().optional()
|
|
30
|
+
});
|
|
31
|
+
//#endregion
|
|
32
|
+
export { slackConnectorSchema as t };
|
|
@@ -1,36 +1,7 @@
|
|
|
1
|
-
import { S as
|
|
1
|
+
import { S as FunnelLogger, b as FunnelConnectorListener, o as ConnectorDiagnosticLog, x as NotifyFn } from "./connector-diagnostic-log-yTOojKUR.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { App } from "@slack/bolt";
|
|
4
4
|
|
|
5
|
-
//#region lib/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
|
|
34
5
|
//#region lib/connectors/slack-event-processor.d.ts
|
|
35
6
|
type SlackRawEvent = Record<string, unknown>;
|
|
36
7
|
/**
|
|
@@ -70,6 +41,35 @@ declare class FunnelSlackEventProcessor {
|
|
|
70
41
|
process(event: SlackRawEvent): SlackProcessed;
|
|
71
42
|
}
|
|
72
43
|
//#endregion
|
|
44
|
+
//#region lib/connectors/slack-connector-schema.d.ts
|
|
45
|
+
/**
|
|
46
|
+
* A slack connector resolves its tokens one of two ways, set at sync time:
|
|
47
|
+
*
|
|
48
|
+
* - literal: `botToken` / `appToken` hold the real `xoxb-`/`xapp-` secret
|
|
49
|
+
* (set by a `fnl channels` command or a TTY prompt at launch).
|
|
50
|
+
* - by reference: `botTokenEnv` / `appTokenEnv` hold the *name* of an env var.
|
|
51
|
+
* The secret never lands in settings.json; the listener resolves it from
|
|
52
|
+
* `process.env` at start. This form is only set through the engine API
|
|
53
|
+
* (`new Funnel(...)`) — funnel.json and the `fnl` CLI produce literals.
|
|
54
|
+
*
|
|
55
|
+
* Both are optional at the schema level (a discriminated-union member can't
|
|
56
|
+
* carry a cross-field refine); the listener requires exactly one resolved
|
|
57
|
+
* token per slot and errors loudly otherwise.
|
|
58
|
+
*/
|
|
59
|
+
declare const slackConnectorSchema: z.ZodObject<{
|
|
60
|
+
id: z.ZodString;
|
|
61
|
+
name: z.ZodString;
|
|
62
|
+
type: z.ZodLiteral<"slack">;
|
|
63
|
+
botToken: z.ZodOptional<z.ZodString>;
|
|
64
|
+
appToken: z.ZodOptional<z.ZodString>;
|
|
65
|
+
botTokenEnv: z.ZodOptional<z.ZodString>;
|
|
66
|
+
appTokenEnv: z.ZodOptional<z.ZodString>;
|
|
67
|
+
minify: z.ZodDefault<z.ZodBoolean>;
|
|
68
|
+
createdAt: z.ZodOptional<z.ZodString>;
|
|
69
|
+
updatedAt: z.ZodOptional<z.ZodString>;
|
|
70
|
+
}, z.core.$strip>;
|
|
71
|
+
type SlackConnectorConfig = z.infer<typeof slackConnectorSchema>;
|
|
72
|
+
//#endregion
|
|
73
73
|
//#region lib/connectors/slack-listener.d.ts
|
|
74
74
|
type SlackOnAppCreated = (app: App) => void | Promise<void>;
|
|
75
75
|
type SlackPreprocessEvent = (event: SlackRawEvent) => SlackRawEvent | null;
|
|
@@ -108,4 +108,4 @@ declare class FunnelSlackListener extends FunnelConnectorListener {
|
|
|
108
108
|
private recordConnection;
|
|
109
109
|
}
|
|
110
110
|
//#endregion
|
|
111
|
-
export {
|
|
111
|
+
export { slackConnectorSchema as a, SlackProcessedEmit as c, SlackSkipReason as d, SlackConnectorConfig as i, SlackProcessedSkip as l, SlackOnAppCreated as n, FunnelSlackEventProcessor as o, SlackPreprocessEvent as r, SlackProcessed as s, FunnelSlackListener as t, SlackRawEvent as u };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as FunnelConnectorAdapter } from "./connector-adapter-D5Utumgz.js";
|
|
2
2
|
import { t as resolveConnectorToken } from "./resolve-connector-token-BHmZLRrV.js";
|
|
3
|
-
import {
|
|
3
|
+
import { t as FunnelConnectorListener } from "./connector-listener-DU54DN-f.js";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import { WebClient } from "@slack/web-api";
|
|
6
6
|
import { App, LogLevel } from "@slack/bolt";
|
|
@@ -364,34 +364,4 @@ const messageOf = (error) => {
|
|
|
364
364
|
return error instanceof Error ? error.message : String(error);
|
|
365
365
|
};
|
|
366
366
|
//#endregion
|
|
367
|
-
|
|
368
|
-
/**
|
|
369
|
-
* A slack connector resolves its tokens one of two ways, set at sync time:
|
|
370
|
-
*
|
|
371
|
-
* - literal: `botToken` / `appToken` hold the real `xoxb-`/`xapp-` secret
|
|
372
|
-
* (set by a `fnl channels` command or a TTY prompt at launch).
|
|
373
|
-
* - by reference: `botTokenEnv` / `appTokenEnv` hold the *name* of an env var.
|
|
374
|
-
* The secret never lands in settings.json; the listener resolves it from
|
|
375
|
-
* `process.env` at start. This form is only set through the engine API
|
|
376
|
-
* (`new Funnel(...)`) — funnel.json and the `fnl` CLI produce literals.
|
|
377
|
-
*
|
|
378
|
-
* Both are optional at the schema level (a discriminated-union member can't
|
|
379
|
-
* carry a cross-field refine); the listener requires exactly one resolved
|
|
380
|
-
* token per slot and errors loudly otherwise.
|
|
381
|
-
*/
|
|
382
|
-
const slackConnectorSchema = z.object({
|
|
383
|
-
id: z.string(),
|
|
384
|
-
name: z.string(),
|
|
385
|
-
type: z.literal("slack"),
|
|
386
|
-
botToken: z.string().startsWith("xoxb-").optional(),
|
|
387
|
-
appToken: z.string().startsWith("xapp-").optional(),
|
|
388
|
-
/** Name of the env var holding the bot token, resolved at listener start. */
|
|
389
|
-
botTokenEnv: z.string().optional(),
|
|
390
|
-
/** Name of the env var holding the app token, resolved at listener start. */
|
|
391
|
-
appTokenEnv: z.string().optional(),
|
|
392
|
-
minify: z.boolean().default(true),
|
|
393
|
-
createdAt: z.string().datetime().optional(),
|
|
394
|
-
updatedAt: z.string().datetime().optional()
|
|
395
|
-
});
|
|
396
|
-
//#endregion
|
|
397
|
-
export { FunnelSlackAdapter as i, FunnelSlackListener as n, FunnelSlackEventProcessor as r, slackConnectorSchema as t };
|
|
367
|
+
export { FunnelSlackEventProcessor as n, FunnelSlackAdapter as r, FunnelSlackListener as t };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@interactive-inc/claude-funnel",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.51.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",
|
|
@@ -42,6 +42,11 @@
|
|
|
42
42
|
"import": "./dist/index.js",
|
|
43
43
|
"default": "./dist/index.js"
|
|
44
44
|
},
|
|
45
|
+
"./claude": {
|
|
46
|
+
"types": "./dist/claude.d.ts",
|
|
47
|
+
"import": "./dist/claude.js",
|
|
48
|
+
"default": "./dist/claude.js"
|
|
49
|
+
},
|
|
45
50
|
"./gateway": {
|
|
46
51
|
"types": "./dist/gateway.d.ts",
|
|
47
52
|
"import": "./dist/gateway.js",
|
|
File without changes
|
/package/dist/{discord-connector-schema-DF4pL3Sc.d.ts → discord-connector-schema-R0Uu-3ns.d.ts}
RENAMED
|
File without changes
|