@clawhive/openclaw-plugin 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/README.md +217 -0
  2. package/dist/api.d.ts +6 -0
  3. package/dist/api.js +6 -0
  4. package/dist/index.d.ts +4 -0
  5. package/dist/index.js +324 -0
  6. package/dist/runtime-api.d.ts +1 -0
  7. package/dist/runtime-api.js +1 -0
  8. package/dist/setup-entry.d.ts +4 -0
  9. package/dist/setup-entry.js +3 -0
  10. package/dist/src/agency-install/claimLoop.d.ts +41 -0
  11. package/dist/src/agency-install/claimLoop.js +188 -0
  12. package/dist/src/agent-panel/claimLoop.d.ts +32 -0
  13. package/dist/src/agent-panel/claimLoop.js +118 -0
  14. package/dist/src/agent-panel/executor.d.ts +8 -0
  15. package/dist/src/agent-panel/executor.js +368 -0
  16. package/dist/src/agent-panel/plan.d.ts +20 -0
  17. package/dist/src/agent-panel/plan.js +111 -0
  18. package/dist/src/agent-panel/prompts.d.ts +38 -0
  19. package/dist/src/agent-panel/prompts.js +87 -0
  20. package/dist/src/agent-panel/types.d.ts +45 -0
  21. package/dist/src/agent-panel/types.js +1 -0
  22. package/dist/src/agents.d.ts +44 -0
  23. package/dist/src/agents.js +195 -0
  24. package/dist/src/authorization.d.ts +34 -0
  25. package/dist/src/authorization.js +183 -0
  26. package/dist/src/channel.d.ts +5 -0
  27. package/dist/src/channel.js +93 -0
  28. package/dist/src/claimPolling.d.ts +9 -0
  29. package/dist/src/claimPolling.js +13 -0
  30. package/dist/src/client.d.ts +386 -0
  31. package/dist/src/client.js +595 -0
  32. package/dist/src/config.d.ts +28 -0
  33. package/dist/src/config.js +94 -0
  34. package/dist/src/defaults.d.ts +40 -0
  35. package/dist/src/defaults.js +52 -0
  36. package/dist/src/deviceCode.d.ts +16 -0
  37. package/dist/src/deviceCode.js +65 -0
  38. package/dist/src/heartbeat.d.ts +25 -0
  39. package/dist/src/heartbeat.js +65 -0
  40. package/dist/src/imageAttachments.d.ts +14 -0
  41. package/dist/src/imageAttachments.js +81 -0
  42. package/dist/src/inbound.d.ts +10 -0
  43. package/dist/src/inbound.js +140 -0
  44. package/dist/src/installMutex.d.ts +4 -0
  45. package/dist/src/installMutex.js +18 -0
  46. package/dist/src/market-install/claimLoop.d.ts +41 -0
  47. package/dist/src/market-install/claimLoop.js +183 -0
  48. package/dist/src/market-install/downloader.d.ts +36 -0
  49. package/dist/src/market-install/downloader.js +133 -0
  50. package/dist/src/market-install/executor.d.ts +28 -0
  51. package/dist/src/market-install/executor.js +352 -0
  52. package/dist/src/market-install/types.d.ts +62 -0
  53. package/dist/src/market-install/types.js +1 -0
  54. package/dist/src/market-install/verifier.d.ts +32 -0
  55. package/dist/src/market-install/verifier.js +60 -0
  56. package/dist/src/market-publish/packager.d.ts +34 -0
  57. package/dist/src/market-publish/packager.js +168 -0
  58. package/dist/src/market-publish/publishFlow.d.ts +70 -0
  59. package/dist/src/market-publish/publishFlow.js +107 -0
  60. package/dist/src/market-publish/uploader.d.ts +73 -0
  61. package/dist/src/market-publish/uploader.js +132 -0
  62. package/dist/src/openclawVersion.d.ts +4 -0
  63. package/dist/src/openclawVersion.js +13 -0
  64. package/dist/src/outbound.d.ts +13 -0
  65. package/dist/src/outbound.js +41 -0
  66. package/dist/src/pairing.d.ts +32 -0
  67. package/dist/src/pairing.js +64 -0
  68. package/dist/src/runtime.d.ts +52 -0
  69. package/dist/src/runtime.js +26 -0
  70. package/dist/src/telemetry.d.ts +34 -0
  71. package/dist/src/telemetry.js +89 -0
  72. package/dist/src/transport/realtime.d.ts +49 -0
  73. package/dist/src/transport/realtime.js +273 -0
  74. package/dist/src/transport.d.ts +38 -0
  75. package/dist/src/transport.js +15 -0
  76. package/dist/src/wake.d.ts +31 -0
  77. package/dist/src/wake.js +101 -0
  78. package/openclaw.config.example.yaml +10 -0
  79. package/openclaw.plugin.json +122 -0
  80. package/package.json +84 -0
@@ -0,0 +1,595 @@
1
+ export class DeviceCodeExpiredError extends Error {
2
+ constructor() {
3
+ super("Device code expired before the user approved it");
4
+ this.name = "DeviceCodeExpiredError";
5
+ }
6
+ }
7
+ export class DeviceCodeDeniedError extends Error {
8
+ constructor() {
9
+ super("The user denied the device authorization request");
10
+ this.name = "DeviceCodeDeniedError";
11
+ }
12
+ }
13
+ /**
14
+ * Preserve low-level transport details so gateway logs show the real fetch cause.
15
+ */
16
+ function formatTransportError(error) {
17
+ if (!(error instanceof Error)) {
18
+ return String(error);
19
+ }
20
+ const details = [error.message];
21
+ const cause = error.cause;
22
+ if (cause instanceof Error) {
23
+ details.push(`cause=${cause.name}: ${cause.message}`);
24
+ }
25
+ else if (cause !== undefined) {
26
+ details.push(`cause=${String(cause)}`);
27
+ }
28
+ const errorWithCode = error;
29
+ if (typeof errorWithCode.code === "string") {
30
+ details.push(`code=${errorWithCode.code}`);
31
+ }
32
+ return details.join("; ");
33
+ }
34
+ function mapPanelContribution(raw) {
35
+ return {
36
+ id: String(raw.id),
37
+ agentId: String(raw.agentId ?? raw.agent_id),
38
+ round: raw.round,
39
+ status: raw.status,
40
+ assignment: raw.assignment ?? null,
41
+ content: raw.content ?? null,
42
+ errorMessage: raw.errorMessage ?? raw.error_message ?? null,
43
+ };
44
+ }
45
+ export class ClawHiveApiError extends Error {
46
+ status;
47
+ errorCode;
48
+ details;
49
+ constructor(payload) {
50
+ super(payload.error);
51
+ this.name = "ClawHiveApiError";
52
+ this.status = payload.status;
53
+ this.errorCode = payload.error;
54
+ this.details = payload.details;
55
+ }
56
+ }
57
+ export class ClawHiveCloudApi {
58
+ config;
59
+ constructor(config) {
60
+ this.config = config;
61
+ }
62
+ get baseUrl() {
63
+ return this.config.projectUrl.replace(/\/$/, "");
64
+ }
65
+ get userId() {
66
+ return this.config.userId ?? null;
67
+ }
68
+ get pluginToken() {
69
+ return this.config.pluginToken ?? null;
70
+ }
71
+ requireUserId() {
72
+ if (!this.config.userId) {
73
+ throw new Error("ClawHiveCloudApi: userId is not set. Call registerPluginNode() before making user-scoped calls.");
74
+ }
75
+ return this.config.userId;
76
+ }
77
+ requirePluginToken() {
78
+ if (!this.config.pluginToken) {
79
+ throw new Error("ClawHiveCloudApi: pluginToken is not set. Call bootstrap() first.");
80
+ }
81
+ return this.config.pluginToken;
82
+ }
83
+ async startDeviceCode(opts) {
84
+ return await this.request({
85
+ path: "plugin-device-code-start",
86
+ method: "POST",
87
+ auth: "none",
88
+ body: {
89
+ node_name: opts?.nodeName ?? this.config.nodeName ?? "OpenClaw Desktop",
90
+ plugin_version: opts?.pluginVersion ?? this.config.pluginVersion ?? "0.2.0",
91
+ description: opts?.description,
92
+ },
93
+ });
94
+ }
95
+ async exchangeDeviceCode(deviceCode) {
96
+ try {
97
+ const result = await this.request({
98
+ path: "plugin-device-code-exchange",
99
+ method: "POST",
100
+ auth: "none",
101
+ body: { device_code: deviceCode },
102
+ });
103
+ if (result.status === "approved") {
104
+ this.config.userId = result.user_id;
105
+ this.config.pluginToken = result.plugin_token;
106
+ return {
107
+ status: "approved",
108
+ user_id: result.user_id,
109
+ plugin_token: result.plugin_token,
110
+ };
111
+ }
112
+ return { status: "pending", interval: result.interval };
113
+ }
114
+ catch (error) {
115
+ if (error instanceof ClawHiveApiError) {
116
+ if (error.errorCode === "expired_token") {
117
+ throw new DeviceCodeExpiredError();
118
+ }
119
+ if (error.errorCode === "access_denied") {
120
+ throw new DeviceCodeDeniedError();
121
+ }
122
+ }
123
+ throw error;
124
+ }
125
+ }
126
+ async registerPluginNode() {
127
+ const body = {
128
+ plugin_node_id: this.config.pluginNodeId ?? null,
129
+ node_name: this.config.nodeName ?? "OpenClaw Desktop",
130
+ plugin_version: this.config.pluginVersion ?? "0.2.0",
131
+ };
132
+ if (this.config.userId) {
133
+ body.user_id = this.config.userId;
134
+ }
135
+ const result = await this.request({
136
+ path: "plugin-register",
137
+ method: "POST",
138
+ auth: "plugin",
139
+ body,
140
+ });
141
+ this.config.userId = result.user_id;
142
+ return result;
143
+ }
144
+ async createPairingCode(pluginNodeId, ttlSeconds) {
145
+ return this.request({
146
+ path: "pairing-code-create",
147
+ method: "POST",
148
+ auth: "plugin",
149
+ body: {
150
+ plugin_node_id: pluginNodeId,
151
+ ttl_seconds: ttlSeconds,
152
+ },
153
+ });
154
+ }
155
+ async heartbeat(params) {
156
+ return this.request({
157
+ path: "plugin-heartbeat",
158
+ method: "POST",
159
+ auth: "plugin",
160
+ body: {
161
+ plugin_node_id: params.pluginNodeId,
162
+ user_id: this.requireUserId(),
163
+ status: params.status ?? "online",
164
+ plugin_version: this.config.pluginVersion ?? "0.2.0",
165
+ },
166
+ });
167
+ }
168
+ async writeAgentMessage(params) {
169
+ return this.request({
170
+ path: "plugin-message-write",
171
+ method: "POST",
172
+ auth: "plugin",
173
+ body: {
174
+ plugin_node_id: params.pluginNodeId,
175
+ session_id: params.sessionId,
176
+ agent_id: params.agentId,
177
+ user_id: this.requireUserId(),
178
+ content: params.content,
179
+ type: params.type,
180
+ metadata: params.metadata,
181
+ client_message_id: params.clientMessageId,
182
+ role: params.role ?? "agent",
183
+ },
184
+ });
185
+ }
186
+ async syncAgents(agents) {
187
+ return this.request({
188
+ path: "plugin-agents-sync",
189
+ method: "POST",
190
+ auth: "plugin",
191
+ body: {
192
+ user_id: this.requireUserId(),
193
+ agents: agents.map((agent) => ({
194
+ openclaw_agent_id: agent.openclawAgentId,
195
+ name: agent.name,
196
+ description: agent.description ?? null,
197
+ avatar_url: agent.avatarUrl ?? null,
198
+ config: agent.config ?? {},
199
+ })),
200
+ },
201
+ });
202
+ }
203
+ async refreshUserSession(refreshToken) {
204
+ return this.request({
205
+ path: "auth-refresh",
206
+ method: "POST",
207
+ auth: "none",
208
+ body: { refreshToken },
209
+ });
210
+ }
211
+ async syncMessages(params) {
212
+ return this.request({
213
+ path: "messages-sync",
214
+ method: "GET",
215
+ auth: "user",
216
+ accessToken: params.accessToken,
217
+ query: {
218
+ session_id: params.sessionId,
219
+ after_sequence: params.afterSequence ?? 0,
220
+ limit: params.limit ?? 100,
221
+ },
222
+ });
223
+ }
224
+ async getMessageAttachmentDownloadUrl(params) {
225
+ return this.request({
226
+ path: "message-attachment-download-url",
227
+ method: "GET",
228
+ auth: "plugin",
229
+ query: {
230
+ message_id: params.messageId,
231
+ storage_path: params.storagePath,
232
+ public_origin: this.baseUrl,
233
+ },
234
+ });
235
+ }
236
+ /**
237
+ * Claim the oldest queued install job for the current plugin node.
238
+ */
239
+ async claimInstallJob(params) {
240
+ return this.request({
241
+ path: "market-install-claim",
242
+ method: "POST",
243
+ auth: "plugin",
244
+ body: {
245
+ pluginNodeId: params.pluginNodeId,
246
+ userId: params.userId ?? this.requireUserId(),
247
+ },
248
+ });
249
+ }
250
+ /**
251
+ * Persist node-side install execution state back to the durable market job.
252
+ */
253
+ async updateInstallJob(params) {
254
+ return this.request({
255
+ path: "market-install-update",
256
+ method: "POST",
257
+ auth: "plugin",
258
+ body: {
259
+ pluginNodeId: params.pluginNodeId,
260
+ jobId: params.jobId,
261
+ status: params.status,
262
+ userId: params.userId ?? this.requireUserId(),
263
+ reasonKind: params.reasonKind,
264
+ errorMessage: params.errorMessage,
265
+ details: params.details ?? {},
266
+ },
267
+ });
268
+ }
269
+ /**
270
+ * Fetch the approved manifest payload for one claimed install job.
271
+ */
272
+ async fetchInstallManifest(params) {
273
+ return this.request({
274
+ path: "market-install-manifest",
275
+ method: "POST",
276
+ auth: "plugin",
277
+ body: {
278
+ pluginNodeId: params.pluginNodeId,
279
+ jobId: params.jobId,
280
+ userId: params.userId ?? this.requireUserId(),
281
+ },
282
+ });
283
+ }
284
+ /**
285
+ * Claim the oldest queued Agency install job for the current plugin node.
286
+ */
287
+ async claimAgencyInstallJob(params) {
288
+ return this.request({
289
+ path: "agency-install-claim",
290
+ method: "POST",
291
+ auth: "plugin",
292
+ body: {
293
+ pluginNodeId: params.pluginNodeId,
294
+ userId: params.userId ?? this.requireUserId(),
295
+ },
296
+ });
297
+ }
298
+ /**
299
+ * Persist node-side Agency install execution state back to the durable job.
300
+ */
301
+ async updateAgencyInstallJob(params) {
302
+ return this.request({
303
+ path: "agency-install-update",
304
+ method: "POST",
305
+ auth: "plugin",
306
+ body: {
307
+ pluginNodeId: params.pluginNodeId,
308
+ jobId: params.jobId,
309
+ status: params.status,
310
+ userId: params.userId ?? this.requireUserId(),
311
+ reasonKind: params.reasonKind,
312
+ errorMessage: params.errorMessage,
313
+ details: params.details ?? {},
314
+ },
315
+ });
316
+ }
317
+ /**
318
+ * Fetch the approved Agency manifest payload for one claimed install job.
319
+ */
320
+ async fetchAgencyInstallManifest(params) {
321
+ return this.request({
322
+ path: "agency-install-manifest",
323
+ method: "POST",
324
+ auth: "plugin",
325
+ body: {
326
+ pluginNodeId: params.pluginNodeId,
327
+ jobId: params.jobId,
328
+ userId: params.userId ?? this.requireUserId(),
329
+ },
330
+ });
331
+ }
332
+ async createMarketListing(params) {
333
+ const body = {
334
+ name: params.name,
335
+ slug: params.slug,
336
+ status: params.status ?? "draft",
337
+ };
338
+ if (params.listingId)
339
+ body.listing_id = params.listingId;
340
+ if (params.authorDisplayName)
341
+ body.author_display_name = params.authorDisplayName;
342
+ if (params.summary)
343
+ body.summary = params.summary;
344
+ if (params.description)
345
+ body.description = params.description;
346
+ if (params.category)
347
+ body.category = params.category;
348
+ if (params.license)
349
+ body.license = params.license;
350
+ if (params.avatarUrl)
351
+ body.avatar_url = params.avatarUrl;
352
+ if (params.tags)
353
+ body.tags = params.tags;
354
+ if (params.sourceNodeId)
355
+ body.source_node_id = params.sourceNodeId;
356
+ return this.request({
357
+ path: "market-listings",
358
+ method: "POST",
359
+ auth: "user",
360
+ accessToken: params.accessToken,
361
+ body,
362
+ });
363
+ }
364
+ async createMarketRelease(params) {
365
+ const body = {
366
+ listing_id: params.listingId,
367
+ version: params.version,
368
+ storage_path: params.storagePath,
369
+ fingerprint: params.fingerprint,
370
+ source_type: params.sourceType,
371
+ source_ref: params.sourceRef,
372
+ publish: params.publish,
373
+ };
374
+ if (params.minPluginVersion)
375
+ body.min_plugin_version = params.minPluginVersion;
376
+ if (params.minOpenClawVersion)
377
+ body.min_openclaw_version = params.minOpenClawVersion;
378
+ if (params.compatibilityNotes)
379
+ body.compatibility_notes = params.compatibilityNotes;
380
+ return this.request({
381
+ path: "market-releases-create",
382
+ method: "POST",
383
+ auth: "user",
384
+ accessToken: params.accessToken,
385
+ body,
386
+ });
387
+ }
388
+ async claimPanelTurn(params) {
389
+ return this.request({
390
+ path: "agent-panel-turn-claim",
391
+ method: "POST",
392
+ auth: "plugin",
393
+ body: {
394
+ pluginNodeId: params.pluginNodeId,
395
+ userId: params.userId ?? this.requireUserId(),
396
+ },
397
+ });
398
+ }
399
+ async updatePanelContribution(params) {
400
+ await this.request({
401
+ path: "agent-panel-contribution-update",
402
+ method: "POST",
403
+ auth: "plugin",
404
+ body: {
405
+ contributionId: params.contributionId,
406
+ status: params.status,
407
+ content: params.content,
408
+ errorMessage: params.errorMessage,
409
+ startedAt: params.startedAt,
410
+ completedAt: params.completedAt,
411
+ assignment: params.assignment,
412
+ },
413
+ });
414
+ }
415
+ async createPanelContribution(params) {
416
+ const result = await this.request({
417
+ path: "agent-panel-contribution-create",
418
+ method: "POST",
419
+ auth: "plugin",
420
+ body: {
421
+ turnId: params.turnId,
422
+ agentId: params.agentId,
423
+ round: params.round,
424
+ assignment: params.assignment,
425
+ },
426
+ });
427
+ return { contribution: mapPanelContribution(result.contribution) };
428
+ }
429
+ async updatePanelTurn(params) {
430
+ await this.request({
431
+ path: "agent-panel-turn-update",
432
+ method: "POST",
433
+ auth: "plugin",
434
+ body: {
435
+ turnId: params.turnId,
436
+ status: params.status,
437
+ errorMessage: params.errorMessage,
438
+ startedAt: params.startedAt,
439
+ completedAt: params.completedAt,
440
+ plan: params.plan,
441
+ planStatus: params.planStatus,
442
+ planErrorMessage: params.planErrorMessage,
443
+ },
444
+ });
445
+ }
446
+ /**
447
+ * Get signed download URL for a release package.
448
+ *
449
+ * This is used during install to obtain a time-limited signed URL for downloading
450
+ * the release package from Supabase Storage (D-12).
451
+ *
452
+ * The signed URL expires after 1 hour. If download fails with 403, the caller should
453
+ * retry by calling this method again to get a fresh signed URL.
454
+ *
455
+ * @param releaseId - Release UUID
456
+ * @param accessToken - User JWT access token
457
+ * @returns Signed URL, fingerprint, and expiry time
458
+ * @throws {ClawHiveApiError} If release is withdrawn (410), not found (404), or other errors
459
+ */
460
+ async getSignedDownloadUrl(releaseId, accessToken) {
461
+ return this.request({
462
+ path: "market-release-download",
463
+ method: "GET",
464
+ auth: "user",
465
+ accessToken,
466
+ query: {
467
+ release_id: releaseId,
468
+ },
469
+ });
470
+ }
471
+ /**
472
+ * Upload a release package to Supabase Storage.
473
+ *
474
+ * This is step 1 of the two-step publish flow (D-08):
475
+ * 1. Upload the tar.gz to Storage via this method → receive storage_path + fingerprint
476
+ * 2. Call market-releases-create with the storage_path + fingerprint + release metadata
477
+ *
478
+ * The upload is idempotent: uploading the same content to the same path is safe.
479
+ * Storage path format: releases/{listing_id}/{version}.tar.gz (D-09)
480
+ * Size limit: 10 MiB (D-10), enforced by the edge function
481
+ *
482
+ * Example usage:
483
+ * ```typescript
484
+ * import { packageAgentDirectory } from "./market-publish/packager.js";
485
+ *
486
+ * // Step 1: Package and upload
487
+ * const pkg = await packageAgentDirectory({ agentDir: "/path/to/agent" });
488
+ * const uploadResult = await client.uploadReleasePackage({
489
+ * listingId: "listing-uuid",
490
+ * version: "v1.0.0",
491
+ * buffer: pkg.buffer,
492
+ * fingerprint: pkg.fingerprint,
493
+ * accessToken: "user-jwt",
494
+ * });
495
+ *
496
+ * // Step 2: Create release record
497
+ * await client.createMarketRelease({
498
+ * listingId: uploadResult.listing_id,
499
+ * version: "v1.0.0",
500
+ * storagePath: uploadResult.storage_path,
501
+ * fingerprint: uploadResult.fingerprint,
502
+ * // ... other release metadata
503
+ * });
504
+ * ```
505
+ *
506
+ * @param params - Upload parameters
507
+ * @returns Upload result with storage_path and fingerprint
508
+ */
509
+ async uploadReleasePackage(params) {
510
+ const url = new URL(`${this.baseUrl}/functions/v1/market-release-upload`);
511
+ const headers = {
512
+ "Content-Type": "application/json",
513
+ apikey: this.config.anonKey,
514
+ Authorization: `Bearer ${params.accessToken}`,
515
+ };
516
+ let response;
517
+ try {
518
+ response = await fetch(url.toString(), {
519
+ method: "POST",
520
+ headers,
521
+ body: JSON.stringify({
522
+ listing_id: params.listingId,
523
+ version: params.version,
524
+ file_data: params.buffer.toString("base64"),
525
+ }),
526
+ });
527
+ }
528
+ catch (error) {
529
+ const reason = formatTransportError(error);
530
+ throw new Error(`ClawHive market-release-upload request failed (POST ${url.toString()}): ${reason}`);
531
+ }
532
+ const text = await response.text();
533
+ const payload = text ? JSON.parse(text) : {};
534
+ if (!response.ok) {
535
+ throw new ClawHiveApiError({
536
+ status: response.status,
537
+ error: typeof payload.error === "string"
538
+ ? payload.error
539
+ : `ClawHive market-release-upload failed (${response.status})`,
540
+ details: payload.details,
541
+ });
542
+ }
543
+ return payload;
544
+ }
545
+ async request(options) {
546
+ const url = new URL(`${this.baseUrl}/functions/v1/${options.path}`);
547
+ const method = options.method ?? "GET";
548
+ for (const [key, value] of Object.entries(options.query ?? {})) {
549
+ if (value !== undefined && value !== null) {
550
+ url.searchParams.set(key, String(value));
551
+ }
552
+ }
553
+ const headers = {
554
+ "Content-Type": "application/json",
555
+ Connection: "close",
556
+ apikey: this.config.anonKey,
557
+ };
558
+ if (options.auth === "plugin") {
559
+ headers.Authorization = `Bearer ${this.config.anonKey}`;
560
+ headers["x-plugin-token"] = this.requirePluginToken();
561
+ }
562
+ else if (options.auth === "user" && options.accessToken) {
563
+ headers.Authorization = `Bearer ${options.accessToken}`;
564
+ }
565
+ else if (options.auth === "none") {
566
+ headers.Authorization = `Bearer ${this.config.anonKey}`;
567
+ }
568
+ let response;
569
+ try {
570
+ response = await fetch(url.toString(), {
571
+ method,
572
+ headers,
573
+ body: options.body && method !== "GET"
574
+ ? JSON.stringify(options.body)
575
+ : undefined,
576
+ });
577
+ }
578
+ catch (error) {
579
+ const reason = formatTransportError(error);
580
+ throw new Error(`ClawHive ${options.path} request failed (${method} ${url.toString()}): ${reason}`);
581
+ }
582
+ const text = await response.text();
583
+ const payload = text ? JSON.parse(text) : {};
584
+ if (!response.ok) {
585
+ throw new ClawHiveApiError({
586
+ status: response.status,
587
+ error: typeof payload.error === "string"
588
+ ? payload.error
589
+ : `ClawHive ${options.path} failed (${response.status})`,
590
+ details: payload.details,
591
+ });
592
+ }
593
+ return payload;
594
+ }
595
+ }
@@ -0,0 +1,28 @@
1
+ import { type ChannelSetupInput, type OpenClawConfig } from "openclaw/plugin-sdk/core";
2
+ export declare const CLAWHIVE_CHANNEL_ID = "clawhive";
3
+ export type ClawHiveResolvedAccount = {
4
+ accountId: string;
5
+ projectUrl: string;
6
+ anonKey: string;
7
+ pluginToken: string;
8
+ userId: string | null;
9
+ pluginNodeId: string | null;
10
+ nodeName: string;
11
+ pluginVersion: string;
12
+ publishSourceRef: string | null;
13
+ publishFingerprint: string | null;
14
+ minPluginVersion: string | null;
15
+ minOpenClawVersion: string | null;
16
+ dmPolicy: string | null;
17
+ allowFrom: Array<string | number>;
18
+ };
19
+ export declare function readRawChannelSection(cfg: OpenClawConfig): Record<string, unknown>;
20
+ export declare function resolveResolvedAccount(cfg: OpenClawConfig, accountId?: string | null): ClawHiveResolvedAccount;
21
+ export declare function writeChannelSection(cfg: OpenClawConfig, input: ChannelSetupInput): OpenClawConfig;
22
+ export declare function writePluginNodeId(cfg: OpenClawConfig, pluginNodeId: string): OpenClawConfig;
23
+ export declare function writeRegistrationIdentity(cfg: OpenClawConfig, patch: {
24
+ userId?: string;
25
+ pluginNodeId?: string;
26
+ pluginToken?: string;
27
+ anonKey?: string;
28
+ }): OpenClawConfig;