@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
package/dist/index.d.ts
CHANGED
|
@@ -64,7 +64,7 @@ type SlackListenerOptions = {
|
|
|
64
64
|
type ScheduleListenerOptions = {
|
|
65
65
|
onFired?: ScheduleOnFired;
|
|
66
66
|
};
|
|
67
|
-
type Deps$
|
|
67
|
+
type Deps$15 = {
|
|
68
68
|
fs?: FunnelFileSystem;
|
|
69
69
|
process?: FunnelProcessRunner;
|
|
70
70
|
logger?: FunnelLogger;
|
|
@@ -91,7 +91,7 @@ declare class FunnelConnectorFactory {
|
|
|
91
91
|
private readonly dir;
|
|
92
92
|
private readonly slackListenerOptions;
|
|
93
93
|
private readonly scheduleListenerOptions;
|
|
94
|
-
constructor(deps?: Deps$
|
|
94
|
+
constructor(deps?: Deps$15);
|
|
95
95
|
createListener(channelId: string, config: ConnectorConfig): FunnelConnectorListener;
|
|
96
96
|
createAdapter(config: ConnectorConfig): FunnelConnectorAdapter | null;
|
|
97
97
|
connectorDir(channelId: string, connectorId: string): string;
|
|
@@ -195,12 +195,14 @@ declare const channelConfigSchema: z.ZodObject<{
|
|
|
195
195
|
}, z.core.$strip>;
|
|
196
196
|
type ChannelConfig = z.infer<typeof channelConfigSchema>;
|
|
197
197
|
declare const profileConfigSchema: z.ZodObject<{
|
|
198
|
+
id: z.ZodString;
|
|
198
199
|
name: z.ZodString;
|
|
199
200
|
path: z.ZodString;
|
|
200
201
|
channelId: z.ZodString;
|
|
201
202
|
options: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
202
203
|
env: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
203
204
|
resume: z.ZodDefault<z.ZodBoolean>;
|
|
205
|
+
sessionId: z.ZodOptional<z.ZodString>;
|
|
204
206
|
}, z.core.$strip>;
|
|
205
207
|
type ProfileConfig = z.infer<typeof profileConfigSchema>;
|
|
206
208
|
declare const SETTINGS_VERSION = 1;
|
|
@@ -256,12 +258,14 @@ declare const settingsSchema: z.ZodObject<{
|
|
|
256
258
|
}, z.core.$strip>], "type">>>;
|
|
257
259
|
}, z.core.$strip>>>;
|
|
258
260
|
profiles: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
261
|
+
id: z.ZodString;
|
|
259
262
|
name: z.ZodString;
|
|
260
263
|
path: z.ZodString;
|
|
261
264
|
channelId: z.ZodString;
|
|
262
265
|
options: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
263
266
|
env: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
264
267
|
resume: z.ZodDefault<z.ZodBoolean>;
|
|
268
|
+
sessionId: z.ZodOptional<z.ZodString>;
|
|
265
269
|
}, z.core.$strip>>>;
|
|
266
270
|
}, z.core.$strip>;
|
|
267
271
|
type Settings = z.infer<typeof settingsSchema>;
|
|
@@ -273,7 +277,7 @@ declare abstract class FunnelSettingsReader {
|
|
|
273
277
|
}
|
|
274
278
|
//#endregion
|
|
275
279
|
//#region lib/engine/channels/channels.d.ts
|
|
276
|
-
type Deps$
|
|
280
|
+
type Deps$14 = {
|
|
277
281
|
store: FunnelSettingsReader;
|
|
278
282
|
factory: FunnelConnectorFactory;
|
|
279
283
|
profileChecker: ProfileChannelChecker;
|
|
@@ -317,7 +321,7 @@ declare class FunnelChannels {
|
|
|
317
321
|
private readonly profileChecker;
|
|
318
322
|
private readonly clock;
|
|
319
323
|
private readonly idGenerator;
|
|
320
|
-
constructor(deps: Deps$
|
|
324
|
+
constructor(deps: Deps$14);
|
|
321
325
|
list(): ChannelConfig[];
|
|
322
326
|
get(name: string): ChannelConfig | null;
|
|
323
327
|
getById(id: string): ChannelConfig | null;
|
|
@@ -375,7 +379,7 @@ type GatewayController = {
|
|
|
375
379
|
//#region lib/engine/mcp/mcp.d.ts
|
|
376
380
|
declare const FUNNEL_MCP_COMMAND = "funnel";
|
|
377
381
|
declare const FUNNEL_MCP_NAME = "funnel";
|
|
378
|
-
type Deps$
|
|
382
|
+
type Deps$13 = {
|
|
379
383
|
fs?: FunnelFileSystem;
|
|
380
384
|
};
|
|
381
385
|
/**
|
|
@@ -385,7 +389,7 @@ type Deps$14 = {
|
|
|
385
389
|
*/
|
|
386
390
|
declare class FunnelMcp {
|
|
387
391
|
private readonly fs;
|
|
388
|
-
constructor(deps?: Deps$
|
|
392
|
+
constructor(deps?: Deps$13);
|
|
389
393
|
install(repoPath: string): void;
|
|
390
394
|
uninstall(repoPath: string): void;
|
|
391
395
|
findInstalledName(cwd: string): string | null;
|
|
@@ -394,46 +398,53 @@ declare class FunnelMcp {
|
|
|
394
398
|
private writeConfig;
|
|
395
399
|
}
|
|
396
400
|
//#endregion
|
|
397
|
-
//#region lib/engine/
|
|
398
|
-
type Deps$
|
|
399
|
-
|
|
401
|
+
//#region lib/engine/profiles/profiles.d.ts
|
|
402
|
+
type Deps$12 = {
|
|
403
|
+
store: FunnelSettingsReader;
|
|
400
404
|
idGenerator: FunnelIdGenerator;
|
|
401
|
-
dir: string;
|
|
402
405
|
};
|
|
403
406
|
/**
|
|
404
|
-
*
|
|
405
|
-
*
|
|
406
|
-
*
|
|
407
|
-
*
|
|
408
|
-
*
|
|
409
|
-
* bleed across workspaces the way claude's `-c` does.
|
|
407
|
+
* Named launch presets for `fnl claude`. Each profile bundles a working
|
|
408
|
+
* directory, the channel id its Claude instance subscribes to, and the launch
|
|
409
|
+
* recipe (`options` prepended to the claude argv, `env` layered under the
|
|
410
|
+
* process, `resume` toggling session reuse). Implements ProfileChannelChecker
|
|
411
|
+
* so FunnelChannels can refuse to remove a channel that is still referenced.
|
|
410
412
|
*
|
|
411
|
-
* `
|
|
412
|
-
*
|
|
413
|
-
*
|
|
414
|
-
*
|
|
413
|
+
* Each profile has a stable `id` (uuid) minted at `add`. That id is the unit
|
|
414
|
+
* everything internal keys on — the PID file, the resumable session id — so a
|
|
415
|
+
* rename never strands either. `name` is purely the CLI/TUI handle; the CRUD
|
|
416
|
+
* methods here take it because that is what the user types, but resolve to the
|
|
417
|
+
* id before touching id-keyed state. The first array entry is the default
|
|
418
|
+
* profile; `asDefault` reorders to put one first.
|
|
415
419
|
*
|
|
416
|
-
*
|
|
417
|
-
*
|
|
418
|
-
* `{ cwd: uuid }` map; the channel directory itself is created lazily.
|
|
420
|
+
* `channelId` always stores the channel's stable id (uuid). CLI surfaces
|
|
421
|
+
* resolve channel name → id before calling `add`/`update` here.
|
|
419
422
|
*/
|
|
420
|
-
declare class
|
|
421
|
-
private readonly
|
|
423
|
+
declare class FunnelProfiles {
|
|
424
|
+
private readonly store;
|
|
422
425
|
private readonly idGenerator;
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
426
|
+
constructor(deps: Deps$12);
|
|
427
|
+
list(): ProfileConfig[];
|
|
428
|
+
get(name: string): ProfileConfig | null;
|
|
429
|
+
getById(id: string): ProfileConfig | null;
|
|
430
|
+
getDefault(): ProfileConfig | null;
|
|
431
|
+
add(input: {
|
|
432
|
+
name: string;
|
|
433
|
+
path: string;
|
|
434
|
+
channelId: string;
|
|
435
|
+
options?: string[];
|
|
436
|
+
env?: Record<string, string>;
|
|
437
|
+
resume?: boolean;
|
|
438
|
+
}): void;
|
|
439
|
+
remove(name: string): void;
|
|
440
|
+
rename(oldName: string, newName: string): void;
|
|
441
|
+
asDefault(name: string): void;
|
|
442
|
+
hasChannelRef(channelId: string): boolean;
|
|
443
|
+
/** Resumable claude session id last launched by this profile (by id), or null. */
|
|
444
|
+
getSessionId(id: string): string | null;
|
|
445
|
+
/** Records the claude session id this profile launched, overwriting any prior one. */
|
|
446
|
+
setSessionId(id: string, sessionId: string): void;
|
|
447
|
+
update(name: string, fields: Partial<Omit<ProfileConfig, "name">>): void;
|
|
437
448
|
}
|
|
438
449
|
//#endregion
|
|
439
450
|
//#region lib/engine/claude/claude.d.ts
|
|
@@ -441,9 +452,16 @@ type LaunchOptions = {
|
|
|
441
452
|
channel: string;
|
|
442
453
|
cwd?: string;
|
|
443
454
|
userArgs?: string[];
|
|
444
|
-
|
|
455
|
+
/** Stable id of the launching profile (uuid). Keys the singleton PID file and
|
|
456
|
+
* the resumable session. Absent for a profile-less launch (raw `--channel`),
|
|
457
|
+
* which never enforces singleton-ness and never resumes. */
|
|
458
|
+
profileId?: string; /** Args prepended to the claude argv (typically a profile's recipe). Defaults to none. */
|
|
445
459
|
options?: string[]; /** Env vars layered under the launched claude process. process.env wins on collision. */
|
|
446
|
-
env?: Record<string, string>;
|
|
460
|
+
env?: Record<string, string>;
|
|
461
|
+
/** Whether to inject a `--session-id`/`--resume` for this profile.
|
|
462
|
+
* Defaults to false: resuming is opt-in and only meaningful for a profile,
|
|
463
|
+
* since the persisted session is owned by the profile (by id). A launch
|
|
464
|
+
* without a profile always starts a fresh session regardless of this flag. */
|
|
447
465
|
resume?: boolean;
|
|
448
466
|
/** Invoked synchronously after the child claude process has been spawned, with its PID.
|
|
449
467
|
* Useful for hosts that need to register the spawned process before it exits
|
|
@@ -454,13 +472,14 @@ type LaunchOptions = {
|
|
|
454
472
|
* does not need the funnel binary as an MCP endpoint. */
|
|
455
473
|
installMcp?: boolean;
|
|
456
474
|
};
|
|
457
|
-
type Deps$
|
|
475
|
+
type Deps$11 = {
|
|
458
476
|
channels: FunnelChannels;
|
|
459
477
|
mcp: FunnelMcp;
|
|
460
478
|
gateway: GatewayController;
|
|
461
|
-
|
|
479
|
+
profiles: FunnelProfiles;
|
|
462
480
|
process?: FunnelProcessRunner;
|
|
463
481
|
fs?: FunnelFileSystem;
|
|
482
|
+
idGenerator?: FunnelIdGenerator;
|
|
464
483
|
logger?: FunnelLogger;
|
|
465
484
|
dir?: string;
|
|
466
485
|
};
|
|
@@ -474,14 +493,15 @@ declare class FunnelClaude {
|
|
|
474
493
|
private readonly channels;
|
|
475
494
|
private readonly mcp;
|
|
476
495
|
private readonly gateway;
|
|
477
|
-
private readonly
|
|
496
|
+
private readonly profiles;
|
|
478
497
|
private readonly process;
|
|
479
498
|
private readonly fs;
|
|
499
|
+
private readonly idGenerator;
|
|
480
500
|
private readonly logger;
|
|
481
501
|
private readonly pidDir;
|
|
482
|
-
constructor(deps: Deps$
|
|
502
|
+
constructor(deps: Deps$11);
|
|
483
503
|
launch(options: LaunchOptions): Promise<number>;
|
|
484
|
-
isRunning(
|
|
504
|
+
isRunning(profileId: string): boolean;
|
|
485
505
|
private pidPath;
|
|
486
506
|
private readPid;
|
|
487
507
|
private writePidFile;
|
|
@@ -495,10 +515,16 @@ declare class FunnelClaude {
|
|
|
495
515
|
* session-shaping flag, since combining them would either confuse claude
|
|
496
516
|
* or override the explicit user intent.
|
|
497
517
|
*
|
|
518
|
+
* The session is owned by the profile (by id), not by cwd: two profiles
|
|
519
|
+
* pointing at the same repo each keep their own conversation, and a launch
|
|
520
|
+
* with no profile never resumes — so an unrelated session in the same repo
|
|
521
|
+
* can't bleed in. The channel never enters into it; sessions belong to the
|
|
522
|
+
* launch layer (profiles), keeping the transport layer ignorant of them.
|
|
523
|
+
*
|
|
498
524
|
* A persisted id is only resumed when its session jsonl still exists on
|
|
499
525
|
* disk. claude errors out on `--resume <id>` for a missing conversation, and
|
|
500
526
|
* a persisted id can outlive its jsonl (claude pruned it, or the very first
|
|
501
|
-
* launch was aborted after
|
|
527
|
+
* launch was aborted after the id was written but before the jsonl
|
|
502
528
|
* appeared). When the file is gone we mint a fresh session instead, which
|
|
503
529
|
* overwrites the dangling entry — so the store self-heals.
|
|
504
530
|
*/
|
|
@@ -527,7 +553,7 @@ declare class FunnelClaude {
|
|
|
527
553
|
type OnFunnelError = (error: Error, context?: Record<string, unknown>) => void;
|
|
528
554
|
//#endregion
|
|
529
555
|
//#region lib/engine/local-config/dotenv-reader.d.ts
|
|
530
|
-
type Deps$
|
|
556
|
+
type Deps$10 = {
|
|
531
557
|
fs: FunnelFileSystem;
|
|
532
558
|
};
|
|
533
559
|
/**
|
|
@@ -538,7 +564,7 @@ type Deps$11 = {
|
|
|
538
564
|
*/
|
|
539
565
|
declare class FunnelDotenvReader {
|
|
540
566
|
private readonly fs;
|
|
541
|
-
constructor(deps: Deps$
|
|
567
|
+
constructor(deps: Deps$10);
|
|
542
568
|
read(cwd: string): Record<string, string>;
|
|
543
569
|
}
|
|
544
570
|
//#endregion
|
|
@@ -599,7 +625,6 @@ declare const channelSpecSchema: z.ZodObject<{
|
|
|
599
625
|
}, z.core.$strip>;
|
|
600
626
|
type ChannelSpec = z.infer<typeof channelSpecSchema>;
|
|
601
627
|
declare const profileSpecSchema: z.ZodObject<{
|
|
602
|
-
name: z.ZodString;
|
|
603
628
|
channel: z.ZodString;
|
|
604
629
|
options: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
605
630
|
env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
@@ -637,7 +662,6 @@ declare const localConfigSchema: z.ZodObject<{
|
|
|
637
662
|
}, z.core.$strip>], "type">>>;
|
|
638
663
|
}, z.core.$strip>>;
|
|
639
664
|
profiles: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
640
|
-
name: z.ZodString;
|
|
641
665
|
channel: z.ZodString;
|
|
642
666
|
options: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
643
667
|
env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
@@ -649,7 +673,7 @@ declare const LOCAL_CONFIG_FILENAME = "funnel.json";
|
|
|
649
673
|
declare const LOCAL_ENV_FILENAME = ".env.local";
|
|
650
674
|
//#endregion
|
|
651
675
|
//#region lib/engine/local-config/local-config.d.ts
|
|
652
|
-
type Deps$
|
|
676
|
+
type Deps$9 = {
|
|
653
677
|
fs: FunnelFileSystem;
|
|
654
678
|
};
|
|
655
679
|
/**
|
|
@@ -660,8 +684,9 @@ type Deps$10 = {
|
|
|
660
684
|
*/
|
|
661
685
|
declare class FunnelLocalConfig {
|
|
662
686
|
private readonly fs;
|
|
663
|
-
constructor(deps: Deps$
|
|
687
|
+
constructor(deps: Deps$9);
|
|
664
688
|
read(cwd: string): LocalConfig | null;
|
|
689
|
+
private assertProfilesValid;
|
|
665
690
|
}
|
|
666
691
|
//#endregion
|
|
667
692
|
//#region lib/engine/token-prompter/token-prompter.d.ts
|
|
@@ -676,7 +701,7 @@ declare abstract class FunnelTokenPrompter {
|
|
|
676
701
|
}
|
|
677
702
|
//#endregion
|
|
678
703
|
//#region lib/engine/local-config/local-config-sync.d.ts
|
|
679
|
-
type Deps$
|
|
704
|
+
type Deps$8 = {
|
|
680
705
|
channels: FunnelChannels;
|
|
681
706
|
dotenv: FunnelDotenvReader;
|
|
682
707
|
prompter: FunnelTokenPrompter;
|
|
@@ -714,7 +739,7 @@ declare class FunnelLocalConfigSync {
|
|
|
714
739
|
private readonly dotenv;
|
|
715
740
|
private readonly prompter;
|
|
716
741
|
private readonly env;
|
|
717
|
-
constructor(deps: Deps$
|
|
742
|
+
constructor(deps: Deps$8);
|
|
718
743
|
ensure(channel: ChannelSpec, cwd: string): Promise<LocalConfigSyncResult>;
|
|
719
744
|
private ensureConnector;
|
|
720
745
|
private ensureSlack;
|
|
@@ -729,44 +754,6 @@ declare class FunnelLocalConfigSync {
|
|
|
729
754
|
private resolveField;
|
|
730
755
|
}
|
|
731
756
|
//#endregion
|
|
732
|
-
//#region lib/engine/profiles/profiles.d.ts
|
|
733
|
-
type Deps$8 = {
|
|
734
|
-
store: FunnelSettingsReader;
|
|
735
|
-
};
|
|
736
|
-
/**
|
|
737
|
-
* Named launch presets for `fnl claude`. Each profile bundles a working
|
|
738
|
-
* directory, the channel id its Claude instance subscribes to, and the launch
|
|
739
|
-
* recipe (`options` prepended to the claude argv, `env` layered under the
|
|
740
|
-
* process, `resume` toggling session reuse). Implements ProfileChannelChecker
|
|
741
|
-
* so FunnelChannels can refuse to remove a channel that is still referenced.
|
|
742
|
-
*
|
|
743
|
-
* The first entry in the persisted array is treated as the default profile;
|
|
744
|
-
* `asDefault` reorders the array to put a named profile first.
|
|
745
|
-
*
|
|
746
|
-
* `channelId` always stores the channel's stable id (uuid). CLI surfaces
|
|
747
|
-
* resolve channel name → id before calling `add`/`update` here.
|
|
748
|
-
*/
|
|
749
|
-
declare class FunnelProfiles {
|
|
750
|
-
private readonly store;
|
|
751
|
-
constructor(deps: Deps$8);
|
|
752
|
-
list(): ProfileConfig[];
|
|
753
|
-
get(name: string): ProfileConfig | null;
|
|
754
|
-
getDefault(): ProfileConfig | null;
|
|
755
|
-
add(input: {
|
|
756
|
-
name: string;
|
|
757
|
-
path: string;
|
|
758
|
-
channelId: string;
|
|
759
|
-
options?: string[];
|
|
760
|
-
env?: Record<string, string>;
|
|
761
|
-
resume?: boolean;
|
|
762
|
-
}): void;
|
|
763
|
-
remove(name: string): void;
|
|
764
|
-
rename(oldName: string, newName: string): void;
|
|
765
|
-
asDefault(name: string): void;
|
|
766
|
-
hasChannelRef(channelId: string): boolean;
|
|
767
|
-
update(name: string, fields: Partial<Omit<ProfileConfig, "name">>): void;
|
|
768
|
-
}
|
|
769
|
-
//#endregion
|
|
770
757
|
//#region lib/gateway/publish-schema.d.ts
|
|
771
758
|
/**
|
|
772
759
|
* Shared schema for `POST /channels/:channel/publish` — used by both the
|
|
@@ -832,9 +819,9 @@ type ReplayableEvent = BroadcastEvent & {
|
|
|
832
819
|
};
|
|
833
820
|
type BroadcastSubscriber = (event: ReplayableEvent) => void;
|
|
834
821
|
/**
|
|
835
|
-
* Optional persistent replay source. Wired in by the gateway-server with
|
|
836
|
-
* `
|
|
837
|
-
* can recover events older than the in-memory buffer via an indexed
|
|
822
|
+
* Optional persistent replay source. Wired in by the gateway-server with a
|
|
823
|
+
* `FunnelEventLog` (SQLite-backed by default) so reconnects across daemon
|
|
824
|
+
* restarts can recover events older than the in-memory buffer via an indexed
|
|
838
825
|
* `seq > since` range scan.
|
|
839
826
|
*/
|
|
840
827
|
type ReplaySource = {
|
|
@@ -873,8 +860,7 @@ type BroadcasterMetrics = {
|
|
|
873
860
|
* `replayBufferSize` events are kept in memory; reconnecting WS clients can
|
|
874
861
|
* pass `?since=<offset>` and the broadcaster resends matching events before
|
|
875
862
|
* resuming the live stream. The in-memory ring covers short reconnects;
|
|
876
|
-
* older history is served from the
|
|
877
|
-
* `persistentReplay`.
|
|
863
|
+
* older history is served from the event log wired in as `persistentReplay`.
|
|
878
864
|
*/
|
|
879
865
|
declare class FunnelBroadcaster {
|
|
880
866
|
private readonly clients;
|
|
@@ -902,8 +888,8 @@ declare class FunnelBroadcaster {
|
|
|
902
888
|
* Two-tier lookup:
|
|
903
889
|
* 1. The in-memory ring buffer (covers short reconnects, last `replayBufferSize` events).
|
|
904
890
|
* 2. If `since` predates the oldest in-memory entry and a persistent replay source
|
|
905
|
-
* is wired in (SQLite), the gap is filled from
|
|
906
|
-
* daemon restarts where the in-memory buffer was lost.
|
|
891
|
+
* is wired in (SQLite by default), the gap is filled from it. This covers reconnects
|
|
892
|
+
* across daemon restarts where the in-memory buffer was lost.
|
|
907
893
|
*
|
|
908
894
|
* Result is sorted ascending by offset and de-duplicated against the in-memory buffer.
|
|
909
895
|
*/
|
|
@@ -1038,6 +1024,51 @@ type Env$1 = {
|
|
|
1038
1024
|
};
|
|
1039
1025
|
};
|
|
1040
1026
|
//#endregion
|
|
1027
|
+
//#region lib/gateway/funnel-event-log.d.ts
|
|
1028
|
+
/**
|
|
1029
|
+
* Replayable event payload persisted by the gateway. Domain events the
|
|
1030
|
+
* broadcaster emits to WS clients land here so reconnects across daemon
|
|
1031
|
+
* restarts can be served from disk. System events (gateway start, channel
|
|
1032
|
+
* connected, etc.) are routed to `FunnelLogger` instead — they never go
|
|
1033
|
+
* through this log, which keeps the offset space clean for replay.
|
|
1034
|
+
*/
|
|
1035
|
+
declare const funnelEventSchema: z.ZodObject<{
|
|
1036
|
+
type: z.ZodString;
|
|
1037
|
+
content: z.ZodString;
|
|
1038
|
+
channel_id: z.ZodNullable<z.ZodString>;
|
|
1039
|
+
connector_id: z.ZodNullable<z.ZodString>;
|
|
1040
|
+
meta: z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1041
|
+
}, z.core.$strip>;
|
|
1042
|
+
type FunnelEvent = z.infer<typeof funnelEventSchema>;
|
|
1043
|
+
/** One broadcast event to persist, carrying the offset the broadcaster assigned. */
|
|
1044
|
+
type FunnelEventRecord = {
|
|
1045
|
+
content: string;
|
|
1046
|
+
channelId: string | null;
|
|
1047
|
+
connectorId: string | null;
|
|
1048
|
+
meta: Record<string, string> | null;
|
|
1049
|
+
offset: number;
|
|
1050
|
+
};
|
|
1051
|
+
/**
|
|
1052
|
+
* Durable, append-only log of broadcaster events keyed by the offset the
|
|
1053
|
+
* broadcaster assigns. The gateway persists every domain event here, and
|
|
1054
|
+
* across restarts it both seeds the broadcaster's offset counter
|
|
1055
|
+
* (`findMaxOffset`) and serves reconnect replay (`loadSince`) from it.
|
|
1056
|
+
*
|
|
1057
|
+
* `loadSince` is the only method the broadcaster itself needs, which makes
|
|
1058
|
+
* any implementation assignable to the broadcaster's narrow `ReplaySource`.
|
|
1059
|
+
*
|
|
1060
|
+
* Implementations:
|
|
1061
|
+
* - `SqliteFunnelEventLog` — the default; durable across daemon restarts.
|
|
1062
|
+
* - `MemoryFunnelEventLog` — an in-process double for tests and embedders
|
|
1063
|
+
* that do not need durability (replay is lost when the process exits).
|
|
1064
|
+
*/
|
|
1065
|
+
declare abstract class FunnelEventLog {
|
|
1066
|
+
abstract record(record: FunnelEventRecord): void;
|
|
1067
|
+
abstract loadSince(since: number): ReplayableEvent[];
|
|
1068
|
+
abstract findMaxOffset(): number;
|
|
1069
|
+
abstract close(): void;
|
|
1070
|
+
}
|
|
1071
|
+
//#endregion
|
|
1041
1072
|
//#region lib/gateway/gateway.d.ts
|
|
1042
1073
|
type Deps$4 = {
|
|
1043
1074
|
process?: FunnelProcessRunner;
|
|
@@ -1093,88 +1124,13 @@ declare class FunnelGateway {
|
|
|
1093
1124
|
private isProcessAlive;
|
|
1094
1125
|
}
|
|
1095
1126
|
//#endregion
|
|
1096
|
-
//#region lib/gateway/funnel-event-store.d.ts
|
|
1097
|
-
/**
|
|
1098
|
-
* Replayable event payload persisted by the gateway. Domain events the
|
|
1099
|
-
* broadcaster emits to WS clients land here so reconnects across daemon
|
|
1100
|
-
* restarts can be served from disk. System events (gateway start, channel
|
|
1101
|
-
* connected, etc.) are routed to `FunnelLogger` instead — they never go
|
|
1102
|
-
* through this store, which keeps the seq space clean for replay.
|
|
1103
|
-
*/
|
|
1104
|
-
declare const funnelEventSchema: z.ZodObject<{
|
|
1105
|
-
type: z.ZodString;
|
|
1106
|
-
content: z.ZodString;
|
|
1107
|
-
channel_id: z.ZodNullable<z.ZodString>;
|
|
1108
|
-
connector_id: z.ZodNullable<z.ZodString>;
|
|
1109
|
-
meta: z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1110
|
-
}, z.core.$strip>;
|
|
1111
|
-
type FunnelEvent = z.infer<typeof funnelEventSchema>;
|
|
1112
|
-
type Props$6 = {
|
|
1113
|
-
/** SQLite database file path. Created on first write. ":memory:" for tests. */path: string; /** Override for tests. Defaults to `Date.now`. */
|
|
1114
|
-
now?: () => number; /** Optional row cap. Pruned on every insert. */
|
|
1115
|
-
maxRows?: number; /** Optional age cap in ms. Pruned on every insert. */
|
|
1116
|
-
maxAgeMs?: number;
|
|
1117
|
-
};
|
|
1118
|
-
/**
|
|
1119
|
-
* SQLite-backed event store. One indexed table holds every broadcaster
|
|
1120
|
-
* event with `channel_id` and `connector_id` as dedicated columns, so
|
|
1121
|
-
* per-channel and per-connector replay is an indexed range scan.
|
|
1122
|
-
*
|
|
1123
|
-
* Concurrency: `seq` is `INTEGER PRIMARY KEY`, so SQLite assigns it
|
|
1124
|
-
* atomically. The broadcaster owns its own offset counter at runtime
|
|
1125
|
-
* (seeded from `findMaxOffset()` at startup); each broadcaster event
|
|
1126
|
-
* flows in here via `record()` with that pre-assigned offset, which the
|
|
1127
|
-
* sink stores via `write()` — PK uniqueness catches double-emit bugs.
|
|
1128
|
-
*
|
|
1129
|
-
* System events (gateway lifecycle, channel connect/disconnect, etc.) do
|
|
1130
|
-
* NOT go through this store. They are diagnostic only and live in
|
|
1131
|
-
* `FunnelLogger`'s file so the seq space here stays exclusive to
|
|
1132
|
-
* broadcaster traffic. This is what makes the broadcaster's seq seeding
|
|
1133
|
-
* (`getMaxSeq()` at startup) correct without per-event coordination.
|
|
1134
|
-
*/
|
|
1135
|
-
declare class FunnelEventStore {
|
|
1136
|
-
private readonly sink;
|
|
1137
|
-
private readonly now;
|
|
1138
|
-
constructor(props: Props$6);
|
|
1139
|
-
/**
|
|
1140
|
-
* Persist a broadcaster-driven event with its assigned offset. Caller
|
|
1141
|
-
* (the gateway-server) supplies the offset from `broadcaster.broadcast()`
|
|
1142
|
-
* so this store and the broadcaster's in-memory ring stay aligned.
|
|
1143
|
-
*/
|
|
1144
|
-
record(props: {
|
|
1145
|
-
content: string;
|
|
1146
|
-
channelId: string | null;
|
|
1147
|
-
connectorId: string | null;
|
|
1148
|
-
meta: Record<string, string> | null;
|
|
1149
|
-
offset: number;
|
|
1150
|
-
}): void;
|
|
1151
|
-
/**
|
|
1152
|
-
* Returns events with offset > since. Filtering by channel/connector is
|
|
1153
|
-
* the broadcaster's responsibility (it knows the client's subscription),
|
|
1154
|
-
* so this returns the full slice and lets the caller filter.
|
|
1155
|
-
*/
|
|
1156
|
-
loadSince(since: number): ReplayableEvent[];
|
|
1157
|
-
/**
|
|
1158
|
-
* Returns events for one channel (and optionally one connector). Used
|
|
1159
|
-
* by the gateway logs CLI for scoped queries. Channel/connector filters
|
|
1160
|
-
* are indexed columns, so this is an indexed range scan.
|
|
1161
|
-
*/
|
|
1162
|
-
loadForChannel(props: {
|
|
1163
|
-
channelId: string;
|
|
1164
|
-
connectorId?: string;
|
|
1165
|
-
sinceSeq?: number;
|
|
1166
|
-
limit?: number;
|
|
1167
|
-
}): ReplayableEvent[];
|
|
1168
|
-
findMaxOffset(): number;
|
|
1169
|
-
close(): void;
|
|
1170
|
-
}
|
|
1171
|
-
//#endregion
|
|
1172
1127
|
//#region lib/gateway/gateway-server.d.ts
|
|
1173
1128
|
type Deps$3 = {
|
|
1174
1129
|
channels: FunnelChannels;
|
|
1175
1130
|
settings: FunnelSettingsReader;
|
|
1176
|
-
port?: number; /** SQLite event store file path. Parent directory is created on demand. Defaults to `<os.tmpdir()>/funnel/events.db`. */
|
|
1177
|
-
dbPath?: string;
|
|
1131
|
+
port?: number; /** SQLite event store file path. Parent directory is created on demand. Defaults to `<os.tmpdir()>/funnel/events.db`. Ignored when `eventLog` is supplied. */
|
|
1132
|
+
dbPath?: string; /** Durable replay log. Defaults to a `SqliteFunnelEventLog` at `dbPath`. Inject a `MemoryFunnelEventLog` (or any `FunnelEventLog`) to swap or disable persistence. */
|
|
1133
|
+
eventLog?: FunnelEventLog;
|
|
1178
1134
|
process?: FunnelProcessRunner;
|
|
1179
1135
|
clock?: FunnelClock;
|
|
1180
1136
|
logger?: FunnelLogger; /** Host hook for surfacing internal exceptions (broadcaster / supervisor). Defaults to no-op. */
|
|
@@ -1202,7 +1158,7 @@ type WsData = {
|
|
|
1202
1158
|
/**
|
|
1203
1159
|
* In-process gateway: runs `Bun.serve` (HTTP + WebSocket /ws), boots connector
|
|
1204
1160
|
* listeners through `FunnelListenerSupervisor`, fans events out via
|
|
1205
|
-
* `FunnelBroadcaster`, and persists them via `
|
|
1161
|
+
* `FunnelBroadcaster`, and persists them via a `FunnelEventLog` (SQLite by default).
|
|
1206
1162
|
* System events (gateway lifecycle, connect/disconnect) flow to `FunnelLogger`
|
|
1207
1163
|
* instead — keeping the SQLite seq space exclusive to broadcaster traffic so
|
|
1208
1164
|
* the broadcaster's offset counter and `getMaxSeq()` stay aligned without
|
|
@@ -1222,7 +1178,7 @@ declare class FunnelGatewayServer {
|
|
|
1222
1178
|
private readonly killCompetingSlack;
|
|
1223
1179
|
private readonly token;
|
|
1224
1180
|
private readonly broadcaster;
|
|
1225
|
-
private readonly
|
|
1181
|
+
private readonly eventLog;
|
|
1226
1182
|
private readonly supervisor;
|
|
1227
1183
|
private readonly nowMs;
|
|
1228
1184
|
private readonly extraRoutes;
|
|
@@ -1240,7 +1196,15 @@ declare class FunnelGatewayServer {
|
|
|
1240
1196
|
};
|
|
1241
1197
|
getBroadcaster(): FunnelBroadcaster;
|
|
1242
1198
|
getSupervisor(): FunnelListenerSupervisor;
|
|
1243
|
-
|
|
1199
|
+
getEventLog(): FunnelEventLog;
|
|
1200
|
+
/**
|
|
1201
|
+
* Register an in-process observer for every broadcast event. Fires after
|
|
1202
|
+
* the event is fanned out to WS clients and recorded in the event log.
|
|
1203
|
+
* Returns an unsubscribe function. Only meaningful in-process (embedded
|
|
1204
|
+
* hosts / `new Funnel(...)` running their own gateway-server); a separate
|
|
1205
|
+
* daemon process cannot be observed this way — use a WS client for that.
|
|
1206
|
+
*/
|
|
1207
|
+
onEvent(handler: BroadcastSubscriber): () => void;
|
|
1244
1208
|
private handleFetch;
|
|
1245
1209
|
private handleWsOpen;
|
|
1246
1210
|
private handleWsClose;
|
|
@@ -1360,7 +1324,7 @@ declare class FunnelListenersClient {
|
|
|
1360
1324
|
}
|
|
1361
1325
|
//#endregion
|
|
1362
1326
|
//#region lib/funnel.d.ts
|
|
1363
|
-
type Props$
|
|
1327
|
+
type Props$6 = {
|
|
1364
1328
|
/** Settings persistence (channels with nested connectors / profiles). Defaults to a FunnelSettingsStore rooted at `dir`. */store?: FunnelSettingsReader; /** Filesystem boundary. Replace with MemoryFunnelFileSystem to sandbox all disk I/O. */
|
|
1365
1329
|
fs?: FunnelFileSystem; /** Process runner used by gateway / claude / gh listener. Replace with MemoryFunnelProcessRunner for tests. */
|
|
1366
1330
|
process?: FunnelProcessRunner; /** Logger flowed into every facet. Replace with MemoryFunnelLogger or NoopFunnelLogger to silence/inspect. */
|
|
@@ -1410,13 +1374,13 @@ type Props$5 = {
|
|
|
1410
1374
|
declare class Funnel {
|
|
1411
1375
|
private readonly props;
|
|
1412
1376
|
private readonly memos;
|
|
1413
|
-
constructor(props?: Props$
|
|
1377
|
+
constructor(props?: Props$6);
|
|
1414
1378
|
/**
|
|
1415
1379
|
* Sandboxed Funnel wired with in-memory implementations for every IO boundary.
|
|
1416
1380
|
* Touches no real disk, processes, wall-clock time, or UUIDs — safe for tests
|
|
1417
1381
|
* and ad-hoc experiments. Override individual fields by passing them in `props`.
|
|
1418
1382
|
*/
|
|
1419
|
-
static inMemory(props?: Props$
|
|
1383
|
+
static inMemory(props?: Props$6): Funnel;
|
|
1420
1384
|
/** Resolved on-disk paths the facade will read/write when methods are called. Pure compute, not memoized. */
|
|
1421
1385
|
get paths(): {
|
|
1422
1386
|
dir: string;
|
|
@@ -1427,8 +1391,8 @@ declare class Funnel {
|
|
|
1427
1391
|
get fs(): FunnelFileSystem;
|
|
1428
1392
|
/** Process runner boundary. Defaults to NodeFunnelProcessRunner. */
|
|
1429
1393
|
get process(): FunnelProcessRunner;
|
|
1430
|
-
/** Logger boundary.
|
|
1431
|
-
get logger(): FunnelLogger;
|
|
1394
|
+
/** Logger boundary. Optional — when no logger is injected, every facet's `this.logger?.x` call is a silent no-op. Production entry points (cli, daemon) inject a NodeFunnelLogger. */
|
|
1395
|
+
get logger(): FunnelLogger | undefined;
|
|
1432
1396
|
/** Clock boundary. Defaults to NodeFunnelClock. */
|
|
1433
1397
|
get clock(): FunnelClock;
|
|
1434
1398
|
/**
|
|
@@ -1446,8 +1410,6 @@ declare class Funnel {
|
|
|
1446
1410
|
get channels(): FunnelChannels;
|
|
1447
1411
|
/** Launch profiles (named presets for `fnl claude`: path + sub-agent + channel id). */
|
|
1448
1412
|
get profiles(): FunnelProfiles;
|
|
1449
|
-
/** Per-(channel, cwd) claude session-id store. Backs `--session-id` injection on launch. */
|
|
1450
|
-
get sessions(): FunnelSessions;
|
|
1451
1413
|
/** Reads `funnel.json` from a cwd. `fnl claude` consults it before falling back to the default profile. */
|
|
1452
1414
|
get localConfig(): FunnelLocalConfig;
|
|
1453
1415
|
/** Parses `.env.local` from a cwd (used by sync to back $VAR references). */
|
|
@@ -1485,7 +1447,8 @@ declare class Funnel {
|
|
|
1485
1447
|
port?: number;
|
|
1486
1448
|
dbPath?: string;
|
|
1487
1449
|
killCompetingSlack?: boolean; /** Override the auth token. Defaults to the persisted gateway.token. Pass "" to disable auth (tests). */
|
|
1488
|
-
token?: string;
|
|
1450
|
+
token?: string; /** Durable replay log. Defaults to a SqliteFunnelEventLog at dbPath; inject a MemoryFunnelEventLog (or any FunnelEventLog) to swap or disable persistence. */
|
|
1451
|
+
eventLog?: FunnelEventLog;
|
|
1489
1452
|
/**
|
|
1490
1453
|
* Additional hono app mounted before the built-in gateway routes.
|
|
1491
1454
|
* Use to embed host-specific endpoints (e.g. an MCP route, custom `/api/*`).
|
|
@@ -1520,13 +1483,23 @@ declare const SETTINGS_PATH: string;
|
|
|
1520
1483
|
type Deps = {
|
|
1521
1484
|
path?: string;
|
|
1522
1485
|
fs?: FunnelFileSystem;
|
|
1486
|
+
idGenerator?: FunnelIdGenerator;
|
|
1523
1487
|
};
|
|
1524
1488
|
declare class FunnelSettingsStore extends FunnelSettingsReader {
|
|
1525
1489
|
private readonly path;
|
|
1526
1490
|
private readonly fs;
|
|
1491
|
+
private readonly idGenerator;
|
|
1527
1492
|
constructor(deps?: Deps);
|
|
1528
1493
|
read(): Settings;
|
|
1529
1494
|
private looksLikeLegacy;
|
|
1495
|
+
/**
|
|
1496
|
+
* Non-destructive migration for profiles written before `id` existed. The id
|
|
1497
|
+
* is a later addition to an otherwise-compatible schema, so rather than
|
|
1498
|
+
* rejecting the file we mint a uuid for each profile that lacks one; the next
|
|
1499
|
+
* `write` persists it. Mutates `parsed` in place (it is freshly JSON-parsed
|
|
1500
|
+
* and discarded after the schema parse, so no shared state is touched).
|
|
1501
|
+
*/
|
|
1502
|
+
private backfillProfileIds;
|
|
1530
1503
|
write(settings: Settings): void;
|
|
1531
1504
|
}
|
|
1532
1505
|
//#endregion
|
|
@@ -1556,7 +1529,7 @@ declare class NodeFunnelFileSystem extends FunnelFileSystem {
|
|
|
1556
1529
|
}
|
|
1557
1530
|
//#endregion
|
|
1558
1531
|
//#region lib/engine/fs/memory-file-system.d.ts
|
|
1559
|
-
type Props$
|
|
1532
|
+
type Props$5 = {
|
|
1560
1533
|
dirs?: string[];
|
|
1561
1534
|
files?: Record<string, string>;
|
|
1562
1535
|
mtimes?: Record<string, number>;
|
|
@@ -1569,7 +1542,7 @@ declare class MemoryFunnelFileSystem extends FunnelFileSystem {
|
|
|
1569
1542
|
private readonly mtimes;
|
|
1570
1543
|
private readonly modes;
|
|
1571
1544
|
private readonly now;
|
|
1572
|
-
constructor(props?: Props$
|
|
1545
|
+
constructor(props?: Props$5);
|
|
1573
1546
|
existsSync(path: string): boolean;
|
|
1574
1547
|
readFileSync(path: string): string;
|
|
1575
1548
|
writeFileSync(path: string, data: string): void;
|
|
@@ -1655,14 +1628,14 @@ declare class MemoryFunnelProcessRunner extends FunnelProcessRunner {
|
|
|
1655
1628
|
}
|
|
1656
1629
|
//#endregion
|
|
1657
1630
|
//#region lib/engine/logger/node-logger.d.ts
|
|
1658
|
-
type Props$
|
|
1631
|
+
type Props$4 = {
|
|
1659
1632
|
file?: string;
|
|
1660
1633
|
now?: () => Date;
|
|
1661
1634
|
};
|
|
1662
1635
|
declare class NodeFunnelLogger extends FunnelLogger {
|
|
1663
1636
|
readonly file: string;
|
|
1664
1637
|
private readonly now;
|
|
1665
|
-
constructor(props?: Props$
|
|
1638
|
+
constructor(props?: Props$4);
|
|
1666
1639
|
info(message: string, meta?: Record<string, unknown>): void;
|
|
1667
1640
|
warn(message: string, meta?: Record<string, unknown>): void;
|
|
1668
1641
|
error(message: string, meta?: Record<string, unknown>): void;
|
|
@@ -1698,12 +1671,12 @@ declare class NodeFunnelClock extends FunnelClock {
|
|
|
1698
1671
|
}
|
|
1699
1672
|
//#endregion
|
|
1700
1673
|
//#region lib/engine/time/memory-clock.d.ts
|
|
1701
|
-
type Props$
|
|
1674
|
+
type Props$3 = {
|
|
1702
1675
|
start?: Date;
|
|
1703
1676
|
};
|
|
1704
1677
|
declare class MemoryFunnelClock extends FunnelClock {
|
|
1705
1678
|
private current;
|
|
1706
|
-
constructor(props?: Props$
|
|
1679
|
+
constructor(props?: Props$3);
|
|
1707
1680
|
now(): Date;
|
|
1708
1681
|
set(date: Date): void;
|
|
1709
1682
|
advance(ms: number): void;
|
|
@@ -1715,13 +1688,13 @@ declare class NodeFunnelIdGenerator extends FunnelIdGenerator {
|
|
|
1715
1688
|
}
|
|
1716
1689
|
//#endregion
|
|
1717
1690
|
//#region lib/engine/id/memory-id-generator.d.ts
|
|
1718
|
-
type Props$
|
|
1691
|
+
type Props$2 = {
|
|
1719
1692
|
prefix?: string;
|
|
1720
1693
|
};
|
|
1721
1694
|
declare class MemoryFunnelIdGenerator extends FunnelIdGenerator {
|
|
1722
1695
|
private counter;
|
|
1723
1696
|
private readonly prefix;
|
|
1724
|
-
constructor(props?: Props$
|
|
1697
|
+
constructor(props?: Props$2);
|
|
1725
1698
|
generate(): string;
|
|
1726
1699
|
}
|
|
1727
1700
|
//#endregion
|
|
@@ -1738,7 +1711,7 @@ declare class NodeFunnelTokenPrompter extends FunnelTokenPrompter {
|
|
|
1738
1711
|
}
|
|
1739
1712
|
//#endregion
|
|
1740
1713
|
//#region lib/engine/token-prompter/memory-token-prompter.d.ts
|
|
1741
|
-
type Props = {
|
|
1714
|
+
type Props$1 = {
|
|
1742
1715
|
answers?: Record<string, string>;
|
|
1743
1716
|
};
|
|
1744
1717
|
/**
|
|
@@ -1748,10 +1721,82 @@ type Props = {
|
|
|
1748
1721
|
declare class MemoryFunnelTokenPrompter extends FunnelTokenPrompter {
|
|
1749
1722
|
private readonly answers;
|
|
1750
1723
|
readonly asked: string[];
|
|
1751
|
-
constructor(props?: Props);
|
|
1724
|
+
constructor(props?: Props$1);
|
|
1752
1725
|
promptSecret(label: string): Promise<string>;
|
|
1753
1726
|
}
|
|
1754
1727
|
//#endregion
|
|
1728
|
+
//#region lib/gateway/sqlite-funnel-event-log.d.ts
|
|
1729
|
+
type Props = {
|
|
1730
|
+
/** SQLite database file path. Created on first write. ":memory:" for tests. */path: string; /** Override for tests. Defaults to `Date.now`. */
|
|
1731
|
+
now?: () => number; /** Optional row cap. Pruned on every insert. */
|
|
1732
|
+
maxRows?: number; /** Optional age cap in ms. Pruned on every insert. */
|
|
1733
|
+
maxAgeMs?: number;
|
|
1734
|
+
};
|
|
1735
|
+
/**
|
|
1736
|
+
* SQLite-backed `FunnelEventLog`. One indexed table holds every broadcaster
|
|
1737
|
+
* event with `channel_id` and `connector_id` as dedicated columns, so
|
|
1738
|
+
* per-channel and per-connector replay is an indexed range scan.
|
|
1739
|
+
*
|
|
1740
|
+
* Concurrency: `seq` is `INTEGER PRIMARY KEY`, so SQLite assigns it
|
|
1741
|
+
* atomically. The broadcaster owns its own offset counter at runtime
|
|
1742
|
+
* (seeded from `findMaxOffset()` at startup); each broadcaster event
|
|
1743
|
+
* flows in here via `record()` with that pre-assigned offset, which the
|
|
1744
|
+
* sink stores via `write()` — PK uniqueness catches double-emit bugs.
|
|
1745
|
+
*
|
|
1746
|
+
* System events (gateway lifecycle, channel connect/disconnect, etc.) do
|
|
1747
|
+
* NOT go through this store. They are diagnostic only and live in
|
|
1748
|
+
* `FunnelLogger`'s file so the seq space here stays exclusive to
|
|
1749
|
+
* broadcaster traffic. This is what makes the broadcaster's seq seeding
|
|
1750
|
+
* (`getMaxSeq()` at startup) correct without per-event coordination.
|
|
1751
|
+
*/
|
|
1752
|
+
declare class SqliteFunnelEventLog extends FunnelEventLog {
|
|
1753
|
+
private readonly sink;
|
|
1754
|
+
private readonly now;
|
|
1755
|
+
constructor(props: Props);
|
|
1756
|
+
/**
|
|
1757
|
+
* Persist a broadcaster-driven event with its assigned offset. Caller
|
|
1758
|
+
* (the gateway-server) supplies the offset from `broadcaster.broadcast()`
|
|
1759
|
+
* so this store and the broadcaster's in-memory ring stay aligned.
|
|
1760
|
+
*/
|
|
1761
|
+
record(record: FunnelEventRecord): void;
|
|
1762
|
+
/**
|
|
1763
|
+
* Returns events with offset > since. Filtering by channel/connector is
|
|
1764
|
+
* the broadcaster's responsibility (it knows the client's subscription),
|
|
1765
|
+
* so this returns the full slice and lets the caller filter.
|
|
1766
|
+
*/
|
|
1767
|
+
loadSince(since: number): ReplayableEvent[];
|
|
1768
|
+
/**
|
|
1769
|
+
* Returns events for one channel (and optionally one connector). Used
|
|
1770
|
+
* by the gateway logs CLI for scoped queries. Channel/connector filters
|
|
1771
|
+
* are indexed columns, so this is an indexed range scan.
|
|
1772
|
+
*/
|
|
1773
|
+
loadForChannel(props: {
|
|
1774
|
+
channelId: string;
|
|
1775
|
+
connectorId?: string;
|
|
1776
|
+
sinceSeq?: number;
|
|
1777
|
+
limit?: number;
|
|
1778
|
+
}): ReplayableEvent[];
|
|
1779
|
+
findMaxOffset(): number;
|
|
1780
|
+
close(): void;
|
|
1781
|
+
}
|
|
1782
|
+
//#endregion
|
|
1783
|
+
//#region lib/gateway/memory-funnel-event-log.d.ts
|
|
1784
|
+
/**
|
|
1785
|
+
* In-process `FunnelEventLog` backed by a plain array. Used by tests and by
|
|
1786
|
+
* embedders that do not need durability — replay works within the process
|
|
1787
|
+
* lifetime but is lost when the process exits. Unlike the SQLite log it does
|
|
1788
|
+
* not truncate content or prune, so it is not meant for unbounded production
|
|
1789
|
+
* traffic.
|
|
1790
|
+
*/
|
|
1791
|
+
declare class MemoryFunnelEventLog extends FunnelEventLog {
|
|
1792
|
+
private readonly events;
|
|
1793
|
+
constructor();
|
|
1794
|
+
record(record: FunnelEventRecord): void;
|
|
1795
|
+
loadSince(since: number): ReplayableEvent[];
|
|
1796
|
+
findMaxOffset(): number;
|
|
1797
|
+
close(): void;
|
|
1798
|
+
}
|
|
1799
|
+
//#endregion
|
|
1755
1800
|
//#region lib/cli/factory.d.ts
|
|
1756
1801
|
type Env = {
|
|
1757
1802
|
Variables: {
|
|
@@ -4386,4 +4431,4 @@ ${string}`;
|
|
|
4386
4431
|
//#region lib/tui/tui.d.ts
|
|
4387
4432
|
declare function launchTui(funnel: Funnel): Promise<void>;
|
|
4388
4433
|
//#endregion
|
|
4389
|
-
export { AliveStub, AttachOptions, BroadcastEvent, BroadcastSubscriber, ChannelConfig, ChannelConnectorView, ChannelDeliveryMode, ChannelServerOptions, ChannelSpec, ConnectorConfig, ConnectorSpec, ConnectorSyncOutcome, ConnectorType, DEFAULT_GATEWAY_TOKEN_PATH, DetachOptions, DiscordConnectorConfig, Env, FUNNEL_DIR, FUNNEL_MCP_COMMAND, FUNNEL_MCP_NAME, FileStat, Funnel, FunnelBroadcaster, FunnelChannelPublisher, FunnelChannels, FunnelClaude, FunnelClock, FunnelConnectorFactory, FunnelConnectorListener, FunnelDotenvReader, FunnelEvent,
|
|
4434
|
+
export { AliveStub, AttachOptions, BroadcastEvent, BroadcastSubscriber, ChannelConfig, ChannelConnectorView, ChannelDeliveryMode, ChannelServerOptions, ChannelSpec, ConnectorConfig, ConnectorSpec, ConnectorSyncOutcome, ConnectorType, DEFAULT_GATEWAY_TOKEN_PATH, DetachOptions, DiscordConnectorConfig, Env, FUNNEL_DIR, FUNNEL_MCP_COMMAND, FUNNEL_MCP_NAME, FileStat, Funnel, FunnelBroadcaster, FunnelChannelPublisher, FunnelChannels, FunnelClaude, FunnelClock, FunnelConnectorFactory, FunnelConnectorListener, FunnelDotenvReader, FunnelEvent, FunnelEventLog, FunnelEventRecord, FunnelFileSystem, FunnelGateway, FunnelGatewayServer, FunnelGatewayToken, FunnelIdGenerator, FunnelListenerSupervisor, FunnelListenersClient, FunnelLocalConfig, FunnelLocalConfigSync, FunnelLogger, FunnelMcp, FunnelProcessRunner, FunnelProfiles, FunnelSettingsReader, FunnelSettingsStore, FunnelSlackEventProcessor, FunnelTokenPrompter, type GatewayEmitInput, type GatewayRouteDeps, type Env$1 as GatewayServerEnv, GhConnectorConfig, LOCAL_CONFIG_FILENAME, LOCAL_ENV_FILENAME, LaunchOptions, ListListenersResult, ListenerEntry, ListenerOpResult, LocalConfig, LocalConfigSyncResult, LogEntry, MemoryFunnelClock, MemoryFunnelEventLog, MemoryFunnelFileSystem, MemoryFunnelIdGenerator, MemoryFunnelLogger, MemoryFunnelProcessRunner, MemoryFunnelTokenPrompter, MemoryProcessCall, MemoryProcessHandler, MemoryProcessResponse, MemoryProcessSyncHandler, MockFunnelSettingsReader, NodeFunnelClock, NodeFunnelFileSystem, NodeFunnelIdGenerator, NodeFunnelLogger, NodeFunnelProcessRunner, NodeFunnelTokenPrompter, NoopFunnelLogger, NotifyFn, OnFunnelError, ProcessListStub, ProcessSnapshot, ProfileConfig, ProfileSpec, PublishRequest, PublishResponse, PublishResult, ReplayableEvent, RunOptions, RunResult, SETTINGS_PATH, SETTINGS_VERSION, ScheduleCatchupPolicy, ScheduleConnectorConfig, ScheduleEntry, ScheduleListenerOptions, Settings, SlackConnectorConfig, SlackListenerOptions, SlackProcessed, SlackProcessedEmit, SlackProcessedSkip, SlackRawEvent, SqliteFunnelEventLog, channelConfigSchema, channelDeliveryModeSchema, channelSpecSchema, app as cliApp, connectorConfigSchema, connectorSpecSchema, createCliApp, createSettings, discordConnectorSchema, factory, funnelEventSchema, funnelJsonSchema, ghConnectorSchema, launchTui, localConfigSchema, profileConfigSchema, profileSpecSchema, publishRequestSchema, publishResponseSchema, queryToCliArgs, scheduleCatchupPolicySchema, scheduleConnectorSchema, scheduleEntrySchema, settingsSchema, slackConnectorSchema, startChannelServer, toRequest };
|