@openclaw/crabline 0.1.11 → 0.1.13

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 (214) hide show
  1. package/README.md +137 -23
  2. package/dist/src/bin/crabline.js +3 -1
  3. package/dist/src/bin/crabline.js.map +1 -1
  4. package/dist/src/cli/program.d.ts +5 -1
  5. package/dist/src/cli/program.js +281 -52
  6. package/dist/src/cli/program.js.map +1 -1
  7. package/dist/src/config/load.js +39 -3
  8. package/dist/src/config/load.js.map +1 -1
  9. package/dist/src/config/schema.d.ts +20 -0
  10. package/dist/src/config/schema.js +163 -35
  11. package/dist/src/config/schema.js.map +1 -1
  12. package/dist/src/core/errors.d.ts +1 -0
  13. package/dist/src/core/errors.js +6 -3
  14. package/dist/src/core/errors.js.map +1 -1
  15. package/dist/src/core/http-path.d.ts +1 -0
  16. package/dist/src/core/http-path.js +14 -0
  17. package/dist/src/core/http-path.js.map +1 -0
  18. package/dist/src/core/matcher.d.ts +3 -1
  19. package/dist/src/core/matcher.js +58 -2
  20. package/dist/src/core/matcher.js.map +1 -1
  21. package/dist/src/core/nonces.d.ts +2 -0
  22. package/dist/src/core/nonces.js +11 -1
  23. package/dist/src/core/nonces.js.map +1 -1
  24. package/dist/src/core/reporters.d.ts +5 -0
  25. package/dist/src/core/reporters.js +26 -2
  26. package/dist/src/core/reporters.js.map +1 -1
  27. package/dist/src/core/run.d.ts +3 -1
  28. package/dist/src/core/run.js +178 -66
  29. package/dist/src/core/run.js.map +1 -1
  30. package/dist/src/index.d.ts +12 -10
  31. package/dist/src/index.js +6 -5
  32. package/dist/src/index.js.map +1 -1
  33. package/dist/src/matrix-ids.d.ts +5 -0
  34. package/dist/src/matrix-ids.js +83 -0
  35. package/dist/src/matrix-ids.js.map +1 -0
  36. package/dist/src/openclaw/artifact-generation.d.ts +7 -6
  37. package/dist/src/openclaw/artifact-generation.js +385 -41
  38. package/dist/src/openclaw/artifact-generation.js.map +1 -1
  39. package/dist/src/openclaw/bridges/discord.d.ts +1 -0
  40. package/dist/src/openclaw/bridges/discord.js +149 -0
  41. package/dist/src/openclaw/bridges/discord.js.map +1 -0
  42. package/dist/src/openclaw/bridges/matrix.js +22 -5
  43. package/dist/src/openclaw/bridges/matrix.js.map +1 -1
  44. package/dist/src/openclaw/bridges/mattermost.js +14 -9
  45. package/dist/src/openclaw/bridges/mattermost.js.map +1 -1
  46. package/dist/src/openclaw/bridges/probe-response.d.ts +1 -0
  47. package/dist/src/openclaw/bridges/probe-response.js +5 -0
  48. package/dist/src/openclaw/bridges/probe-response.js.map +1 -0
  49. package/dist/src/openclaw/bridges/signal.js +16 -7
  50. package/dist/src/openclaw/bridges/signal.js.map +1 -1
  51. package/dist/src/openclaw/bridges/slack.js +117 -24
  52. package/dist/src/openclaw/bridges/slack.js.map +1 -1
  53. package/dist/src/openclaw/bridges/telegram.js +46 -20
  54. package/dist/src/openclaw/bridges/telegram.js.map +1 -1
  55. package/dist/src/openclaw/bridges/whatsapp.js +33 -17
  56. package/dist/src/openclaw/bridges/whatsapp.js.map +1 -1
  57. package/dist/src/openclaw/bridges/zalo.js +9 -4
  58. package/dist/src/openclaw/bridges/zalo.js.map +1 -1
  59. package/dist/src/openclaw/outbound-contract.js +3 -0
  60. package/dist/src/openclaw/outbound-contract.js.map +1 -1
  61. package/dist/src/openclaw/private-file.d.ts +38 -3
  62. package/dist/src/openclaw/private-file.js +2008 -87
  63. package/dist/src/openclaw/private-file.js.map +1 -1
  64. package/dist/src/openclaw/{smoke-lock.d.ts → provider-readiness-lock.d.ts} +14 -5
  65. package/dist/src/openclaw/provider-readiness-lock.js +1320 -0
  66. package/dist/src/openclaw/provider-readiness-lock.js.map +1 -0
  67. package/dist/src/openclaw/shared.d.ts +10 -17
  68. package/dist/src/openclaw/shared.js +53 -19
  69. package/dist/src/openclaw/shared.js.map +1 -1
  70. package/dist/src/openclaw.d.ts +3 -5
  71. package/dist/src/openclaw.js +245 -60
  72. package/dist/src/openclaw.js.map +1 -1
  73. package/dist/src/platform/process-owned-lock.d.ts +11 -0
  74. package/dist/src/platform/process-owned-lock.js +1698 -0
  75. package/dist/src/platform/process-owned-lock.js.map +1 -0
  76. package/dist/src/platform/recorder-directory.d.ts +1 -0
  77. package/dist/src/platform/recorder-directory.js +14 -0
  78. package/dist/src/platform/recorder-directory.js.map +1 -0
  79. package/dist/src/platform/windows-acl.d.ts +18 -0
  80. package/dist/src/platform/windows-acl.js +1367 -0
  81. package/dist/src/platform/windows-acl.js.map +1 -0
  82. package/dist/src/platform/windows-lock-root.d.ts +13 -0
  83. package/dist/src/platform/windows-lock-root.js +98 -0
  84. package/dist/src/platform/windows-lock-root.js.map +1 -0
  85. package/dist/src/providers/builtin/discord.d.ts +4 -0
  86. package/dist/src/providers/builtin/discord.js +52 -9
  87. package/dist/src/providers/builtin/discord.js.map +1 -1
  88. package/dist/src/providers/builtin/external-webhook-auth.d.ts +1 -0
  89. package/dist/src/providers/builtin/external-webhook-auth.js +38 -1
  90. package/dist/src/providers/builtin/external-webhook-auth.js.map +1 -1
  91. package/dist/src/providers/builtin/feishu.d.ts +1 -0
  92. package/dist/src/providers/builtin/feishu.js +96 -26
  93. package/dist/src/providers/builtin/feishu.js.map +1 -1
  94. package/dist/src/providers/builtin/googlechat.d.ts +1 -0
  95. package/dist/src/providers/builtin/googlechat.js +95 -26
  96. package/dist/src/providers/builtin/googlechat.js.map +1 -1
  97. package/dist/src/providers/builtin/imessage.js +60 -17
  98. package/dist/src/providers/builtin/imessage.js.map +1 -1
  99. package/dist/src/providers/builtin/loopback.js +88 -35
  100. package/dist/src/providers/builtin/loopback.js.map +1 -1
  101. package/dist/src/providers/builtin/matrix.d.ts +2 -2
  102. package/dist/src/providers/builtin/matrix.js +78 -21
  103. package/dist/src/providers/builtin/matrix.js.map +1 -1
  104. package/dist/src/providers/builtin/mattermost.d.ts +11 -7
  105. package/dist/src/providers/builtin/mattermost.js +138 -24
  106. package/dist/src/providers/builtin/mattermost.js.map +1 -1
  107. package/dist/src/providers/builtin/msteams.d.ts +1 -0
  108. package/dist/src/providers/builtin/msteams.js +118 -38
  109. package/dist/src/providers/builtin/msteams.js.map +1 -1
  110. package/dist/src/providers/builtin/native-local-mock.js +4 -4
  111. package/dist/src/providers/builtin/native-local-mock.js.map +1 -1
  112. package/dist/src/providers/builtin/script.js +1057 -146
  113. package/dist/src/providers/builtin/script.js.map +1 -1
  114. package/dist/src/providers/builtin/slack.d.ts +8 -1
  115. package/dist/src/providers/builtin/slack.js +327 -24
  116. package/dist/src/providers/builtin/slack.js.map +1 -1
  117. package/dist/src/providers/builtin/telegram.d.ts +1 -1
  118. package/dist/src/providers/builtin/telegram.js +55 -14
  119. package/dist/src/providers/builtin/telegram.js.map +1 -1
  120. package/dist/src/providers/builtin/whatsapp.d.ts +4 -3
  121. package/dist/src/providers/builtin/whatsapp.js +157 -29
  122. package/dist/src/providers/builtin/whatsapp.js.map +1 -1
  123. package/dist/src/providers/builtin/zalo.d.ts +5 -2
  124. package/dist/src/providers/builtin/zalo.js +31 -7
  125. package/dist/src/providers/builtin/zalo.js.map +1 -1
  126. package/dist/src/providers/catalog.d.ts +1 -1
  127. package/dist/src/providers/catalog.js +1 -1
  128. package/dist/src/providers/catalog.js.map +1 -1
  129. package/dist/src/providers/local-mock.d.ts +4 -0
  130. package/dist/src/providers/local-mock.js +162 -35
  131. package/dist/src/providers/local-mock.js.map +1 -1
  132. package/dist/src/providers/native-ids.d.ts +2 -0
  133. package/dist/src/providers/native-ids.js +3 -0
  134. package/dist/src/providers/native-ids.js.map +1 -1
  135. package/dist/src/providers/recorder.d.ts +14 -3
  136. package/dist/src/providers/recorder.js +521 -41
  137. package/dist/src/providers/recorder.js.map +1 -1
  138. package/dist/src/providers/registry.d.ts +1 -0
  139. package/dist/src/providers/registry.js +65 -20
  140. package/dist/src/providers/registry.js.map +1 -1
  141. package/dist/src/providers/signed-jwt.d.ts +6 -1
  142. package/dist/src/providers/signed-jwt.js +241 -50
  143. package/dist/src/providers/signed-jwt.js.map +1 -1
  144. package/dist/src/providers/slack-ids.d.ts +1 -0
  145. package/dist/src/providers/slack-ids.js +5 -0
  146. package/dist/src/providers/slack-ids.js.map +1 -1
  147. package/dist/src/providers/target-normalizers.d.ts +9 -1
  148. package/dist/src/providers/target-normalizers.js +177 -58
  149. package/dist/src/providers/target-normalizers.js.map +1 -1
  150. package/dist/src/providers/webhook-server.d.ts +3 -0
  151. package/dist/src/providers/webhook-server.js +268 -47
  152. package/dist/src/providers/webhook-server.js.map +1 -1
  153. package/dist/src/servers/discord.d.ts +40 -0
  154. package/dist/src/servers/discord.js +842 -0
  155. package/dist/src/servers/discord.js.map +1 -0
  156. package/dist/src/servers/http.d.ts +14 -2
  157. package/dist/src/servers/http.js +229 -58
  158. package/dist/src/servers/http.js.map +1 -1
  159. package/dist/src/servers/index.d.ts +10 -4
  160. package/dist/src/servers/index.js +4 -0
  161. package/dist/src/servers/index.js.map +1 -1
  162. package/dist/src/servers/matrix.d.ts +3 -0
  163. package/dist/src/servers/matrix.js +268 -110
  164. package/dist/src/servers/matrix.js.map +1 -1
  165. package/dist/src/servers/mattermost.d.ts +5 -0
  166. package/dist/src/servers/mattermost.js +389 -91
  167. package/dist/src/servers/mattermost.js.map +1 -1
  168. package/dist/src/servers/recorder.d.ts +11 -0
  169. package/dist/src/servers/recorder.js +1072 -69
  170. package/dist/src/servers/recorder.js.map +1 -1
  171. package/dist/src/servers/signal.d.ts +1 -0
  172. package/dist/src/servers/signal.js +279 -44
  173. package/dist/src/servers/signal.js.map +1 -1
  174. package/dist/src/servers/slack.d.ts +15 -0
  175. package/dist/src/servers/slack.js +270 -54
  176. package/dist/src/servers/slack.js.map +1 -1
  177. package/dist/src/servers/telegram-identity.d.ts +6 -0
  178. package/dist/src/servers/telegram-identity.js +27 -0
  179. package/dist/src/servers/telegram-identity.js.map +1 -0
  180. package/dist/src/servers/telegram.d.ts +17 -6
  181. package/dist/src/servers/telegram.js +1218 -107
  182. package/dist/src/servers/telegram.js.map +1 -1
  183. package/dist/src/servers/webhook-target.d.ts +12 -4
  184. package/dist/src/servers/webhook-target.js +226 -28
  185. package/dist/src/servers/webhook-target.js.map +1 -1
  186. package/dist/src/servers/whatsapp-baileys-websocket.d.ts +60 -1
  187. package/dist/src/servers/whatsapp-baileys-websocket.js +782 -112
  188. package/dist/src/servers/whatsapp-baileys-websocket.js.map +1 -1
  189. package/dist/src/servers/whatsapp-jid.d.ts +1 -0
  190. package/dist/src/servers/whatsapp-jid.js +9 -5
  191. package/dist/src/servers/whatsapp-jid.js.map +1 -1
  192. package/dist/src/servers/whatsapp-wire/binary-node.d.ts +1 -0
  193. package/dist/src/servers/whatsapp-wire/binary-node.js +37 -13
  194. package/dist/src/servers/whatsapp-wire/binary-node.js.map +1 -1
  195. package/dist/src/servers/whatsapp-wire/crypto.d.ts +3 -0
  196. package/dist/src/servers/whatsapp-wire/crypto.js +23 -8
  197. package/dist/src/servers/whatsapp-wire/crypto.js.map +1 -1
  198. package/dist/src/servers/whatsapp-wire/handshake.d.ts +9 -3
  199. package/dist/src/servers/whatsapp-wire/handshake.js +173 -12
  200. package/dist/src/servers/whatsapp-wire/handshake.js.map +1 -1
  201. package/dist/src/servers/whatsapp-wire/signal.js +3 -3
  202. package/dist/src/servers/whatsapp-wire/signal.js.map +1 -1
  203. package/dist/src/servers/whatsapp.d.ts +7 -1
  204. package/dist/src/servers/whatsapp.js +149 -25
  205. package/dist/src/servers/whatsapp.js.map +1 -1
  206. package/dist/src/servers/zalo.d.ts +1 -0
  207. package/dist/src/servers/zalo.js +193 -82
  208. package/dist/src/servers/zalo.js.map +1 -1
  209. package/docs/channel-setup.md +251 -64
  210. package/fixtures/examples/crabline.example.yaml +3 -2
  211. package/package.json +18 -10
  212. package/dist/src/openclaw/smoke-lock.js +0 -1004
  213. package/dist/src/openclaw/smoke-lock.js.map +0 -1
  214. package/fixtures/examples/openclaw-bridge.yaml +0 -125
package/README.md CHANGED
@@ -5,8 +5,10 @@
5
5
  Deterministic local messaging-channel mocks for OpenClaw QA.
6
6
 
7
7
  `crabline` is config-driven, CI-friendly, and deliberately has no `openclaw`
8
- dependency. It can run fixture-level local mocks, and it can also serve local
9
- provider APIs that OpenClaw live adapters can target during deterministic QA.
8
+ dependency. A fixture-level **local mock provider** is a Crabline adapter used
9
+ directly by fixture commands. A **local provider server** is a separate process
10
+ that the Crabline channel driver starts so a real OpenClaw channel plugin can
11
+ exercise its normal provider protocol during deterministic QA.
10
12
 
11
13
  ## What It Provides
12
14
 
@@ -15,16 +17,17 @@ provider APIs that OpenClaw live adapters can target during deterministic QA.
15
17
  `whatsapp`, and `zalo`
16
18
  - a `script` bridge for channels that are still exercised by external commands
17
19
  - per-provider local webhook endpoints for inbound events
18
- - local provider servers for live-adapter smoke tests for Mattermost, Matrix,
19
- Signal, Slack, Telegram, WhatsApp, and Zalo
20
+ - local provider servers for Crabline channel-driver tests for Discord,
21
+ Mattermost, Matrix, Signal, Slack, Telegram, WhatsApp, and Zalo
20
22
  - JSONL recorder files for deterministic wait/watch behavior
21
23
  - nonce-based `send`, `roundtrip`, `agent`, `probe`, `run`, `watch`, and
22
24
  `doctor` commands
23
25
  - text output by default and stable `--json` output for automation
24
26
 
25
- Crabline local servers are not live-provider coverage. They let OpenClaw run its
26
- normal channel adapter code against a local provider-shaped API. Release lanes
27
- still need the `live` driver and real provider credentials.
27
+ Crabline local provider servers are not live-provider coverage and are not the
28
+ fixture-level local mock provider feature. They let the real OpenClaw channel
29
+ plugin run against a local provider-shaped API. Release lanes still need the
30
+ `live` driver and real provider credentials.
28
31
 
29
32
  ## Install
30
33
 
@@ -41,6 +44,11 @@ pnpm dev fixtures --config fixtures/examples/crabline.example.yaml
41
44
  pnpm dev roundtrip telegram-dm --config fixtures/examples/crabline.example.yaml
42
45
  ```
43
46
 
47
+ The source checkout does not link its own `crabline` bin into
48
+ `node_modules/.bin`, so use `pnpm dev` there rather than
49
+ `pnpm exec crabline`. An installed package exposes the `crabline` command used
50
+ in the examples below.
51
+
44
52
  ## Quality Gate
45
53
 
46
54
  ```bash
@@ -98,6 +106,10 @@ Telegram `secretToken`, and Zalo `webhookSecret` enforce provider-native
98
106
  webhook authentication. Feishu `verificationToken` remains an additional or
99
107
  loopback-only callback check. Microsoft Teams also requires `appId` for
100
108
  non-loopback or explicitly public webhook endpoints.
109
+ Authenticated external webhook ingress must advertise an HTTPS `publicUrl`;
110
+ plain HTTP is limited to loopback-local testing.
111
+ Feishu text callbacks require valid JSON-encoded `message.content`; malformed
112
+ content is rejected.
101
113
 
102
114
  ## Built-In Mock Channels
103
115
 
@@ -134,15 +146,83 @@ them only from sources you trust and review changes before use.
134
146
 
135
147
  ## Local Provider Servers
136
148
 
137
- `serve` starts provider-shaped HTTP APIs for OpenClaw live adapters. This is the
138
- preferred Smoke CI path because OpenClaw still uses its normal channel adapter,
139
- but the provider endpoint is local and deterministic.
149
+ `serve` starts local provider servers for real OpenClaw channel plugins. This is
150
+ the preferred Crabline channel-driver path because the plugin still uses its
151
+ normal provider protocol while the provider endpoint is local and
152
+ deterministic. It does not use Crabline's fixture-level local mock provider.
153
+
154
+ Commands in this section use the installed-package form. In a source checkout,
155
+ replace `crabline` with `pnpm dev`.
156
+
157
+ `serve` never accepts credential values in command-line arguments. Set
158
+ `CRABLINE_ACCESS_TOKEN`, `CRABLINE_ADMIN_TOKEN`, `CRABLINE_BOT_TOKEN`, or
159
+ `CRABLINE_SIGNING_SECRET`, or pass a bounded JSON object through a file
160
+ descriptor. Package runners should use stdin:
161
+
162
+ ```bash
163
+ pnpm dev --json serve slack --credentials-fd 0 < .crabline/serve-credentials.json
164
+ ```
165
+
166
+ The installed CLI can also use an inherited descriptor when its launcher
167
+ preserves descriptors above 2:
168
+
169
+ ```bash
170
+ crabline --json serve slack --credentials-fd 3 3< .crabline/serve-credentials.json
171
+ ```
172
+
173
+ The JSON fields are `accessToken`, `adminToken`, `botToken`, and
174
+ `signingSecret`. File-descriptor values override environment fallbacks. Do not
175
+ pass descriptors above 2 through package runners such as `pnpm`; use fd 0
176
+ instead. Keep credential files owner-readable or pipe the JSON directly from a
177
+ secret manager.
178
+
179
+ Ready files contain generated provider and admin credentials. Crabline creates
180
+ or replaces them with POSIX mode `0600`, but the parent directory still needs
181
+ to be private. Exclude ready files from version control and CI artifact
182
+ collection, and delete them after use. On non-POSIX or shared filesystems,
183
+ verify the effective ACLs before publishing one.
140
184
 
141
185
  Library callers can pass `onEvent` to `startCrablineServer`, an individual
142
186
  provider server, or `startOpenClawCrablineAdapter`. Crabline awaits the callback
143
187
  after appending each API/admin event to `recorderPath`, so callers can react in
144
188
  process while retaining the JSONL artifact as durable evidence.
145
189
 
190
+ Recorder files should normally have one filesystem name. If multiple processes
191
+ cannot share the same OS account home, the home is read-only, or they write
192
+ through hardlinks to the same recorder inode, set
193
+ `CRABLINE_RECORDER_LOCK_DIR` to the same absolute writable directory for every
194
+ writer. Pre-create that directory with the ownership, group, or ACLs required
195
+ by those writers. Crabline refuses hardlinked server-recorder writes without
196
+ this shared lock namespace. The configured path must be canonical and contain
197
+ no symlink components. Scope each lock directory to one recorder filesystem;
198
+ lock identities omit device numbers so containers that mount the same inode
199
+ under different device IDs still coordinate. Otherwise, Unix writers coordinate
200
+ through the OS account's `~/.cache/crabline/locks/server-recorder` namespace.
201
+
202
+ Discord:
203
+
204
+ ```bash
205
+ crabline --json serve discord --ready-file .crabline/discord-server.json
206
+ ```
207
+
208
+ The manifest contains the bot/application identity, bot token, REST API root,
209
+ Gateway metadata endpoint, Gateway WebSocket URL, authenticated admin ingress,
210
+ and recorder path. The server implements the Discord REST v10 and Gateway
211
+ subset used by the real OpenClaw Discord plugin: bot identity, `/gateway/bot`,
212
+ JSON Gateway HELLO/IDENTIFY/READY/heartbeat/resume, DM and guild text channels,
213
+ message sends and replies, typing, basic guild/member lookups, and application
214
+ command registration. Admin ingress turns an injected user message into a
215
+ normal `MESSAGE_CREATE` Gateway dispatch.
216
+
217
+ This local provider server is separate from the fixture-level Discord local
218
+ mock provider listed under Built-In Mock Channels. The fixture adapter models
219
+ Discord interactions directly for Crabline commands; the server lets a real
220
+ Discord client exercise provider-native REST and Gateway boundaries.
221
+
222
+ The supported Gateway is v10 JSON with one shard. Transport compression,
223
+ voice, interactions, attachments/multipart uploads, audit logs, and Discord's
224
+ distributed permission and rate-limit systems are outside the current subset.
225
+
146
226
  Mattermost:
147
227
 
148
228
  ```bash
@@ -153,6 +233,7 @@ The JSON manifest contains:
153
233
 
154
234
  - `baseUrl`: OpenClaw `channels.mattermost.baseUrl` / `MATTERMOST_URL`
155
235
  - `botToken`: OpenClaw `channels.mattermost.botToken` / `MATTERMOST_BOT_TOKEN`
236
+ - `webhookToken` / `MATTERMOST_TOKEN`: verifies native outgoing webhook posts
156
237
  - `endpoints.websocketUrl`: native Mattermost WebSocket endpoint
157
238
  - `adminToken`: send this as the `X-Crabline-Admin-Token` header when posting
158
239
  test user messages
@@ -163,7 +244,10 @@ The server implements a Mattermost API subset for text DM and channel
163
244
  roundtrips, including REST authentication/status codes, WebSocket
164
245
  authentication and `hello`, sequenced events, typing, and post
165
246
  create/edit/delete events. Admin ingress is only the test control plane;
166
- injected messages are delivered to clients as native `posted` events.
247
+ injected messages require native 26-character lowercase channel/user IDs and
248
+ are delivered to clients as channel-scoped native `posted` events. Optional
249
+ `channelName` and `channelDisplayName` values populate the native event fields.
250
+ `POST /api/v4/posts` requires a JSON media type.
167
251
 
168
252
  Matrix:
169
253
 
@@ -187,7 +271,9 @@ The server implements an unencrypted Matrix Client-Server API subset including
187
271
  `whoami`, filters, push rules, joined rooms and members, room state, `/sync`,
188
272
  room event sends, typing, and read receipts. Admin ingress is only the test
189
273
  control plane; injected messages are delivered to clients as native
190
- `m.room.message` events through `/sync`.
274
+ `m.room.message` events through `/sync`. Optional `roomName` sets newly created
275
+ room state, `direct: true` publishes `m.direct` account data, and `threadId`
276
+ accepts the raw Matrix root event ID used in the native thread relation.
191
277
 
192
278
  Slack:
193
279
 
@@ -208,8 +294,8 @@ The JSON manifest contains:
208
294
  - `endpoints.eventsUrl`: local Slack Events API endpoint
209
295
  - `recorderPath`: JSONL file of local provider API/admin traffic
210
296
 
211
- The admin token is generated randomly unless `--admin-token <token>` is
212
- provided. Implemented Slack Web API endpoints include `auth.test`,
297
+ The admin token is generated randomly unless `adminToken` is supplied through
298
+ the credential ingress above. Implemented Slack Web API endpoints include `auth.test`,
213
299
  `chat.postMessage`, `conversations.open`, `conversations.info`,
214
300
  `conversations.history`, and `conversations.replies`.
215
301
 
@@ -251,16 +337,19 @@ The JSON manifest contains:
251
337
  messages; OpenClaw reads them through Telegram `getUpdates`
252
338
  - `recorderPath`: JSONL file of local provider API/admin traffic
253
339
 
254
- The admin token is generated randomly unless `--admin-token <token>` is
255
- provided. The inbound endpoint rejects requests without the matching admin
256
- header (or `Authorization: Bearer <token>`).
340
+ The admin token is generated randomly unless `adminToken` is supplied through
341
+ the credential ingress above. The inbound endpoint rejects requests without
342
+ the matching admin header (or `Authorization: Bearer <token>`).
257
343
 
258
344
  Implemented Telegram Bot API endpoints include `getMe`, `sendMessage`,
259
345
  `sendPhoto`, `sendDocument`, `sendVideo`, `sendAudio`, `sendAnimation`, `editMessageText`,
260
346
  `deleteMessage`, `setMessageReaction`, `createForumTopic`, `editForumTopic`,
261
347
  `pinChatMessage`, `unpinChatMessage`, `getUpdates`, `deleteWebhook`,
262
348
  `setWebhook`, `setMyCommands`, `deleteMyCommands`, `sendChatAction`, and
263
- `answerCallbackQuery`.
349
+ `answerCallbackQuery`. Webhook secrets use Telegram's 1-256 character
350
+ letter/digit/underscore/hyphen alphabet. Text and caption fields enforce native
351
+ string types and 4,096/1,024 UTF-16 limits, entity metadata is retained, and
352
+ `@username` method targets resolve to numeric `Chat.id` values.
264
353
 
265
354
  WhatsApp:
266
355
 
@@ -286,7 +375,6 @@ The JSON manifest contains:
286
375
  - `endpoints.adminInboundUrl`: authenticated POST endpoint for test user
287
376
  messages using the WhatsApp Business webhook payload shape
288
377
  - `endpoints.messagesUrl`: provider-native Cloud API message and status endpoint
289
- - `endpoints.statusUrl`: alias for the same provider-native status endpoint
290
378
  - `recorderPath`: JSONL file of local provider API/admin traffic and Baileys
291
379
  WebSocket stanzas
292
380
 
@@ -301,7 +389,8 @@ Group outbound uses sender-key `skmsg` encryption and is outside this supported
301
389
  subset, so OpenClaw Crabline outbound targets are direct users only. Group
302
390
  inbound injection remains supported. The WebSocket endpoint rejects clients
303
391
  that do not present the access token embedded in the manifest URL. The admin
304
- token is generated randomly unless `--admin-token <token>` is provided.
392
+ token is generated randomly unless `adminToken` is supplied through the
393
+ credential ingress above.
305
394
 
306
395
  OpenClaw bridge callers should post injected user messages with the
307
396
  `providerUrl`, `providerHeaders`, and `providerBody` returned by
@@ -331,7 +420,9 @@ API methods accept GET query parameters or POST requests. Admin
331
420
  ingress injects a native Zalo update into the active polling or webhook
332
421
  transport. Webhook delivery posts the native `{ event_name, message }` update
333
422
  directly. OpenClaw-specific endpoint, config, and target mapping remain in the
334
- isolated bridge.
423
+ isolated bridge. Programmatic `startZaloServer()` callers can tune the retained
424
+ polling queue with `maxPendingInboundEvents` and `maxPendingInboundBytes`; the
425
+ byte limit defaults to 64 MiB.
335
426
 
336
427
  The admin ingress accepts JSON like:
337
428
 
@@ -367,13 +458,34 @@ target:
367
458
  Examples:
368
459
 
369
460
  - Slack conversations: `C1234567890`, `G1234567890`, or `D1234567890`
461
+ - Slack direct sends may also target user IDs such as `U1234567890` or
462
+ `W1234567890`
370
463
  - Slack threads: `1700000000.000100`
371
464
  - Telegram chats: `-1001234567890` or `@channelusername`
372
465
  - Telegram topics: `42`
373
- - WhatsApp Cloud API users: digits-only `wa_id` values such as `15551234567`
374
- - WhatsApp groups: `120363001234567890@g.us`
466
+ - Telegram username targets require `@`, contain 5-32 letters, digits, or
467
+ underscores, and normalize to lowercase. Numeric chat IDs must be nonzero and
468
+ have an absolute value no greater than `2^52 - 1`.
469
+ - Built-in WhatsApp Cloud API users: digits-only `wa_id` values such as
470
+ `15551234567`
471
+ - Built-in WhatsApp Cloud API fixtures do not support `threadId` targets.
472
+ - OpenClaw WhatsApp bridge users: `15551234567@s.whatsapp.net`
473
+ (legacy `15551234567@c.us` inputs are accepted and canonicalized)
474
+ - OpenClaw WhatsApp bridge groups: `120363001234567890@g.us`
375
475
  - Discord channels and threads: Discord snowflake ids such as
376
476
  `123456789012345678`
477
+ - iMessage recipients: E.164 phone numbers such as `+15551234567`, email
478
+ addresses such as `user@example.com`, or chat GUIDs such as
479
+ `iMessage;-;chat-guid` and `SMS;+;chat-guid`
480
+ - Matrix rooms: scoped IDs such as `!abcdef:matrix.org` or Matrix v12
481
+ domainless room IDs; thread IDs are raw root event IDs such as
482
+ `$eventid:matrix.org`
483
+ - Mattermost channels, users, and root posts: exactly 26 lowercase alphanumeric
484
+ characters, such as `abcdefghijklmnopqrstuvwx12`
485
+ - Microsoft Teams: non-empty opaque Bot Connector `conversation.id` values such
486
+ as `a:opaque-conversation-id` or `19:conversation@thread.v2`
487
+ - Zalo users, OAs, and chats: non-whitespace provider IDs such as `user-1` or
488
+ `group-1`
377
489
 
378
490
  ## Webhooks
379
491
 
@@ -403,6 +515,8 @@ Nested message payloads are also accepted:
403
515
  ```
404
516
 
405
517
  Malformed webhooks return `400`, and non-JSON requests return `415`.
518
+ Configured webhook paths must be canonical URL pathnames without normalization,
519
+ query, or fragment ambiguity.
406
520
 
407
521
  ## Evidence Flow
408
522
 
@@ -1,6 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { runCli } from "../cli/program.js";
3
- const exitCode = await runCli(process.argv);
3
+ const exitCode = await runCli(process.argv, {
4
+ forceExit: (code) => process.exit(code),
5
+ });
4
6
  if (exitCode !== 0) {
5
7
  process.exitCode = exitCode;
6
8
  }
@@ -1 +1 @@
1
- {"version":3,"file":"crabline.js","sourceRoot":"","sources":["../../../src/bin/crabline.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AAC5C,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;IACnB,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;AAC9B,CAAC","sourcesContent":["#!/usr/bin/env node\n\nimport { runCli } from \"../cli/program.js\";\n\nconst exitCode = await runCli(process.argv);\nif (exitCode !== 0) {\n process.exitCode = exitCode;\n}\n"]}
1
+ {"version":3,"file":"crabline.js","sourceRoot":"","sources":["../../../src/bin/crabline.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE;IAC1C,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;CACxC,CAAC,CAAC;AACH,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;IACnB,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;AAC9B,CAAC","sourcesContent":["#!/usr/bin/env node\n\nimport { runCli } from \"../cli/program.js\";\n\nconst exitCode = await runCli(process.argv, {\n forceExit: (code) => process.exit(code),\n});\nif (exitCode !== 0) {\n process.exitCode = exitCode;\n}\n"]}
@@ -16,6 +16,10 @@ type ProgramDependencies = {
16
16
  removeReadyFile?: (filePath: string, expectedContents: string, expectedIdentity: ReadyFileIdentity) => Promise<void>;
17
17
  startServer?: (params: StartCrablineServerParams) => Promise<StartedCrablineServer>;
18
18
  };
19
+ type RunCliOptions = {
20
+ dependencies?: ProgramDependencies;
21
+ forceExit?: (code: number) => never;
22
+ };
19
23
  export declare function createProgram(setExitCode?: SetExitCode, dependencies?: ProgramDependencies): Command;
20
24
  type ShutdownSignal = "SIGINT" | "SIGTERM";
21
25
  type SignalTarget = {
@@ -25,5 +29,5 @@ type SignalTarget = {
25
29
  export declare function publishReadyFile(filePath: string, contents: string): Promise<ReadyFileIdentity>;
26
30
  export declare function removeReadyFile(filePath: string, expectedContents: string, expectedIdentity: ReadyFileIdentity): Promise<void>;
27
31
  export declare function waitForShutdown(close: () => Promise<void>, signalTarget?: SignalTarget): Promise<void>;
28
- export declare function runCli(argv: string[]): Promise<number>;
32
+ export declare function runCli(argv: string[], options?: RunCliOptions): Promise<number>;
29
33
  export {};