@securecoms/agent-bridge 0.3.2 → 0.5.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.
Files changed (47) hide show
  1. package/README.md +21 -1
  2. package/dist/bin.js +1073 -90
  3. package/dist/bridge-agent.d.ts +68 -7
  4. package/dist/config.d.ts +7 -0
  5. package/dist/http-server.d.ts +42 -0
  6. package/dist/index.js +837 -63
  7. package/dist/memory/hermes-provider.d.ts +21 -0
  8. package/dist/memory/hermes-session-map.d.ts +8 -0
  9. package/dist/memory/hermes-store.d.ts +32 -0
  10. package/dist/memory/hermes-test-fixture.d.ts +5 -0
  11. package/dist/memory/openclaw-provider.d.ts +24 -0
  12. package/dist/memory/openclaw-session-log.d.ts +15 -0
  13. package/dist/memory/openclaw-session-map.d.ts +7 -0
  14. package/dist/memory/provider.d.ts +29 -0
  15. package/dist/memory-taps.d.ts +13 -0
  16. package/dist/preflight-modern.cjs +35 -0
  17. package/dist/preflight-modern.d.cts +1 -0
  18. package/dist/preflight-upgrade.d.cts +30 -0
  19. package/dist/preflight.cjs +277 -0
  20. package/dist/preflight.d.cts +14 -0
  21. package/dist/service/config.d.ts +1 -0
  22. package/dist/service/install-prep.d.ts +68 -0
  23. package/package.json +3 -5
  24. package/dist/attachments.js +0 -49
  25. package/dist/auth.js +0 -56
  26. package/dist/bin.js.pre-c1-f803007 +0 -5795
  27. package/dist/bin.js.pre-c3-096a9a3 +0 -5832
  28. package/dist/bin.js.pre-ffrebuild-b162d4a +0 -5639
  29. package/dist/bin.js.pre-kpheal-20260708-150924 +0 -5531
  30. package/dist/bin.js.pre-kppersist-20260708-152341 +0 -5543
  31. package/dist/bin.js.pre-p0-20260708-102415 +0 -5196
  32. package/dist/bin.js.pre-p1b-02f47e1 +0 -5639
  33. package/dist/bin.js.pre-warmfix-20260708-153705 +0 -5613
  34. package/dist/bin.js.pretrace-113205 +0 -5395
  35. package/dist/bridge-agent.js +0 -831
  36. package/dist/config.js +0 -74
  37. package/dist/coordination.js +0 -63
  38. package/dist/errors.js +0 -25
  39. package/dist/http-server.js +0 -220
  40. package/dist/index.js.pre-p0-20260708-102415 +0 -4879
  41. package/dist/latency.js +0 -87
  42. package/dist/rate-limit.js +0 -56
  43. package/dist/service/config.js +0 -26
  44. package/dist/service/install.js +0 -60
  45. package/dist/service/launchd.js +0 -30
  46. package/dist/service/systemd.js +0 -25
  47. package/dist/ws-server.js +0 -254
@@ -327,6 +327,13 @@ export declare class BridgeAgent {
327
327
  private readonly listeners;
328
328
  private startedAt;
329
329
  private readonly store;
330
+ private readonly memory;
331
+ /** Task 2: warn-once-per-channel guard for the enclave-map fallback (below). */
332
+ private enclaveFallbackWarned;
333
+ /** Task 2: dedupe guard so ingestOnce writes a channel's enclave at most once
334
+ * per process — a channel's enclave is immutable, so no need to UPSERT on
335
+ * every message on the hot receive path (audit M2). */
336
+ private channelEnclaveRecorded;
330
337
  private readonly latency;
331
338
  /** Track 5: injectable blob download fn (default: fetch-based). */
332
339
  private readonly downloadBlobImpl;
@@ -350,6 +357,17 @@ export declare class BridgeAgent {
350
357
  start(): Promise<void>;
351
358
  /** C3: a random 0..SELF_HEAL_SWEEP_JITTER_MS decorrelation offset. */
352
359
  private sweepJitter;
360
+ /**
361
+ * Task 2 (multi-enclave core fix): resolve the enclave to stamp on outbound
362
+ * traffic for `channelId`. The daemon previously stamped `cfg.enclaveId`
363
+ * (its "home" enclave) on EVERY channel, so an agent admitted to a second
364
+ * enclave got a backend 400 on every send/reply there. The channel→enclave
365
+ * map (`channel_meta`, Task 1) is fed by inbound envelopes (`ingestOnce`)
366
+ * and by `listChannels`; a channel not yet in the map (never seen inbound,
367
+ * never discovered) falls back to home and logs once so the fallback is
368
+ * diagnosable (audit H3) rather than silently wrong.
369
+ */
370
+ private resolveEnclave;
353
371
  private reconcileJoin;
354
372
  /**
355
373
  * The held-KP re-Welcome signal (Task 11), shared by EVERY heal path: the
@@ -479,20 +497,57 @@ export declare class BridgeAgent {
479
497
  message_id: string;
480
498
  status: "sent";
481
499
  }>;
482
- listChannels(): Promise<Array<{
500
+ /** Task 3: delegates to the configured MemoryProvider (SecureComsLocal | Null). */
501
+ recordMemory(input: import("@agentvault/connect-mls-store").MemoryRecordInput): Promise<{
502
+ seq: number;
503
+ deduped: boolean;
504
+ }>;
505
+ memoryContext(conversationId: string, limit?: number): Promise<import("@agentvault/connect-mls-store").MemoryContextResult>;
506
+ /**
507
+ * List channels in one enclave (default: the daemon's own home enclave).
508
+ * Task 3: called per-*known* enclave by refreshChannelMeta so a
509
+ * cross-enclave room's is_dm gets resolved — see the scope caveat there
510
+ * (same-tenant only; a cross-tenant enclave 404s under the agent's bearer).
511
+ */
512
+ listChannels(enclaveId?: string): Promise<Array<{
483
513
  channel_id: string;
484
514
  name: string | null;
485
515
  is_dm: boolean;
486
516
  joined: boolean;
517
+ enclave_id: string;
487
518
  }>>;
488
- /** A live channelMeta entry, or undefined if missing OR expired past the TTL. */
519
+ /**
520
+ * A live channelMeta entry, or undefined if missing OR expired past the
521
+ * TTL. A never-cached-this-process channel (no in-memory entry at all —
522
+ * cold start, or every listChannels() call in refreshChannelMeta failed,
523
+ * e.g. network down) falls back to the store's persisted is_dm (Task 3) so
524
+ * a cross-enclave room stays classified across a restart instead of
525
+ * reverting to UNKNOWN/fail-open. The store has no TTL (is_dm is immutable
526
+ * per channel); `name` is not persisted so it comes back undefined on this
527
+ * path and re-resolves once a listChannels() call succeeds.
528
+ *
529
+ * A TTL-*expired* in-memory entry deliberately does NOT use the store
530
+ * fallback and is still treated as a miss — that miss is what drives
531
+ * ingestOnce to retry a refresh each cycle (S-2: keeping `name` fresh after
532
+ * a rename); serving the persisted is_dm there would silently suppress
533
+ * that retry forever.
534
+ */
489
535
  private freshMeta;
490
536
  /**
491
- * One-shot, whole-listing refresh of channelMeta. Called AT MOST ONCE per
492
- * ingest cycle (the caller guards with a cycle-local "refreshed" flag), so a
493
- * burst of K unknown channels fires a single listChannels() instead of K. Any
494
- * listChannels failure is swallowed (UNKNOWN → fail open) so ingest never
495
- * blocks on the network.
537
+ * Whole-listing refresh of channelMeta, one listChannels() call per *known*
538
+ * enclave — the daemon's own home enclave plus every enclave it has learned
539
+ * about from inbound envelopes or a prior discovery (store.distinctEnclaveIds()).
540
+ * Called AT MOST ONCE per ingest cycle (the caller guards with a
541
+ * cycle-local "refreshed" flag). Task 3 (M1): without this, a cross-enclave
542
+ * room is never listed under the home-enclave-only call, so its is_dm never
543
+ * resolves and the @mention filter fails open for that room.
544
+ *
545
+ * Each enclave is wrapped in its own try/catch (scope caveat — audit
546
+ * H2/tenant): list_channels_in_enclave filters on tenant_id, so a
547
+ * same-tenant enclave the agent has learned about resolves fine, but a
548
+ * cross-TENANT federated-partner enclave 404s under this agent's bearer;
549
+ * that enclave's channels are left unresolved (fail open) without aborting
550
+ * the other enclaves in the set.
496
551
  */
497
552
  private refreshChannelMeta;
498
553
  /** A live roster for a channel, or undefined if missing OR expired past the TTL. */
@@ -608,6 +663,12 @@ export declare class BridgeAgent {
608
663
  delivery_pings: number;
609
664
  uptime_s: number;
610
665
  version: string;
666
+ /** Optional memory-adapter counters (e.g. Hermes provider); present only when the active provider exposes stats(). */
667
+ hermes_no_session?: number;
668
+ hermes_skipped?: number;
669
+ hermes_write_failed?: number;
670
+ openclaw_no_session?: number;
671
+ openclaw_read_failed?: number;
611
672
  };
612
673
  /**
613
674
  * Loopback observability snapshot served at GET /v1/metrics.
package/dist/config.d.ts CHANGED
@@ -17,7 +17,14 @@ export interface BridgeConfig {
17
17
  rateLimitCapacity?: number;
18
18
  /** Per-channel send-floor refill rate per minute. Default 20. */
19
19
  rateLimitRefillPerMinute?: number;
20
+ /** Per-agent memory provider. Default "securecoms"; "none" disables the memory taps; "hermes"/"openclaw" read the named harness store. */
21
+ memoryProvider: "securecoms" | "none" | "hermes" | "openclaw";
22
+ /** For memoryProvider="hermes"/"openclaw": base dir of the harness install (default "~/.hermes" / "~/.openclaw"). */
23
+ memoryBaseDir?: string;
24
+ /** For memoryProvider="openclaw": the OpenClaw agent dir slug, e.g. "cortina" (→ <base_dir>/agents/<agent>/). */
25
+ memoryAgent?: string;
20
26
  }
27
+ export declare const REQUIRED: readonly ["api_key", "identity_id", "device_id", "signing_private_key", "enclave_id", "api_base"];
21
28
  export declare function loadConfig(opts: {
22
29
  credentialPath: string;
23
30
  storePath?: string;
@@ -1,4 +1,5 @@
1
1
  import { type Server } from "node:http";
2
+ import { z } from "zod";
2
3
  import type { BridgeAgent, BridgeMessage } from "./bridge-agent.js";
3
4
  export declare function writeSse(res: {
4
5
  destroyed?: boolean;
@@ -24,6 +25,47 @@ export declare function capabilities(opts: {
24
25
  send_types: string[];
25
26
  webhook_push: boolean;
26
27
  };
28
+ export declare const memoryRecordSchema: z.ZodEffects<z.ZodObject<{
29
+ conversation_id: z.ZodString;
30
+ role: z.ZodEnum<["peer", "agent"]>;
31
+ peer_id: z.ZodOptional<z.ZodString>;
32
+ text: z.ZodString;
33
+ modality: z.ZodEnum<["text", "voice"]>;
34
+ message_id: z.ZodOptional<z.ZodString>;
35
+ idempotency_key: z.ZodOptional<z.ZodString>;
36
+ }, "strip", z.ZodTypeAny, {
37
+ role: "peer" | "agent";
38
+ text: string;
39
+ conversation_id: string;
40
+ modality: "text" | "voice";
41
+ message_id?: string | undefined;
42
+ idempotency_key?: string | undefined;
43
+ peer_id?: string | undefined;
44
+ }, {
45
+ role: "peer" | "agent";
46
+ text: string;
47
+ conversation_id: string;
48
+ modality: "text" | "voice";
49
+ message_id?: string | undefined;
50
+ idempotency_key?: string | undefined;
51
+ peer_id?: string | undefined;
52
+ }>, {
53
+ role: "peer" | "agent";
54
+ text: string;
55
+ conversation_id: string;
56
+ modality: "text" | "voice";
57
+ message_id?: string | undefined;
58
+ idempotency_key?: string | undefined;
59
+ peer_id?: string | undefined;
60
+ }, {
61
+ role: "peer" | "agent";
62
+ text: string;
63
+ conversation_id: string;
64
+ modality: "text" | "voice";
65
+ message_id?: string | undefined;
66
+ idempotency_key?: string | undefined;
67
+ peer_id?: string | undefined;
68
+ }>;
27
69
  export declare function createHttpServer(agent: BridgeAgent, opts: HttpServerOptions): {
28
70
  server: Server;
29
71
  closeAllSseStreams: () => void;