aibroker 0.5.1 → 0.6.2

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 (133) hide show
  1. package/README.md +263 -104
  2. package/dist/adapters/iterm/iterm2-api.d.ts +20 -0
  3. package/dist/adapters/iterm/iterm2-api.d.ts.map +1 -0
  4. package/dist/adapters/iterm/iterm2-api.js +244 -0
  5. package/dist/adapters/iterm/iterm2-api.js.map +1 -0
  6. package/dist/adapters/iterm/sessions.d.ts +1 -0
  7. package/dist/adapters/iterm/sessions.d.ts.map +1 -1
  8. package/dist/adapters/iterm/sessions.js +26 -2
  9. package/dist/adapters/iterm/sessions.js.map +1 -1
  10. package/dist/adapters/kokoro/media.js +2 -2
  11. package/dist/adapters/kokoro/media.js.map +1 -1
  12. package/dist/adapters/pailot/gateway.d.ts +5 -6
  13. package/dist/adapters/pailot/gateway.d.ts.map +1 -1
  14. package/dist/adapters/pailot/gateway.js +575 -34
  15. package/dist/adapters/pailot/gateway.js.map +1 -1
  16. package/dist/aibp/bridge.d.ts +123 -0
  17. package/dist/aibp/bridge.d.ts.map +1 -0
  18. package/dist/aibp/bridge.js +363 -0
  19. package/dist/aibp/bridge.js.map +1 -0
  20. package/dist/aibp/envelope.d.ts +26 -0
  21. package/dist/aibp/envelope.d.ts.map +1 -0
  22. package/dist/aibp/envelope.js +101 -0
  23. package/dist/aibp/envelope.js.map +1 -0
  24. package/dist/aibp/index.d.ts +11 -0
  25. package/dist/aibp/index.d.ts.map +1 -0
  26. package/dist/aibp/index.js +10 -0
  27. package/dist/aibp/index.js.map +1 -0
  28. package/dist/aibp/registry.d.ts +71 -0
  29. package/dist/aibp/registry.d.ts.map +1 -0
  30. package/dist/aibp/registry.js +408 -0
  31. package/dist/aibp/registry.js.map +1 -0
  32. package/dist/aibp/types.d.ts +91 -0
  33. package/dist/aibp/types.d.ts.map +1 -0
  34. package/dist/aibp/types.js +8 -0
  35. package/dist/aibp/types.js.map +1 -0
  36. package/dist/core/hybrid.d.ts +2 -0
  37. package/dist/core/hybrid.d.ts.map +1 -1
  38. package/dist/core/hybrid.js +8 -0
  39. package/dist/core/hybrid.js.map +1 -1
  40. package/dist/core/state.d.ts +12 -0
  41. package/dist/core/state.d.ts.map +1 -1
  42. package/dist/core/state.js +34 -0
  43. package/dist/core/state.js.map +1 -1
  44. package/dist/core/status-cache.d.ts +51 -0
  45. package/dist/core/status-cache.d.ts.map +1 -0
  46. package/dist/core/status-cache.js +62 -0
  47. package/dist/core/status-cache.js.map +1 -0
  48. package/dist/daemon/adapter-registry.d.ts +5 -0
  49. package/dist/daemon/adapter-registry.d.ts.map +1 -1
  50. package/dist/daemon/adapter-registry.js +94 -4
  51. package/dist/daemon/adapter-registry.js.map +1 -1
  52. package/dist/daemon/cli.d.ts +1 -0
  53. package/dist/daemon/cli.d.ts.map +1 -1
  54. package/dist/daemon/cli.js +95 -3
  55. package/dist/daemon/cli.js.map +1 -1
  56. package/dist/daemon/command-context.d.ts +28 -0
  57. package/dist/daemon/command-context.d.ts.map +1 -0
  58. package/dist/daemon/command-context.js +13 -0
  59. package/dist/daemon/command-context.js.map +1 -0
  60. package/dist/daemon/commands.d.ts +22 -0
  61. package/dist/daemon/commands.d.ts.map +1 -0
  62. package/dist/daemon/commands.js +849 -0
  63. package/dist/daemon/commands.js.map +1 -0
  64. package/dist/daemon/core-handlers.d.ts.map +1 -1
  65. package/dist/daemon/core-handlers.js +758 -3
  66. package/dist/daemon/core-handlers.js.map +1 -1
  67. package/dist/daemon/create-adapter.js +2 -1
  68. package/dist/daemon/create-adapter.js.map +1 -1
  69. package/dist/daemon/image-context.d.ts +56 -0
  70. package/dist/daemon/image-context.d.ts.map +1 -0
  71. package/dist/daemon/image-context.js +116 -0
  72. package/dist/daemon/image-context.js.map +1 -0
  73. package/dist/daemon/image-gen/index.d.ts +22 -0
  74. package/dist/daemon/image-gen/index.d.ts.map +1 -0
  75. package/dist/daemon/image-gen/index.js +129 -0
  76. package/dist/daemon/image-gen/index.js.map +1 -0
  77. package/dist/daemon/image-gen/providers/cloudflare.d.ts +13 -0
  78. package/dist/daemon/image-gen/providers/cloudflare.d.ts.map +1 -0
  79. package/dist/daemon/image-gen/providers/cloudflare.js +63 -0
  80. package/dist/daemon/image-gen/providers/cloudflare.js.map +1 -0
  81. package/dist/daemon/image-gen/providers/huggingface.d.ts +12 -0
  82. package/dist/daemon/image-gen/providers/huggingface.d.ts.map +1 -0
  83. package/dist/daemon/image-gen/providers/huggingface.js +58 -0
  84. package/dist/daemon/image-gen/providers/huggingface.js.map +1 -0
  85. package/dist/daemon/image-gen/providers/pollinations.d.ts +11 -0
  86. package/dist/daemon/image-gen/providers/pollinations.d.ts.map +1 -0
  87. package/dist/daemon/image-gen/providers/pollinations.js +39 -0
  88. package/dist/daemon/image-gen/providers/pollinations.js.map +1 -0
  89. package/dist/daemon/image-gen/providers/replicate.d.ts +9 -0
  90. package/dist/daemon/image-gen/providers/replicate.d.ts.map +1 -0
  91. package/dist/daemon/image-gen/providers/replicate.js +158 -0
  92. package/dist/daemon/image-gen/providers/replicate.js.map +1 -0
  93. package/dist/daemon/image-gen/types.d.ts +41 -0
  94. package/dist/daemon/image-gen/types.d.ts.map +1 -0
  95. package/dist/daemon/image-gen/types.js +5 -0
  96. package/dist/daemon/image-gen/types.js.map +1 -0
  97. package/dist/daemon/index.d.ts.map +1 -1
  98. package/dist/daemon/index.js +260 -6
  99. package/dist/daemon/index.js.map +1 -1
  100. package/dist/daemon/screenshot.d.ts +12 -0
  101. package/dist/daemon/screenshot.d.ts.map +1 -0
  102. package/dist/daemon/screenshot.js +252 -0
  103. package/dist/daemon/screenshot.js.map +1 -0
  104. package/dist/daemon/session-content.d.ts +27 -0
  105. package/dist/daemon/session-content.d.ts.map +1 -0
  106. package/dist/daemon/session-content.js +76 -0
  107. package/dist/daemon/session-content.js.map +1 -0
  108. package/dist/daemon/vision.d.ts +46 -0
  109. package/dist/daemon/vision.d.ts.map +1 -0
  110. package/dist/daemon/vision.js +176 -0
  111. package/dist/daemon/vision.js.map +1 -0
  112. package/dist/index.d.ts +6 -1
  113. package/dist/index.d.ts.map +1 -1
  114. package/dist/index.js +4 -1
  115. package/dist/index.js.map +1 -1
  116. package/dist/ipc/validate.d.ts +52 -0
  117. package/dist/ipc/validate.d.ts.map +1 -0
  118. package/dist/ipc/validate.js +129 -0
  119. package/dist/ipc/validate.js.map +1 -0
  120. package/dist/mcp/index.d.ts +23 -0
  121. package/dist/mcp/index.d.ts.map +1 -0
  122. package/dist/mcp/index.js +787 -0
  123. package/dist/mcp/index.js.map +1 -0
  124. package/dist/types/broker.d.ts +3 -1
  125. package/dist/types/broker.d.ts.map +1 -1
  126. package/dist/types/broker.js.map +1 -1
  127. package/package.json +5 -2
  128. package/templates/adapter/ONBOARDING_PROMPT.md +51 -29
  129. package/templates/adapter/README.md.tmpl +14 -31
  130. package/templates/adapter/package.json.tmpl +1 -1
  131. package/templates/adapter/src/watcher/commands.ts.tmpl +24 -126
  132. package/templates/adapter/src/watcher/index.ts.tmpl +112 -88
  133. package/templates/adapter/src/watcher/ipc-server.ts.tmpl +27 -3
@@ -0,0 +1,26 @@
1
+ /**
2
+ * AIBP envelope utilities — create, parse, and validate AIBP messages.
3
+ */
4
+ import type { AibpMessage, CommandPayload, ImagePayload, StatusPayload, SystemEvent, SystemPayload, TextPayload, TypingPayload, VoicePayload } from "./types.js";
5
+ export declare function text(src: string, dst: string, content: string): AibpMessage<TextPayload>;
6
+ export declare function voice(src: string, dst: string, audioBase64: string, transcript: string, durationMs?: number): AibpMessage<VoicePayload>;
7
+ export declare function image(src: string, dst: string, imageBase64: string, mimeType: string, caption?: string): AibpMessage<ImagePayload>;
8
+ export declare function typing(src: string, dst: string, active: boolean): AibpMessage<TypingPayload>;
9
+ export declare function status(src: string, dst: string, subject: string, state: StatusPayload["state"], summary?: string): AibpMessage<StatusPayload>;
10
+ export declare function command(src: string, dst: string, cmd: string, args?: Record<string, unknown>): AibpMessage<CommandPayload>;
11
+ export declare function system(src: string, dst: string, event: SystemEvent, data?: Record<string, unknown>): AibpMessage<SystemPayload>;
12
+ export declare function parse(raw: string): AibpMessage | null;
13
+ export declare function isAibpMessage(obj: unknown): obj is AibpMessage;
14
+ export declare function serialize(msg: AibpMessage): string;
15
+ /** Extract the address type prefix (e.g., "session" from "session:ABC123") */
16
+ export declare function addressType(address: string): string;
17
+ /** Extract the address value (e.g., "ABC123" from "session:ABC123") */
18
+ export declare function addressValue(address: string): string;
19
+ /** Check if an address is a hub-local address (not a remote hub reference) */
20
+ export declare function isLocal(address: string): boolean;
21
+ /** For mesh addresses like "hub:mac-mini/session:DEF456", extract the hub and local parts */
22
+ export declare function parseMeshAddress(address: string): {
23
+ hub: string;
24
+ local: string;
25
+ } | null;
26
+ //# sourceMappingURL=envelope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../src/aibp/envelope.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EACV,WAAW,EAEX,cAAc,EACd,YAAY,EAEZ,aAAa,EACb,WAAW,EACX,aAAa,EACb,WAAW,EACX,aAAa,EACb,YAAY,EACb,MAAM,YAAY,CAAC;AAyBpB,wBAAgB,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,WAAW,CAAC,WAAW,CAAC,CAExF;AAED,wBAAgB,KAAK,CACnB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,UAAU,CAAC,EAAE,MAAM,GAClB,WAAW,CAAC,YAAY,CAAC,CAE3B;AAED,wBAAgB,KAAK,CACnB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,MAAM,GACf,WAAW,CAAC,YAAY,CAAC,CAE3B;AAED,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,WAAW,CAAC,aAAa,CAAC,CAE5F;AAED,wBAAgB,MAAM,CACpB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,EAC7B,OAAO,CAAC,EAAE,MAAM,GACf,WAAW,CAAC,aAAa,CAAC,CAE5B;AAED,wBAAgB,OAAO,CACrB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACjC,WAAW,CAAC,cAAc,CAAC,CAE7B;AAED,wBAAgB,MAAM,CACpB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,WAAW,EAClB,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACjC,WAAW,CAAC,aAAa,CAAC,CAE5B;AAMD,wBAAgB,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAQrD;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,WAAW,CAa9D;AAMD,wBAAgB,SAAS,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,CAElD;AAMD,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGnD;AAED,uEAAuE;AACvE,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGpD;AAED,8EAA8E;AAC9E,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEhD;AAED,6FAA6F;AAC7F,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAOvF"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * AIBP envelope utilities — create, parse, and validate AIBP messages.
3
+ */
4
+ import { randomUUID } from "node:crypto";
5
+ const AIBP_VERSION = "0.1";
6
+ // ---------------------------------------------------------------------------
7
+ // Factory — create typed messages with automatic envelope fields
8
+ // ---------------------------------------------------------------------------
9
+ function envelope(src, dst, type, payload) {
10
+ return {
11
+ aibp: AIBP_VERSION,
12
+ id: randomUUID(),
13
+ ts: Date.now(),
14
+ src,
15
+ dst,
16
+ type,
17
+ payload,
18
+ };
19
+ }
20
+ export function text(src, dst, content) {
21
+ return envelope(src, dst, "TEXT", { content });
22
+ }
23
+ export function voice(src, dst, audioBase64, transcript, durationMs) {
24
+ return envelope(src, dst, "VOICE", { audioBase64, transcript, durationMs });
25
+ }
26
+ export function image(src, dst, imageBase64, mimeType, caption) {
27
+ return envelope(src, dst, "IMAGE", { imageBase64, mimeType, caption });
28
+ }
29
+ export function typing(src, dst, active) {
30
+ return envelope(src, dst, "TYPING", { active });
31
+ }
32
+ export function status(src, dst, subject, state, summary) {
33
+ return envelope(src, dst, "STATUS", { subject, state, summary });
34
+ }
35
+ export function command(src, dst, cmd, args = {}) {
36
+ return envelope(src, dst, "COMMAND", { command: cmd, args });
37
+ }
38
+ export function system(src, dst, event, data = {}) {
39
+ return envelope(src, dst, "SYSTEM", { event, ...data });
40
+ }
41
+ // ---------------------------------------------------------------------------
42
+ // Parsing — validate incoming JSON
43
+ // ---------------------------------------------------------------------------
44
+ export function parse(raw) {
45
+ try {
46
+ const obj = JSON.parse(raw);
47
+ if (!isAibpMessage(obj))
48
+ return null;
49
+ return obj;
50
+ }
51
+ catch {
52
+ return null;
53
+ }
54
+ }
55
+ export function isAibpMessage(obj) {
56
+ if (typeof obj !== "object" || obj === null)
57
+ return false;
58
+ const m = obj;
59
+ return (typeof m.aibp === "string" &&
60
+ typeof m.id === "string" &&
61
+ typeof m.ts === "number" &&
62
+ typeof m.src === "string" &&
63
+ typeof m.dst === "string" &&
64
+ typeof m.type === "string" &&
65
+ typeof m.payload === "object" &&
66
+ m.payload !== null);
67
+ }
68
+ // ---------------------------------------------------------------------------
69
+ // Serialize — NDJSON line
70
+ // ---------------------------------------------------------------------------
71
+ export function serialize(msg) {
72
+ return JSON.stringify(msg) + "\n";
73
+ }
74
+ // ---------------------------------------------------------------------------
75
+ // Address helpers
76
+ // ---------------------------------------------------------------------------
77
+ /** Extract the address type prefix (e.g., "session" from "session:ABC123") */
78
+ export function addressType(address) {
79
+ const colon = address.indexOf(":");
80
+ return colon > 0 ? address.slice(0, colon) : address;
81
+ }
82
+ /** Extract the address value (e.g., "ABC123" from "session:ABC123") */
83
+ export function addressValue(address) {
84
+ const colon = address.indexOf(":");
85
+ return colon > 0 ? address.slice(colon + 1) : address;
86
+ }
87
+ /** Check if an address is a hub-local address (not a remote hub reference) */
88
+ export function isLocal(address) {
89
+ return !address.includes("/");
90
+ }
91
+ /** For mesh addresses like "hub:mac-mini/session:DEF456", extract the hub and local parts */
92
+ export function parseMeshAddress(address) {
93
+ const slash = address.indexOf("/");
94
+ if (slash < 0)
95
+ return null;
96
+ return {
97
+ hub: address.slice(0, slash),
98
+ local: address.slice(slash + 1),
99
+ };
100
+ }
101
+ //# sourceMappingURL=envelope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envelope.js","sourceRoot":"","sources":["../../src/aibp/envelope.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * AIBP — AIBroker Interchange Protocol
3
+ *
4
+ * Public API for the protocol layer.
5
+ */
6
+ export * from "./types.js";
7
+ export * as msg from "./envelope.js";
8
+ export { PluginRegistry } from "./registry.js";
9
+ export type { SendFn } from "./registry.js";
10
+ export { AibpBridge } from "./bridge.js";
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/aibp/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,YAAY,CAAC;AAC3B,OAAO,KAAK,GAAG,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,YAAY,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * AIBP — AIBroker Interchange Protocol
3
+ *
4
+ * Public API for the protocol layer.
5
+ */
6
+ export * from "./types.js";
7
+ export * as msg from "./envelope.js";
8
+ export { PluginRegistry } from "./registry.js";
9
+ export { AibpBridge } from "./bridge.js";
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/aibp/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,YAAY,CAAC;AAC3B,OAAO,KAAK,GAAG,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * AIBP Plugin Registry — manages plugin connections, channels, and routing.
3
+ *
4
+ * This is the hub's brain. It knows:
5
+ * - Which plugins are registered and their capabilities
6
+ * - Which channels exist and who has joined them
7
+ * - Where to route each message based on dst address
8
+ * - What to buffer when a recipient is offline
9
+ */
10
+ import type { AibpMessage, ChannelMembership, CommandSpec, PluginSpec, RegisteredPlugin } from "./types.js";
11
+ export type SendFn = (msg: AibpMessage) => void;
12
+ export declare class PluginRegistry {
13
+ /** address → connection */
14
+ private plugins;
15
+ /** channel name → membership */
16
+ private channels;
17
+ /** command name → plugin address */
18
+ private commands;
19
+ /**
20
+ * Register a plugin. Returns the REGISTER_ACK message to send back,
21
+ * or an ERROR message if registration fails.
22
+ */
23
+ register(spec: PluginSpec, send: SendFn): AibpMessage;
24
+ /**
25
+ * Unregister a plugin (graceful disconnect or crash cleanup).
26
+ */
27
+ unregister(address: string, reason?: string): void;
28
+ /**
29
+ * Join a channel. Creates the channel if it doesn't exist.
30
+ */
31
+ join(address: string, channel: string): AibpMessage;
32
+ /**
33
+ * Part a channel.
34
+ */
35
+ part(address: string, channel: string, reason?: string): AibpMessage;
36
+ /**
37
+ * Route a message to its destination.
38
+ *
39
+ * Routing rules:
40
+ * 1. If dst is a direct address (plugin/session/mobile), deliver to that plugin
41
+ * 2. If dst is a channel, fan out to all members
42
+ * 3. If dst is "hub:local", handle as a hub command
43
+ * 4. If dst contains "/" (mesh), forward to bridge plugin
44
+ * 5. If recipient is offline, buffer in outbox
45
+ */
46
+ route(msg: AibpMessage): void;
47
+ private fanOut;
48
+ private routeToMesh;
49
+ private handleHubMessage;
50
+ private handleBuiltinCommand;
51
+ private bufferMessage;
52
+ private drainOutbox;
53
+ /**
54
+ * Call periodically (e.g., every 30s) to check plugin health.
55
+ */
56
+ heartbeatCheck(): void;
57
+ getPlugin(address: string): RegisteredPlugin | undefined;
58
+ getChannel(channel: string): ChannelMembership | undefined;
59
+ getPluginByType(type: string): RegisteredPlugin[];
60
+ getCommandOwner(command: string): string | undefined;
61
+ listPlugins(): RegisteredPlugin[];
62
+ listChannels(): ChannelMembership[];
63
+ listCommands(): Array<{
64
+ name: string;
65
+ owner: string;
66
+ spec?: CommandSpec;
67
+ }>;
68
+ private sendTo;
69
+ private resolveAddress;
70
+ }
71
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/aibp/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EACV,WAAW,EACX,iBAAiB,EACjB,WAAW,EACX,UAAU,EACV,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAOpB,MAAM,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,WAAW,KAAK,IAAI,CAAC;AAOhD,qBAAa,cAAc;IACzB,2BAA2B;IAC3B,OAAO,CAAC,OAAO,CAAuC;IACtD,gCAAgC;IAChC,OAAO,CAAC,QAAQ,CAAwC;IACxD,oCAAoC;IACpC,OAAO,CAAC,QAAQ,CAA6B;IAM7C;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW;IA6CrD;;OAEG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAiB,GAAG,IAAI;IAoC1D;;OAEG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,WAAW;IA6BnD;;OAEG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,GAAG,WAAW;IA2BpE;;;;;;;;;OASG;IACH,KAAK,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI;IA8C7B,OAAO,CAAC,MAAM;IAsBd,OAAO,CAAC,WAAW;IAqBnB,OAAO,CAAC,gBAAgB;IA8BxB,OAAO,CAAC,oBAAoB;IAiD5B,OAAO,CAAC,aAAa;IAWrB,OAAO,CAAC,WAAW;IA+BnB;;OAEG;IACH,cAAc,IAAI,IAAI;IAkBtB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS;IAIxD,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS;IAI1D,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,EAAE;IAMjD,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIpD,WAAW,IAAI,gBAAgB,EAAE;IAIjC,YAAY,IAAI,iBAAiB,EAAE;IAInC,YAAY,IAAI,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,WAAW,CAAA;KAAE,CAAC;IAY1E,OAAO,CAAC,MAAM;IAKd,OAAO,CAAC,cAAc;CAkBvB"}
@@ -0,0 +1,408 @@
1
+ /**
2
+ * AIBP Plugin Registry — manages plugin connections, channels, and routing.
3
+ *
4
+ * This is the hub's brain. It knows:
5
+ * - Which plugins are registered and their capabilities
6
+ * - Which channels exist and who has joined them
7
+ * - Where to route each message based on dst address
8
+ * - What to buffer when a recipient is offline
9
+ */
10
+ import { log } from "../core/log.js";
11
+ import * as envelope from "./envelope.js";
12
+ const MAX_OUTBOX = 50;
13
+ const HEARTBEAT_INTERVAL_MS = 30_000;
14
+ const HEARTBEAT_MISS_DEGRADED = 3;
15
+ const HEARTBEAT_MISS_DEAD = 5;
16
+ export class PluginRegistry {
17
+ /** address → connection */
18
+ plugins = new Map();
19
+ /** channel name → membership */
20
+ channels = new Map();
21
+ /** command name → plugin address */
22
+ commands = new Map();
23
+ // -------------------------------------------------------------------------
24
+ // Plugin lifecycle
25
+ // -------------------------------------------------------------------------
26
+ /**
27
+ * Register a plugin. Returns the REGISTER_ACK message to send back,
28
+ * or an ERROR message if registration fails.
29
+ */
30
+ register(spec, send) {
31
+ const address = this.resolveAddress(spec);
32
+ // Reject duplicate
33
+ if (this.plugins.has(address)) {
34
+ log(`[AIBP] REGISTER rejected: ${address} already registered`);
35
+ return envelope.system("hub:local", address, "ERROR", {
36
+ code: "REGISTER_REJECTED",
37
+ reason: `Plugin address ${address} already registered`,
38
+ });
39
+ }
40
+ const plugin = {
41
+ spec,
42
+ address,
43
+ connectedAt: Date.now(),
44
+ missedPings: 0,
45
+ status: "active",
46
+ joinedChannels: new Set(),
47
+ };
48
+ this.plugins.set(address, { plugin, send });
49
+ // Register commands
50
+ if (spec.commands) {
51
+ for (const cmd of spec.commands) {
52
+ this.commands.set(cmd.name, address);
53
+ }
54
+ }
55
+ // Auto-join declared channels
56
+ for (const ch of spec.channels) {
57
+ this.join(address, ch);
58
+ }
59
+ log(`[AIBP] REGISTER ${spec.type}:${spec.id} → ${address}`);
60
+ const peers = Array.from(this.plugins.keys()).filter((a) => a !== address);
61
+ return envelope.system("hub:local", address, "REGISTER_ACK", {
62
+ assignedAddress: address,
63
+ hubVersion: "0.1",
64
+ peers,
65
+ });
66
+ }
67
+ /**
68
+ * Unregister a plugin (graceful disconnect or crash cleanup).
69
+ */
70
+ unregister(address, reason = "disconnected") {
71
+ const conn = this.plugins.get(address);
72
+ if (!conn)
73
+ return;
74
+ // Part all joined channels
75
+ for (const ch of conn.plugin.joinedChannels) {
76
+ this.part(address, ch, reason);
77
+ }
78
+ // Remove commands
79
+ if (conn.plugin.spec.commands) {
80
+ for (const cmd of conn.plugin.spec.commands) {
81
+ if (this.commands.get(cmd.name) === address) {
82
+ this.commands.delete(cmd.name);
83
+ }
84
+ }
85
+ }
86
+ this.plugins.delete(address);
87
+ log(`[AIBP] UNREGISTER ${address} (${reason})`);
88
+ // Notify all remaining plugins
89
+ for (const [, other] of this.plugins) {
90
+ other.send(envelope.system("hub:local", other.plugin.address, "PLUGIN_OFFLINE", {
91
+ plugin: address,
92
+ reason,
93
+ }));
94
+ }
95
+ }
96
+ // -------------------------------------------------------------------------
97
+ // Channel management
98
+ // -------------------------------------------------------------------------
99
+ /**
100
+ * Join a channel. Creates the channel if it doesn't exist.
101
+ */
102
+ join(address, channel) {
103
+ let membership = this.channels.get(channel);
104
+ if (!membership) {
105
+ membership = { channel, members: new Set(), outbox: [] };
106
+ this.channels.set(channel, membership);
107
+ }
108
+ membership.members.add(address);
109
+ const conn = this.plugins.get(address);
110
+ if (conn) {
111
+ conn.plugin.joinedChannels.add(channel);
112
+ }
113
+ log(`[AIBP] JOIN ${address} → ${channel} (${membership.members.size} members)`);
114
+ // Drain outbox for this member
115
+ const buffered = membership.outbox.length;
116
+ if (buffered > 0) {
117
+ this.drainOutbox(address, channel);
118
+ }
119
+ return envelope.system("hub:local", address, "JOIN_ACK", {
120
+ channel,
121
+ members: Array.from(membership.members),
122
+ unreadCount: buffered,
123
+ });
124
+ }
125
+ /**
126
+ * Part a channel.
127
+ */
128
+ part(address, channel, reason = "left") {
129
+ const membership = this.channels.get(channel);
130
+ if (membership) {
131
+ membership.members.delete(address);
132
+ // Clean up empty channels (except persistent session channels)
133
+ if (membership.members.size === 0 && !channel.startsWith("session:")) {
134
+ this.channels.delete(channel);
135
+ }
136
+ }
137
+ const conn = this.plugins.get(address);
138
+ if (conn) {
139
+ conn.plugin.joinedChannels.delete(channel);
140
+ }
141
+ log(`[AIBP] PART ${address} ← ${channel} (${reason})`);
142
+ return envelope.system("hub:local", address, "PART_ACK", {
143
+ channel,
144
+ reason,
145
+ });
146
+ }
147
+ // -------------------------------------------------------------------------
148
+ // Message routing — the core of AIBP
149
+ // -------------------------------------------------------------------------
150
+ /**
151
+ * Route a message to its destination.
152
+ *
153
+ * Routing rules:
154
+ * 1. If dst is a direct address (plugin/session/mobile), deliver to that plugin
155
+ * 2. If dst is a channel, fan out to all members
156
+ * 3. If dst is "hub:local", handle as a hub command
157
+ * 4. If dst contains "/" (mesh), forward to bridge plugin
158
+ * 5. If recipient is offline, buffer in outbox
159
+ */
160
+ route(msg) {
161
+ const { dst } = msg;
162
+ // Mesh routing — forward to the appropriate bridge
163
+ const mesh = envelope.parseMeshAddress(dst);
164
+ if (mesh) {
165
+ this.routeToMesh(msg, mesh.hub, mesh.local);
166
+ return;
167
+ }
168
+ // Hub command
169
+ if (dst === "hub:local") {
170
+ this.handleHubMessage(msg);
171
+ return;
172
+ }
173
+ // Direct plugin address
174
+ const directConn = this.plugins.get(dst);
175
+ if (directConn) {
176
+ directConn.send(msg);
177
+ return;
178
+ }
179
+ // Channel fan-out
180
+ const membership = this.channels.get(dst);
181
+ if (membership) {
182
+ this.fanOut(msg, membership);
183
+ return;
184
+ }
185
+ // Try to match as a session channel
186
+ if (dst.startsWith("session:")) {
187
+ // Auto-create the channel and buffer
188
+ const newMembership = {
189
+ channel: dst,
190
+ members: new Set(),
191
+ outbox: [],
192
+ };
193
+ this.channels.set(dst, newMembership);
194
+ this.bufferMessage(newMembership, msg);
195
+ return;
196
+ }
197
+ log(`[AIBP] ROUTE FAIL: no destination for ${dst} (from ${msg.src})`);
198
+ }
199
+ fanOut(msg, membership) {
200
+ membership.lastMessageId = msg.id;
201
+ membership.lastMessageTs = msg.ts;
202
+ let delivered = 0;
203
+ for (const member of membership.members) {
204
+ // Don't echo back to sender
205
+ if (member === msg.src)
206
+ continue;
207
+ const conn = this.plugins.get(member);
208
+ if (conn) {
209
+ conn.send(msg);
210
+ delivered++;
211
+ }
212
+ }
213
+ // Buffer for offline members who have joined this channel before
214
+ if (delivered === 0 && membership.members.size === 0) {
215
+ this.bufferMessage(membership, msg);
216
+ }
217
+ }
218
+ routeToMesh(msg, hubAddress, localDst) {
219
+ // Extract the hub ID from hub address (e.g., "hub:mac-mini" → "mac-mini")
220
+ const hubId = hubAddress.startsWith("hub:") ? hubAddress.slice(4) : hubAddress;
221
+ // Try to find the specific bridge for this hub first
222
+ const specificBridge = this.plugins.get(`bridge:${hubId}`);
223
+ if (specificBridge) {
224
+ specificBridge.send(msg);
225
+ return;
226
+ }
227
+ // Fallback: find any bridge plugin
228
+ for (const [, conn] of this.plugins) {
229
+ if (conn.plugin.spec.type === "bridge") {
230
+ conn.send(msg);
231
+ return;
232
+ }
233
+ }
234
+ log(`[AIBP] MESH FAIL: no bridge plugin for ${hubAddress}`);
235
+ }
236
+ handleHubMessage(msg) {
237
+ if (msg.type === "COMMAND") {
238
+ const payload = msg.payload;
239
+ const cmdOwner = this.commands.get(payload.command);
240
+ if (cmdOwner) {
241
+ const conn = this.plugins.get(cmdOwner);
242
+ if (conn) {
243
+ conn.send(msg);
244
+ return;
245
+ }
246
+ }
247
+ // Built-in hub commands
248
+ this.handleBuiltinCommand(msg, payload.command, payload.args);
249
+ return;
250
+ }
251
+ if (msg.type === "SYSTEM") {
252
+ const payload = msg.payload;
253
+ if (payload.event === "PING") {
254
+ const conn = this.plugins.get(msg.src);
255
+ if (conn) {
256
+ conn.plugin.lastPing = Date.now();
257
+ conn.plugin.missedPings = 0;
258
+ conn.plugin.status = "active";
259
+ conn.send(envelope.system("hub:local", msg.src, "PONG"));
260
+ }
261
+ }
262
+ }
263
+ }
264
+ handleBuiltinCommand(msg, cmd, args) {
265
+ const src = msg.src;
266
+ switch (cmd) {
267
+ case "list_channels": {
268
+ const channels = Array.from(this.channels.entries()).map(([name, m]) => ({
269
+ name,
270
+ members: m.members.size,
271
+ lastActivity: m.lastMessageTs,
272
+ outboxSize: m.outbox.length,
273
+ }));
274
+ const reply = envelope.system("hub:local", src, "REGISTER_ACK", { channels });
275
+ this.sendTo(src, reply);
276
+ break;
277
+ }
278
+ case "list_plugins": {
279
+ const plugins = Array.from(this.plugins.entries()).map(([addr, c]) => ({
280
+ address: addr,
281
+ type: c.plugin.spec.type,
282
+ name: c.plugin.spec.name,
283
+ status: c.plugin.status,
284
+ channels: Array.from(c.plugin.joinedChannels),
285
+ }));
286
+ const reply = envelope.system("hub:local", src, "REGISTER_ACK", { plugins });
287
+ this.sendTo(src, reply);
288
+ break;
289
+ }
290
+ default:
291
+ log(`[AIBP] Unknown hub command: ${cmd}`);
292
+ this.sendTo(src, envelope.system("hub:local", src, "ERROR", {
293
+ code: "UNKNOWN_COMMAND",
294
+ command: cmd,
295
+ }));
296
+ }
297
+ }
298
+ // -------------------------------------------------------------------------
299
+ // Outbox
300
+ // -------------------------------------------------------------------------
301
+ bufferMessage(membership, msg) {
302
+ // Don't buffer typing indicators or pings
303
+ if (msg.type === "TYPING" || msg.type === "SYSTEM")
304
+ return;
305
+ if (membership.outbox.length >= MAX_OUTBOX) {
306
+ membership.outbox.shift(); // Drop oldest
307
+ }
308
+ membership.outbox.push(msg);
309
+ log(`[AIBP] OUTBOX ${msg.dst}: ${membership.outbox.length} buffered`);
310
+ }
311
+ drainOutbox(address, channel) {
312
+ const membership = this.channels.get(channel);
313
+ if (!membership || membership.outbox.length === 0)
314
+ return;
315
+ const conn = this.plugins.get(address);
316
+ if (!conn)
317
+ return;
318
+ const count = membership.outbox.length;
319
+ // Send drain header
320
+ conn.send(envelope.system("hub:local", address, "OUTBOX_DRAIN", {
321
+ channel,
322
+ count,
323
+ summary: `${count} message${count > 1 ? "s" : ""} while offline`,
324
+ }));
325
+ // Deliver buffered messages
326
+ for (const msg of membership.outbox) {
327
+ conn.send(msg);
328
+ }
329
+ membership.outbox = [];
330
+ log(`[AIBP] OUTBOX DRAIN ${channel} → ${address}: ${count} messages`);
331
+ }
332
+ // -------------------------------------------------------------------------
333
+ // Heartbeat monitoring
334
+ // -------------------------------------------------------------------------
335
+ /**
336
+ * Call periodically (e.g., every 30s) to check plugin health.
337
+ */
338
+ heartbeatCheck() {
339
+ for (const [address, conn] of this.plugins) {
340
+ conn.plugin.missedPings++;
341
+ if (conn.plugin.missedPings >= HEARTBEAT_MISS_DEAD) {
342
+ log(`[AIBP] Plugin dead: ${address} (${conn.plugin.missedPings} missed pings)`);
343
+ this.unregister(address, "heartbeat timeout");
344
+ }
345
+ else if (conn.plugin.missedPings >= HEARTBEAT_MISS_DEGRADED) {
346
+ conn.plugin.status = "degraded";
347
+ log(`[AIBP] Plugin degraded: ${address}`);
348
+ }
349
+ }
350
+ }
351
+ // -------------------------------------------------------------------------
352
+ // Queries
353
+ // -------------------------------------------------------------------------
354
+ getPlugin(address) {
355
+ return this.plugins.get(address)?.plugin;
356
+ }
357
+ getChannel(channel) {
358
+ return this.channels.get(channel);
359
+ }
360
+ getPluginByType(type) {
361
+ return Array.from(this.plugins.values())
362
+ .filter((c) => c.plugin.spec.type === type)
363
+ .map((c) => c.plugin);
364
+ }
365
+ getCommandOwner(command) {
366
+ return this.commands.get(command);
367
+ }
368
+ listPlugins() {
369
+ return Array.from(this.plugins.values()).map((c) => c.plugin);
370
+ }
371
+ listChannels() {
372
+ return Array.from(this.channels.values());
373
+ }
374
+ listCommands() {
375
+ return Array.from(this.commands.entries()).map(([name, owner]) => {
376
+ const conn = this.plugins.get(owner);
377
+ const spec = conn?.plugin.spec.commands?.find((c) => c.name === name);
378
+ return { name, owner, spec };
379
+ });
380
+ }
381
+ // -------------------------------------------------------------------------
382
+ // Internal helpers
383
+ // -------------------------------------------------------------------------
384
+ sendTo(address, msg) {
385
+ const conn = this.plugins.get(address);
386
+ if (conn)
387
+ conn.send(msg);
388
+ }
389
+ resolveAddress(spec) {
390
+ switch (spec.type) {
391
+ case "transport":
392
+ return `transport:${spec.id}`;
393
+ case "terminal":
394
+ return `terminal:${spec.id}`;
395
+ case "mobile":
396
+ return `mobile:${spec.id}`;
397
+ case "bridge":
398
+ return `bridge:${spec.id}`;
399
+ case "mcp":
400
+ return `mcp:${spec.id}`;
401
+ case "hub":
402
+ return `hub:${spec.id}`;
403
+ default:
404
+ return `plugin:${spec.id}`;
405
+ }
406
+ }
407
+ }
408
+ //# sourceMappingURL=registry.js.map