aibroker 0.2.6 → 0.6.1

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 (170) hide show
  1. package/README.md +164 -4
  2. package/dist/adapters/iterm/core.d.ts +2 -0
  3. package/dist/adapters/iterm/core.d.ts.map +1 -1
  4. package/dist/adapters/iterm/core.js +13 -5
  5. package/dist/adapters/iterm/core.js.map +1 -1
  6. package/dist/adapters/iterm/iterm2-api.d.ts +20 -0
  7. package/dist/adapters/iterm/iterm2-api.d.ts.map +1 -0
  8. package/dist/adapters/iterm/iterm2-api.js +244 -0
  9. package/dist/adapters/iterm/iterm2-api.js.map +1 -0
  10. package/dist/adapters/iterm/sessions.d.ts.map +1 -1
  11. package/dist/adapters/iterm/sessions.js +3 -2
  12. package/dist/adapters/iterm/sessions.js.map +1 -1
  13. package/dist/adapters/kokoro/media.d.ts +2 -1
  14. package/dist/adapters/kokoro/media.d.ts.map +1 -1
  15. package/dist/adapters/kokoro/media.js +53 -5
  16. package/dist/adapters/kokoro/media.js.map +1 -1
  17. package/dist/adapters/pailot/gateway (SFConflict mnott 2026-03-06-21-13-56).d.ts +49 -0
  18. package/dist/adapters/pailot/gateway (SFConflict mnott 2026-03-06-21-13-56).d.ts.map +1 -0
  19. package/dist/adapters/pailot/gateway (SFConflict mnott 2026-03-06-21-13-56).js +632 -0
  20. package/dist/adapters/pailot/gateway (SFConflict mnott 2026-03-06-21-13-56).js.map +1 -0
  21. package/dist/adapters/pailot/gateway (SFConflict mnott 2026-03-06-21-13-59).js +632 -0
  22. package/dist/adapters/pailot/gateway (SFConflict mnott 2026-03-06-21-15-36).d.ts +49 -0
  23. package/dist/adapters/pailot/gateway (SFConflict mnott 2026-03-06-21-15-36).d.ts.map +1 -0
  24. package/dist/adapters/pailot/gateway (SFConflict mnott 2026-03-06-21-15-36).js +614 -0
  25. package/dist/adapters/pailot/gateway (SFConflict mnott 2026-03-06-21-15-36).js.map +1 -0
  26. package/dist/adapters/pailot/gateway (SFConflict mnott 2026-03-06-21-15-46).js +614 -0
  27. package/dist/adapters/pailot/gateway.d.ts +48 -0
  28. package/dist/adapters/pailot/gateway.d.ts (SFConflict mnott 2026-03-06-21-13-59).map +1 -0
  29. package/dist/adapters/pailot/gateway.d.ts (SFConflict mnott 2026-03-06-21-15-46).map +1 -0
  30. package/dist/adapters/pailot/gateway.d.ts.map +1 -0
  31. package/dist/adapters/pailot/gateway.js +828 -0
  32. package/dist/adapters/pailot/gateway.js (SFConflict mnott 2026-03-06-21-13-59).map +1 -0
  33. package/dist/adapters/pailot/gateway.js (SFConflict mnott 2026-03-06-21-15-46).map +1 -0
  34. package/dist/adapters/pailot/gateway.js.map +1 -0
  35. package/dist/backend/api.d.ts +5 -1
  36. package/dist/backend/api.d.ts.map +1 -1
  37. package/dist/backend/api.js +74 -3
  38. package/dist/backend/api.js.map +1 -1
  39. package/dist/core/hybrid.d.ts +7 -0
  40. package/dist/core/hybrid.d.ts.map +1 -1
  41. package/dist/core/hybrid.js +33 -0
  42. package/dist/core/hybrid.js.map +1 -1
  43. package/dist/core/state.d.ts +3 -0
  44. package/dist/core/state.d.ts.map +1 -1
  45. package/dist/core/state.js +4 -0
  46. package/dist/core/state.js.map +1 -1
  47. package/dist/core/status-cache.d.ts +51 -0
  48. package/dist/core/status-cache.d.ts.map +1 -0
  49. package/dist/core/status-cache.js +62 -0
  50. package/dist/core/status-cache.js.map +1 -0
  51. package/dist/daemon/adapter-registry (SFConflict mnott 2026-03-06-21-15-36).d.ts +63 -0
  52. package/dist/daemon/adapter-registry (SFConflict mnott 2026-03-06-21-15-36).d.ts.map +1 -0
  53. package/dist/daemon/adapter-registry (SFConflict mnott 2026-03-06-21-15-36).js +229 -0
  54. package/dist/daemon/adapter-registry (SFConflict mnott 2026-03-06-21-15-36).js.map +1 -0
  55. package/dist/daemon/adapter-registry.d.ts +63 -0
  56. package/dist/daemon/adapter-registry.d.ts.map +1 -0
  57. package/dist/daemon/adapter-registry.js +240 -0
  58. package/dist/daemon/adapter-registry.js.map +1 -0
  59. package/dist/daemon/cli.d.ts +14 -0
  60. package/dist/daemon/cli.d.ts.map +1 -0
  61. package/dist/daemon/cli.js +150 -0
  62. package/dist/daemon/cli.js.map +1 -0
  63. package/dist/daemon/command-context.d.ts +24 -0
  64. package/dist/daemon/command-context.d.ts.map +1 -0
  65. package/dist/daemon/command-context.js +13 -0
  66. package/dist/daemon/command-context.js.map +1 -0
  67. package/dist/daemon/commands.d.ts +22 -0
  68. package/dist/daemon/commands.d.ts.map +1 -0
  69. package/dist/daemon/commands.js +632 -0
  70. package/dist/daemon/commands.js.map +1 -0
  71. package/dist/daemon/core-handlers.d.ts +24 -0
  72. package/dist/daemon/core-handlers.d.ts.map +1 -0
  73. package/dist/daemon/core-handlers.js +640 -0
  74. package/dist/daemon/core-handlers.js.map +1 -0
  75. package/dist/daemon/create-adapter.d.ts +22 -0
  76. package/dist/daemon/create-adapter.d.ts.map +1 -0
  77. package/dist/daemon/create-adapter.js +153 -0
  78. package/dist/daemon/create-adapter.js.map +1 -0
  79. package/dist/daemon/image-gen.d.ts +28 -0
  80. package/dist/daemon/image-gen.d.ts.map +1 -0
  81. package/dist/daemon/image-gen.js +97 -0
  82. package/dist/daemon/image-gen.js.map +1 -0
  83. package/dist/daemon/index.d.ts +12 -0
  84. package/dist/daemon/index.d.ts.map +1 -0
  85. package/dist/daemon/index.js +184 -0
  86. package/dist/daemon/index.js.map +1 -0
  87. package/dist/daemon/pai-projects.d.ts +68 -0
  88. package/dist/daemon/pai-projects.d.ts.map +1 -0
  89. package/dist/daemon/pai-projects.js +174 -0
  90. package/dist/daemon/pai-projects.js.map +1 -0
  91. package/dist/daemon/screenshot (SFConflict mnott 2026-03-06-21-13-56).d.ts +12 -0
  92. package/dist/daemon/screenshot (SFConflict mnott 2026-03-06-21-13-56).d.ts.map +1 -0
  93. package/dist/daemon/screenshot (SFConflict mnott 2026-03-06-21-13-56).js +252 -0
  94. package/dist/daemon/screenshot (SFConflict mnott 2026-03-06-21-13-56).js.map +1 -0
  95. package/dist/daemon/screenshot (SFConflict mnott 2026-03-06-21-13-59).js +252 -0
  96. package/dist/daemon/screenshot (SFConflict mnott 2026-03-06-21-15-36).d.ts +12 -0
  97. package/dist/daemon/screenshot (SFConflict mnott 2026-03-06-21-15-36).d.ts.map +1 -0
  98. package/dist/daemon/screenshot (SFConflict mnott 2026-03-06-21-15-36).js +240 -0
  99. package/dist/daemon/screenshot (SFConflict mnott 2026-03-06-21-15-36).js.map +1 -0
  100. package/dist/daemon/screenshot (SFConflict mnott 2026-03-06-21-15-46).js +240 -0
  101. package/dist/daemon/screenshot.d.ts +12 -0
  102. package/dist/daemon/screenshot.d.ts (SFConflict mnott 2026-03-06-21-13-59).map +1 -0
  103. package/dist/daemon/screenshot.d.ts (SFConflict mnott 2026-03-06-21-15-46).map +1 -0
  104. package/dist/daemon/screenshot.d.ts.map +1 -0
  105. package/dist/daemon/screenshot.js +252 -0
  106. package/dist/daemon/screenshot.js (SFConflict mnott 2026-03-06-21-13-59).map +1 -0
  107. package/dist/daemon/screenshot.js (SFConflict mnott 2026-03-06-21-15-46).map +1 -0
  108. package/dist/daemon/screenshot.js.map +1 -0
  109. package/dist/daemon/session-content.d.ts +27 -0
  110. package/dist/daemon/session-content.d.ts.map +1 -0
  111. package/dist/daemon/session-content.js +76 -0
  112. package/dist/daemon/session-content.js.map +1 -0
  113. package/dist/daemon/vision.d.ts +46 -0
  114. package/dist/daemon/vision.d.ts.map +1 -0
  115. package/dist/daemon/vision.js +176 -0
  116. package/dist/daemon/vision.js.map +1 -0
  117. package/dist/index.d.ts +16 -2
  118. package/dist/index.d.ts.map +1 -1
  119. package/dist/index.js +12 -1
  120. package/dist/index.js.map +1 -1
  121. package/dist/ipc/client.d.ts +4 -1
  122. package/dist/ipc/client.d.ts.map +1 -1
  123. package/dist/ipc/client.js +10 -1
  124. package/dist/ipc/client.js.map +1 -1
  125. package/dist/ipc/validate.d.ts +52 -0
  126. package/dist/ipc/validate.d.ts.map +1 -0
  127. package/dist/ipc/validate.js +129 -0
  128. package/dist/ipc/validate.js.map +1 -0
  129. package/dist/mcp/index (SFConflict mnott 2026-03-06-21-13-56).d.ts +23 -0
  130. package/dist/mcp/index (SFConflict mnott 2026-03-06-21-13-56).d.ts.map +1 -0
  131. package/dist/mcp/index (SFConflict mnott 2026-03-06-21-13-56).js +595 -0
  132. package/dist/mcp/index (SFConflict mnott 2026-03-06-21-13-56).js.map +1 -0
  133. package/dist/mcp/index (SFConflict mnott 2026-03-06-21-13-59).js +595 -0
  134. package/dist/mcp/index (SFConflict mnott 2026-03-06-21-15-36).d.ts +23 -0
  135. package/dist/mcp/index (SFConflict mnott 2026-03-06-21-15-36).d.ts.map +1 -0
  136. package/dist/mcp/index (SFConflict mnott 2026-03-06-21-15-36).js +592 -0
  137. package/dist/mcp/index (SFConflict mnott 2026-03-06-21-15-36).js.map +1 -0
  138. package/dist/mcp/index (SFConflict mnott 2026-03-06-21-15-46).js +592 -0
  139. package/dist/mcp/index.d.ts +23 -0
  140. package/dist/mcp/index.d.ts.map +1 -0
  141. package/dist/mcp/index.js +660 -0
  142. package/dist/mcp/index.js (SFConflict mnott 2026-03-06-21-13-59).map +1 -0
  143. package/dist/mcp/index.js (SFConflict mnott 2026-03-06-21-15-46).map +1 -0
  144. package/dist/mcp/index.js.map +1 -0
  145. package/dist/types/adapter.d.ts +41 -0
  146. package/dist/types/adapter.d.ts.map +1 -0
  147. package/dist/types/adapter.js +2 -0
  148. package/dist/types/adapter.js.map +1 -0
  149. package/dist/types/backend.d.ts +29 -1
  150. package/dist/types/backend.d.ts.map +1 -1
  151. package/dist/types/broker.d.ts +47 -0
  152. package/dist/types/broker.d.ts.map +1 -0
  153. package/dist/types/broker.js +21 -0
  154. package/dist/types/broker.js.map +1 -0
  155. package/dist/types/index.d.ts +2 -0
  156. package/dist/types/index.d.ts.map +1 -1
  157. package/dist/types/index.js +2 -0
  158. package/dist/types/index.js.map +1 -1
  159. package/package.json +12 -2
  160. package/templates/adapter/ONBOARDING_PROMPT.md +309 -0
  161. package/templates/adapter/README.md.tmpl +81 -0
  162. package/templates/adapter/package.json.tmpl +23 -0
  163. package/templates/adapter/src/watcher/cli.ts.tmpl +12 -0
  164. package/templates/adapter/src/watcher/commands.ts.tmpl +44 -0
  165. package/templates/adapter/src/watcher/connection.ts.tmpl +59 -0
  166. package/templates/adapter/src/watcher/index.ts.tmpl +201 -0
  167. package/templates/adapter/src/watcher/ipc-server.ts.tmpl +250 -0
  168. package/templates/adapter/src/watcher/send.ts.tmpl +62 -0
  169. package/templates/adapter/src/watcher/state.ts.tmpl +39 -0
  170. package/templates/adapter/tsconfig.json.tmpl +14 -0
@@ -0,0 +1,309 @@
1
+ # AIBroker Adapter Onboarding — AI-Guided Creation
2
+
3
+ You are helping a developer create a new AIBroker messaging adapter. Your job is to ask up to 5 targeted questions, then generate a complete, working adapter from the scaffold templates.
4
+
5
+ Work through the following phases in order.
6
+
7
+ ---
8
+
9
+ ## Phase 1: Interview (5 questions max)
10
+
11
+ Ask only what you need. If the answer is obvious from context (e.g. the user says "Discord"), skip the question. Combine questions where sensible. Never ask more than 5.
12
+
13
+ **The 5 questions:**
14
+
15
+ 1. **Service name** — What service are you connecting? (e.g. Signal, Discord, Slack, IRC, Matrix)
16
+ 2. **Package name** — What npm package should be used? (If you don't know, say "search for me" — you will search npm.)
17
+ 3. **Auth method** — How does the SDK authenticate? (QR code scan, phone number + OTP, API key, OAuth, bot token, username/password)
18
+ 4. **Message model** — Does the service have the concept of channels/rooms/groups, or is it always a 1:1 direct chat? Who is the default recipient?
19
+ 5. **Voice support** — Does the service support sending voice/audio messages? If yes, what format does it accept? (Most accept OGG Opus or MP3.)
20
+
21
+ If the user already answered any of these in their initial message, skip those questions.
22
+
23
+ ---
24
+
25
+ ## Phase 2: npm Research
26
+
27
+ Before generating code, search npm for the best library for this service:
28
+
29
+ ```bash
30
+ # Search npm for available packages
31
+ npm search <service-name> --json | head -20
32
+
33
+ # Read the top candidate's README
34
+ npm show <package-name> readme
35
+ ```
36
+
37
+ Pick the most maintained package (high weekly downloads, recent publish date, active repo). If the user specified a package, verify it exists and read its docs anyway.
38
+
39
+ Read the package README for:
40
+ - Connection/auth pattern (how to establish a session)
41
+ - How to receive incoming messages (event name, callback signature)
42
+ - How to send a text message (method name, arguments)
43
+ - How to send a file/audio (if applicable)
44
+ - Session persistence (does it save credentials to disk?)
45
+
46
+ ---
47
+
48
+ ## Phase 3: Generate the Adapter
49
+
50
+ Generate all files listed below. Use the scaffold templates in `templates/adapter/` as the starting point and replace all `{{ADAPTER_NAME}}` and `{{DISPLAY_NAME}}` placeholders.
51
+
52
+ **Variable substitution:**
53
+ - `{{ADAPTER_NAME}}` — lowercase hyphenated package name (e.g. `signal-bridge`, `discord-adapter`)
54
+ - `{{DISPLAY_NAME}}` — human-readable service name (e.g. `Signal`, `Discord`)
55
+
56
+ ### Files to generate
57
+
58
+ **`package.json`** — from `templates/adapter/package.json.tmpl`
59
+ - Fill in name, description
60
+ - Add the chosen npm library to `dependencies`
61
+
62
+ **`tsconfig.json`** — from `templates/adapter/tsconfig.json.tmpl`
63
+ - No changes needed
64
+
65
+ **`src/watcher/state.ts`** — from `templates/adapter/src/watcher/state.ts.tmpl`
66
+ - Replace placeholders only
67
+ - The socket path must be `/tmp/{{ADAPTER_NAME}}-watcher.sock`
68
+
69
+ **`src/watcher/connection.ts`** — from `templates/adapter/src/watcher/connection.ts.tmpl`
70
+ - THIS IS THE CORE IMPLEMENTATION FILE — replace the stub with real SDK code
71
+ - Implement `connectWatcher()` using the library you researched
72
+ - The function must:
73
+ 1. Load credentials from `appDir` (use `getAppDir()` from aibroker if available, or `os.homedir()` + `.{{ADAPTER_NAME}}/auth/`)
74
+ 2. Establish connection to the service
75
+ 3. Subscribe to incoming messages, calling `onMessage(text, timestamp)` for each
76
+ 4. Return `cleanup()` to disconnect gracefully
77
+ 5. Return `triggerLogin()` to start a fresh auth flow (QR, OTP, etc.)
78
+ - Include all necessary imports from the chosen npm package
79
+ - Handle reconnection if the SDK supports it
80
+ - Log connection events with `log()` from aibroker
81
+
82
+ **`src/watcher/send.ts`** — from `templates/adapter/src/watcher/send.ts.tmpl`
83
+ - Replace stubs with real SDK delivery calls
84
+ - `sendText(text, recipient?)` — send plain text
85
+ - `sendVoice(audioPath, recipient?)` — send OGG Opus audio file (skip with a clear comment if service does not support voice)
86
+ - `sendFile(filePath, caption?, mimetype?, recipient?)` — send document attachment
87
+
88
+ **`src/watcher/commands.ts`** — from `templates/adapter/src/watcher/commands.ts.tmpl`
89
+ - Replace placeholders only
90
+ - This is a thin handler — only /restart and /login are local
91
+ - All other commands are forwarded to the hub by index.ts
92
+
93
+ **`src/watcher/ipc-server.ts`** — from `templates/adapter/src/watcher/ipc-server.ts.tmpl`
94
+ - Replace placeholders only
95
+ - The required IPC handlers are already present: `deliver`, `health`, `connection_status`, `login`
96
+
97
+ **`src/watcher/index.ts`** — from `templates/adapter/src/watcher/index.ts.tmpl`
98
+ - Replace placeholders only
99
+ - The hub-required pattern (connectToHub with retry, heartbeat, re-registration) is built in
100
+
101
+ **`src/watcher/cli.ts`** — from `templates/adapter/src/watcher/cli.ts.tmpl`
102
+ - Replace placeholders only
103
+
104
+ **`src/index.ts`** — MCP server entry point
105
+ - Model this on Whazaa's `src/index.ts` (the reference implementation)
106
+ - Expose MCP tools named `<service>_send`, `<service>_status`, `<service>_tts` (voice, if supported), `<service>_send_file`
107
+ - Wire each tool to the corresponding IPC handler via `WatcherClient`
108
+ - Socket path: `/tmp/{{ADAPTER_NAME}}-watcher.sock`
109
+
110
+ **`README.md`** — from `templates/adapter/README.md.tmpl`
111
+ - Fill in service name, auth instructions, and any service-specific setup steps
112
+
113
+ ---
114
+
115
+ ## Phase 4: Wire into AIBroker Config
116
+
117
+ After generating the adapter files, register the adapter with the AIBroker hub:
118
+
119
+ 1. **Check if `~/.aibroker/config.json` exists.** If yes, add an entry to the `adapters` array:
120
+ ```json
121
+ {
122
+ "name": "{{ADAPTER_NAME}}",
123
+ "socketPath": "/tmp/{{ADAPTER_NAME}}-watcher.sock",
124
+ "autoStart": false
125
+ }
126
+ ```
127
+
128
+ 2. **Register as an MCP server** in `~/.claude.json` under `mcpServers`:
129
+ ```json
130
+ "{{ADAPTER_NAME}}": {
131
+ "type": "stdio",
132
+ "command": "node",
133
+ "args": ["/path/to/{{ADAPTER_NAME}}/dist/index.js"],
134
+ "description": "{{DISPLAY_NAME}} MCP adapter"
135
+ }
136
+ ```
137
+
138
+ 3. **Add permission** in `~/.claude/settings.json` under `permissions.allow`:
139
+ ```json
140
+ "mcp__{{ADAPTER_NAME}}"
141
+ ```
142
+
143
+ ---
144
+
145
+ ## Phase 5: Test the Connection
146
+
147
+ After generating all files:
148
+
149
+ ```bash
150
+ # Ensure the AIBroker hub is running
151
+ aibroker start
152
+
153
+ # Build and start the adapter
154
+ cd /path/to/{{ADAPTER_NAME}}
155
+ npm install
156
+ npm run build
157
+ node dist/watcher/cli.js watch
158
+ ```
159
+
160
+ The adapter will:
161
+ 1. Connect to the AIBroker hub (fails if hub is not running)
162
+ 2. Connect to the upstream service
163
+ 3. Register with the hub
164
+ 4. Start its IPC server
165
+
166
+ Verify the IPC server is responding:
167
+ ```bash
168
+ node -e "
169
+ import { WatcherClient } from 'aibroker';
170
+ const c = new WatcherClient('/tmp/{{ADAPTER_NAME}}-watcher.sock');
171
+ c.call_raw('health', {}).then(r => console.log(JSON.stringify(r, null, 2)));
172
+ "
173
+ ```
174
+
175
+ Expected health response:
176
+ ```json
177
+ {
178
+ "ok": true,
179
+ "result": {
180
+ "status": "ok",
181
+ "connectionStatus": "connected",
182
+ "stats": { "messagesReceived": 0, "messagesSent": 0, "errors": 0 },
183
+ "lastMessageAgo": null
184
+ }
185
+ }
186
+ ```
187
+
188
+ If `status` is `"down"` or `connectionStatus` is not `"connected"`, check the watcher logs for auth/connection errors and run `triggerLogin()` via the `login` IPC handler.
189
+
190
+ ---
191
+
192
+ ## Interface Contracts (Reference)
193
+
194
+ ### MessengerAdapter interface
195
+
196
+ Every adapter fulfills this interface structurally via IPC handlers:
197
+
198
+ ```typescript
199
+ interface MessengerAdapter {
200
+ // Lifecycle
201
+ start(config: AdapterConfig): Promise<void>;
202
+ stop(): Promise<void>;
203
+ health(): Promise<AdapterHealth>; // IPC: "health"
204
+
205
+ // Auth
206
+ login(): Promise<string>; // IPC: "login"
207
+ connectionStatus(): Promise<AdapterConnectionStatus>; // IPC: "connection_status"
208
+
209
+ // Outbound
210
+ sendText(text, recipient?): Promise<void>; // IPC: "send"
211
+ sendVoice(audioPath, recipient?): Promise<void>; // IPC: "send_voice"
212
+ sendFile(filePath, caption?, mimetype?, recipient?): Promise<void>; // IPC: "send_file"
213
+ sendImage(imagePath, caption?, recipient?): Promise<void>; // IPC: "send_image"
214
+ }
215
+ ```
216
+
217
+ ### AdapterHealth contract
218
+
219
+ ```typescript
220
+ interface AdapterHealth {
221
+ status: "ok" | "degraded" | "down";
222
+ connectionStatus: "connected" | "connecting" | "disconnected" | "error";
223
+ stats: {
224
+ messagesReceived: number;
225
+ messagesSent: number;
226
+ errors: number;
227
+ };
228
+ lastMessageAgo: number | null;
229
+ detail?: string;
230
+ }
231
+ ```
232
+
233
+ ### BrokerMessage (hub envelope)
234
+
235
+ ```typescript
236
+ interface BrokerMessage {
237
+ id: string; // UUID
238
+ timestamp: number; // epoch ms
239
+ source: string; // adapter name that sent it
240
+ target?: string; // target adapter name (omit for default routing)
241
+ type: "text" | "voice" | "file" | "image" | "command" | "status";
242
+ payload: {
243
+ text?: string;
244
+ filePath?: string;
245
+ audioPath?: string;
246
+ buffer?: string; // base64-encoded binary data (images, voice)
247
+ mimetype?: string;
248
+ caption?: string;
249
+ recipient?: string;
250
+ channel?: string;
251
+ metadata?: Record<string, unknown>;
252
+ };
253
+ }
254
+ ```
255
+
256
+ ### Required IPC handlers
257
+
258
+ | Handler | Called by | Must return |
259
+ |---------|-----------|-------------|
260
+ | `deliver` | Hub, when routing a BrokerMessage to this adapter | `{ ok: true, result: { delivered: true } }` or `{ ok: false, error: string }` |
261
+ | `health` | Hub health polling (every 10s) | `{ ok: true, result: AdapterHealth }` |
262
+ | `connection_status` | Hub, MCP tools | `{ ok: true, result: { status: AdapterConnectionStatus } }` |
263
+ | `login` | User, via MCP tool | `{ ok: true, result: { message: string } }` |
264
+ | `send` | MCP tool | `{ ok: true, result: { sent: true } }` |
265
+ | `send_voice` | MCP tool | `{ ok: true, result: { sent: true } }` |
266
+ | `send_file` | MCP tool | `{ ok: true, result: { sent: true } }` |
267
+ | `status` | MCP tool | Human-readable status object |
268
+
269
+ ### Hub-required architecture
270
+
271
+ The adapter **requires** the AIBroker hub daemon to be running:
272
+
273
+ ```
274
+ Adapter startup:
275
+ 1. connectToHub() — probe hub via "ping", retry 3x, fail if unreachable
276
+ 2. connectWatcher() — establish upstream service connection
277
+ 3. startIpcServer() — start adapter IPC server on its socket
278
+ 4. register_adapter — announce to hub so it can push outbound messages
279
+ 5. heartbeat loop — ping hub every 30s, re-register if it restarts
280
+ ```
281
+
282
+ Adapters do NOT:
283
+ - Create their own APIBackend or HybridSessionManager
284
+ - Handle commands locally (except /restart and /login)
285
+ - Run TTS, STT, screenshots, or image generation
286
+ - Manage sessions
287
+
288
+ ---
289
+
290
+ ## Reference Implementation
291
+
292
+ **Whazaa** is the canonical reference adapter. When in doubt, model behaviour on Whazaa:
293
+
294
+ - Repo: `~/dev/ai/Whazaa/`
295
+ - Key file — connection: `src/watcher/baileys.ts` (WhatsApp-specific connection)
296
+ - Key file — send: `src/watcher/send.ts`
297
+ - Key file — IPC: `src/watcher/ipc-server.ts`
298
+ - Key file — MCP tools: `src/index.ts`
299
+ - Key file — watcher: `src/watcher/index.ts` (thin hub-required adapter pattern)
300
+ - Key pattern — Baileys saves auth state to `~/.whazaa/auth/` via `useMultiFileAuthState()`
301
+
302
+ The Whazaa pattern for `connectWatcher()` is:
303
+ 1. Call `useMultiFileAuthState(authDir)` (or equivalent for your SDK)
304
+ 2. Create the client instance with the auth state
305
+ 3. Set up message event listener calling `onMessage(text, timestamp)`
306
+ 4. Call `client.connect()` or equivalent
307
+ 5. Return `cleanup` (calls `client.logout()` or `client.disconnect()`) and `triggerLogin` (generates new QR/pairing)
308
+
309
+ Follow this pattern exactly. The template scaffold maps cleanly onto it.
@@ -0,0 +1,81 @@
1
+ # {{ADAPTER_NAME}}
2
+
3
+ AIBroker adapter for {{DISPLAY_NAME}}.
4
+
5
+ ## Overview
6
+
7
+ This adapter bridges {{DISPLAY_NAME}} and the [AIBroker](https://github.com/mnott/AIBroker) hub, enabling bidirectional message routing between {{DISPLAY_NAME}} and AI backends (Claude Code, Anthropic API, etc.).
8
+
9
+ **Requires the AIBroker daemon to be running.** The adapter is a thin transport pipe — all command handling, session management, TTS, and media processing are owned by the hub.
10
+
11
+ ## Setup
12
+
13
+ ### 1. Install dependencies
14
+
15
+ ```bash
16
+ npm install
17
+ ```
18
+
19
+ ### 2. Implement the connection
20
+
21
+ Open `src/watcher/connection.ts` and implement `connectWatcher()` with your {{DISPLAY_NAME}} SDK.
22
+
23
+ The function must:
24
+ - Connect to {{DISPLAY_NAME}} using your credentials
25
+ - Call `onMessage(text, timestamp)` for each incoming message
26
+ - Return `cleanup()` (disconnect) and `triggerLogin()` (fresh auth flow)
27
+
28
+ ### 3. Implement outbound delivery
29
+
30
+ Open `src/watcher/send.ts` and implement `sendText()`, `sendVoice()`, and `sendFile()`.
31
+
32
+ ### 4. Build
33
+
34
+ ```bash
35
+ npm run build
36
+ ```
37
+
38
+ ### 5. Run
39
+
40
+ ```bash
41
+ # Start the AIBroker hub first
42
+ aibroker start
43
+
44
+ # Then start the adapter — it auto-registers with the hub
45
+ npm run watch
46
+ ```
47
+
48
+ ## Architecture
49
+
50
+ ```
51
+ {{DISPLAY_NAME}} <── connectWatcher() ──> watcher/index.ts
52
+
53
+ forward to hub startIpcServer()
54
+ │ │
55
+ AIBroker hub ◄── deliver ─┘
56
+ ```
57
+
58
+ The adapter:
59
+ - Forwards all incoming messages to the hub via `route_message`
60
+ - Receives outbound messages from the hub via the `deliver` IPC handler
61
+ - Only handles `/restart` and `/login` locally
62
+ - Maintains a 30s heartbeat with the hub; re-registers if hub restarts
63
+
64
+ ## IPC Methods
65
+
66
+ The adapter exposes these methods on its Unix socket (`/tmp/{{ADAPTER_NAME}}-watcher.sock`):
67
+
68
+ | Method | Description |
69
+ |--------|-------------|
70
+ | `deliver` | Hub pushes a BrokerMessage for outbound delivery |
71
+ | `health` | Returns adapter health (status, stats, lastMessageAgo) |
72
+ | `connection_status` | Returns upstream connection status string |
73
+ | `send` | Send a text message |
74
+ | `send_voice` | Send a voice note (OGG Opus path) |
75
+ | `send_file` | Send a file attachment |
76
+ | `login` | Trigger a fresh login / QR pairing flow |
77
+ | `status` | Human-readable adapter status summary |
78
+
79
+ ## License
80
+
81
+ MIT
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "{{ADAPTER_NAME}}",
3
+ "version": "0.1.0",
4
+ "description": "AIBroker adapter for {{DISPLAY_NAME}}",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "{{ADAPTER_NAME}}": "dist/watcher/cli.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "dev": "tsc --watch",
13
+ "watch": "node dist/watcher/cli.js watch",
14
+ "prepublishOnly": "npm run build"
15
+ },
16
+ "dependencies": {
17
+ "aibroker": "^0.6.0"
18
+ },
19
+ "devDependencies": {
20
+ "@types/node": "^22.0.0",
21
+ "typescript": "^5.0.0"
22
+ }
23
+ }
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ import { watch } from "./index.js";
3
+
4
+ const command = process.argv[2];
5
+ if (command === "watch" || !command) {
6
+ watch().catch((err) => {
7
+ console.error("Fatal:", err);
8
+ process.exit(1);
9
+ });
10
+ } else {
11
+ console.log(`Usage: {{ADAPTER_NAME}} watch`);
12
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * commands.ts — Thin adapter-local command handler for {{DISPLAY_NAME}}
3
+ *
4
+ * Only handles commands that require direct upstream service access
5
+ * (/restart, /login). All other commands are forwarded to the AIBroker
6
+ * hub daemon via route_message in index.ts.
7
+ */
8
+
9
+ import { log } from "aibroker";
10
+ import { sendText } from "./send.js";
11
+
12
+ /**
13
+ * Create the local message handler for adapter-specific commands.
14
+ *
15
+ * Only /restart and /login are handled here. Everything else should have
16
+ * been routed to the hub by index.ts — this handler is the fallback for
17
+ * commands that need direct adapter access.
18
+ */
19
+ export function createMessageHandler(): (text: string, timestamp: number) => void {
20
+ return function handleMessage(text: string, _timestamp: number): void {
21
+ const trimmed = text.trim();
22
+
23
+ if (trimmed === "/restart") {
24
+ log("/restart: watcher restart requested");
25
+ sendText("Restarting {{ADAPTER_NAME}} watcher...").catch(() => {});
26
+ setTimeout(() => {
27
+ log("/restart: exiting — process manager will restart us");
28
+ process.exit(0);
29
+ }, 1500);
30
+ return;
31
+ }
32
+
33
+ // /login is handled via the triggerLogin callback in index.ts,
34
+ // not here. This is just a safety net.
35
+ if (trimmed === "/login") {
36
+ sendText("Use the login flow — handled by the watcher.").catch(() => {});
37
+ return;
38
+ }
39
+
40
+ // Everything else should have gone to the hub. If we get here,
41
+ // something went wrong with routing.
42
+ log(`[{{ADAPTER_NAME}}] commands.ts: unexpected local message: ${trimmed.slice(0, 60)}`);
43
+ };
44
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * connection.ts — Connect to {{DISPLAY_NAME}}
3
+ *
4
+ * TODO: Implement the upstream service connection here.
5
+ * This is the adapter-specific part — use the SDK/library for your service.
6
+ *
7
+ * Replace this stub with a real connection using the appropriate SDK, e.g.:
8
+ * - @whiskeysockets/baileys for WhatsApp
9
+ * - gramjs / telegram for Telegram
10
+ * - discord.js for Discord
11
+ * - signal-cli for Signal
12
+ *
13
+ * The onMessage callback receives every incoming message text so the watcher
14
+ * can route it through the command handler / hub forwarding.
15
+ */
16
+
17
+ export interface ConnectionResult {
18
+ /** Call to cleanly disconnect from the upstream service. */
19
+ cleanup: () => void;
20
+ /**
21
+ * Trigger a new login flow (QR code, pairing, etc.) and return a
22
+ * human-readable status string to send back to the user.
23
+ */
24
+ triggerLogin: () => Promise<string>;
25
+ }
26
+
27
+ /**
28
+ * Establish the upstream connection.
29
+ *
30
+ * @param onMessage - Called for each incoming message the adapter should process.
31
+ * Receives the message text and the message timestamp (epoch ms).
32
+ */
33
+ export async function connectWatcher(
34
+ onMessage: (text: string, timestamp: number) => void,
35
+ ): Promise<ConnectionResult> {
36
+ // TODO: Replace this stub with your actual connection logic.
37
+ //
38
+ // Typical pattern:
39
+ // 1. Load credentials from appDir (set by setAppDir() in index.ts)
40
+ // 2. Connect to the upstream service
41
+ // 3. Subscribe to incoming messages, calling onMessage() for each
42
+ // 4. Return cleanup() and triggerLogin() implementations
43
+ //
44
+ console.log("[{{ADAPTER_NAME}}] Connection stub — implement connectWatcher()");
45
+
46
+ // Suppress unused-parameter warning in stub
47
+ void onMessage;
48
+
49
+ return {
50
+ cleanup: () => {
51
+ // TODO: close WebSocket, stop polling, revoke auth, etc.
52
+ console.log("[{{ADAPTER_NAME}}] cleanup() called");
53
+ },
54
+ triggerLogin: async () => {
55
+ // TODO: start QR code / pairing flow, return status string
56
+ return "Login not yet implemented for {{DISPLAY_NAME}}";
57
+ },
58
+ };
59
+ }