@byokit/openclaw 0.1.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 (64) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/LICENSE +202 -0
  3. package/README.md +174 -0
  4. package/dist/approvals.d.ts +29 -0
  5. package/dist/approvals.js +200 -0
  6. package/dist/bridge.d.ts +78 -0
  7. package/dist/bridge.js +345 -0
  8. package/dist/classify.d.ts +4 -0
  9. package/dist/classify.js +14 -0
  10. package/dist/config.d.ts +13 -0
  11. package/dist/config.js +74 -0
  12. package/dist/constants.d.ts +3 -0
  13. package/dist/constants.js +13 -0
  14. package/dist/device.d.ts +63 -0
  15. package/dist/device.js +192 -0
  16. package/dist/engine.d.ts +43 -0
  17. package/dist/engine.js +212 -0
  18. package/dist/generated/events.d.ts +61 -0
  19. package/dist/generated/events.js +1 -0
  20. package/dist/generated/methods.d.ts +2368 -0
  21. package/dist/generated/methods.js +1 -0
  22. package/dist/generated/params.d.ts +1717 -0
  23. package/dist/generated/params.js +5 -0
  24. package/dist/generated/report.json +1356 -0
  25. package/dist/index.d.ts +4 -0
  26. package/dist/index.js +5 -0
  27. package/dist/kit.d.ts +108 -0
  28. package/dist/kit.js +655 -0
  29. package/dist/link.d.ts +24 -0
  30. package/dist/link.js +273 -0
  31. package/dist/members.d.ts +11 -0
  32. package/dist/members.js +23 -0
  33. package/dist/migrate.d.ts +22 -0
  34. package/dist/migrate.js +118 -0
  35. package/dist/notices.d.ts +9 -0
  36. package/dist/notices.js +75 -0
  37. package/dist/routes.d.ts +9 -0
  38. package/dist/routes.js +15 -0
  39. package/dist/routes.json +398 -0
  40. package/dist/runs.d.ts +14 -0
  41. package/dist/runs.js +110 -0
  42. package/dist/signin.d.ts +24 -0
  43. package/dist/signin.js +251 -0
  44. package/dist/testing/contract.d.ts +12 -0
  45. package/dist/testing/contract.js +250 -0
  46. package/dist/testing/fake-gateway.d.ts +19 -0
  47. package/dist/testing/fake-gateway.js +378 -0
  48. package/dist/testing/index.d.ts +3 -0
  49. package/dist/testing/index.js +4 -0
  50. package/dist/testing/model-stub.d.ts +29 -0
  51. package/dist/testing/model-stub.js +182 -0
  52. package/dist/transport.d.ts +22 -0
  53. package/dist/transport.js +94 -0
  54. package/dist/types.d.ts +125 -0
  55. package/dist/types.js +2 -0
  56. package/dist/words.d.ts +12 -0
  57. package/dist/words.js +26 -0
  58. package/dist/words.json +20 -0
  59. package/engine/package-lock.json +4680 -0
  60. package/engine/package.json +1 -0
  61. package/package.json +68 -0
  62. package/plugin/index.js +183 -0
  63. package/plugin/package.json +1 -0
  64. package/policy/policy.mjs +197 -0
package/dist/kit.js ADDED
@@ -0,0 +1,655 @@
1
+ // The OpenClawKit facade: state, complete pass-through (D6), members, sign-in, runs, approvals, config (5.3).
2
+ // Built in O4 (and O5/O6/O8 for the delegated parts); until then every body refuses to run.
3
+ import { readFileSync } from 'node:fs';
4
+ import { join } from 'node:path';
5
+ import { setTimeout as delay } from 'node:timers/promises';
6
+ import { fileURLToPath } from 'node:url';
7
+ import { PROTOCOL_VERSION } from "./constants.js";
8
+ import { Approvals } from "./approvals.js";
9
+ import { Bridge } from "./bridge.js";
10
+ import { Engine } from "./engine.js";
11
+ import { gatewayTransport } from "./transport.js";
12
+ import { createMembers } from "./members.js";
13
+ import { confirmRetainedLogin as confirmLogin, migrateRetainedLogin as migrateLogin } from "./migrate.js";
14
+ import { createRuns } from "./runs.js";
15
+ import { routes as routeTable } from "./routes.js";
16
+ import { providers as engineProviders, signIn as startSignIn, signOut as engineSignOut } from "./signin.js";
17
+ import { reconcileConfig, memoryLimited as configMemoryLimited } from "./config.js";
18
+ const operatorMethods = new Set([
19
+ 'agent',
20
+ 'agent.identity.get',
21
+ 'agent.wait',
22
+ 'agents.create',
23
+ 'agents.delete',
24
+ 'agents.files.get',
25
+ 'agents.files.list',
26
+ 'agents.files.set',
27
+ 'agents.list',
28
+ 'agents.update',
29
+ 'agents.workspace.get',
30
+ 'agents.workspace.list',
31
+ 'approval.get',
32
+ 'approval.history',
33
+ 'approval.resolve',
34
+ 'artifacts.download',
35
+ 'artifacts.get',
36
+ 'artifacts.list',
37
+ 'assistant.media.get',
38
+ 'attach.grant',
39
+ 'attach.revoke',
40
+ 'audit.activity.list',
41
+ 'audit.list',
42
+ 'audit.run.inspect',
43
+ 'board.action',
44
+ 'board.data.read',
45
+ 'board.event',
46
+ 'board.get',
47
+ 'board.prompt.authorize',
48
+ 'board.update',
49
+ 'board.widget.appView',
50
+ 'board.widget.grant',
51
+ 'board.widget.put',
52
+ 'channels.logout',
53
+ 'channels.pairing.approve',
54
+ 'channels.pairing.dismiss',
55
+ 'channels.pairing.list',
56
+ 'channels.start',
57
+ 'channels.status',
58
+ 'channels.stop',
59
+ 'chat.abort',
60
+ 'chat.history',
61
+ 'chat.inject',
62
+ 'chat.message.get',
63
+ 'chat.metadata',
64
+ 'chat.send',
65
+ 'chat.startup',
66
+ 'chat.toolTitles',
67
+ 'commands.list',
68
+ 'config.apply',
69
+ 'config.get',
70
+ 'config.openFile',
71
+ 'config.patch',
72
+ 'config.schema',
73
+ 'config.schema.lookup',
74
+ 'config.set',
75
+ 'connect',
76
+ 'controlUi.githubPreview',
77
+ 'controlUi.sessionPreview',
78
+ 'controlUi.sessionPullRequests.subscribe',
79
+ 'conversations.list',
80
+ 'conversations.send',
81
+ 'conversations.turn',
82
+ 'conversations.turn.cancel',
83
+ 'cron.add',
84
+ 'cron.get',
85
+ 'cron.list',
86
+ 'cron.remove',
87
+ 'cron.run',
88
+ 'cron.runs',
89
+ 'cron.scratch.get',
90
+ 'cron.scratch.set',
91
+ 'cron.status',
92
+ 'cron.update',
93
+ 'desktop.launch',
94
+ 'desktop.observe',
95
+ 'device.pair.approve',
96
+ 'device.pair.list',
97
+ 'device.pair.reject',
98
+ 'device.pair.remove',
99
+ 'device.pair.rename',
100
+ 'device.pair.setupCode',
101
+ 'device.pair.setupStatus',
102
+ 'device.scopes.requestUpgrade',
103
+ 'device.scopes.waitUpgrade',
104
+ 'device.token.revoke',
105
+ 'device.token.rotate',
106
+ 'diagnostics.lanes',
107
+ 'diagnostics.stability',
108
+ 'doctor.memory.backfillDreamDiary',
109
+ 'doctor.memory.dedupeDreamDiary',
110
+ 'doctor.memory.dreamDiary',
111
+ 'doctor.memory.repairDreamingArtifacts',
112
+ 'doctor.memory.resetDreamDiary',
113
+ 'doctor.memory.resetGroundedShortTerm',
114
+ 'doctor.memory.status',
115
+ 'environments.create',
116
+ 'environments.destroy',
117
+ 'environments.list',
118
+ 'environments.status',
119
+ 'exec.approval.get',
120
+ 'exec.approval.grants.list',
121
+ 'exec.approval.grants.revoke',
122
+ 'exec.approval.list',
123
+ 'exec.approval.request',
124
+ 'exec.approval.resolve',
125
+ 'exec.approval.waitDecision',
126
+ 'exec.approvals.get',
127
+ 'exec.approvals.node.get',
128
+ 'exec.approvals.node.set',
129
+ 'exec.approvals.set',
130
+ 'fs.listDir',
131
+ 'gateway.identity.get',
132
+ 'gateway.restart.preflight',
133
+ 'gateway.restart.request',
134
+ 'gateway.suspend.prepare',
135
+ 'gateway.suspend.resume',
136
+ 'gateway.suspend.status',
137
+ 'health',
138
+ 'hooks.status',
139
+ 'last-heartbeat',
140
+ 'logs.tail',
141
+ 'mcp.app.callTool',
142
+ 'mcp.app.listResourceTemplates',
143
+ 'mcp.app.listResources',
144
+ 'mcp.app.listTools',
145
+ 'mcp.app.readResource',
146
+ 'mcp.app.updateModelContext',
147
+ 'mcp.app.view',
148
+ 'memory.search',
149
+ 'message.action',
150
+ 'migrations.memory.apply',
151
+ 'migrations.memory.plan',
152
+ 'models.authLogout',
153
+ 'models.authStatus',
154
+ 'models.list',
155
+ 'models.probe',
156
+ 'nativeHook.invoke',
157
+ 'node.describe',
158
+ 'node.invoke',
159
+ 'node.list',
160
+ 'node.pair.approve',
161
+ 'node.pair.list',
162
+ 'node.pair.reject',
163
+ 'node.pair.remove',
164
+ 'node.pending.enqueue',
165
+ 'node.rename',
166
+ 'openclaw.approval.list',
167
+ 'openclaw.changes.list',
168
+ 'openclaw.chat',
169
+ 'openclaw.chat.history',
170
+ 'openclaw.setup.activate',
171
+ 'openclaw.setup.auth.start',
172
+ 'openclaw.setup.detect',
173
+ 'openclaw.setup.prepare.start',
174
+ 'openclaw.setup.verify',
175
+ 'plugin.approval.list',
176
+ 'plugin.approval.request',
177
+ 'plugin.approval.resolve',
178
+ 'plugin.approval.waitDecision',
179
+ 'plugin.surface.refresh',
180
+ 'plugins.inspect',
181
+ 'plugins.install',
182
+ 'plugins.list',
183
+ 'plugins.refresh',
184
+ 'plugins.search',
185
+ 'plugins.sessionAction',
186
+ 'plugins.setEnabled',
187
+ 'plugins.uiDescriptors',
188
+ 'plugins.uninstall',
189
+ 'poll',
190
+ 'portal.close',
191
+ 'portal.list',
192
+ 'portal.open',
193
+ 'progressCard.get',
194
+ 'progressCard.put',
195
+ 'projects.add',
196
+ 'projects.list',
197
+ 'projects.register',
198
+ 'projects.remove',
199
+ 'projects.searchRemote',
200
+ 'push.test',
201
+ 'push.web.preferences.get',
202
+ 'push.web.preferences.set',
203
+ 'push.web.subscribe',
204
+ 'push.web.test',
205
+ 'push.web.unsubscribe',
206
+ 'push.web.vapidPublicKey',
207
+ 'question.get',
208
+ 'question.list',
209
+ 'question.request',
210
+ 'question.resolve',
211
+ 'question.waitAnswer',
212
+ 'secrets.reload',
213
+ 'secrets.resolve',
214
+ 'secrets.store.delete',
215
+ 'secrets.store.list',
216
+ 'secrets.store.set',
217
+ 'send',
218
+ 'session.discussion.info',
219
+ 'session.discussion.open',
220
+ 'session.members.add',
221
+ 'session.members.list',
222
+ 'session.members.listEvidence',
223
+ 'session.members.remove',
224
+ 'session.suggestions.add',
225
+ 'session.suggestions.list',
226
+ 'session.suggestions.resolve',
227
+ 'session.typing',
228
+ 'session.visibility.set',
229
+ 'sessions.abort',
230
+ 'sessions.assignOwner',
231
+ 'sessions.branches.list',
232
+ 'sessions.branches.switch',
233
+ 'sessions.catalog.archive',
234
+ 'sessions.catalog.continue',
235
+ 'sessions.catalog.list',
236
+ 'sessions.catalog.read',
237
+ 'sessions.catalog.startTerminal',
238
+ 'sessions.cleanup',
239
+ 'sessions.compact',
240
+ 'sessions.compaction.branch',
241
+ 'sessions.compaction.list',
242
+ 'sessions.compaction.restore',
243
+ 'sessions.companion.ask',
244
+ 'sessions.companion.reset',
245
+ 'sessions.companion.state',
246
+ 'sessions.create',
247
+ 'sessions.delete',
248
+ 'sessions.describe',
249
+ 'sessions.diff',
250
+ 'sessions.dispatch',
251
+ 'sessions.files.get',
252
+ 'sessions.files.list',
253
+ 'sessions.files.reveal',
254
+ 'sessions.files.set',
255
+ 'sessions.fork',
256
+ 'sessions.get',
257
+ 'sessions.github.publish',
258
+ 'sessions.goal.clear',
259
+ 'sessions.goal.update',
260
+ 'sessions.groups.defaults',
261
+ 'sessions.groups.delete',
262
+ 'sessions.groups.list',
263
+ 'sessions.groups.put',
264
+ 'sessions.groups.rename',
265
+ 'sessions.groups.update',
266
+ 'sessions.list',
267
+ 'sessions.messages.subscribe',
268
+ 'sessions.messages.unsubscribe',
269
+ 'sessions.move',
270
+ 'sessions.observer.visibility',
271
+ 'sessions.patch',
272
+ 'sessions.patchMany',
273
+ 'sessions.pluginPatch',
274
+ 'sessions.preview',
275
+ 'sessions.reclaim',
276
+ 'sessions.recover',
277
+ 'sessions.reset',
278
+ 'sessions.resolve',
279
+ 'sessions.rewind',
280
+ 'sessions.search',
281
+ 'sessions.send',
282
+ 'sessions.steer',
283
+ 'sessions.subscribe',
284
+ 'sessions.usage',
285
+ 'sessions.usage.logs',
286
+ 'sessions.usage.timeseries',
287
+ 'sessions.viewers.set',
288
+ 'set-heartbeats',
289
+ 'skills.curator.pin',
290
+ 'skills.curator.restore',
291
+ 'skills.curator.status',
292
+ 'skills.curator.unpin',
293
+ 'skills.detail',
294
+ 'skills.install',
295
+ 'skills.proposals.apply',
296
+ 'skills.proposals.create',
297
+ 'skills.proposals.evaluate',
298
+ 'skills.proposals.events.list',
299
+ 'skills.proposals.historyScan',
300
+ 'skills.proposals.historyStatus',
301
+ 'skills.proposals.inspect',
302
+ 'skills.proposals.list',
303
+ 'skills.proposals.quarantine',
304
+ 'skills.proposals.reject',
305
+ 'skills.proposals.requestRevision',
306
+ 'skills.proposals.revise',
307
+ 'skills.proposals.update',
308
+ 'skills.search',
309
+ 'skills.securityVerdicts',
310
+ 'skills.skillCard',
311
+ 'skills.status',
312
+ 'skills.update',
313
+ 'skills.upload.begin',
314
+ 'skills.upload.chunk',
315
+ 'skills.upload.commit',
316
+ 'status',
317
+ 'system-event',
318
+ 'system-presence',
319
+ 'system.info',
320
+ 'talk.catalog',
321
+ 'talk.client.close',
322
+ 'talk.client.create',
323
+ 'talk.client.steer',
324
+ 'talk.client.toolCall',
325
+ 'talk.client.transcript',
326
+ 'talk.config',
327
+ 'talk.mode',
328
+ 'talk.session.acknowledgeMark',
329
+ 'talk.session.appendAudio',
330
+ 'talk.session.cancelOutput',
331
+ 'talk.session.close',
332
+ 'talk.session.create',
333
+ 'talk.session.steer',
334
+ 'talk.session.submitToolResult',
335
+ 'talk.speak',
336
+ 'taskSuggestions.accept',
337
+ 'taskSuggestions.create',
338
+ 'taskSuggestions.dismiss',
339
+ 'taskSuggestions.list',
340
+ 'tasks.cancel',
341
+ 'tasks.dismiss',
342
+ 'tasks.get',
343
+ 'tasks.list',
344
+ 'tasks.retry',
345
+ 'terminal.attach',
346
+ 'terminal.close',
347
+ 'terminal.input',
348
+ 'terminal.list',
349
+ 'terminal.open',
350
+ 'terminal.resize',
351
+ 'terminal.upload',
352
+ 'tools.catalog',
353
+ 'tools.effective',
354
+ 'tools.github.authorize.cancel',
355
+ 'tools.github.authorize.poll',
356
+ 'tools.github.authorize.start',
357
+ 'tools.github.configure',
358
+ 'tools.github.status',
359
+ 'tools.invoke',
360
+ 'tts.convert',
361
+ 'tts.disable',
362
+ 'tts.enable',
363
+ 'tts.personas',
364
+ 'tts.providers',
365
+ 'tts.setPersona',
366
+ 'tts.setProvider',
367
+ 'tts.speak',
368
+ 'tts.status',
369
+ 'ui.command',
370
+ 'update.hold',
371
+ 'update.run',
372
+ 'update.status',
373
+ 'usage.cost',
374
+ 'usage.status',
375
+ 'users.linkEmail',
376
+ 'users.list',
377
+ 'users.prefs.get',
378
+ 'users.prefs.set',
379
+ 'users.self',
380
+ 'users.setAvatar',
381
+ 'users.setDisplayName',
382
+ 'users.setRole',
383
+ 'voicewake.get',
384
+ 'voicewake.routing.get',
385
+ 'voicewake.set',
386
+ 'wake',
387
+ 'web.login.start',
388
+ 'web.login.wait',
389
+ 'wizard.cancel',
390
+ 'wizard.next',
391
+ 'wizard.start',
392
+ 'wizard.status',
393
+ 'worker.desktop.launch',
394
+ 'worker.desktop.observe',
395
+ 'worktrees.branches',
396
+ 'worktrees.create',
397
+ 'worktrees.gc',
398
+ 'worktrees.list',
399
+ 'worktrees.remove',
400
+ 'worktrees.restore',
401
+ ]);
402
+ const nodeMethods = new Set([
403
+ 'node.event',
404
+ 'node.invoke.progress',
405
+ 'node.invoke.result',
406
+ 'node.pending.ack',
407
+ 'node.pending.drain',
408
+ 'node.pending.pull',
409
+ 'node.pluginSurface.refresh',
410
+ 'node.pluginTools.update',
411
+ 'node.runnerInventory.update',
412
+ 'node.skills.update',
413
+ 'skills.bins',
414
+ ]);
415
+ export class OpenClawKit {
416
+ engine;
417
+ o;
418
+ current = { phase: 'stopped' };
419
+ transport;
420
+ greeting;
421
+ members;
422
+ // One bridge and one approval surface per kit: listeners and run registrations survive reconnects (B3).
423
+ // Only the socket itself is per-connection. Approvals always reaches the live transport through this.request().
424
+ bridge;
425
+ approvalsCtl;
426
+ listeners = new Set();
427
+ off = [];
428
+ starting;
429
+ stopping = false;
430
+ failures = 0;
431
+ constructor(o) {
432
+ if (o.tools?.length && !o.host)
433
+ throw new Error('host required when tools are registered');
434
+ // The engine lowercases and alias-maps a tool name before the gate hook sees it (bash -> exec, cron ->
435
+ // automations); a name it would rewrite reaches the gate as a builtin, so refuse it here.
436
+ for (const t of o.tools ?? []) {
437
+ if (!/^[a-z][a-z0-9_]*$/.test(t.name) || t.name === 'bash' || t.name === 'cron')
438
+ throw new Error(`invalid tool name: ${t.name}`);
439
+ }
440
+ this.o = o;
441
+ this.engine = new Engine({ ...o, pluginId: o.plugin?.id ?? 'byokit', tools: o.tools ?? [],
442
+ gateBuiltins: o.gateBuiltins !== false, spawnEngine: o.spawnEngine !== false,
443
+ onState: (s) => this.setState(s), onExit: () => this.closed('engine exited') });
444
+ const slot = {};
445
+ this.approvalsCtl = new Approvals({
446
+ request: (method, params, co) => this.request()(method, params, co),
447
+ bridge: { resolveAsk: (id, d) => slot.bridge?.resolveAsk(id, d) ?? false },
448
+ });
449
+ this.bridge = new Bridge({ path: this.engine.bridgeSock, host: o.host, tools: new Set((o.tools ?? []).map((t) => t.name)),
450
+ permitted: o.permitted ?? (() => true), approvalTimeoutMs: o.approvalTimeoutMs ?? 180_000,
451
+ onAsk: (a) => this.approvalsCtl.add(a), onAskGone: (id) => this.approvalsCtl.remove(id) });
452
+ slot.bridge = this.bridge;
453
+ }
454
+ setState(s) { this.current = s; this.o.onState?.(s); }
455
+ get state() { return this.current; }
456
+ prepare() { return this.engine.prepare(); }
457
+ start() {
458
+ if (this.current.phase === 'ready')
459
+ return Promise.resolve();
460
+ if (this.starting)
461
+ return this.starting;
462
+ this.stopping = false;
463
+ const task = this.connect();
464
+ this.starting = task;
465
+ void task.finally(() => { if (this.starting === task)
466
+ this.starting = undefined; }).catch(() => { });
467
+ return task;
468
+ }
469
+ async connect() {
470
+ let transport;
471
+ try {
472
+ const ctx = await this.engine.start();
473
+ if (this.stopping)
474
+ return;
475
+ this.setState({ phase: 'starting' });
476
+ transport = (this.o.transport ?? gatewayTransport)({ ...ctx, bridgeSock: this.engine.bridgeSock });
477
+ this.transport = transport;
478
+ this.off = [transport.onEvent((e) => { for (const fn of this.listeners)
479
+ fn(e); }), transport.onClose((why) => this.closed(why))];
480
+ const hello = await Promise.race([transport.start(), delay(90_000, undefined, { ref: false }).then(() => { throw new Error('gateway handshake timed out'); })]);
481
+ if (this.stopping || this.transport !== transport)
482
+ return;
483
+ if (hello.protocol !== PROTOCOL_VERSION) {
484
+ this.setState({ phase: 'needs-update', why: 'version' });
485
+ throw new Error(`gateway protocol ${hello.protocol} != ${PROTOCOL_VERSION}`);
486
+ }
487
+ this.greeting = hello;
488
+ for (const name of operatorMethods)
489
+ if (!hello.methods.includes(name))
490
+ this.o.log?.(`gateway missing generated method: ${name}`);
491
+ for (const name of hello.methods)
492
+ if (!operatorMethods.has(name) && !nodeMethods.has(name))
493
+ this.o.log?.(`gateway has unknown method: ${name}`);
494
+ this.members = createMembers({ request: transport.request.bind(transport), root: this.engine.root });
495
+ // The fail-closed tool bridge feeds the kit's single Approval surface (5.9, O5).
496
+ await this.bridge.start();
497
+ this.off.push(transport.onEvent((e) => this.approvalsCtl.handleEvent(e)));
498
+ this.failures = 0;
499
+ this.setState({ phase: 'ready' });
500
+ // Replays the engine's native approval lists over the now-live transport (N9).
501
+ await this.approvalsCtl.resync();
502
+ }
503
+ catch (error) {
504
+ if (transport && this.transport === transport)
505
+ await this.disconnect();
506
+ if (this.current.phase !== 'needs-update' && !this.stopping)
507
+ this.setState({ phase: 'failed', why: 'handshake' });
508
+ throw error;
509
+ }
510
+ }
511
+ async disconnect() {
512
+ this.off.splice(0).forEach((fn) => fn());
513
+ const transport = this.transport;
514
+ this.transport = undefined;
515
+ this.greeting = undefined;
516
+ this.members = undefined;
517
+ this.bridge.stop();
518
+ await transport?.stop();
519
+ }
520
+ closed(_why) {
521
+ if (this.stopping || this.current.phase !== 'ready')
522
+ return;
523
+ void this.disconnect();
524
+ if (this.o.spawnEngine === false) {
525
+ this.setState({ phase: 'failed', why: 'handshake' });
526
+ return;
527
+ }
528
+ const retryAt = Date.now() + Math.min(30_000, 1000 * 2 ** this.failures++);
529
+ this.setState({ phase: 'restarting', retryAt });
530
+ void delay(retryAt - Date.now()).then(() => { if (!this.stopping && this.current.phase === 'restarting')
531
+ void this.start().catch(() => { }); });
532
+ }
533
+ async stop() {
534
+ this.stopping = true;
535
+ await this.disconnect();
536
+ await this.engine.stop();
537
+ }
538
+ request() {
539
+ if (!this.transport || this.current.phase !== 'ready')
540
+ throw new Error('gateway not ready');
541
+ return this.transport.request.bind(this.transport);
542
+ }
543
+ call(method, params, o) {
544
+ try {
545
+ return this.request()(method, params, o);
546
+ }
547
+ catch (error) {
548
+ return Promise.reject(error);
549
+ }
550
+ }
551
+ callDynamic(method, params, o) {
552
+ if (operatorMethods.has(method) || nodeMethods.has(method))
553
+ return Promise.reject(new Error(`use typed call for generated method: ${method}`));
554
+ try {
555
+ return this.request()(method, params, o);
556
+ }
557
+ catch (error) {
558
+ return Promise.reject(error);
559
+ }
560
+ }
561
+ get hello() { return this.greeting; }
562
+ onEvent(event, fn) {
563
+ const listener = (e) => {
564
+ if (event === '*' || e.event === event)
565
+ fn(e.payload, e.event);
566
+ };
567
+ this.listeners.add(listener);
568
+ return () => { this.listeners.delete(listener); };
569
+ }
570
+ ensureMember(member) {
571
+ if (!this.members)
572
+ return Promise.reject(new Error('gateway not ready'));
573
+ return this.members.ensure(member);
574
+ }
575
+ // sign-in (5.7): every body here is the module's, with this kit's transport, members and ports.
576
+ signInCtx() {
577
+ return { request: (method, params, o) => this.request()(method, params, o),
578
+ ensure: (member) => this.ensureMember(member), callbackPort: this.o.callbackPort ?? 1455 };
579
+ }
580
+ routes() {
581
+ return routeTable();
582
+ }
583
+ providers(member) {
584
+ return engineProviders(this.signInCtx(), member);
585
+ }
586
+ signedIn(member, provider) {
587
+ return engineProviders(this.signInCtx(), member).then((names) => names.includes(provider)).catch(() => false);
588
+ }
589
+ signIn(member, o, on) {
590
+ return startSignIn(this.signInCtx(), member, o, on);
591
+ }
592
+ signOut(member, provider) {
593
+ return engineSignOut(this.signInCtx(), member, provider);
594
+ }
595
+ migrateRetainedLogin(member, source) {
596
+ return migrateLogin({ root: this.engine.root, prepare: () => this.prepare(), doctor: () => this.engine.doctor(120_000) }, member, source);
597
+ }
598
+ confirmRetainedLogin(member, source) {
599
+ return confirmLogin(this.signInCtx(), member, source);
600
+ }
601
+ // runs (5.8): the facade owns no run state; every call delegates to the O8 module
602
+ // with this kit's live transport, member table and bridge (firstmate clearance, O9).
603
+ runs() {
604
+ return createRuns({
605
+ request: (method, params, o) => this.request()(method, params, o),
606
+ onEvent: (fn) => {
607
+ this.listeners.add(fn);
608
+ return () => {
609
+ this.listeners.delete(fn);
610
+ };
611
+ },
612
+ ensure: (member) => this.ensureMember(member),
613
+ bridge: this.bridge,
614
+ });
615
+ }
616
+ run(spec, on) {
617
+ return this.runs().run(spec, on);
618
+ }
619
+ steer(sessionKey, text) {
620
+ return this.runs().steer(sessionKey, text);
621
+ }
622
+ abort(sessionKey) {
623
+ return this.runs().abort(sessionKey);
624
+ }
625
+ // approvals (5.9)
626
+ approvals(member) {
627
+ return this.approvalsCtl.list(member);
628
+ }
629
+ onApproval(fn) {
630
+ return this.approvalsCtl.on(fn);
631
+ }
632
+ decide(id, d) {
633
+ return this.approvalsCtl.decide(id, d);
634
+ }
635
+ allowOnce(rule, ms) {
636
+ this.bridge.allowOnce(rule, ms);
637
+ }
638
+ disallowOnce() {
639
+ this.bridge.disallowOnce();
640
+ }
641
+ // config
642
+ async patchConfig(patch, o) {
643
+ const response = await this.request()('config.get');
644
+ const safe = reconcileConfig(response.config, { root: this.engine.root, stateDir: this.o.stateDir,
645
+ port: Number(readFileSync(join(this.engine.root, 'port'), 'utf8')), pluginId: this.o.plugin?.id ?? 'byokit',
646
+ pluginDir: join(this.engine.root, 'plugin'), policyPath: fileURLToPath(new URL('../policy/policy.mjs', import.meta.url)), app: patch,
647
+ installPolicy: this.o.installPolicy });
648
+ await this.request()('config.patch', { raw: JSON.stringify(safe), baseHash: response.hash, ...(o?.agentId ? { agentId: o.agentId } : {}) });
649
+ }
650
+ memoryLimited(member) {
651
+ const config = JSON.parse(readFileSync(join(this.engine.root, 'openclaw.json'), 'utf8'));
652
+ return configMemoryLimited(config, member);
653
+ }
654
+ doctorContext() { return this.engine.doctorContext(); }
655
+ }
package/dist/link.d.ts ADDED
@@ -0,0 +1,24 @@
1
+ import { type IncomingMessage, type ServerResponse } from 'node:http';
2
+ import { type Grant, type Host, type HostOptions } from '@byokit/link';
3
+ import { type ServeIngress, type Via } from '@byokit/reach';
4
+ import type { PushAction, RelayClient } from '@byokit/relay';
5
+ import type { OpenClawKit } from './kit.ts';
6
+ import type { Member } from './types.ts';
7
+ export declare function openclawLink(kit: OpenClawKit, o: {
8
+ memberOf: (grant: Grant) => Member | undefined;
9
+ passThrough?: (method: string, grant: Grant) => boolean;
10
+ relay?: RelayClient;
11
+ }): Pick<HostOptions, 'handle' | 'stream' | 'allow'> & {
12
+ onAction(a: PushAction): Promise<unknown>;
13
+ };
14
+ export declare function serve(o: {
15
+ host: Host;
16
+ port: number;
17
+ via?: Via;
18
+ previous?: ServeIngress;
19
+ http?: (req: IncomingMessage, res: ServerResponse) => void;
20
+ }): Promise<{
21
+ urls: string[];
22
+ ingress?: ServeIngress;
23
+ close(): Promise<void>;
24
+ }>;