@clawrent/provider 0.1.1 → 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.
- package/dist/index.d.ts +76 -1
- package/dist/index.js +160 -11
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { EventEmitter } from 'node:events';
|
|
2
2
|
import WebSocket from 'ws';
|
|
3
|
+
import { GuardrailDecision } from '@clawrent/protocol';
|
|
3
4
|
|
|
4
5
|
interface ClawRentConfig {
|
|
5
6
|
apiUrl: string;
|
|
@@ -238,6 +239,8 @@ interface ActiveSession {
|
|
|
238
239
|
taskDescription?: string;
|
|
239
240
|
consumerUserId?: string;
|
|
240
241
|
slotIndex?: number;
|
|
242
|
+
/** 平台护栏决策(R3b/R1,来自 session.new 事件):block/advisory/未设置 */
|
|
243
|
+
guardrailDecision?: GuardrailDecision;
|
|
241
244
|
}
|
|
242
245
|
interface SessionSummary {
|
|
243
246
|
sessionId: string;
|
|
@@ -277,6 +280,16 @@ interface ProviderClientOptions {
|
|
|
277
280
|
heartbeatIntervalMs?: number;
|
|
278
281
|
maxReconnectAttempts?: number;
|
|
279
282
|
autoApprove?: boolean;
|
|
283
|
+
/** Initial backoff for presence REST retries (getMyAgent/activateAgent). Default 1000ms. */
|
|
284
|
+
restRetryInitialMs?: number;
|
|
285
|
+
/** Cap for presence REST retry backoff. Default 30000ms. */
|
|
286
|
+
restRetryMaxDelayMs?: number;
|
|
287
|
+
/** Max attempts for presence REST retries. undefined = persistent (default, for unattended providers). */
|
|
288
|
+
restRetryMaxAttempts?: number;
|
|
289
|
+
/** Initial backoff for /ws/agent reconnect. Default 1000ms. */
|
|
290
|
+
agentReconnectInitialMs?: number;
|
|
291
|
+
/** Cap for /ws/agent reconnect backoff. Default 30000ms. */
|
|
292
|
+
agentReconnectMaxDelayMs?: number;
|
|
280
293
|
}
|
|
281
294
|
interface ProviderCallbacks {
|
|
282
295
|
onMessage: (session: ActiveSession, message: Record<string, unknown>) => void | Promise<void>;
|
|
@@ -309,12 +322,26 @@ declare class ProviderClient extends EventEmitter {
|
|
|
309
322
|
private readonly heartbeatIntervalMs;
|
|
310
323
|
private readonly maxReconnectAttempts;
|
|
311
324
|
private readonly autoApprove;
|
|
325
|
+
private readonly restRetryInitialMs;
|
|
326
|
+
private readonly restRetryMaxDelayMs;
|
|
327
|
+
private readonly restRetryMaxAttempts;
|
|
328
|
+
private readonly agentReconnectInitialMs;
|
|
329
|
+
private readonly agentReconnectMaxDelayMs;
|
|
330
|
+
/** /ws/agent reconnect state. */
|
|
331
|
+
private agentReconnectAttempts;
|
|
332
|
+
private agentReconnectTimer;
|
|
312
333
|
private agentToken;
|
|
313
334
|
private agentId;
|
|
314
335
|
private agentWs;
|
|
315
336
|
private sessionManager;
|
|
316
337
|
private heartbeatTimer;
|
|
317
338
|
private _running;
|
|
339
|
+
private _stopped;
|
|
340
|
+
/** Latch: has /ws/agent ever reached 'open'? Distinguishes first-connect failure
|
|
341
|
+
* (reject start()) from a reconnect failure (route via close → reschedule). Also
|
|
342
|
+
* used by reconnect gates which key off _stopped (teardown) — _running is false
|
|
343
|
+
* throughout the start window, so it can't gate reconnect. */
|
|
344
|
+
private _agentOpenedOnce;
|
|
318
345
|
private readonly activeSessions;
|
|
319
346
|
/**
|
|
320
347
|
* Per-session in-flight promise chain: each `session:message` for the same
|
|
@@ -332,6 +359,12 @@ declare class ProviderClient extends EventEmitter {
|
|
|
332
359
|
* hosts calling in a tight loop; hosts wanting a steady indicator should
|
|
333
360
|
* call every ~2s — the peer clears the indicator after a 3s gap). */
|
|
334
361
|
private readonly lastTypingSent;
|
|
362
|
+
/** One-shot latch: settles (resolve on first success / reject on terminal 4xx)
|
|
363
|
+
* when the FIRST activateAgent completes. start() awaits it (α semantics).
|
|
364
|
+
* Reused across reconnects but only the first settle matters; later calls are no-ops. */
|
|
365
|
+
private firstActivationResolve;
|
|
366
|
+
private firstActivationReject;
|
|
367
|
+
private readonly firstActivation;
|
|
335
368
|
constructor(opts: ProviderClientOptions);
|
|
336
369
|
get running(): boolean;
|
|
337
370
|
get currentAgentId(): string | null;
|
|
@@ -343,6 +376,13 @@ declare class ProviderClient extends EventEmitter {
|
|
|
343
376
|
private bindSessionManager;
|
|
344
377
|
private resumeActive;
|
|
345
378
|
private connectAgent;
|
|
379
|
+
/**
|
|
380
|
+
* Reconnect /ws/agent after an abnormal (non-terminal) close. Persistent
|
|
381
|
+
* (never gives up) with exponential backoff capped at agentReconnectMaxDelayMs.
|
|
382
|
+
* Guarded by _running: stop() cancels. On the new socket's 'open', the existing
|
|
383
|
+
* open handler resets attempts + fires activateWithRetry (re-activation).
|
|
384
|
+
*/
|
|
385
|
+
private scheduleAgentReconnect;
|
|
346
386
|
/**
|
|
347
387
|
* Parses an inbound /ws/agent frame and routes it.
|
|
348
388
|
*
|
|
@@ -414,9 +454,44 @@ declare class ProviderClient extends EventEmitter {
|
|
|
414
454
|
* consumer message and while generating a reply; stop once the reply is sent.
|
|
415
455
|
*/
|
|
416
456
|
sendTyping(sessionId: string): boolean;
|
|
457
|
+
/**
|
|
458
|
+
* Retry with exponential backoff. Used to harden presence-critical REST calls
|
|
459
|
+
* (getMyAgent, activateAgent) against transient network failures.
|
|
460
|
+
*
|
|
461
|
+
* Public (no `private` keyword) so tests can drive it directly via bracket
|
|
462
|
+
* access as a hook — matches the `handleSessionMessage` precedent. Tasks 3-5
|
|
463
|
+
* will wire it into `start()`; until then it has no internal call site, which
|
|
464
|
+
* is why it cannot be `private` (TS6133 under `noUnusedLocals`).
|
|
465
|
+
*
|
|
466
|
+
* - maxAttempts === undefined => persistent (never gives up) — the default for
|
|
467
|
+
* unattended providers with no external restart.
|
|
468
|
+
* - Terminal REST errors (4xx except 429) throw immediately — bad tokens won't
|
|
469
|
+
* fix themselves.
|
|
470
|
+
* - Network errors / 5xx / 429 retry with exponential backoff capped at
|
|
471
|
+
* maxDelayMs. onRetry (if set) fires BEFORE each sleep so callers can emit.
|
|
472
|
+
*/
|
|
473
|
+
retryWithBackoff<T>(fn: () => Promise<T>, opts: {
|
|
474
|
+
initialMs: number;
|
|
475
|
+
maxDelayMs: number;
|
|
476
|
+
maxAttempts?: number;
|
|
477
|
+
onRetry?: (attempt: number, err: unknown, delayMs: number) => void;
|
|
478
|
+
isCancelled?: () => boolean;
|
|
479
|
+
}): Promise<T>;
|
|
480
|
+
/** 4xx (except 429) are terminal — auth/validation won't self-heal. */
|
|
481
|
+
private isTerminalRestError;
|
|
482
|
+
/**
|
|
483
|
+
* Activate the agent with persistent retry. Called on every /ws/agent (re)connect.
|
|
484
|
+
* Emits: agent:warning per failed attempt; agent:activated on success;
|
|
485
|
+
* agent:activation:failed on terminal 4xx (or maxAttempts exhausted).
|
|
486
|
+
* On the FIRST connect (before _running), settles firstActivation:
|
|
487
|
+
* success -> resolve (start() proceeds); terminal -> reject (start() rejects).
|
|
488
|
+
* On reconnects (_running true), just emits (firstActivation already settled).
|
|
489
|
+
*/
|
|
490
|
+
private activateWithRetry;
|
|
491
|
+
private clearHeartbeat;
|
|
417
492
|
stop(): void;
|
|
418
493
|
}
|
|
419
494
|
|
|
420
|
-
declare const PROVIDER_PACKAGE_VERSION = "0.
|
|
495
|
+
declare const PROVIDER_PACKAGE_VERSION = "0.2.0";
|
|
421
496
|
|
|
422
497
|
export { type ActiveSession, ApiClient, type ClawRentConfig, type CursorStore, FileCursorStore, InMemoryCursorStore, PROVIDER_PACKAGE_VERSION, type ProviderCallbacks, ProviderClient, type ProviderClientOptions, type SessionConnection, type SessionDiff, SessionManager, type SessionSummary, clearConfig, diffSessionStates, getConfigDir, getConfigPath, loadConfig, resumeActiveSessions, saveConfig };
|
package/dist/index.js
CHANGED
|
@@ -553,18 +553,33 @@ function diffSessionStates(prev, curr) {
|
|
|
553
553
|
import { EventEmitter as EventEmitter2 } from "events";
|
|
554
554
|
import WebSocket2 from "ws";
|
|
555
555
|
import { ControlSignalType, wsAgentControlEventSchema } from "@clawrent/protocol";
|
|
556
|
+
var AGENT_TERMINAL_CLOSE_CODES = /* @__PURE__ */ new Set([4e3, 4001]);
|
|
556
557
|
var ProviderClient = class extends EventEmitter2 {
|
|
557
558
|
client;
|
|
558
559
|
cursor;
|
|
559
560
|
heartbeatIntervalMs;
|
|
560
561
|
maxReconnectAttempts;
|
|
561
562
|
autoApprove;
|
|
563
|
+
restRetryInitialMs;
|
|
564
|
+
restRetryMaxDelayMs;
|
|
565
|
+
restRetryMaxAttempts;
|
|
566
|
+
agentReconnectInitialMs;
|
|
567
|
+
agentReconnectMaxDelayMs;
|
|
568
|
+
/** /ws/agent reconnect state. */
|
|
569
|
+
agentReconnectAttempts = 0;
|
|
570
|
+
agentReconnectTimer = null;
|
|
562
571
|
agentToken;
|
|
563
572
|
agentId = null;
|
|
564
573
|
agentWs = null;
|
|
565
574
|
sessionManager = null;
|
|
566
575
|
heartbeatTimer = null;
|
|
567
576
|
_running = false;
|
|
577
|
+
_stopped = false;
|
|
578
|
+
/** Latch: has /ws/agent ever reached 'open'? Distinguishes first-connect failure
|
|
579
|
+
* (reject start()) from a reconnect failure (route via close → reschedule). Also
|
|
580
|
+
* used by reconnect gates which key off _stopped (teardown) — _running is false
|
|
581
|
+
* throughout the start window, so it can't gate reconnect. */
|
|
582
|
+
_agentOpenedOnce = false;
|
|
568
583
|
activeSessions = /* @__PURE__ */ new Map();
|
|
569
584
|
/**
|
|
570
585
|
* Per-session in-flight promise chain: each `session:message` for the same
|
|
@@ -582,6 +597,15 @@ var ProviderClient = class extends EventEmitter2 {
|
|
|
582
597
|
* hosts calling in a tight loop; hosts wanting a steady indicator should
|
|
583
598
|
* call every ~2s — the peer clears the indicator after a 3s gap). */
|
|
584
599
|
lastTypingSent = /* @__PURE__ */ new Map();
|
|
600
|
+
/** One-shot latch: settles (resolve on first success / reject on terminal 4xx)
|
|
601
|
+
* when the FIRST activateAgent completes. start() awaits it (α semantics).
|
|
602
|
+
* Reused across reconnects but only the first settle matters; later calls are no-ops. */
|
|
603
|
+
firstActivationResolve;
|
|
604
|
+
firstActivationReject;
|
|
605
|
+
firstActivation = new Promise((resolve, reject) => {
|
|
606
|
+
this.firstActivationResolve = resolve;
|
|
607
|
+
this.firstActivationReject = reject;
|
|
608
|
+
});
|
|
585
609
|
constructor(opts) {
|
|
586
610
|
super();
|
|
587
611
|
const config = {
|
|
@@ -595,6 +619,11 @@ var ProviderClient = class extends EventEmitter2 {
|
|
|
595
619
|
this.heartbeatIntervalMs = opts.heartbeatIntervalMs ?? 25e3;
|
|
596
620
|
this.maxReconnectAttempts = opts.maxReconnectAttempts ?? 5;
|
|
597
621
|
this.autoApprove = opts.autoApprove ?? true;
|
|
622
|
+
this.restRetryInitialMs = opts.restRetryInitialMs ?? 1e3;
|
|
623
|
+
this.restRetryMaxDelayMs = opts.restRetryMaxDelayMs ?? 3e4;
|
|
624
|
+
this.restRetryMaxAttempts = opts.restRetryMaxAttempts;
|
|
625
|
+
this.agentReconnectInitialMs = opts.agentReconnectInitialMs ?? 1e3;
|
|
626
|
+
this.agentReconnectMaxDelayMs = opts.agentReconnectMaxDelayMs ?? 3e4;
|
|
598
627
|
}
|
|
599
628
|
get running() {
|
|
600
629
|
return this._running;
|
|
@@ -615,7 +644,16 @@ var ProviderClient = class extends EventEmitter2 {
|
|
|
615
644
|
if (callbacks.agentId) {
|
|
616
645
|
this.agentId = callbacks.agentId;
|
|
617
646
|
} else {
|
|
618
|
-
const me = await this.
|
|
647
|
+
const me = await this.retryWithBackoff(
|
|
648
|
+
() => this.client.getMyAgent(),
|
|
649
|
+
{
|
|
650
|
+
initialMs: this.restRetryInitialMs,
|
|
651
|
+
maxDelayMs: this.restRetryMaxDelayMs,
|
|
652
|
+
maxAttempts: this.restRetryMaxAttempts,
|
|
653
|
+
isCancelled: () => this._stopped,
|
|
654
|
+
onRetry: (a, err, delay) => this.emit("agent:warning", `getMyAgent attempt ${a} failed: ${err.message}; retry in ${delay}ms`)
|
|
655
|
+
}
|
|
656
|
+
);
|
|
619
657
|
this.agentId = me["id"] ?? me["agentId"] ?? null;
|
|
620
658
|
}
|
|
621
659
|
if (!this.agentId) throw new Error("Could not resolve agentId (pass callbacks.agentId or ensure token is valid)");
|
|
@@ -623,11 +661,7 @@ var ProviderClient = class extends EventEmitter2 {
|
|
|
623
661
|
this.sessionManager.agentId = this.agentId;
|
|
624
662
|
this.bindSessionManager(callbacks);
|
|
625
663
|
await this.connectAgent();
|
|
626
|
-
|
|
627
|
-
await this.client.activateAgent(this.agentId);
|
|
628
|
-
} catch (err) {
|
|
629
|
-
this.emit("agent:warning", `activation failed: ${err.message}`);
|
|
630
|
-
}
|
|
664
|
+
await this.firstActivation;
|
|
631
665
|
this._running = true;
|
|
632
666
|
this.emit("agent:started", this.agentId);
|
|
633
667
|
void this.resumeActive(callbacks);
|
|
@@ -679,11 +713,24 @@ var ProviderClient = class extends EventEmitter2 {
|
|
|
679
713
|
}
|
|
680
714
|
}, this.heartbeatIntervalMs);
|
|
681
715
|
this.emit("agent:connected");
|
|
716
|
+
this._agentOpenedOnce = true;
|
|
717
|
+
this.agentReconnectAttempts = 0;
|
|
718
|
+
void this.activateWithRetry();
|
|
682
719
|
resolve();
|
|
683
720
|
});
|
|
684
|
-
ws.on("error",
|
|
721
|
+
ws.on("error", (err) => {
|
|
722
|
+
if (!this._agentOpenedOnce) reject(err);
|
|
723
|
+
});
|
|
685
724
|
ws.on("close", (code, reason) => {
|
|
725
|
+
this.clearHeartbeat();
|
|
686
726
|
this.emit("agent:disconnected", code, reason.toString());
|
|
727
|
+
if (this._stopped) return;
|
|
728
|
+
if (AGENT_TERMINAL_CLOSE_CODES.has(code)) {
|
|
729
|
+
this._running = false;
|
|
730
|
+
this.emit("agent:dead", this.agentId, `terminal close ${code}: ${reason.toString()}`);
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
this.scheduleAgentReconnect();
|
|
687
734
|
});
|
|
688
735
|
ws.on("message", (raw) => {
|
|
689
736
|
void this.handleAgentMessage(raw).catch((err) => {
|
|
@@ -692,6 +739,27 @@ var ProviderClient = class extends EventEmitter2 {
|
|
|
692
739
|
});
|
|
693
740
|
});
|
|
694
741
|
}
|
|
742
|
+
/**
|
|
743
|
+
* Reconnect /ws/agent after an abnormal (non-terminal) close. Persistent
|
|
744
|
+
* (never gives up) with exponential backoff capped at agentReconnectMaxDelayMs.
|
|
745
|
+
* Guarded by _running: stop() cancels. On the new socket's 'open', the existing
|
|
746
|
+
* open handler resets attempts + fires activateWithRetry (re-activation).
|
|
747
|
+
*/
|
|
748
|
+
scheduleAgentReconnect() {
|
|
749
|
+
if (this._stopped) return;
|
|
750
|
+
const delay = Math.min(
|
|
751
|
+
this.agentReconnectInitialMs * 2 ** this.agentReconnectAttempts,
|
|
752
|
+
this.agentReconnectMaxDelayMs
|
|
753
|
+
);
|
|
754
|
+
this.agentReconnectAttempts++;
|
|
755
|
+
this.emit("agent:reconnecting", delay);
|
|
756
|
+
this.agentReconnectTimer = setTimeout(() => {
|
|
757
|
+
this.agentReconnectTimer = null;
|
|
758
|
+
if (this._stopped) return;
|
|
759
|
+
void this.connectAgent().catch(() => {
|
|
760
|
+
});
|
|
761
|
+
}, delay);
|
|
762
|
+
}
|
|
695
763
|
/**
|
|
696
764
|
* Parses an inbound /ws/agent frame and routes it.
|
|
697
765
|
*
|
|
@@ -755,7 +823,8 @@ var ProviderClient = class extends EventEmitter2 {
|
|
|
755
823
|
sessionId,
|
|
756
824
|
sessionToken: sessionToken ?? "",
|
|
757
825
|
taskDescription: payload.taskDescription,
|
|
758
|
-
consumerUserId: payload.consumerUserId
|
|
826
|
+
consumerUserId: payload.consumerUserId,
|
|
827
|
+
guardrailDecision: payload.guardrailDecision
|
|
759
828
|
};
|
|
760
829
|
this.activeSessions.set(sessionId, active);
|
|
761
830
|
this.boundCallbacks?.onSessionNew?.(active);
|
|
@@ -872,12 +941,92 @@ var ProviderClient = class extends EventEmitter2 {
|
|
|
872
941
|
this.lastTypingSent.set(sessionId, now);
|
|
873
942
|
return sm.send(sessionId, { type: ControlSignalType.DIALOGUE_TYPING, payload: {} });
|
|
874
943
|
}
|
|
875
|
-
|
|
876
|
-
|
|
944
|
+
/**
|
|
945
|
+
* Retry with exponential backoff. Used to harden presence-critical REST calls
|
|
946
|
+
* (getMyAgent, activateAgent) against transient network failures.
|
|
947
|
+
*
|
|
948
|
+
* Public (no `private` keyword) so tests can drive it directly via bracket
|
|
949
|
+
* access as a hook — matches the `handleSessionMessage` precedent. Tasks 3-5
|
|
950
|
+
* will wire it into `start()`; until then it has no internal call site, which
|
|
951
|
+
* is why it cannot be `private` (TS6133 under `noUnusedLocals`).
|
|
952
|
+
*
|
|
953
|
+
* - maxAttempts === undefined => persistent (never gives up) — the default for
|
|
954
|
+
* unattended providers with no external restart.
|
|
955
|
+
* - Terminal REST errors (4xx except 429) throw immediately — bad tokens won't
|
|
956
|
+
* fix themselves.
|
|
957
|
+
* - Network errors / 5xx / 429 retry with exponential backoff capped at
|
|
958
|
+
* maxDelayMs. onRetry (if set) fires BEFORE each sleep so callers can emit.
|
|
959
|
+
*/
|
|
960
|
+
async retryWithBackoff(fn, opts) {
|
|
961
|
+
let attempt = 0;
|
|
962
|
+
while (opts.maxAttempts === void 0 || attempt < opts.maxAttempts) {
|
|
963
|
+
if (opts.isCancelled?.()) throw new Error("cancelled");
|
|
964
|
+
try {
|
|
965
|
+
return await fn();
|
|
966
|
+
} catch (err) {
|
|
967
|
+
attempt++;
|
|
968
|
+
if (this.isTerminalRestError(err)) throw err;
|
|
969
|
+
if (opts.maxAttempts !== void 0 && attempt >= opts.maxAttempts) throw err;
|
|
970
|
+
const delay = Math.min(opts.initialMs * 2 ** (attempt - 1), opts.maxDelayMs);
|
|
971
|
+
opts.onRetry?.(attempt, err, delay);
|
|
972
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
throw new Error("retryWithBackoff: exhausted");
|
|
976
|
+
}
|
|
977
|
+
/** 4xx (except 429) are terminal — auth/validation won't self-heal. */
|
|
978
|
+
isTerminalRestError(err) {
|
|
979
|
+
if (!(err instanceof Error)) return false;
|
|
980
|
+
const m = err.message.match(/^API error (\d+):/);
|
|
981
|
+
if (!m) return false;
|
|
982
|
+
const status = Number(m[1]);
|
|
983
|
+
return status >= 400 && status < 500 && status !== 429;
|
|
984
|
+
}
|
|
985
|
+
/**
|
|
986
|
+
* Activate the agent with persistent retry. Called on every /ws/agent (re)connect.
|
|
987
|
+
* Emits: agent:warning per failed attempt; agent:activated on success;
|
|
988
|
+
* agent:activation:failed on terminal 4xx (or maxAttempts exhausted).
|
|
989
|
+
* On the FIRST connect (before _running), settles firstActivation:
|
|
990
|
+
* success -> resolve (start() proceeds); terminal -> reject (start() rejects).
|
|
991
|
+
* On reconnects (_running true), just emits (firstActivation already settled).
|
|
992
|
+
*/
|
|
993
|
+
async activateWithRetry() {
|
|
994
|
+
if (!this.agentId) return;
|
|
995
|
+
try {
|
|
996
|
+
await this.retryWithBackoff(
|
|
997
|
+
() => this.client.activateAgent(this.agentId),
|
|
998
|
+
{
|
|
999
|
+
initialMs: this.restRetryInitialMs,
|
|
1000
|
+
maxDelayMs: this.restRetryMaxDelayMs,
|
|
1001
|
+
maxAttempts: this.restRetryMaxAttempts,
|
|
1002
|
+
isCancelled: () => this._stopped,
|
|
1003
|
+
onRetry: (a, err, delay) => this.emit("agent:warning", `activation attempt ${a} failed: ${err.message}; retry in ${delay}ms`)
|
|
1004
|
+
}
|
|
1005
|
+
);
|
|
1006
|
+
} catch (err) {
|
|
1007
|
+
if (this._stopped) return;
|
|
1008
|
+
this.emit("agent:activation:failed", this.agentId, err);
|
|
1009
|
+
if (!this._running) this.firstActivationReject(err);
|
|
1010
|
+
return;
|
|
1011
|
+
}
|
|
1012
|
+
this.emit("agent:activated", this.agentId);
|
|
1013
|
+
if (!this._running) this.firstActivationResolve();
|
|
1014
|
+
}
|
|
1015
|
+
clearHeartbeat() {
|
|
877
1016
|
if (this.heartbeatTimer) {
|
|
878
1017
|
clearInterval(this.heartbeatTimer);
|
|
879
1018
|
this.heartbeatTimer = null;
|
|
880
1019
|
}
|
|
1020
|
+
}
|
|
1021
|
+
stop() {
|
|
1022
|
+
this._running = false;
|
|
1023
|
+
this._stopped = true;
|
|
1024
|
+
if (this.agentReconnectTimer) {
|
|
1025
|
+
clearTimeout(this.agentReconnectTimer);
|
|
1026
|
+
this.agentReconnectTimer = null;
|
|
1027
|
+
}
|
|
1028
|
+
this.firstActivationReject(new Error("Provider stopped"));
|
|
1029
|
+
this.clearHeartbeat();
|
|
881
1030
|
this.sessionManager?.disconnectAll();
|
|
882
1031
|
if (this.agentWs) {
|
|
883
1032
|
this.agentWs.close(1e3, "Provider stopping");
|
|
@@ -890,7 +1039,7 @@ var ProviderClient = class extends EventEmitter2 {
|
|
|
890
1039
|
};
|
|
891
1040
|
|
|
892
1041
|
// src/index.ts
|
|
893
|
-
var PROVIDER_PACKAGE_VERSION = "0.
|
|
1042
|
+
var PROVIDER_PACKAGE_VERSION = "0.2.0";
|
|
894
1043
|
export {
|
|
895
1044
|
ApiClient,
|
|
896
1045
|
FileCursorStore,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/api-client.ts","../src/config.ts","../src/session-manager.ts","../src/cursor.ts","../src/helpers.ts","../src/provider-client.ts","../src/index.ts"],"sourcesContent":["import type { ClawRentConfig } from './config.js';\r\n\r\nexport class ApiClient {\r\n private config: ClawRentConfig;\r\n /** When set (e.g. by ProviderAgent.start), overrides config.token for REST auth. */\r\n private agentTokenOverride: string | null = null;\r\n\r\n constructor(config: ClawRentConfig) {\r\n this.config = config;\r\n }\r\n\r\n /**\r\n * Set a token that overrides config.token for subsequent REST requests.\r\n * Used by the in-process provider agent: once serving with an agentToken,\r\n * provider REST calls (approve/list/end + internal autoApprove) authenticate\r\n * as the agent owner via this token, so they work without a separate user\r\n * JWT login. The backend's resolveAuth accepts the agt_clawrent_* prefix.\r\n * Pass null to clear (e.g. on stop_serving).\r\n */\r\n setAgentToken(token: string | null): void {\r\n this.agentTokenOverride = token;\r\n }\r\n\r\n get apiUrl(): string {\r\n return this.config.apiUrl;\r\n }\r\n\r\n get wsUrl(): string {\r\n return this.config.wsUrl;\r\n }\r\n\r\n get userId(): string | undefined {\r\n return this.config.userId;\r\n }\r\n\r\n // --- Auth (no auth needed) ---\r\n\r\n async sendVerification(email: string): Promise<{ message: string }> {\r\n return this.request('POST', '/api/auth/send-verification', { email }, false);\r\n }\r\n\r\n async registerUser(input: {\r\n email: string;\r\n password: string;\r\n name: string;\r\n verificationCode: string;\r\n }): Promise<{ user: { id: string; email: string; name: string; role: string }; token: string; apiKey: string }> {\r\n return this.request('POST', '/api/auth/register', input, false);\r\n }\r\n\r\n async login(email: string, password: string): Promise<{ user: { id: string; email: string; name: string; role: string }; token: string }> {\r\n return this.request('POST', '/api/auth/login', { email, password }, false);\r\n }\r\n\r\n async getMe(): Promise<Record<string, unknown>> {\r\n return this.request('GET', '/api/auth/me');\r\n }\r\n\r\n // --- Marketplace ---\r\n\r\n async browse(query?: { search?: string; category?: string; page?: number; limit?: number }): Promise<unknown> {\r\n const params = new URLSearchParams();\r\n if (query?.search) params.set('search', query.search);\r\n if (query?.category) params.set('category', query.category);\r\n if (query?.page) params.set('page', String(query.page));\r\n if (query?.limit) params.set('limit', String(query.limit));\r\n const qs = params.toString();\r\n return this.request('GET', `/api/marketplace/browse${qs ? `?${qs}` : ''}`);\r\n }\r\n\r\n async getAgent(slug: string): Promise<unknown> {\r\n return this.request('GET', `/api/marketplace/agents/${encodeURIComponent(slug)}`);\r\n }\r\n\r\n // --- Sessions ---\r\n\r\n async rent(options: { agentId: string; taskDescription: string; grantedPermissions?: Record<string, unknown> }): Promise<unknown> {\r\n return this.request('POST', '/api/sessions', {\r\n agentId: options.agentId,\r\n taskDescription: options.taskDescription,\r\n grantedPermissions: options.grantedPermissions ?? {},\r\n });\r\n }\r\n\r\n async getSessions(query?: { role?: string; status?: string; page?: number; limit?: number }): Promise<unknown> {\r\n const params = new URLSearchParams();\r\n if (query?.role) params.set('role', query.role);\r\n if (query?.status) params.set('status', query.status);\r\n if (query?.page) params.set('page', String(query.page));\r\n if (query?.limit) params.set('limit', String(query.limit));\r\n const qs = params.toString();\r\n return this.request('GET', `/api/sessions${qs ? `?${qs}` : ''}`);\r\n }\r\n\r\n async getSession(sessionId: string): Promise<Record<string, unknown>> {\r\n return this.request('GET', `/api/sessions/${encodeURIComponent(sessionId)}`);\r\n }\r\n\r\n async getSessionMessages(\r\n sessionId: string,\r\n options?: { since?: string; limit?: number },\r\n ): Promise<unknown> {\r\n const params = new URLSearchParams();\r\n if (options?.since) params.set('since', options.since);\r\n if (options?.limit) params.set('limit', String(options.limit));\r\n const qs = params.toString();\r\n return this.request(\r\n 'GET',\r\n `/api/sessions/${encodeURIComponent(sessionId)}/messages${qs ? `?${qs}` : ''}`,\r\n );\r\n }\r\n\r\n /** POST a message via REST (WS fallback, e.g. session not attached after restart). */\r\n async sendSessionMessage(\r\n sessionId: string,\r\n body: { type: string; payload: Record<string, unknown> },\r\n ): Promise<unknown> {\r\n return this.request(\r\n 'POST',\r\n `/api/sessions/${encodeURIComponent(sessionId)}/messages`,\r\n body,\r\n );\r\n }\r\n\r\n async endSession(sessionId: string): Promise<unknown> {\r\n return this.request('POST', `/api/sessions/${encodeURIComponent(sessionId)}/end`);\r\n }\r\n\r\n async approveSession(sessionId: string): Promise<unknown> {\r\n return this.request('POST', `/api/sessions/${encodeURIComponent(sessionId)}/approve`);\r\n }\r\n\r\n // --- Billing ---\r\n\r\n async getBalance(): Promise<{ balance: string }> {\r\n return this.request('GET', '/api/billing/wallet');\r\n }\r\n\r\n async topUp(amount: string): Promise<{ balance: string }> {\r\n return this.request('POST', '/api/billing/wallet/topup', { amount });\r\n }\r\n\r\n // --- Provider: Agents ---\r\n\r\n async registerAgent(data: Record<string, unknown>): Promise<unknown> {\r\n return this.request('POST', '/api/agents', data);\r\n }\r\n\r\n async getMyAgents(query?: { page?: number; limit?: number; roles?: string }): Promise<unknown> {\r\n const params = new URLSearchParams();\r\n if (query?.page) params.set('page', String(query.page));\r\n if (query?.limit) params.set('limit', String(query.limit));\r\n if (query?.roles) params.set('roles', query.roles);\r\n const qs = params.toString();\r\n return this.request('GET', `/api/agents/my${qs ? `?${qs}` : ''}`);\r\n }\r\n\r\n /** Resolve the current agent from agentToken. Requires agt_clawrent_ token auth. */\r\n async getMyAgent(): Promise<Record<string, unknown>> {\r\n return this.request('GET', '/api/agents/me/agent');\r\n }\r\n\r\n async applyProvider(agentId: string, data: Record<string, unknown>): Promise<unknown> {\r\n return this.request('POST', `/api/agents/${encodeURIComponent(agentId)}/apply-provider`, data);\r\n }\r\n\r\n /** Publish agent — simplified apply-provider with defaults, submits for admin review */\r\n async publishAgent(agentId: string, data?: Record<string, unknown>): Promise<unknown> {\r\n return this.request('POST', `/api/agents/${encodeURIComponent(agentId)}/publish`, data ?? {});\r\n }\r\n\r\n /** Activate agent — verify admin-approved + WebSocket connected, then go online */\r\n async activateAgent(agentId: string): Promise<unknown> {\r\n return this.request('POST', `/api/agents/${encodeURIComponent(agentId)}/activate`);\r\n }\r\n\r\n async setOnlineStatus(agentId: string, onlineStatus: string): Promise<unknown> {\r\n return this.request('PATCH', `/api/agents/${encodeURIComponent(agentId)}/status`, { onlineStatus });\r\n }\r\n\r\n async generateAgentToken(agentId: string): Promise<{ agentId: string; token: string; createdAt: string; warning: string }> {\r\n return this.request('POST', `/api/agents/${encodeURIComponent(agentId)}/token`);\r\n }\r\n\r\n async revokeAgentToken(agentId: string): Promise<{ message: string }> {\r\n return this.request('DELETE', `/api/agents/${encodeURIComponent(agentId)}/token`);\r\n }\r\n\r\n // --- Orders ---\r\n\r\n async createOrder(data: {\r\n items: Array<{ providerAgentId: string; consumerAgentId?: string; taskDescription: string; grantedPermissions?: Record<string, unknown> }>;\r\n note?: string;\r\n fromCart?: boolean;\r\n }): Promise<unknown> {\r\n return this.request('POST', '/api/orders', data);\r\n }\r\n\r\n async getOrders(query?: { status?: string; page?: number; limit?: number }): Promise<unknown> {\r\n const params = new URLSearchParams();\r\n if (query?.status) params.set('status', query.status);\r\n if (query?.page) params.set('page', String(query.page));\r\n if (query?.limit) params.set('limit', String(query.limit));\r\n const qs = params.toString();\r\n return this.request('GET', `/api/orders${qs ? `?${qs}` : ''}`);\r\n }\r\n\r\n async getOrder(orderId: string): Promise<unknown> {\r\n return this.request('GET', `/api/orders/${encodeURIComponent(orderId)}`);\r\n }\r\n\r\n async cancelOrder(orderId: string): Promise<unknown> {\r\n return this.request('POST', `/api/orders/${encodeURIComponent(orderId)}/cancel`);\r\n }\r\n\r\n // --- Cart ---\r\n\r\n async getCart(): Promise<unknown> {\r\n return this.request('GET', '/api/cart');\r\n }\r\n\r\n async addToCart(data: { providerAgentId: string; taskDescription: string }): Promise<unknown> {\r\n return this.request('POST', '/api/cart', data);\r\n }\r\n\r\n async updateCartItem(itemId: string, data: { taskDescription: string }): Promise<unknown> {\r\n return this.request('PATCH', `/api/cart/${encodeURIComponent(itemId)}`, data);\r\n }\r\n\r\n async removeFromCart(itemId: string): Promise<unknown> {\r\n return this.request('DELETE', `/api/cart/${encodeURIComponent(itemId)}`);\r\n }\r\n\r\n async clearCart(): Promise<unknown> {\r\n return this.request('DELETE', '/api/cart');\r\n }\r\n\r\n // --- Favorites ---\r\n\r\n async listFavorites(query?: { page?: number; limit?: number }): Promise<unknown> {\r\n const params = new URLSearchParams();\r\n if (query?.page) params.set('page', String(query.page));\r\n if (query?.limit) params.set('limit', String(query.limit));\r\n const qs = params.toString();\r\n return this.request('GET', `/api/favorites${qs ? `?${qs}` : ''}`);\r\n }\r\n\r\n async addFavorite(agentId: string): Promise<unknown> {\r\n return this.request('POST', `/api/favorites/${encodeURIComponent(agentId)}`);\r\n }\r\n\r\n async removeFavorite(agentId: string): Promise<unknown> {\r\n return this.request('DELETE', `/api/favorites/${encodeURIComponent(agentId)}`);\r\n }\r\n\r\n // --- Health ---\r\n\r\n async health(): Promise<unknown> {\r\n return this.request('GET', '/api/health', undefined, false);\r\n }\r\n\r\n // --- Docs (MCP interface) ---\r\n\r\n async getDocsTree(): Promise<unknown> {\r\n return this.request('GET', '/api/mcp/docs/tree', undefined, false);\r\n }\r\n\r\n async getDocByPath(path: string): Promise<unknown> {\r\n return this.request('GET', `/api/mcp/docs/by-path/${encodeURI(path)}`, undefined, false);\r\n }\r\n\r\n async searchDocs(query: string): Promise<unknown> {\r\n const params = new URLSearchParams({ q: query });\r\n return this.request('GET', `/api/mcp/docs/search?${params.toString()}`, undefined, false);\r\n }\r\n\r\n async getDoc(id: string): Promise<unknown> {\r\n return this.request('GET', `/api/mcp/docs/${encodeURIComponent(id)}`, undefined, false);\r\n }\r\n\r\n async createDoc(data: { type: string; title: string; parentId?: string; content?: string; slug?: string; icon?: string }): Promise<unknown> {\r\n return this.request('POST', '/api/mcp/docs', data);\r\n }\r\n\r\n async updateDoc(id: string, data: { title?: string; content?: string; changeSummary?: string }): Promise<unknown> {\r\n return this.request('PATCH', `/api/mcp/docs/${encodeURIComponent(id)}`, data);\r\n }\r\n\r\n async deleteDoc(id: string): Promise<unknown> {\r\n return this.request('DELETE', `/api/mcp/docs/${encodeURIComponent(id)}`);\r\n }\r\n\r\n async publishDoc(id: string): Promise<unknown> {\r\n return this.request('POST', `/api/mcp/docs/${encodeURIComponent(id)}/publish`);\r\n }\r\n\r\n async unpublishDoc(id: string): Promise<unknown> {\r\n return this.request('POST', `/api/mcp/docs/${encodeURIComponent(id)}/unpublish`);\r\n }\r\n\r\n // --- Private ---\r\n\r\n private async request<T = any>(method: string, path: string, body?: unknown, requireAuth: boolean = true): Promise<T> {\r\n const url = `${this.config.apiUrl}${path}`;\r\n const headers: Record<string, string> = {};\r\n\r\n if (body !== undefined) {\r\n headers['Content-Type'] = 'application/json';\r\n }\r\n\r\n if (requireAuth) {\r\n if (this.agentTokenOverride) {\r\n headers['Authorization'] = `Bearer ${this.agentTokenOverride}`;\r\n } else if (this.config.token) {\r\n headers['Authorization'] = `Bearer ${this.config.token}`;\r\n } else if (this.config.apiKey) {\r\n headers['x-api-key'] = this.config.apiKey;\r\n } else {\r\n throw new Error('Not authenticated. Run `clawrent auth login` first.');\r\n }\r\n }\r\n\r\n const response = await fetch(url, {\r\n method,\r\n headers,\r\n body: body ? JSON.stringify(body) : undefined,\r\n });\r\n\r\n if (!response.ok) {\r\n const errBody = await response.json().catch(() => ({ message: response.statusText })) as Record<string, unknown>;\r\n throw new Error(`API error ${response.status}: ${errBody['message'] ?? JSON.stringify(errBody)}`);\r\n }\r\n\r\n return response.json() as Promise<T>;\r\n }\r\n}\r\n","import { readFileSync, writeFileSync, mkdirSync, unlinkSync, existsSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\nimport { homedir } from 'node:os';\r\n\r\nexport interface ClawRentConfig {\r\n apiUrl: string;\r\n wsUrl: string;\r\n token?: string;\r\n apiKey?: string;\r\n userId?: string;\r\n email?: string;\r\n name?: string;\r\n}\r\n\r\nconst DEFAULT_CONFIG: ClawRentConfig = {\r\n apiUrl: 'https://clawrent.cloud',\r\n wsUrl: 'wss://clawrent.cloud',\r\n};\r\n\r\nexport function getConfigDir(): string {\r\n return join(homedir(), '.clawrent');\r\n}\r\n\r\nfunction getConfigFilePath(): string {\r\n return join(getConfigDir(), 'config.json');\r\n}\r\n\r\nexport function getConfigPath(): string {\r\n return getConfigFilePath();\r\n}\r\n\r\nexport function loadConfig(): ClawRentConfig {\r\n let fileConfig: Partial<ClawRentConfig> = {};\r\n\r\n const configPath = getConfigFilePath();\r\n if (existsSync(configPath)) {\r\n try {\r\n const raw = readFileSync(configPath, 'utf-8');\r\n fileConfig = JSON.parse(raw) as Partial<ClawRentConfig>;\r\n } catch {\r\n // Ignore corrupt config file\r\n }\r\n }\r\n\r\n // Migration: remove stale localhost URLs saved by older CLI versions.\r\n // These override the new production defaults and break remote connections.\r\n if (fileConfig.apiUrl?.includes('localhost') || fileConfig.wsUrl?.includes('localhost')) {\r\n delete fileConfig.apiUrl;\r\n delete fileConfig.wsUrl;\r\n // Persist the cleanup so it only runs once\r\n try {\r\n const cleaned = { ...fileConfig };\r\n writeFileSync(configPath, JSON.stringify(cleaned, null, 2), 'utf-8');\r\n } catch {\r\n // Non-fatal\r\n }\r\n }\r\n\r\n // Merge: defaults < file < env vars\r\n const config: ClawRentConfig = {\r\n ...DEFAULT_CONFIG,\r\n ...fileConfig,\r\n };\r\n\r\n // Env vars always override\r\n const envApiUrl = process.env['CLAWRENT_API_URL'];\r\n const envWsUrl = process.env['CLAWRENT_WS_URL'];\r\n const envToken = process.env['CLAWRENT_TOKEN'];\r\n const envApiKey = process.env['CLAWRENT_API_KEY'];\r\n const envUserId = process.env['CLAWRENT_USER_ID'];\r\n\r\n if (envApiUrl) config.apiUrl = envApiUrl;\r\n if (envWsUrl) config.wsUrl = envWsUrl;\r\n if (envToken) config.token = envToken;\r\n if (envApiKey) config.apiKey = envApiKey;\r\n if (envUserId) config.userId = envUserId;\r\n\r\n return config;\r\n}\r\n\r\nexport function saveConfig(partial: Partial<ClawRentConfig>): void {\r\n const configDir = getConfigDir();\r\n if (!existsSync(configDir)) {\r\n mkdirSync(configDir, { recursive: true });\r\n }\r\n\r\n let existing: Partial<ClawRentConfig> = {};\r\n const configPath = getConfigFilePath();\r\n if (existsSync(configPath)) {\r\n try {\r\n existing = JSON.parse(readFileSync(configPath, 'utf-8')) as Partial<ClawRentConfig>;\r\n } catch {\r\n // Overwrite corrupt file\r\n }\r\n }\r\n\r\n const merged = { ...existing, ...partial };\r\n writeFileSync(configPath, JSON.stringify(merged, null, 2), 'utf-8');\r\n}\r\n\r\nexport function clearConfig(): void {\r\n const configPath = getConfigFilePath();\r\n if (existsSync(configPath)) {\r\n unlinkSync(configPath);\r\n }\r\n}\r\n","import { EventEmitter } from 'node:events';\r\nimport WebSocket from 'ws';\r\n\r\n/** Backend close codes that mean the session can never be (re)attached —\r\n * stop immediately instead of retrying. Aligned with apps/platform-api ws-handler\r\n * (4000 bad params, 4001 bad role, 4002 token mismatch, 4003 session not active,\r\n * 4004 slot missing). 4005 was removed; 4006 (concurrency) is transient. */\r\nconst TERMINAL_CLOSE_CODES = new Set([4000, 4001, 4002, 4003, 4004]);\r\n\r\nexport interface SessionConnection {\r\n sessionId: string;\r\n sessionToken: string;\r\n ws: WebSocket;\r\n heartbeatTimer: ReturnType<typeof setInterval> | null;\r\n reconnectAttempts: number;\r\n}\r\n\r\n/**\r\n * SessionManager manages multiple concurrent WebSocket connections,\r\n * one per active session.\r\n */\r\nexport class SessionManager extends EventEmitter {\r\n private sessions = new Map<string, SessionConnection>();\r\n private wsUrl: string;\r\n private heartbeatInterval: number;\r\n private maxReconnectDelay: number;\r\n private maxReconnectAttempts: number;\r\n public agentId?: string;\r\n\r\n constructor(\r\n wsUrl: string,\r\n heartbeatInterval = 25_000,\r\n maxReconnectDelay = 30_000,\r\n maxReconnectAttempts = 5,\r\n ) {\r\n super();\r\n this.wsUrl = wsUrl;\r\n this.heartbeatInterval = heartbeatInterval;\r\n this.maxReconnectDelay = maxReconnectDelay;\r\n this.maxReconnectAttempts = maxReconnectAttempts;\r\n }\r\n\r\n /** Connect to a session via WebSocket as provider */\r\n connect(sessionId: string, sessionToken: string): void {\r\n if (this.sessions.has(sessionId)) {\r\n return; // Already connected\r\n }\r\n\r\n const url = `${this.wsUrl}/ws/session?sessionId=${sessionId}&token=${sessionToken}&role=provider`;\r\n const ws = new WebSocket(url);\r\n\r\n const conn: SessionConnection = {\r\n sessionId,\r\n sessionToken,\r\n ws,\r\n heartbeatTimer: null,\r\n reconnectAttempts: 0,\r\n };\r\n\r\n this.sessions.set(sessionId, conn);\r\n\r\n ws.on('open', () => {\r\n conn.reconnectAttempts = 0;\r\n conn.heartbeatTimer = setInterval(() => {\r\n if (ws.readyState === WebSocket.OPEN) {\r\n ws.send(JSON.stringify({ type: 'system.heartbeat', payload: {} }));\r\n }\r\n }, this.heartbeatInterval);\r\n\r\n this.emit('session:connected', sessionId);\r\n });\r\n\r\n ws.on('message', (raw) => {\r\n try {\r\n const message = JSON.parse(raw.toString()) as Record<string, unknown>;\r\n // Skip heartbeat acks\r\n if (message['type'] === 'system.heartbeat_ack') return;\r\n\r\n this.emit('session:message', sessionId, message);\r\n } catch {\r\n // Ignore parse errors\r\n }\r\n });\r\n\r\n ws.on('close', (code, reason) => {\r\n this.clearHeartbeat(conn);\r\n\r\n // Terminal codes (bad params / auth / session state) — never retry,\r\n // otherwise a stale sessionToken causes infinite reconnect noise.\r\n if (TERMINAL_CLOSE_CODES.has(code)) {\r\n this.sessions.delete(sessionId);\r\n this.emit('session:dead', sessionId, `session rejected (code ${code}: ${reason.toString()})`);\r\n return;\r\n }\r\n\r\n if (code !== 1000) {\r\n // Abnormal close — retry up to maxReconnectAttempts, then give up.\r\n if (conn.reconnectAttempts >= this.maxReconnectAttempts) {\r\n this.sessions.delete(sessionId);\r\n this.emit('session:dead', sessionId, `max reconnect attempts (${this.maxReconnectAttempts}) reached`);\r\n return;\r\n }\r\n const delay = Math.min(\r\n 1000 * Math.pow(2, conn.reconnectAttempts),\r\n this.maxReconnectDelay,\r\n );\r\n conn.reconnectAttempts++;\r\n\r\n this.emit('session:reconnecting', sessionId, delay);\r\n\r\n setTimeout(() => {\r\n this.sessions.delete(sessionId);\r\n this.connect(sessionId, sessionToken);\r\n }, delay);\r\n } else {\r\n this.sessions.delete(sessionId);\r\n this.emit('session:disconnected', sessionId, reason.toString());\r\n }\r\n });\r\n\r\n ws.on('error', (err) => {\r\n this.emit('session:error', sessionId, err);\r\n });\r\n }\r\n\r\n /** Send a message to a specific session, auto-wrapping with protocol envelope */\r\n send(sessionId: string, message: Record<string, unknown>): boolean {\r\n const conn = this.sessions.get(sessionId);\r\n if (!conn || conn.ws.readyState !== WebSocket.OPEN) {\r\n return false;\r\n }\r\n // Ensure full ClawRentMessage envelope\r\n const envelope = {\r\n id: message['id'] ?? `msg_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`,\r\n sessionId: message['sessionId'] ?? sessionId,\r\n timestamp: message['timestamp'] ?? Date.now(),\r\n sender: message['sender'] ?? { role: 'provider', agentId: this.agentId ?? 'unknown' },\r\n type: message['type'] ?? 'result.success',\r\n payload: message['payload'] ?? {},\r\n };\r\n conn.ws.send(JSON.stringify(envelope));\r\n return true;\r\n }\r\n\r\n /** Disconnect a specific session */\r\n disconnect(sessionId: string): void {\r\n const conn = this.sessions.get(sessionId);\r\n if (!conn) return;\r\n\r\n this.clearHeartbeat(conn);\r\n if (conn.ws.readyState === WebSocket.OPEN || conn.ws.readyState === WebSocket.CONNECTING) {\r\n conn.ws.close(1000, 'Provider disconnecting');\r\n }\r\n this.sessions.delete(sessionId);\r\n }\r\n\r\n /** Disconnect all sessions */\r\n disconnectAll(): void {\r\n for (const sessionId of this.sessions.keys()) {\r\n this.disconnect(sessionId);\r\n }\r\n }\r\n\r\n /** Get active session count */\r\n get activeCount(): number {\r\n return this.sessions.size;\r\n }\r\n\r\n /** Check if a session is connected */\r\n isConnected(sessionId: string): boolean {\r\n const conn = this.sessions.get(sessionId);\r\n return conn?.ws.readyState === WebSocket.OPEN;\r\n }\r\n\r\n private clearHeartbeat(conn: SessionConnection): void {\r\n if (conn.heartbeatTimer) {\r\n clearInterval(conn.heartbeatTimer);\r\n conn.heartbeatTimer = null;\r\n }\r\n }\r\n}\r\n","import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs';\nimport { dirname } from 'node:path';\n\n/** Per-session \"last processed message createdAt\" store. Implementations must be durable\n * for at-least-once delivery across restarts. set() only advances forward. */\nexport interface CursorStore {\n get(sessionId: string): string | null;\n set(sessionId: string, createdAt: string): void;\n}\n\nexport class InMemoryCursorStore implements CursorStore {\n private map = new Map<string, string>();\n get(sessionId: string): string | null {\n return this.map.get(sessionId) ?? null;\n }\n set(sessionId: string, createdAt: string): void {\n const prev = this.map.get(sessionId);\n if (prev === undefined || createdAt > prev) this.map.set(sessionId, createdAt);\n }\n}\n\nexport class FileCursorStore implements CursorStore {\n private cache: Map<string, string> | null = null;\n constructor(private readonly path: string) {}\n\n private load(): Map<string, string> {\n if (this.cache) return this.cache;\n if (!existsSync(this.path)) {\n this.cache = new Map();\n return this.cache;\n }\n const raw = readFileSync(this.path, 'utf8');\n try {\n this.cache = new Map(Object.entries(JSON.parse(raw)));\n } catch {\n this.cache = new Map();\n }\n return this.cache;\n }\n\n private persist(): void {\n if (!this.cache) return;\n mkdirSync(dirname(this.path), { recursive: true });\n writeFileSync(this.path, JSON.stringify(Object.fromEntries(this.cache), null, 2), 'utf8');\n }\n\n get(sessionId: string): string | null {\n return this.load().get(sessionId) ?? null;\n }\n set(sessionId: string, createdAt: string): void {\n const m = this.load();\n const prev = m.get(sessionId);\n if (prev === undefined || createdAt > prev) {\n m.set(sessionId, createdAt);\n this.persist();\n }\n }\n}\n","import type { ApiClient } from './api-client.js';\nimport type { SessionManager } from './session-manager.js';\nimport type { ActiveSession, SessionSummary, SessionDiff } from './types.js';\n\n/**\n * Pull active provider sessions and (re)attach their /ws/session. Returns the\n * sessions that were attached. Extracted from the old ProviderAgent.reattachActiveSessions.\n *\n * Backend getSessions returns `{ data: Array<{ id, sessionToken?, ... }> }`.\n * We accept either `id` or `sessionId` defensively; sessions missing a\n * sessionToken are skipped (their WS cannot be re-attached).\n */\nexport async function resumeActiveSessions(\n client: ApiClient,\n sessionManager: SessionManager,\n): Promise<ActiveSession[]> {\n const res = (await client.getSessions({ role: 'provider', status: 'active' })) as {\n data?: Array<Record<string, unknown>>;\n };\n const list = res?.data ?? [];\n const attached: ActiveSession[] = [];\n for (const s of list) {\n const sessionId = s['sessionId'] ?? s['id'];\n const sessionToken = s['sessionToken'];\n if (typeof sessionId !== 'string' || typeof sessionToken !== 'string') continue;\n attached.push({\n sessionId,\n sessionToken,\n taskDescription: typeof s['taskDescription'] === 'string' ? s['taskDescription'] : undefined,\n consumerUserId: typeof s['consumerUserId'] === 'string' ? s['consumerUserId'] : undefined,\n slotIndex: typeof s['slotIndex'] === 'number' ? s['slotIndex'] : undefined,\n });\n sessionManager.connect(sessionId, sessionToken);\n }\n return attached;\n}\n\n/**\n * Diff two snapshots of getSessions() to surface lifecycle transitions.\n * Used by REST-only providers that poll (no push channel) to detect:\n * - newPending: session appeared in `curr` (not in `prev`) with status pending_approval\n * - activated: session moved from pending_approval (prev) to active (curr)\n * - ended: session present in `prev` but missing from `curr`\n */\nexport function diffSessionStates(prev: SessionSummary[], curr: SessionSummary[]): SessionDiff {\n const prevMap = new Map(prev.map((s): [string, SessionSummary] => [s.sessionId, s]));\n const currMap = new Map(curr.map((s): [string, SessionSummary] => [s.sessionId, s]));\n const newPending: SessionSummary[] = [];\n const activated: SessionSummary[] = [];\n const ended: SessionSummary[] = [];\n\n for (const [id, c] of currMap) {\n const p = prevMap.get(id);\n if (!p) {\n if (c.status === 'pending_approval') newPending.push(c);\n } else if (p.status === 'pending_approval' && c.status === 'active') {\n activated.push(c);\n }\n }\n for (const [id, p] of prevMap) {\n if (!currMap.has(id)) ended.push(p);\n }\n return { newPending, activated, ended };\n}\n","import { EventEmitter } from 'node:events';\nimport WebSocket from 'ws';\nimport { ControlSignalType, wsAgentControlEventSchema, type WsAgentControlEvent } from '@clawrent/protocol';\nimport { ApiClient } from './api-client.js';\nimport type { ClawRentConfig } from './config.js';\nimport { SessionManager } from './session-manager.js';\nimport { InMemoryCursorStore } from './cursor.js';\nimport type { CursorStore } from './cursor.js';\nimport { resumeActiveSessions } from './helpers.js';\nimport type { ActiveSession } from './types.js';\n\nexport interface ProviderClientOptions {\n apiUrl?: string;\n wsUrl?: string;\n agentToken: string;\n cursorStore?: CursorStore;\n heartbeatIntervalMs?: number;\n maxReconnectAttempts?: number;\n autoApprove?: boolean;\n}\n\nexport interface ProviderCallbacks {\n onMessage: (session: ActiveSession, message: Record<string, unknown>) => void | Promise<void>;\n onSessionNew?: (session: ActiveSession) => void;\n onSessionEnded?: (session: ActiveSession, reason?: string) => void;\n onPendingApproval?: (session: ActiveSession) => boolean | Promise<boolean>;\n agentId?: string;\n}\n\n/**\n * ProviderClient — the core embeddable class of @clawrent/provider.\n *\n * Lifecycle (Task 6a scope):\n * construct -> start() -> connects /ws/agent (presence) + activates the agent\n * -> stop() disconnects everything cleanly.\n *\n * Task 6b wires:\n * - bindSessionManager: forwards SessionManager events; routes session:message\n * through handleSessionMessage (cursor dedupe -> onMessage).\n * - resumeActive: re-attaches active provider sessions on startup.\n * - handleAgentMessage: parses /ws/agent frames (discriminated union on `type`\n * with fields under `payload`), routes session.new/session.approved to\n * /ws/session connect (with optional autoApprove), and gracefully handles\n * the non-schema frame types (agent.connected / system.error / heartbeat_ack).\n * - handleSessionMessage: public test-hook method that dedupes inbound\n * /ws/session messages by per-session cursor and fires onMessage.\n */\nexport class ProviderClient extends EventEmitter {\n private readonly client: ApiClient;\n private readonly cursor: CursorStore;\n private readonly heartbeatIntervalMs: number;\n private readonly maxReconnectAttempts: number;\n private readonly autoApprove: boolean;\n private agentToken: string;\n private agentId: string | null = null;\n private agentWs: WebSocket | null = null;\n private sessionManager: SessionManager | null = null;\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n private _running = false;\n private readonly activeSessions = new Map<string, ActiveSession>();\n /**\n * Per-session in-flight promise chain: each `session:message` for the same\n * sessionId is chained onto the previous one so calls serialize. Without this,\n * two socket frames arriving in the same tick would both pass the cursor\n * dedupe check (the first call's `cursor.set` is queued behind its `await`\n * and hasn't run when the second call reads the cursor) and onMessage would\n * fire twice. The Map entry is cleared when the tail settles so it doesn't\n * grow unbounded.\n */\n private readonly inflight = new Map<string, Promise<void>>();\n /** Callbacks captured at start(); used by handleAgentMessage/handleSessionMessage. */\n private boundCallbacks: ProviderCallbacks | null = null;\n /** Per-session last-sent timestamp for sendTyping debounce (guard against\n * hosts calling in a tight loop; hosts wanting a steady indicator should\n * call every ~2s — the peer clears the indicator after a 3s gap). */\n private readonly lastTypingSent = new Map<string, number>();\n\n constructor(opts: ProviderClientOptions) {\n super();\n const config: ClawRentConfig = {\n apiUrl: opts.apiUrl ?? 'https://clawrent.cloud',\n wsUrl: opts.wsUrl ?? 'wss://clawrent.cloud',\n };\n this.client = new ApiClient(config);\n this.client.setAgentToken(opts.agentToken);\n this.agentToken = opts.agentToken;\n this.cursor = opts.cursorStore ?? new InMemoryCursorStore();\n this.heartbeatIntervalMs = opts.heartbeatIntervalMs ?? 25_000;\n this.maxReconnectAttempts = opts.maxReconnectAttempts ?? 5;\n this.autoApprove = opts.autoApprove ?? true;\n }\n\n get running(): boolean { return this._running; }\n get currentAgentId(): string | null { return this.agentId; }\n /** Cursor store used for per-session message dedupe (wired in Task 6b). */\n get cursorStore(): CursorStore { return this.cursor; }\n /** Whether sessions are auto-approved on arrival (wired in Task 6b). */\n get isAutoApprove(): boolean { return this.autoApprove; }\n\n async start(callbacks: ProviderCallbacks): Promise<void> {\n if (this._running) throw new Error('ProviderClient already started');\n\n // resolve agentId\n if (callbacks.agentId) {\n this.agentId = callbacks.agentId;\n } else {\n const me = await this.client.getMyAgent();\n this.agentId = (me['id'] as string) ?? (me['agentId'] as string) ?? null;\n }\n if (!this.agentId) throw new Error('Could not resolve agentId (pass callbacks.agentId or ensure token is valid)');\n\n // wire session manager\n this.sessionManager = new SessionManager(this.client.wsUrl, this.heartbeatIntervalMs, 30_000, this.maxReconnectAttempts);\n this.sessionManager.agentId = this.agentId;\n this.bindSessionManager(callbacks);\n\n // connect /ws/agent (control channel -> presence)\n await this.connectAgent();\n\n // activate (WS now connected -> isAgentConnected gate passes).\n // Failure is tolerated: profile may not be admin-approved yet, but WS\n // presence is up so the agent is reachable. Warn, don't crash.\n try {\n await this.client.activateAgent(this.agentId);\n } catch (err) {\n this.emit('agent:warning', `activation failed: ${(err as Error).message}`);\n }\n\n this._running = true;\n this.emit('agent:started', this.agentId);\n\n // re-attach active sessions (Task 6b expands this)\n void this.resumeActive(callbacks);\n }\n\n private bindSessionManager(callbacks: ProviderCallbacks): void {\n this.boundCallbacks = callbacks;\n const sm = this.sessionManager;\n if (!sm) return;\n sm.on('session:connected', (sid: string) => this.emit('session:connected', sid));\n sm.on('session:disconnected', (sid: string, reason: string) => this.emit('session:disconnected', sid, reason));\n sm.on('session:message', (sid: string, message: Record<string, unknown>) => {\n // Per-session serialization: chain this call onto the previous one for\n // the same sessionId so two frames arriving in the same tick do not both\n // pass the cursor dedupe check inside handleSessionMessage. The .catch\n // also covers Fix 3 — if a cursor-op (cursor.get/set) itself throws, the\n // rejection is caught here and surfaced as session:error instead of\n // becoming an unhandled rejection.\n const prev = this.inflight.get(sid) ?? Promise.resolve();\n const next = prev\n .then(() => this.handleSessionMessage(sid, message))\n .catch(err => { this.emit('session:error', sid, err); });\n this.inflight.set(sid, next);\n next.finally(() => {\n if (this.inflight.get(sid) === next) this.inflight.delete(sid);\n });\n });\n sm.on('session:dead', (sid: string, reason: string) => {\n const active = this.activeSessions.get(sid) ?? { sessionId: sid, sessionToken: '' };\n this.activeSessions.delete(sid);\n callbacks.onSessionEnded?.(active, reason);\n });\n }\n\n private async resumeActive(callbacks: ProviderCallbacks): Promise<void> {\n if (!this.sessionManager) return;\n try {\n const sessions = await resumeActiveSessions(this.client, this.sessionManager);\n for (const s of sessions) {\n this.activeSessions.set(s.sessionId, s);\n callbacks.onSessionNew?.(s);\n this.emit('session:reattached', s.sessionId);\n }\n } catch (err) {\n this.emit('agent:warning', `resume failed: ${(err as Error).message}`);\n }\n }\n\n private connectAgent(): Promise<void> {\n return new Promise((resolve, reject) => {\n const url = `${this.client.wsUrl}/ws/agent?token=${encodeURIComponent(this.agentToken)}`;\n const ws = new WebSocket(url);\n this.agentWs = ws;\n ws.on('open', () => {\n this.heartbeatTimer = setInterval(() => {\n if (ws.readyState === WebSocket.OPEN) {\n ws.send(JSON.stringify({ type: 'system.heartbeat', payload: {} }));\n }\n }, this.heartbeatIntervalMs);\n this.emit('agent:connected');\n resolve();\n });\n ws.on('error', reject);\n ws.on('close', (code, reason) => {\n this.emit('agent:disconnected', code, reason.toString());\n // exponential backoff reconnect guarded by running (expanded in Task 6b; keep simple here)\n });\n ws.on('message', raw => {\n void this.handleAgentMessage(raw).catch(err => {\n this.emit('agent:warning', `agent message handler failed: ${(err as Error).message}`);\n });\n });\n });\n }\n\n /**\n * Parses an inbound /ws/agent frame and routes it.\n *\n * `session.new` / `session.approved` are validated against the protocol\n * discriminated-union schema (fields under `payload`). Other /ws/agent frame\n * types pushed by the backend (agent.connected / agent.status_updated /\n * system.error / system.heartbeat_ack — see apps/platform-api ws-agent-handler.ts)\n * are NOT in wsAgentControlEventSchema, so we route them by `type` directly\n * instead of forcing them through the schema (which would reject them).\n * Unknown types are ignored gracefully.\n *\n * Note: backend does NOT push `session.ended` on /ws/agent; session\n * terminations arrive as `system.session_ended` on /ws/session.\n */\n private async handleAgentMessage(raw: WebSocket.RawData): Promise<void> {\n let frame: unknown;\n try {\n frame = JSON.parse(raw.toString());\n } catch {\n return; // malformed JSON — ignore\n }\n if (typeof frame !== 'object' || frame === null) return;\n const type = (frame as Record<string, unknown>)['type'];\n\n // --- Session control events (schema-validated) ---\n if (type === 'session.new' || type === 'session.approved') {\n let parsed: WsAgentControlEvent;\n try {\n parsed = wsAgentControlEventSchema.parse(frame);\n } catch {\n return; // malformed control frame — drop, don't crash the socket\n }\n if (parsed.type === 'session.new') {\n await this.onSessionNew(parsed.payload);\n } else {\n this.onSessionApproved(parsed.payload);\n }\n return;\n }\n\n // --- Non-schema /ws/agent frames (route by `type` only) ---\n const payload = (frame as Record<string, unknown>)['payload'];\n switch (type) {\n case 'system.heartbeat_ack':\n return; // heartbeat acknowledgement — ignore\n case 'system.error':\n this.emit('agent:warning', `server error: ${JSON.stringify(payload) ?? 'no payload'}`);\n return;\n case 'agent.connected':\n this.emit('agent:connected', payload);\n return;\n case 'agent.status_updated':\n this.emit('agent:status', payload);\n return;\n default:\n // Unknown frame type — ignore gracefully (no crash, no emit).\n return;\n }\n }\n\n /** session.new: register, notify host, optionally auto-approve + connect /ws/session. */\n private async onSessionNew(\n payload: Extract<WsAgentControlEvent, { type: 'session.new' }>['payload'],\n ): Promise<void> {\n const sessionId = payload.sessionId;\n const sessionToken = payload.sessionToken;\n const active: ActiveSession = {\n sessionId,\n sessionToken: sessionToken ?? '',\n taskDescription: payload.taskDescription,\n consumerUserId: payload.consumerUserId,\n };\n this.activeSessions.set(sessionId, active);\n this.boundCallbacks?.onSessionNew?.(active);\n this.emit('session:new', active);\n\n // Decide whether to approve + connect /ws/session now.\n const shouldApprove = this.autoApprove\n ? true\n : this.boundCallbacks?.onPendingApproval\n ? await this.boundCallbacks.onPendingApproval(active)\n : false;\n if (!shouldApprove) return;\n\n if (this.autoApprove) {\n try {\n await this.client.approveSession(sessionId);\n } catch (err) {\n this.emit('agent:warning', `approve failed for ${sessionId}: ${(err as Error).message}`);\n return;\n }\n }\n // SessionManager.connect is idempotent (guards on already-connected).\n // A subsequent session.approved frame will re-enter connect as a no-op.\n if (sessionToken) {\n this.sessionManager?.connect(sessionId, sessionToken);\n } else {\n this.emit('agent:warning', `session.new for ${sessionId} carried no sessionToken; deferring /ws/session connect until session.approved`);\n }\n }\n\n /** session.approved: ensure tracked + connect /ws/session (idempotent). */\n private onSessionApproved(\n payload: Extract<WsAgentControlEvent, { type: 'session.approved' }>['payload'],\n ): void {\n const sessionId = payload.sessionId;\n const sessionToken = payload.sessionToken;\n const existing = this.activeSessions.get(sessionId);\n const active: ActiveSession = existing ?? {\n sessionId,\n sessionToken: sessionToken ?? '',\n };\n if (sessionToken) active.sessionToken = sessionToken;\n this.activeSessions.set(sessionId, active);\n this.emit('session:approved', active);\n if (sessionToken) {\n this.sessionManager?.connect(sessionId, sessionToken);\n }\n }\n\n /**\n * Dedupes an inbound /ws/session message by per-session cursor, then invokes\n * the host's onMessage callback. Public (no underscore prefix) so the\n * integration test can drive the cursor/dedupe path directly as a hook.\n *\n * At-least-once invariant (Task 6b fix round 1): the cursor is advanced ONLY\n * AFTER `await onMessage` completes successfully. If onMessage throws, the\n * cursor is left un-advanced and `session:error` is emitted — so a future\n * redelivery (e.g. backend replay on restart) will pass the dedupe check and\n * re-process the message. onMessage MUST be idempotent precisely because of\n * this redelivery semantics. The per-session in-flight chain in\n * `bindSessionManager`'s `session:message` handler serializes concurrent\n * frames for the same session so the cursor-after-success commit has a chance\n * to run before the next frame's dedupe check reads the cursor.\n *\n * `createdAt` is canonical UTC ISO, taken from `_meta.timestamp` (backend\n * pushes ISO `...Z`) with a `new Date(message.timestamp).toISOString()`\n * fallback (ms epoch).\n */\n async handleSessionMessage(sessionId: string, message: Record<string, unknown>): Promise<void> {\n const onMessage = this.boundCallbacks?.onMessage;\n if (!onMessage) return;\n\n const meta = message['_meta'] as { timestamp?: unknown } | undefined;\n const metaTs = meta?.timestamp;\n const msgTs = message['timestamp'];\n const createdAt: string =\n typeof metaTs === 'string'\n ? metaTs\n : typeof msgTs === 'number'\n ? new Date(msgTs).toISOString()\n : new Date().toISOString();\n\n const last = this.cursor.get(sessionId);\n if (last && createdAt <= last) return; // already processed (dedupe)\n\n const session = this.activeSessions.get(sessionId) ?? { sessionId, sessionToken: '' };\n try {\n await onMessage(session, message);\n } catch (err) {\n // Do NOT advance the cursor: a future redelivery must re-process this\n // message (at-least-once across the onMessage failure).\n this.emit('session:error', sessionId, err);\n return;\n }\n this.cursor.set(sessionId, createdAt); // success → advance + persist\n }\n\n /**\n * Send an outbound message to a session. Prefers the /ws/session socket when\n * it is OPEN (low latency, no HTTP overhead); falls back to the REST\n * `POST /api/sessions/:id/messages` endpoint when the socket is absent or not\n * yet open (e.g. before start(), during reconnect, or for sessions not yet\n * attached). Returns the transport actually used so callers can observe it.\n *\n * Note: this method does NOT throw when WS is unavailable — it silently falls\n * back to REST. REST errors propagate to the caller as-is.\n */\n async send(\n sessionId: string,\n message: { type: string; payload: Record<string, unknown> },\n ): Promise<{ via: 'ws' | 'rest' }> {\n // Local binding so TS narrows `sm` to NonNullable inside the if-block\n // (this.sessionManager is mutable class state and isn't narrowed by `?.`).\n const sm = this.sessionManager;\n if (sm?.isConnected(sessionId)) {\n const ok = sm.send(sessionId, message);\n if (ok) return { via: 'ws' };\n }\n // REST fallback\n await this.client.sendSessionMessage(sessionId, message);\n return { via: 'rest' };\n }\n\n /**\n * Send a transient \"typing\" indicator to a session. Fire-and-forget over the\n * /ws/session socket ONLY — never REST (the REST POST /messages endpoint does\n * NOT short-circuit dialogue.typing, so it would persist a typing row and\n * pollute message history). The backend forwards the frame to the peer and\n * skips validation/persistence/metering/ACK.\n *\n * Debounced to one send per 500ms per session as a guard against hosts\n * calling in a tight loop. No-op (returns false) when the session socket is\n * not OPEN or the call is suppressed by debounce; returns true when a typing\n * frame was actually sent.\n *\n * Hosts control timing: call this periodically (every ~2s) after receiving a\n * consumer message and while generating a reply; stop once the reply is sent.\n */\n sendTyping(sessionId: string): boolean {\n const sm = this.sessionManager;\n if (!sm?.isConnected(sessionId)) return false;\n const now = Date.now();\n const last = this.lastTypingSent.get(sessionId) ?? 0;\n if (now - last < 500) return false;\n this.lastTypingSent.set(sessionId, now);\n return sm.send(sessionId, { type: ControlSignalType.DIALOGUE_TYPING, payload: {} });\n }\n\n stop(): void {\n this._running = false;\n if (this.heartbeatTimer) { clearInterval(this.heartbeatTimer); this.heartbeatTimer = null; }\n this.sessionManager?.disconnectAll();\n if (this.agentWs) { this.agentWs.close(1000, 'Provider stopping'); this.agentWs = null; }\n this.activeSessions.clear();\n this.client.setAgentToken(null);\n this.emit('stopped');\n }\n}\n","export const PROVIDER_PACKAGE_VERSION = '0.1.1';\n\nexport { ApiClient } from './api-client.js';\nexport type { ClawRentConfig } from './config.js';\nexport { loadConfig, saveConfig, clearConfig, getConfigPath, getConfigDir } from './config.js';\nexport { SessionManager } from './session-manager.js';\nexport type { SessionConnection } from './session-manager.js';\nexport { InMemoryCursorStore, FileCursorStore } from './cursor.js';\nexport type { CursorStore } from './cursor.js';\nexport { resumeActiveSessions, diffSessionStates } from './helpers.js';\nexport type { ActiveSession, SessionSummary, SessionDiff } from './types.js';\nexport { ProviderClient } from './provider-client.js';\nexport type { ProviderClientOptions, ProviderCallbacks } from './provider-client.js';\n"],"mappings":"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","names":["readFileSync","writeFileSync","mkdirSync","existsSync","EventEmitter","WebSocket","EventEmitter","WebSocket"]}
|
|
1
|
+
{"version":3,"sources":["../src/api-client.ts","../src/config.ts","../src/session-manager.ts","../src/cursor.ts","../src/helpers.ts","../src/provider-client.ts","../src/index.ts"],"sourcesContent":["import type { ClawRentConfig } from './config.js';\r\n\r\nexport class ApiClient {\r\n private config: ClawRentConfig;\r\n /** When set (e.g. by ProviderAgent.start), overrides config.token for REST auth. */\r\n private agentTokenOverride: string | null = null;\r\n\r\n constructor(config: ClawRentConfig) {\r\n this.config = config;\r\n }\r\n\r\n /**\r\n * Set a token that overrides config.token for subsequent REST requests.\r\n * Used by the in-process provider agent: once serving with an agentToken,\r\n * provider REST calls (approve/list/end + internal autoApprove) authenticate\r\n * as the agent owner via this token, so they work without a separate user\r\n * JWT login. The backend's resolveAuth accepts the agt_clawrent_* prefix.\r\n * Pass null to clear (e.g. on stop_serving).\r\n */\r\n setAgentToken(token: string | null): void {\r\n this.agentTokenOverride = token;\r\n }\r\n\r\n get apiUrl(): string {\r\n return this.config.apiUrl;\r\n }\r\n\r\n get wsUrl(): string {\r\n return this.config.wsUrl;\r\n }\r\n\r\n get userId(): string | undefined {\r\n return this.config.userId;\r\n }\r\n\r\n // --- Auth (no auth needed) ---\r\n\r\n async sendVerification(email: string): Promise<{ message: string }> {\r\n return this.request('POST', '/api/auth/send-verification', { email }, false);\r\n }\r\n\r\n async registerUser(input: {\r\n email: string;\r\n password: string;\r\n name: string;\r\n verificationCode: string;\r\n }): Promise<{ user: { id: string; email: string; name: string; role: string }; token: string; apiKey: string }> {\r\n return this.request('POST', '/api/auth/register', input, false);\r\n }\r\n\r\n async login(email: string, password: string): Promise<{ user: { id: string; email: string; name: string; role: string }; token: string }> {\r\n return this.request('POST', '/api/auth/login', { email, password }, false);\r\n }\r\n\r\n async getMe(): Promise<Record<string, unknown>> {\r\n return this.request('GET', '/api/auth/me');\r\n }\r\n\r\n // --- Marketplace ---\r\n\r\n async browse(query?: { search?: string; category?: string; page?: number; limit?: number }): Promise<unknown> {\r\n const params = new URLSearchParams();\r\n if (query?.search) params.set('search', query.search);\r\n if (query?.category) params.set('category', query.category);\r\n if (query?.page) params.set('page', String(query.page));\r\n if (query?.limit) params.set('limit', String(query.limit));\r\n const qs = params.toString();\r\n return this.request('GET', `/api/marketplace/browse${qs ? `?${qs}` : ''}`);\r\n }\r\n\r\n async getAgent(slug: string): Promise<unknown> {\r\n return this.request('GET', `/api/marketplace/agents/${encodeURIComponent(slug)}`);\r\n }\r\n\r\n // --- Sessions ---\r\n\r\n async rent(options: { agentId: string; taskDescription: string; grantedPermissions?: Record<string, unknown> }): Promise<unknown> {\r\n return this.request('POST', '/api/sessions', {\r\n agentId: options.agentId,\r\n taskDescription: options.taskDescription,\r\n grantedPermissions: options.grantedPermissions ?? {},\r\n });\r\n }\r\n\r\n async getSessions(query?: { role?: string; status?: string; page?: number; limit?: number }): Promise<unknown> {\r\n const params = new URLSearchParams();\r\n if (query?.role) params.set('role', query.role);\r\n if (query?.status) params.set('status', query.status);\r\n if (query?.page) params.set('page', String(query.page));\r\n if (query?.limit) params.set('limit', String(query.limit));\r\n const qs = params.toString();\r\n return this.request('GET', `/api/sessions${qs ? `?${qs}` : ''}`);\r\n }\r\n\r\n async getSession(sessionId: string): Promise<Record<string, unknown>> {\r\n return this.request('GET', `/api/sessions/${encodeURIComponent(sessionId)}`);\r\n }\r\n\r\n async getSessionMessages(\r\n sessionId: string,\r\n options?: { since?: string; limit?: number },\r\n ): Promise<unknown> {\r\n const params = new URLSearchParams();\r\n if (options?.since) params.set('since', options.since);\r\n if (options?.limit) params.set('limit', String(options.limit));\r\n const qs = params.toString();\r\n return this.request(\r\n 'GET',\r\n `/api/sessions/${encodeURIComponent(sessionId)}/messages${qs ? `?${qs}` : ''}`,\r\n );\r\n }\r\n\r\n /** POST a message via REST (WS fallback, e.g. session not attached after restart). */\r\n async sendSessionMessage(\r\n sessionId: string,\r\n body: { type: string; payload: Record<string, unknown> },\r\n ): Promise<unknown> {\r\n return this.request(\r\n 'POST',\r\n `/api/sessions/${encodeURIComponent(sessionId)}/messages`,\r\n body,\r\n );\r\n }\r\n\r\n async endSession(sessionId: string): Promise<unknown> {\r\n return this.request('POST', `/api/sessions/${encodeURIComponent(sessionId)}/end`);\r\n }\r\n\r\n async approveSession(sessionId: string): Promise<unknown> {\r\n return this.request('POST', `/api/sessions/${encodeURIComponent(sessionId)}/approve`);\r\n }\r\n\r\n // --- Billing ---\r\n\r\n async getBalance(): Promise<{ balance: string }> {\r\n return this.request('GET', '/api/billing/wallet');\r\n }\r\n\r\n async topUp(amount: string): Promise<{ balance: string }> {\r\n return this.request('POST', '/api/billing/wallet/topup', { amount });\r\n }\r\n\r\n // --- Provider: Agents ---\r\n\r\n async registerAgent(data: Record<string, unknown>): Promise<unknown> {\r\n return this.request('POST', '/api/agents', data);\r\n }\r\n\r\n async getMyAgents(query?: { page?: number; limit?: number; roles?: string }): Promise<unknown> {\r\n const params = new URLSearchParams();\r\n if (query?.page) params.set('page', String(query.page));\r\n if (query?.limit) params.set('limit', String(query.limit));\r\n if (query?.roles) params.set('roles', query.roles);\r\n const qs = params.toString();\r\n return this.request('GET', `/api/agents/my${qs ? `?${qs}` : ''}`);\r\n }\r\n\r\n /** Resolve the current agent from agentToken. Requires agt_clawrent_ token auth. */\r\n async getMyAgent(): Promise<Record<string, unknown>> {\r\n return this.request('GET', '/api/agents/me/agent');\r\n }\r\n\r\n async applyProvider(agentId: string, data: Record<string, unknown>): Promise<unknown> {\r\n return this.request('POST', `/api/agents/${encodeURIComponent(agentId)}/apply-provider`, data);\r\n }\r\n\r\n /** Publish agent — simplified apply-provider with defaults, submits for admin review */\r\n async publishAgent(agentId: string, data?: Record<string, unknown>): Promise<unknown> {\r\n return this.request('POST', `/api/agents/${encodeURIComponent(agentId)}/publish`, data ?? {});\r\n }\r\n\r\n /** Activate agent — verify admin-approved + WebSocket connected, then go online */\r\n async activateAgent(agentId: string): Promise<unknown> {\r\n return this.request('POST', `/api/agents/${encodeURIComponent(agentId)}/activate`);\r\n }\r\n\r\n async setOnlineStatus(agentId: string, onlineStatus: string): Promise<unknown> {\r\n return this.request('PATCH', `/api/agents/${encodeURIComponent(agentId)}/status`, { onlineStatus });\r\n }\r\n\r\n async generateAgentToken(agentId: string): Promise<{ agentId: string; token: string; createdAt: string; warning: string }> {\r\n return this.request('POST', `/api/agents/${encodeURIComponent(agentId)}/token`);\r\n }\r\n\r\n async revokeAgentToken(agentId: string): Promise<{ message: string }> {\r\n return this.request('DELETE', `/api/agents/${encodeURIComponent(agentId)}/token`);\r\n }\r\n\r\n // --- Orders ---\r\n\r\n async createOrder(data: {\r\n items: Array<{ providerAgentId: string; consumerAgentId?: string; taskDescription: string; grantedPermissions?: Record<string, unknown> }>;\r\n note?: string;\r\n fromCart?: boolean;\r\n }): Promise<unknown> {\r\n return this.request('POST', '/api/orders', data);\r\n }\r\n\r\n async getOrders(query?: { status?: string; page?: number; limit?: number }): Promise<unknown> {\r\n const params = new URLSearchParams();\r\n if (query?.status) params.set('status', query.status);\r\n if (query?.page) params.set('page', String(query.page));\r\n if (query?.limit) params.set('limit', String(query.limit));\r\n const qs = params.toString();\r\n return this.request('GET', `/api/orders${qs ? `?${qs}` : ''}`);\r\n }\r\n\r\n async getOrder(orderId: string): Promise<unknown> {\r\n return this.request('GET', `/api/orders/${encodeURIComponent(orderId)}`);\r\n }\r\n\r\n async cancelOrder(orderId: string): Promise<unknown> {\r\n return this.request('POST', `/api/orders/${encodeURIComponent(orderId)}/cancel`);\r\n }\r\n\r\n // --- Cart ---\r\n\r\n async getCart(): Promise<unknown> {\r\n return this.request('GET', '/api/cart');\r\n }\r\n\r\n async addToCart(data: { providerAgentId: string; taskDescription: string }): Promise<unknown> {\r\n return this.request('POST', '/api/cart', data);\r\n }\r\n\r\n async updateCartItem(itemId: string, data: { taskDescription: string }): Promise<unknown> {\r\n return this.request('PATCH', `/api/cart/${encodeURIComponent(itemId)}`, data);\r\n }\r\n\r\n async removeFromCart(itemId: string): Promise<unknown> {\r\n return this.request('DELETE', `/api/cart/${encodeURIComponent(itemId)}`);\r\n }\r\n\r\n async clearCart(): Promise<unknown> {\r\n return this.request('DELETE', '/api/cart');\r\n }\r\n\r\n // --- Favorites ---\r\n\r\n async listFavorites(query?: { page?: number; limit?: number }): Promise<unknown> {\r\n const params = new URLSearchParams();\r\n if (query?.page) params.set('page', String(query.page));\r\n if (query?.limit) params.set('limit', String(query.limit));\r\n const qs = params.toString();\r\n return this.request('GET', `/api/favorites${qs ? `?${qs}` : ''}`);\r\n }\r\n\r\n async addFavorite(agentId: string): Promise<unknown> {\r\n return this.request('POST', `/api/favorites/${encodeURIComponent(agentId)}`);\r\n }\r\n\r\n async removeFavorite(agentId: string): Promise<unknown> {\r\n return this.request('DELETE', `/api/favorites/${encodeURIComponent(agentId)}`);\r\n }\r\n\r\n // --- Health ---\r\n\r\n async health(): Promise<unknown> {\r\n return this.request('GET', '/api/health', undefined, false);\r\n }\r\n\r\n // --- Docs (MCP interface) ---\r\n\r\n async getDocsTree(): Promise<unknown> {\r\n return this.request('GET', '/api/mcp/docs/tree', undefined, false);\r\n }\r\n\r\n async getDocByPath(path: string): Promise<unknown> {\r\n return this.request('GET', `/api/mcp/docs/by-path/${encodeURI(path)}`, undefined, false);\r\n }\r\n\r\n async searchDocs(query: string): Promise<unknown> {\r\n const params = new URLSearchParams({ q: query });\r\n return this.request('GET', `/api/mcp/docs/search?${params.toString()}`, undefined, false);\r\n }\r\n\r\n async getDoc(id: string): Promise<unknown> {\r\n return this.request('GET', `/api/mcp/docs/${encodeURIComponent(id)}`, undefined, false);\r\n }\r\n\r\n async createDoc(data: { type: string; title: string; parentId?: string; content?: string; slug?: string; icon?: string }): Promise<unknown> {\r\n return this.request('POST', '/api/mcp/docs', data);\r\n }\r\n\r\n async updateDoc(id: string, data: { title?: string; content?: string; changeSummary?: string }): Promise<unknown> {\r\n return this.request('PATCH', `/api/mcp/docs/${encodeURIComponent(id)}`, data);\r\n }\r\n\r\n async deleteDoc(id: string): Promise<unknown> {\r\n return this.request('DELETE', `/api/mcp/docs/${encodeURIComponent(id)}`);\r\n }\r\n\r\n async publishDoc(id: string): Promise<unknown> {\r\n return this.request('POST', `/api/mcp/docs/${encodeURIComponent(id)}/publish`);\r\n }\r\n\r\n async unpublishDoc(id: string): Promise<unknown> {\r\n return this.request('POST', `/api/mcp/docs/${encodeURIComponent(id)}/unpublish`);\r\n }\r\n\r\n // --- Private ---\r\n\r\n private async request<T = any>(method: string, path: string, body?: unknown, requireAuth: boolean = true): Promise<T> {\r\n const url = `${this.config.apiUrl}${path}`;\r\n const headers: Record<string, string> = {};\r\n\r\n if (body !== undefined) {\r\n headers['Content-Type'] = 'application/json';\r\n }\r\n\r\n if (requireAuth) {\r\n if (this.agentTokenOverride) {\r\n headers['Authorization'] = `Bearer ${this.agentTokenOverride}`;\r\n } else if (this.config.token) {\r\n headers['Authorization'] = `Bearer ${this.config.token}`;\r\n } else if (this.config.apiKey) {\r\n headers['x-api-key'] = this.config.apiKey;\r\n } else {\r\n throw new Error('Not authenticated. Run `clawrent auth login` first.');\r\n }\r\n }\r\n\r\n const response = await fetch(url, {\r\n method,\r\n headers,\r\n body: body ? JSON.stringify(body) : undefined,\r\n });\r\n\r\n if (!response.ok) {\r\n const errBody = await response.json().catch(() => ({ message: response.statusText })) as Record<string, unknown>;\r\n throw new Error(`API error ${response.status}: ${errBody['message'] ?? JSON.stringify(errBody)}`);\r\n }\r\n\r\n return response.json() as Promise<T>;\r\n }\r\n}\r\n","import { readFileSync, writeFileSync, mkdirSync, unlinkSync, existsSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\nimport { homedir } from 'node:os';\r\n\r\nexport interface ClawRentConfig {\r\n apiUrl: string;\r\n wsUrl: string;\r\n token?: string;\r\n apiKey?: string;\r\n userId?: string;\r\n email?: string;\r\n name?: string;\r\n}\r\n\r\nconst DEFAULT_CONFIG: ClawRentConfig = {\r\n apiUrl: 'https://clawrent.cloud',\r\n wsUrl: 'wss://clawrent.cloud',\r\n};\r\n\r\nexport function getConfigDir(): string {\r\n return join(homedir(), '.clawrent');\r\n}\r\n\r\nfunction getConfigFilePath(): string {\r\n return join(getConfigDir(), 'config.json');\r\n}\r\n\r\nexport function getConfigPath(): string {\r\n return getConfigFilePath();\r\n}\r\n\r\nexport function loadConfig(): ClawRentConfig {\r\n let fileConfig: Partial<ClawRentConfig> = {};\r\n\r\n const configPath = getConfigFilePath();\r\n if (existsSync(configPath)) {\r\n try {\r\n const raw = readFileSync(configPath, 'utf-8');\r\n fileConfig = JSON.parse(raw) as Partial<ClawRentConfig>;\r\n } catch {\r\n // Ignore corrupt config file\r\n }\r\n }\r\n\r\n // Migration: remove stale localhost URLs saved by older CLI versions.\r\n // These override the new production defaults and break remote connections.\r\n if (fileConfig.apiUrl?.includes('localhost') || fileConfig.wsUrl?.includes('localhost')) {\r\n delete fileConfig.apiUrl;\r\n delete fileConfig.wsUrl;\r\n // Persist the cleanup so it only runs once\r\n try {\r\n const cleaned = { ...fileConfig };\r\n writeFileSync(configPath, JSON.stringify(cleaned, null, 2), 'utf-8');\r\n } catch {\r\n // Non-fatal\r\n }\r\n }\r\n\r\n // Merge: defaults < file < env vars\r\n const config: ClawRentConfig = {\r\n ...DEFAULT_CONFIG,\r\n ...fileConfig,\r\n };\r\n\r\n // Env vars always override\r\n const envApiUrl = process.env['CLAWRENT_API_URL'];\r\n const envWsUrl = process.env['CLAWRENT_WS_URL'];\r\n const envToken = process.env['CLAWRENT_TOKEN'];\r\n const envApiKey = process.env['CLAWRENT_API_KEY'];\r\n const envUserId = process.env['CLAWRENT_USER_ID'];\r\n\r\n if (envApiUrl) config.apiUrl = envApiUrl;\r\n if (envWsUrl) config.wsUrl = envWsUrl;\r\n if (envToken) config.token = envToken;\r\n if (envApiKey) config.apiKey = envApiKey;\r\n if (envUserId) config.userId = envUserId;\r\n\r\n return config;\r\n}\r\n\r\nexport function saveConfig(partial: Partial<ClawRentConfig>): void {\r\n const configDir = getConfigDir();\r\n if (!existsSync(configDir)) {\r\n mkdirSync(configDir, { recursive: true });\r\n }\r\n\r\n let existing: Partial<ClawRentConfig> = {};\r\n const configPath = getConfigFilePath();\r\n if (existsSync(configPath)) {\r\n try {\r\n existing = JSON.parse(readFileSync(configPath, 'utf-8')) as Partial<ClawRentConfig>;\r\n } catch {\r\n // Overwrite corrupt file\r\n }\r\n }\r\n\r\n const merged = { ...existing, ...partial };\r\n writeFileSync(configPath, JSON.stringify(merged, null, 2), 'utf-8');\r\n}\r\n\r\nexport function clearConfig(): void {\r\n const configPath = getConfigFilePath();\r\n if (existsSync(configPath)) {\r\n unlinkSync(configPath);\r\n }\r\n}\r\n","import { EventEmitter } from 'node:events';\r\nimport WebSocket from 'ws';\r\n\r\n/** Backend close codes that mean the session can never be (re)attached —\r\n * stop immediately instead of retrying. Aligned with apps/platform-api ws-handler\r\n * (4000 bad params, 4001 bad role, 4002 token mismatch, 4003 session not active,\r\n * 4004 slot missing). 4005 was removed; 4006 (concurrency) is transient. */\r\nconst TERMINAL_CLOSE_CODES = new Set([4000, 4001, 4002, 4003, 4004]);\r\n\r\nexport interface SessionConnection {\r\n sessionId: string;\r\n sessionToken: string;\r\n ws: WebSocket;\r\n heartbeatTimer: ReturnType<typeof setInterval> | null;\r\n reconnectAttempts: number;\r\n}\r\n\r\n/**\r\n * SessionManager manages multiple concurrent WebSocket connections,\r\n * one per active session.\r\n */\r\nexport class SessionManager extends EventEmitter {\r\n private sessions = new Map<string, SessionConnection>();\r\n private wsUrl: string;\r\n private heartbeatInterval: number;\r\n private maxReconnectDelay: number;\r\n private maxReconnectAttempts: number;\r\n public agentId?: string;\r\n\r\n constructor(\r\n wsUrl: string,\r\n heartbeatInterval = 25_000,\r\n maxReconnectDelay = 30_000,\r\n maxReconnectAttempts = 5,\r\n ) {\r\n super();\r\n this.wsUrl = wsUrl;\r\n this.heartbeatInterval = heartbeatInterval;\r\n this.maxReconnectDelay = maxReconnectDelay;\r\n this.maxReconnectAttempts = maxReconnectAttempts;\r\n }\r\n\r\n /** Connect to a session via WebSocket as provider */\r\n connect(sessionId: string, sessionToken: string): void {\r\n if (this.sessions.has(sessionId)) {\r\n return; // Already connected\r\n }\r\n\r\n const url = `${this.wsUrl}/ws/session?sessionId=${sessionId}&token=${sessionToken}&role=provider`;\r\n const ws = new WebSocket(url);\r\n\r\n const conn: SessionConnection = {\r\n sessionId,\r\n sessionToken,\r\n ws,\r\n heartbeatTimer: null,\r\n reconnectAttempts: 0,\r\n };\r\n\r\n this.sessions.set(sessionId, conn);\r\n\r\n ws.on('open', () => {\r\n conn.reconnectAttempts = 0;\r\n conn.heartbeatTimer = setInterval(() => {\r\n if (ws.readyState === WebSocket.OPEN) {\r\n ws.send(JSON.stringify({ type: 'system.heartbeat', payload: {} }));\r\n }\r\n }, this.heartbeatInterval);\r\n\r\n this.emit('session:connected', sessionId);\r\n });\r\n\r\n ws.on('message', (raw) => {\r\n try {\r\n const message = JSON.parse(raw.toString()) as Record<string, unknown>;\r\n // Skip heartbeat acks\r\n if (message['type'] === 'system.heartbeat_ack') return;\r\n\r\n this.emit('session:message', sessionId, message);\r\n } catch {\r\n // Ignore parse errors\r\n }\r\n });\r\n\r\n ws.on('close', (code, reason) => {\r\n this.clearHeartbeat(conn);\r\n\r\n // Terminal codes (bad params / auth / session state) — never retry,\r\n // otherwise a stale sessionToken causes infinite reconnect noise.\r\n if (TERMINAL_CLOSE_CODES.has(code)) {\r\n this.sessions.delete(sessionId);\r\n this.emit('session:dead', sessionId, `session rejected (code ${code}: ${reason.toString()})`);\r\n return;\r\n }\r\n\r\n if (code !== 1000) {\r\n // Abnormal close — retry up to maxReconnectAttempts, then give up.\r\n if (conn.reconnectAttempts >= this.maxReconnectAttempts) {\r\n this.sessions.delete(sessionId);\r\n this.emit('session:dead', sessionId, `max reconnect attempts (${this.maxReconnectAttempts}) reached`);\r\n return;\r\n }\r\n const delay = Math.min(\r\n 1000 * Math.pow(2, conn.reconnectAttempts),\r\n this.maxReconnectDelay,\r\n );\r\n conn.reconnectAttempts++;\r\n\r\n this.emit('session:reconnecting', sessionId, delay);\r\n\r\n setTimeout(() => {\r\n this.sessions.delete(sessionId);\r\n this.connect(sessionId, sessionToken);\r\n }, delay);\r\n } else {\r\n this.sessions.delete(sessionId);\r\n this.emit('session:disconnected', sessionId, reason.toString());\r\n }\r\n });\r\n\r\n ws.on('error', (err) => {\r\n this.emit('session:error', sessionId, err);\r\n });\r\n }\r\n\r\n /** Send a message to a specific session, auto-wrapping with protocol envelope */\r\n send(sessionId: string, message: Record<string, unknown>): boolean {\r\n const conn = this.sessions.get(sessionId);\r\n if (!conn || conn.ws.readyState !== WebSocket.OPEN) {\r\n return false;\r\n }\r\n // Ensure full ClawRentMessage envelope\r\n const envelope = {\r\n id: message['id'] ?? `msg_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`,\r\n sessionId: message['sessionId'] ?? sessionId,\r\n timestamp: message['timestamp'] ?? Date.now(),\r\n sender: message['sender'] ?? { role: 'provider', agentId: this.agentId ?? 'unknown' },\r\n type: message['type'] ?? 'result.success',\r\n payload: message['payload'] ?? {},\r\n };\r\n conn.ws.send(JSON.stringify(envelope));\r\n return true;\r\n }\r\n\r\n /** Disconnect a specific session */\r\n disconnect(sessionId: string): void {\r\n const conn = this.sessions.get(sessionId);\r\n if (!conn) return;\r\n\r\n this.clearHeartbeat(conn);\r\n if (conn.ws.readyState === WebSocket.OPEN || conn.ws.readyState === WebSocket.CONNECTING) {\r\n conn.ws.close(1000, 'Provider disconnecting');\r\n }\r\n this.sessions.delete(sessionId);\r\n }\r\n\r\n /** Disconnect all sessions */\r\n disconnectAll(): void {\r\n for (const sessionId of this.sessions.keys()) {\r\n this.disconnect(sessionId);\r\n }\r\n }\r\n\r\n /** Get active session count */\r\n get activeCount(): number {\r\n return this.sessions.size;\r\n }\r\n\r\n /** Check if a session is connected */\r\n isConnected(sessionId: string): boolean {\r\n const conn = this.sessions.get(sessionId);\r\n return conn?.ws.readyState === WebSocket.OPEN;\r\n }\r\n\r\n private clearHeartbeat(conn: SessionConnection): void {\r\n if (conn.heartbeatTimer) {\r\n clearInterval(conn.heartbeatTimer);\r\n conn.heartbeatTimer = null;\r\n }\r\n }\r\n}\r\n","import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs';\nimport { dirname } from 'node:path';\n\n/** Per-session \"last processed message createdAt\" store. Implementations must be durable\n * for at-least-once delivery across restarts. set() only advances forward. */\nexport interface CursorStore {\n get(sessionId: string): string | null;\n set(sessionId: string, createdAt: string): void;\n}\n\nexport class InMemoryCursorStore implements CursorStore {\n private map = new Map<string, string>();\n get(sessionId: string): string | null {\n return this.map.get(sessionId) ?? null;\n }\n set(sessionId: string, createdAt: string): void {\n const prev = this.map.get(sessionId);\n if (prev === undefined || createdAt > prev) this.map.set(sessionId, createdAt);\n }\n}\n\nexport class FileCursorStore implements CursorStore {\n private cache: Map<string, string> | null = null;\n constructor(private readonly path: string) {}\n\n private load(): Map<string, string> {\n if (this.cache) return this.cache;\n if (!existsSync(this.path)) {\n this.cache = new Map();\n return this.cache;\n }\n const raw = readFileSync(this.path, 'utf8');\n try {\n this.cache = new Map(Object.entries(JSON.parse(raw)));\n } catch {\n this.cache = new Map();\n }\n return this.cache;\n }\n\n private persist(): void {\n if (!this.cache) return;\n mkdirSync(dirname(this.path), { recursive: true });\n writeFileSync(this.path, JSON.stringify(Object.fromEntries(this.cache), null, 2), 'utf8');\n }\n\n get(sessionId: string): string | null {\n return this.load().get(sessionId) ?? null;\n }\n set(sessionId: string, createdAt: string): void {\n const m = this.load();\n const prev = m.get(sessionId);\n if (prev === undefined || createdAt > prev) {\n m.set(sessionId, createdAt);\n this.persist();\n }\n }\n}\n","import type { ApiClient } from './api-client.js';\nimport type { SessionManager } from './session-manager.js';\nimport type { ActiveSession, SessionSummary, SessionDiff } from './types.js';\n\n/**\n * Pull active provider sessions and (re)attach their /ws/session. Returns the\n * sessions that were attached. Extracted from the old ProviderAgent.reattachActiveSessions.\n *\n * Backend getSessions returns `{ data: Array<{ id, sessionToken?, ... }> }`.\n * We accept either `id` or `sessionId` defensively; sessions missing a\n * sessionToken are skipped (their WS cannot be re-attached).\n */\nexport async function resumeActiveSessions(\n client: ApiClient,\n sessionManager: SessionManager,\n): Promise<ActiveSession[]> {\n const res = (await client.getSessions({ role: 'provider', status: 'active' })) as {\n data?: Array<Record<string, unknown>>;\n };\n const list = res?.data ?? [];\n const attached: ActiveSession[] = [];\n for (const s of list) {\n const sessionId = s['sessionId'] ?? s['id'];\n const sessionToken = s['sessionToken'];\n if (typeof sessionId !== 'string' || typeof sessionToken !== 'string') continue;\n attached.push({\n sessionId,\n sessionToken,\n taskDescription: typeof s['taskDescription'] === 'string' ? s['taskDescription'] : undefined,\n consumerUserId: typeof s['consumerUserId'] === 'string' ? s['consumerUserId'] : undefined,\n slotIndex: typeof s['slotIndex'] === 'number' ? s['slotIndex'] : undefined,\n });\n sessionManager.connect(sessionId, sessionToken);\n }\n return attached;\n}\n\n/**\n * Diff two snapshots of getSessions() to surface lifecycle transitions.\n * Used by REST-only providers that poll (no push channel) to detect:\n * - newPending: session appeared in `curr` (not in `prev`) with status pending_approval\n * - activated: session moved from pending_approval (prev) to active (curr)\n * - ended: session present in `prev` but missing from `curr`\n */\nexport function diffSessionStates(prev: SessionSummary[], curr: SessionSummary[]): SessionDiff {\n const prevMap = new Map(prev.map((s): [string, SessionSummary] => [s.sessionId, s]));\n const currMap = new Map(curr.map((s): [string, SessionSummary] => [s.sessionId, s]));\n const newPending: SessionSummary[] = [];\n const activated: SessionSummary[] = [];\n const ended: SessionSummary[] = [];\n\n for (const [id, c] of currMap) {\n const p = prevMap.get(id);\n if (!p) {\n if (c.status === 'pending_approval') newPending.push(c);\n } else if (p.status === 'pending_approval' && c.status === 'active') {\n activated.push(c);\n }\n }\n for (const [id, p] of prevMap) {\n if (!currMap.has(id)) ended.push(p);\n }\n return { newPending, activated, ended };\n}\n","import { EventEmitter } from 'node:events';\nimport WebSocket from 'ws';\nimport { ControlSignalType, wsAgentControlEventSchema, type WsAgentControlEvent } from '@clawrent/protocol';\nimport { ApiClient } from './api-client.js';\nimport type { ClawRentConfig } from './config.js';\nimport { SessionManager } from './session-manager.js';\nimport { InMemoryCursorStore } from './cursor.js';\nimport type { CursorStore } from './cursor.js';\nimport { resumeActiveSessions } from './helpers.js';\nimport type { ActiveSession } from './types.js';\n\n/** Backend /ws/agent close codes that mean the connection can never be\n * re-established — stop reconnecting. From apps/platform-api ws-agent-handler.ts:\n * 4000 missing token, 4001 invalid agent token. (Different from /ws/session's\n * 4000-4004 set — SessionManager uses its own; do not share.) */\nconst AGENT_TERMINAL_CLOSE_CODES = new Set([4000, 4001]);\n\nexport interface ProviderClientOptions {\n apiUrl?: string;\n wsUrl?: string;\n agentToken: string;\n cursorStore?: CursorStore;\n heartbeatIntervalMs?: number;\n maxReconnectAttempts?: number;\n autoApprove?: boolean;\n /** Initial backoff for presence REST retries (getMyAgent/activateAgent). Default 1000ms. */\n restRetryInitialMs?: number;\n /** Cap for presence REST retry backoff. Default 30000ms. */\n restRetryMaxDelayMs?: number;\n /** Max attempts for presence REST retries. undefined = persistent (default, for unattended providers). */\n restRetryMaxAttempts?: number;\n /** Initial backoff for /ws/agent reconnect. Default 1000ms. */\n agentReconnectInitialMs?: number;\n /** Cap for /ws/agent reconnect backoff. Default 30000ms. */\n agentReconnectMaxDelayMs?: number;\n}\n\nexport interface ProviderCallbacks {\n onMessage: (session: ActiveSession, message: Record<string, unknown>) => void | Promise<void>;\n onSessionNew?: (session: ActiveSession) => void;\n onSessionEnded?: (session: ActiveSession, reason?: string) => void;\n onPendingApproval?: (session: ActiveSession) => boolean | Promise<boolean>;\n agentId?: string;\n}\n\n/**\n * ProviderClient — the core embeddable class of @clawrent/provider.\n *\n * Lifecycle (Task 6a scope):\n * construct -> start() -> connects /ws/agent (presence) + activates the agent\n * -> stop() disconnects everything cleanly.\n *\n * Task 6b wires:\n * - bindSessionManager: forwards SessionManager events; routes session:message\n * through handleSessionMessage (cursor dedupe -> onMessage).\n * - resumeActive: re-attaches active provider sessions on startup.\n * - handleAgentMessage: parses /ws/agent frames (discriminated union on `type`\n * with fields under `payload`), routes session.new/session.approved to\n * /ws/session connect (with optional autoApprove), and gracefully handles\n * the non-schema frame types (agent.connected / system.error / heartbeat_ack).\n * - handleSessionMessage: public test-hook method that dedupes inbound\n * /ws/session messages by per-session cursor and fires onMessage.\n */\nexport class ProviderClient extends EventEmitter {\n private readonly client: ApiClient;\n private readonly cursor: CursorStore;\n private readonly heartbeatIntervalMs: number;\n private readonly maxReconnectAttempts: number;\n private readonly autoApprove: boolean;\n private readonly restRetryInitialMs: number;\n private readonly restRetryMaxDelayMs: number;\n private readonly restRetryMaxAttempts: number | undefined;\n private readonly agentReconnectInitialMs: number;\n private readonly agentReconnectMaxDelayMs: number;\n /** /ws/agent reconnect state. */\n private agentReconnectAttempts = 0;\n private agentReconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private agentToken: string;\n private agentId: string | null = null;\n private agentWs: WebSocket | null = null;\n private sessionManager: SessionManager | null = null;\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n private _running = false;\n private _stopped = false;\n /** Latch: has /ws/agent ever reached 'open'? Distinguishes first-connect failure\n * (reject start()) from a reconnect failure (route via close → reschedule). Also\n * used by reconnect gates which key off _stopped (teardown) — _running is false\n * throughout the start window, so it can't gate reconnect. */\n private _agentOpenedOnce = false;\n private readonly activeSessions = new Map<string, ActiveSession>();\n /**\n * Per-session in-flight promise chain: each `session:message` for the same\n * sessionId is chained onto the previous one so calls serialize. Without this,\n * two socket frames arriving in the same tick would both pass the cursor\n * dedupe check (the first call's `cursor.set` is queued behind its `await`\n * and hasn't run when the second call reads the cursor) and onMessage would\n * fire twice. The Map entry is cleared when the tail settles so it doesn't\n * grow unbounded.\n */\n private readonly inflight = new Map<string, Promise<void>>();\n /** Callbacks captured at start(); used by handleAgentMessage/handleSessionMessage. */\n private boundCallbacks: ProviderCallbacks | null = null;\n /** Per-session last-sent timestamp for sendTyping debounce (guard against\n * hosts calling in a tight loop; hosts wanting a steady indicator should\n * call every ~2s — the peer clears the indicator after a 3s gap). */\n private readonly lastTypingSent = new Map<string, number>();\n /** One-shot latch: settles (resolve on first success / reject on terminal 4xx)\n * when the FIRST activateAgent completes. start() awaits it (α semantics).\n * Reused across reconnects but only the first settle matters; later calls are no-ops. */\n private firstActivationResolve!: () => void;\n private firstActivationReject!: (err: unknown) => void;\n private readonly firstActivation: Promise<void> = new Promise((resolve, reject) => {\n this.firstActivationResolve = resolve;\n this.firstActivationReject = reject;\n });\n\n constructor(opts: ProviderClientOptions) {\n super();\n const config: ClawRentConfig = {\n apiUrl: opts.apiUrl ?? 'https://clawrent.cloud',\n wsUrl: opts.wsUrl ?? 'wss://clawrent.cloud',\n };\n this.client = new ApiClient(config);\n this.client.setAgentToken(opts.agentToken);\n this.agentToken = opts.agentToken;\n this.cursor = opts.cursorStore ?? new InMemoryCursorStore();\n this.heartbeatIntervalMs = opts.heartbeatIntervalMs ?? 25_000;\n this.maxReconnectAttempts = opts.maxReconnectAttempts ?? 5;\n this.autoApprove = opts.autoApprove ?? true;\n this.restRetryInitialMs = opts.restRetryInitialMs ?? 1_000;\n this.restRetryMaxDelayMs = opts.restRetryMaxDelayMs ?? 30_000;\n this.restRetryMaxAttempts = opts.restRetryMaxAttempts; // undefined => persistent\n this.agentReconnectInitialMs = opts.agentReconnectInitialMs ?? 1_000;\n this.agentReconnectMaxDelayMs = opts.agentReconnectMaxDelayMs ?? 30_000;\n }\n\n get running(): boolean { return this._running; }\n get currentAgentId(): string | null { return this.agentId; }\n /** Cursor store used for per-session message dedupe (wired in Task 6b). */\n get cursorStore(): CursorStore { return this.cursor; }\n /** Whether sessions are auto-approved on arrival (wired in Task 6b). */\n get isAutoApprove(): boolean { return this.autoApprove; }\n\n async start(callbacks: ProviderCallbacks): Promise<void> {\n if (this._running) throw new Error('ProviderClient already started');\n\n // resolve agentId (with retry — symptom A fix: transient fetch blip at startup\n // no longer kills the provider).\n if (callbacks.agentId) {\n this.agentId = callbacks.agentId;\n } else {\n const me = await this.retryWithBackoff(\n () => this.client.getMyAgent(),\n {\n initialMs: this.restRetryInitialMs,\n maxDelayMs: this.restRetryMaxDelayMs,\n maxAttempts: this.restRetryMaxAttempts,\n isCancelled: () => this._stopped,\n onRetry: (a, err, delay) => this.emit('agent:warning', `getMyAgent attempt ${a} failed: ${(err as Error).message}; retry in ${delay}ms`),\n },\n );\n this.agentId = (me['id'] as string) ?? (me['agentId'] as string) ?? null;\n }\n if (!this.agentId) throw new Error('Could not resolve agentId (pass callbacks.agentId or ensure token is valid)');\n\n // wire session manager\n this.sessionManager = new SessionManager(this.client.wsUrl, this.heartbeatIntervalMs, 30_000, this.maxReconnectAttempts);\n this.sessionManager.agentId = this.agentId;\n this.bindSessionManager(callbacks);\n\n // connect /ws/agent (control channel -> presence). The open handler triggers\n // activateWithRetry on every (re)connect.\n await this.connectAgent();\n\n // α: wait for the first successful activation before declaring running.\n // On terminal 4xx activation, firstActivation rejects -> start() rejects\n // (bad token / not approved won't self-heal; plugin logs startProvider failed).\n await this.firstActivation;\n\n this._running = true;\n this.emit('agent:started', this.agentId);\n\n // re-attach active sessions (Task 6b expands this)\n void this.resumeActive(callbacks);\n }\n\n private bindSessionManager(callbacks: ProviderCallbacks): void {\n this.boundCallbacks = callbacks;\n const sm = this.sessionManager;\n if (!sm) return;\n sm.on('session:connected', (sid: string) => this.emit('session:connected', sid));\n sm.on('session:disconnected', (sid: string, reason: string) => this.emit('session:disconnected', sid, reason));\n sm.on('session:message', (sid: string, message: Record<string, unknown>) => {\n // Per-session serialization: chain this call onto the previous one for\n // the same sessionId so two frames arriving in the same tick do not both\n // pass the cursor dedupe check inside handleSessionMessage. The .catch\n // also covers Fix 3 — if a cursor-op (cursor.get/set) itself throws, the\n // rejection is caught here and surfaced as session:error instead of\n // becoming an unhandled rejection.\n const prev = this.inflight.get(sid) ?? Promise.resolve();\n const next = prev\n .then(() => this.handleSessionMessage(sid, message))\n .catch(err => { this.emit('session:error', sid, err); });\n this.inflight.set(sid, next);\n next.finally(() => {\n if (this.inflight.get(sid) === next) this.inflight.delete(sid);\n });\n });\n sm.on('session:dead', (sid: string, reason: string) => {\n const active = this.activeSessions.get(sid) ?? { sessionId: sid, sessionToken: '' };\n this.activeSessions.delete(sid);\n callbacks.onSessionEnded?.(active, reason);\n });\n }\n\n private async resumeActive(callbacks: ProviderCallbacks): Promise<void> {\n if (!this.sessionManager) return;\n try {\n const sessions = await resumeActiveSessions(this.client, this.sessionManager);\n for (const s of sessions) {\n this.activeSessions.set(s.sessionId, s);\n callbacks.onSessionNew?.(s);\n this.emit('session:reattached', s.sessionId);\n }\n } catch (err) {\n this.emit('agent:warning', `resume failed: ${(err as Error).message}`);\n }\n }\n\n private connectAgent(): Promise<void> {\n return new Promise((resolve, reject) => {\n const url = `${this.client.wsUrl}/ws/agent?token=${encodeURIComponent(this.agentToken)}`;\n const ws = new WebSocket(url);\n this.agentWs = ws;\n ws.on('open', () => {\n this.heartbeatTimer = setInterval(() => {\n if (ws.readyState === WebSocket.OPEN) {\n ws.send(JSON.stringify({ type: 'system.heartbeat', payload: {} }));\n }\n }, this.heartbeatIntervalMs);\n this.emit('agent:connected');\n this._agentOpenedOnce = true; // first-connect resolved — future errors route via close, not start()\n this.agentReconnectAttempts = 0; // (re)connected — reset reconnect backoff\n void this.activateWithRetry(); // Task 4: activate on every (re)connect\n resolve();\n });\n ws.on('error', err => {\n if (!this._agentOpenedOnce) reject(err); // first-connect failure (never opened) -> reject start(); after first open, 'error' is followed by 'close' which reschedules\n });\n ws.on('close', (code, reason) => {\n this.clearHeartbeat();\n this.emit('agent:disconnected', code, reason.toString());\n if (this._stopped) return; // tearing down — don't reconnect\n if (AGENT_TERMINAL_CLOSE_CODES.has(code)) {\n this._running = false; // terminal = unrecoverable; reflect in the public getter (don't full-stop; host owns teardown)\n this.emit('agent:dead', this.agentId, `terminal close ${code}: ${reason.toString()}`);\n return; // bad token etc. — won't fix, don't loop\n }\n this.scheduleAgentReconnect();\n });\n ws.on('message', raw => {\n void this.handleAgentMessage(raw).catch(err => {\n this.emit('agent:warning', `agent message handler failed: ${(err as Error).message}`);\n });\n });\n });\n }\n\n /**\n * Reconnect /ws/agent after an abnormal (non-terminal) close. Persistent\n * (never gives up) with exponential backoff capped at agentReconnectMaxDelayMs.\n * Guarded by _running: stop() cancels. On the new socket's 'open', the existing\n * open handler resets attempts + fires activateWithRetry (re-activation).\n */\n private scheduleAgentReconnect(): void {\n if (this._stopped) return;\n const delay = Math.min(\n this.agentReconnectInitialMs * 2 ** this.agentReconnectAttempts,\n this.agentReconnectMaxDelayMs,\n );\n this.agentReconnectAttempts++;\n this.emit('agent:reconnecting', delay);\n this.agentReconnectTimer = setTimeout(() => {\n this.agentReconnectTimer = null;\n if (this._stopped) return;\n // Fire-and-forget: open handler activates; errors route back to close → reschedule.\n void this.connectAgent().catch(() => { /* close handler reschedules */ });\n }, delay);\n }\n\n /**\n * Parses an inbound /ws/agent frame and routes it.\n *\n * `session.new` / `session.approved` are validated against the protocol\n * discriminated-union schema (fields under `payload`). Other /ws/agent frame\n * types pushed by the backend (agent.connected / agent.status_updated /\n * system.error / system.heartbeat_ack — see apps/platform-api ws-agent-handler.ts)\n * are NOT in wsAgentControlEventSchema, so we route them by `type` directly\n * instead of forcing them through the schema (which would reject them).\n * Unknown types are ignored gracefully.\n *\n * Note: backend does NOT push `session.ended` on /ws/agent; session\n * terminations arrive as `system.session_ended` on /ws/session.\n */\n private async handleAgentMessage(raw: WebSocket.RawData): Promise<void> {\n let frame: unknown;\n try {\n frame = JSON.parse(raw.toString());\n } catch {\n return; // malformed JSON — ignore\n }\n if (typeof frame !== 'object' || frame === null) return;\n const type = (frame as Record<string, unknown>)['type'];\n\n // --- Session control events (schema-validated) ---\n if (type === 'session.new' || type === 'session.approved') {\n let parsed: WsAgentControlEvent;\n try {\n parsed = wsAgentControlEventSchema.parse(frame);\n } catch {\n return; // malformed control frame — drop, don't crash the socket\n }\n if (parsed.type === 'session.new') {\n await this.onSessionNew(parsed.payload);\n } else {\n this.onSessionApproved(parsed.payload);\n }\n return;\n }\n\n // --- Non-schema /ws/agent frames (route by `type` only) ---\n const payload = (frame as Record<string, unknown>)['payload'];\n switch (type) {\n case 'system.heartbeat_ack':\n return; // heartbeat acknowledgement — ignore\n case 'system.error':\n this.emit('agent:warning', `server error: ${JSON.stringify(payload) ?? 'no payload'}`);\n return;\n case 'agent.connected':\n this.emit('agent:connected', payload);\n return;\n case 'agent.status_updated':\n this.emit('agent:status', payload);\n return;\n default:\n // Unknown frame type — ignore gracefully (no crash, no emit).\n return;\n }\n }\n\n /** session.new: register, notify host, optionally auto-approve + connect /ws/session. */\n private async onSessionNew(\n payload: Extract<WsAgentControlEvent, { type: 'session.new' }>['payload'],\n ): Promise<void> {\n const sessionId = payload.sessionId;\n const sessionToken = payload.sessionToken;\n const active: ActiveSession = {\n sessionId,\n sessionToken: sessionToken ?? '',\n taskDescription: payload.taskDescription,\n consumerUserId: payload.consumerUserId,\n guardrailDecision: payload.guardrailDecision,\n };\n this.activeSessions.set(sessionId, active);\n this.boundCallbacks?.onSessionNew?.(active);\n this.emit('session:new', active);\n\n // Decide whether to approve + connect /ws/session now.\n const shouldApprove = this.autoApprove\n ? true\n : this.boundCallbacks?.onPendingApproval\n ? await this.boundCallbacks.onPendingApproval(active)\n : false;\n if (!shouldApprove) return;\n\n if (this.autoApprove) {\n try {\n await this.client.approveSession(sessionId);\n } catch (err) {\n this.emit('agent:warning', `approve failed for ${sessionId}: ${(err as Error).message}`);\n return;\n }\n }\n // SessionManager.connect is idempotent (guards on already-connected).\n // A subsequent session.approved frame will re-enter connect as a no-op.\n if (sessionToken) {\n this.sessionManager?.connect(sessionId, sessionToken);\n } else {\n this.emit('agent:warning', `session.new for ${sessionId} carried no sessionToken; deferring /ws/session connect until session.approved`);\n }\n }\n\n /** session.approved: ensure tracked + connect /ws/session (idempotent). */\n private onSessionApproved(\n payload: Extract<WsAgentControlEvent, { type: 'session.approved' }>['payload'],\n ): void {\n const sessionId = payload.sessionId;\n const sessionToken = payload.sessionToken;\n const existing = this.activeSessions.get(sessionId);\n const active: ActiveSession = existing ?? {\n sessionId,\n sessionToken: sessionToken ?? '',\n };\n if (sessionToken) active.sessionToken = sessionToken;\n this.activeSessions.set(sessionId, active);\n this.emit('session:approved', active);\n if (sessionToken) {\n this.sessionManager?.connect(sessionId, sessionToken);\n }\n }\n\n /**\n * Dedupes an inbound /ws/session message by per-session cursor, then invokes\n * the host's onMessage callback. Public (no underscore prefix) so the\n * integration test can drive the cursor/dedupe path directly as a hook.\n *\n * At-least-once invariant (Task 6b fix round 1): the cursor is advanced ONLY\n * AFTER `await onMessage` completes successfully. If onMessage throws, the\n * cursor is left un-advanced and `session:error` is emitted — so a future\n * redelivery (e.g. backend replay on restart) will pass the dedupe check and\n * re-process the message. onMessage MUST be idempotent precisely because of\n * this redelivery semantics. The per-session in-flight chain in\n * `bindSessionManager`'s `session:message` handler serializes concurrent\n * frames for the same session so the cursor-after-success commit has a chance\n * to run before the next frame's dedupe check reads the cursor.\n *\n * `createdAt` is canonical UTC ISO, taken from `_meta.timestamp` (backend\n * pushes ISO `...Z`) with a `new Date(message.timestamp).toISOString()`\n * fallback (ms epoch).\n */\n async handleSessionMessage(sessionId: string, message: Record<string, unknown>): Promise<void> {\n const onMessage = this.boundCallbacks?.onMessage;\n if (!onMessage) return;\n\n const meta = message['_meta'] as { timestamp?: unknown } | undefined;\n const metaTs = meta?.timestamp;\n const msgTs = message['timestamp'];\n const createdAt: string =\n typeof metaTs === 'string'\n ? metaTs\n : typeof msgTs === 'number'\n ? new Date(msgTs).toISOString()\n : new Date().toISOString();\n\n const last = this.cursor.get(sessionId);\n if (last && createdAt <= last) return; // already processed (dedupe)\n\n const session = this.activeSessions.get(sessionId) ?? { sessionId, sessionToken: '' };\n try {\n await onMessage(session, message);\n } catch (err) {\n // Do NOT advance the cursor: a future redelivery must re-process this\n // message (at-least-once across the onMessage failure).\n this.emit('session:error', sessionId, err);\n return;\n }\n this.cursor.set(sessionId, createdAt); // success → advance + persist\n }\n\n /**\n * Send an outbound message to a session. Prefers the /ws/session socket when\n * it is OPEN (low latency, no HTTP overhead); falls back to the REST\n * `POST /api/sessions/:id/messages` endpoint when the socket is absent or not\n * yet open (e.g. before start(), during reconnect, or for sessions not yet\n * attached). Returns the transport actually used so callers can observe it.\n *\n * Note: this method does NOT throw when WS is unavailable — it silently falls\n * back to REST. REST errors propagate to the caller as-is.\n */\n async send(\n sessionId: string,\n message: { type: string; payload: Record<string, unknown> },\n ): Promise<{ via: 'ws' | 'rest' }> {\n // Local binding so TS narrows `sm` to NonNullable inside the if-block\n // (this.sessionManager is mutable class state and isn't narrowed by `?.`).\n const sm = this.sessionManager;\n if (sm?.isConnected(sessionId)) {\n const ok = sm.send(sessionId, message);\n if (ok) return { via: 'ws' };\n }\n // REST fallback\n await this.client.sendSessionMessage(sessionId, message);\n return { via: 'rest' };\n }\n\n /**\n * Send a transient \"typing\" indicator to a session. Fire-and-forget over the\n * /ws/session socket ONLY — never REST (the REST POST /messages endpoint does\n * NOT short-circuit dialogue.typing, so it would persist a typing row and\n * pollute message history). The backend forwards the frame to the peer and\n * skips validation/persistence/metering/ACK.\n *\n * Debounced to one send per 500ms per session as a guard against hosts\n * calling in a tight loop. No-op (returns false) when the session socket is\n * not OPEN or the call is suppressed by debounce; returns true when a typing\n * frame was actually sent.\n *\n * Hosts control timing: call this periodically (every ~2s) after receiving a\n * consumer message and while generating a reply; stop once the reply is sent.\n */\n sendTyping(sessionId: string): boolean {\n const sm = this.sessionManager;\n if (!sm?.isConnected(sessionId)) return false;\n const now = Date.now();\n const last = this.lastTypingSent.get(sessionId) ?? 0;\n if (now - last < 500) return false;\n this.lastTypingSent.set(sessionId, now);\n return sm.send(sessionId, { type: ControlSignalType.DIALOGUE_TYPING, payload: {} });\n }\n\n /**\n * Retry with exponential backoff. Used to harden presence-critical REST calls\n * (getMyAgent, activateAgent) against transient network failures.\n *\n * Public (no `private` keyword) so tests can drive it directly via bracket\n * access as a hook — matches the `handleSessionMessage` precedent. Tasks 3-5\n * will wire it into `start()`; until then it has no internal call site, which\n * is why it cannot be `private` (TS6133 under `noUnusedLocals`).\n *\n * - maxAttempts === undefined => persistent (never gives up) — the default for\n * unattended providers with no external restart.\n * - Terminal REST errors (4xx except 429) throw immediately — bad tokens won't\n * fix themselves.\n * - Network errors / 5xx / 429 retry with exponential backoff capped at\n * maxDelayMs. onRetry (if set) fires BEFORE each sleep so callers can emit.\n */\n async retryWithBackoff<T>(\n fn: () => Promise<T>,\n opts: {\n initialMs: number;\n maxDelayMs: number;\n maxAttempts?: number;\n onRetry?: (attempt: number, err: unknown, delayMs: number) => void;\n isCancelled?: () => boolean;\n },\n ): Promise<T> {\n let attempt = 0;\n // maxAttempts undefined => persistent\n while (opts.maxAttempts === undefined || attempt < opts.maxAttempts) {\n if (opts.isCancelled?.()) throw new Error('cancelled');\n try {\n return await fn();\n } catch (err) {\n attempt++;\n if (this.isTerminalRestError(err)) throw err;\n if (opts.maxAttempts !== undefined && attempt >= opts.maxAttempts) throw err;\n const delay = Math.min(opts.initialMs * 2 ** (attempt - 1), opts.maxDelayMs);\n opts.onRetry?.(attempt, err, delay);\n await new Promise(r => setTimeout(r, delay));\n }\n }\n // unreachable (loop covers all paths), but satisfies TS return type\n throw new Error('retryWithBackoff: exhausted');\n }\n\n /** 4xx (except 429) are terminal — auth/validation won't self-heal. */\n private isTerminalRestError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n const m = err.message.match(/^API error (\\d+):/);\n if (!m) return false; // network error (no API status) => retry\n const status = Number(m[1]);\n return status >= 400 && status < 500 && status !== 429;\n }\n\n /**\n * Activate the agent with persistent retry. Called on every /ws/agent (re)connect.\n * Emits: agent:warning per failed attempt; agent:activated on success;\n * agent:activation:failed on terminal 4xx (or maxAttempts exhausted).\n * On the FIRST connect (before _running), settles firstActivation:\n * success -> resolve (start() proceeds); terminal -> reject (start() rejects).\n * On reconnects (_running true), just emits (firstActivation already settled).\n */\n private async activateWithRetry(): Promise<void> {\n if (!this.agentId) return;\n try {\n await this.retryWithBackoff(\n () => this.client.activateAgent(this.agentId!),\n {\n initialMs: this.restRetryInitialMs,\n maxDelayMs: this.restRetryMaxDelayMs,\n maxAttempts: this.restRetryMaxAttempts,\n isCancelled: () => this._stopped,\n onRetry: (a, err, delay) => this.emit('agent:warning', `activation attempt ${a} failed: ${(err as Error).message}; retry in ${delay}ms`),\n },\n );\n } catch (err) {\n if (this._stopped) return; // cancelled by stop — silent; stop() already rejected firstActivation\n this.emit('agent:activation:failed', this.agentId, err);\n if (!this._running) this.firstActivationReject(err);\n return;\n }\n this.emit('agent:activated', this.agentId);\n if (!this._running) this.firstActivationResolve();\n }\n\n private clearHeartbeat(): void {\n if (this.heartbeatTimer) { clearInterval(this.heartbeatTimer); this.heartbeatTimer = null; }\n }\n\n stop(): void {\n this._running = false;\n this._stopped = true;\n if (this.agentReconnectTimer) { clearTimeout(this.agentReconnectTimer); this.agentReconnectTimer = null; }\n this.firstActivationReject(new Error('Provider stopped'));\n this.clearHeartbeat();\n this.sessionManager?.disconnectAll();\n if (this.agentWs) { this.agentWs.close(1000, 'Provider stopping'); this.agentWs = null; }\n this.activeSessions.clear();\n this.client.setAgentToken(null);\n this.emit('stopped');\n }\n}\n","export const PROVIDER_PACKAGE_VERSION = '0.2.0';\n\nexport { ApiClient } from './api-client.js';\nexport type { ClawRentConfig } from './config.js';\nexport { loadConfig, saveConfig, clearConfig, getConfigPath, getConfigDir } from './config.js';\nexport { SessionManager } from './session-manager.js';\nexport type { SessionConnection } from './session-manager.js';\nexport { InMemoryCursorStore, FileCursorStore } from './cursor.js';\nexport type { CursorStore } from './cursor.js';\nexport { resumeActiveSessions, diffSessionStates } from './helpers.js';\nexport type { ActiveSession, SessionSummary, SessionDiff } from './types.js';\nexport { ProviderClient } from './provider-client.js';\nexport type { ProviderClientOptions, ProviderCallbacks } from './provider-client.js';\n"],"mappings":";AAEO,IAAM,YAAN,MAAgB;AAAA,EACb;AAAA;AAAA,EAEA,qBAAoC;AAAA,EAE5C,YAAY,QAAwB;AAClC,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,cAAc,OAA4B;AACxC,SAAK,qBAAqB;AAAA,EAC5B;AAAA,EAEA,IAAI,SAAiB;AACnB,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA,EAEA,IAAI,QAAgB;AAClB,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA,EAEA,IAAI,SAA6B;AAC/B,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA;AAAA,EAIA,MAAM,iBAAiB,OAA6C;AAClE,WAAO,KAAK,QAAQ,QAAQ,+BAA+B,EAAE,MAAM,GAAG,KAAK;AAAA,EAC7E;AAAA,EAEA,MAAM,aAAa,OAK6F;AAC9G,WAAO,KAAK,QAAQ,QAAQ,sBAAsB,OAAO,KAAK;AAAA,EAChE;AAAA,EAEA,MAAM,MAAM,OAAe,UAA+G;AACxI,WAAO,KAAK,QAAQ,QAAQ,mBAAmB,EAAE,OAAO,SAAS,GAAG,KAAK;AAAA,EAC3E;AAAA,EAEA,MAAM,QAA0C;AAC9C,WAAO,KAAK,QAAQ,OAAO,cAAc;AAAA,EAC3C;AAAA;AAAA,EAIA,MAAM,OAAO,OAAiG;AAC5G,UAAM,SAAS,IAAI,gBAAgB;AACnC,QAAI,OAAO,OAAQ,QAAO,IAAI,UAAU,MAAM,MAAM;AACpD,QAAI,OAAO,SAAU,QAAO,IAAI,YAAY,MAAM,QAAQ;AAC1D,QAAI,OAAO,KAAM,QAAO,IAAI,QAAQ,OAAO,MAAM,IAAI,CAAC;AACtD,QAAI,OAAO,MAAO,QAAO,IAAI,SAAS,OAAO,MAAM,KAAK,CAAC;AACzD,UAAM,KAAK,OAAO,SAAS;AAC3B,WAAO,KAAK,QAAQ,OAAO,0BAA0B,KAAK,IAAI,EAAE,KAAK,EAAE,EAAE;AAAA,EAC3E;AAAA,EAEA,MAAM,SAAS,MAAgC;AAC7C,WAAO,KAAK,QAAQ,OAAO,2BAA2B,mBAAmB,IAAI,CAAC,EAAE;AAAA,EAClF;AAAA;AAAA,EAIA,MAAM,KAAK,SAAuH;AAChI,WAAO,KAAK,QAAQ,QAAQ,iBAAiB;AAAA,MAC3C,SAAS,QAAQ;AAAA,MACjB,iBAAiB,QAAQ;AAAA,MACzB,oBAAoB,QAAQ,sBAAsB,CAAC;AAAA,IACrD,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,YAAY,OAA6F;AAC7G,UAAM,SAAS,IAAI,gBAAgB;AACnC,QAAI,OAAO,KAAM,QAAO,IAAI,QAAQ,MAAM,IAAI;AAC9C,QAAI,OAAO,OAAQ,QAAO,IAAI,UAAU,MAAM,MAAM;AACpD,QAAI,OAAO,KAAM,QAAO,IAAI,QAAQ,OAAO,MAAM,IAAI,CAAC;AACtD,QAAI,OAAO,MAAO,QAAO,IAAI,SAAS,OAAO,MAAM,KAAK,CAAC;AACzD,UAAM,KAAK,OAAO,SAAS;AAC3B,WAAO,KAAK,QAAQ,OAAO,gBAAgB,KAAK,IAAI,EAAE,KAAK,EAAE,EAAE;AAAA,EACjE;AAAA,EAEA,MAAM,WAAW,WAAqD;AACpE,WAAO,KAAK,QAAQ,OAAO,iBAAiB,mBAAmB,SAAS,CAAC,EAAE;AAAA,EAC7E;AAAA,EAEA,MAAM,mBACJ,WACA,SACkB;AAClB,UAAM,SAAS,IAAI,gBAAgB;AACnC,QAAI,SAAS,MAAO,QAAO,IAAI,SAAS,QAAQ,KAAK;AACrD,QAAI,SAAS,MAAO,QAAO,IAAI,SAAS,OAAO,QAAQ,KAAK,CAAC;AAC7D,UAAM,KAAK,OAAO,SAAS;AAC3B,WAAO,KAAK;AAAA,MACV;AAAA,MACA,iBAAiB,mBAAmB,SAAS,CAAC,YAAY,KAAK,IAAI,EAAE,KAAK,EAAE;AAAA,IAC9E;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,mBACJ,WACA,MACkB;AAClB,WAAO,KAAK;AAAA,MACV;AAAA,MACA,iBAAiB,mBAAmB,SAAS,CAAC;AAAA,MAC9C;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,WAAW,WAAqC;AACpD,WAAO,KAAK,QAAQ,QAAQ,iBAAiB,mBAAmB,SAAS,CAAC,MAAM;AAAA,EAClF;AAAA,EAEA,MAAM,eAAe,WAAqC;AACxD,WAAO,KAAK,QAAQ,QAAQ,iBAAiB,mBAAmB,SAAS,CAAC,UAAU;AAAA,EACtF;AAAA;AAAA,EAIA,MAAM,aAA2C;AAC/C,WAAO,KAAK,QAAQ,OAAO,qBAAqB;AAAA,EAClD;AAAA,EAEA,MAAM,MAAM,QAA8C;AACxD,WAAO,KAAK,QAAQ,QAAQ,6BAA6B,EAAE,OAAO,CAAC;AAAA,EACrE;AAAA;AAAA,EAIA,MAAM,cAAc,MAAiD;AACnE,WAAO,KAAK,QAAQ,QAAQ,eAAe,IAAI;AAAA,EACjD;AAAA,EAEA,MAAM,YAAY,OAA6E;AAC7F,UAAM,SAAS,IAAI,gBAAgB;AACnC,QAAI,OAAO,KAAM,QAAO,IAAI,QAAQ,OAAO,MAAM,IAAI,CAAC;AACtD,QAAI,OAAO,MAAO,QAAO,IAAI,SAAS,OAAO,MAAM,KAAK,CAAC;AACzD,QAAI,OAAO,MAAO,QAAO,IAAI,SAAS,MAAM,KAAK;AACjD,UAAM,KAAK,OAAO,SAAS;AAC3B,WAAO,KAAK,QAAQ,OAAO,iBAAiB,KAAK,IAAI,EAAE,KAAK,EAAE,EAAE;AAAA,EAClE;AAAA;AAAA,EAGA,MAAM,aAA+C;AACnD,WAAO,KAAK,QAAQ,OAAO,sBAAsB;AAAA,EACnD;AAAA,EAEA,MAAM,cAAc,SAAiB,MAAiD;AACpF,WAAO,KAAK,QAAQ,QAAQ,eAAe,mBAAmB,OAAO,CAAC,mBAAmB,IAAI;AAAA,EAC/F;AAAA;AAAA,EAGA,MAAM,aAAa,SAAiB,MAAkD;AACpF,WAAO,KAAK,QAAQ,QAAQ,eAAe,mBAAmB,OAAO,CAAC,YAAY,QAAQ,CAAC,CAAC;AAAA,EAC9F;AAAA;AAAA,EAGA,MAAM,cAAc,SAAmC;AACrD,WAAO,KAAK,QAAQ,QAAQ,eAAe,mBAAmB,OAAO,CAAC,WAAW;AAAA,EACnF;AAAA,EAEA,MAAM,gBAAgB,SAAiB,cAAwC;AAC7E,WAAO,KAAK,QAAQ,SAAS,eAAe,mBAAmB,OAAO,CAAC,WAAW,EAAE,aAAa,CAAC;AAAA,EACpG;AAAA,EAEA,MAAM,mBAAmB,SAAkG;AACzH,WAAO,KAAK,QAAQ,QAAQ,eAAe,mBAAmB,OAAO,CAAC,QAAQ;AAAA,EAChF;AAAA,EAEA,MAAM,iBAAiB,SAA+C;AACpE,WAAO,KAAK,QAAQ,UAAU,eAAe,mBAAmB,OAAO,CAAC,QAAQ;AAAA,EAClF;AAAA;AAAA,EAIA,MAAM,YAAY,MAIG;AACnB,WAAO,KAAK,QAAQ,QAAQ,eAAe,IAAI;AAAA,EACjD;AAAA,EAEA,MAAM,UAAU,OAA8E;AAC5F,UAAM,SAAS,IAAI,gBAAgB;AACnC,QAAI,OAAO,OAAQ,QAAO,IAAI,UAAU,MAAM,MAAM;AACpD,QAAI,OAAO,KAAM,QAAO,IAAI,QAAQ,OAAO,MAAM,IAAI,CAAC;AACtD,QAAI,OAAO,MAAO,QAAO,IAAI,SAAS,OAAO,MAAM,KAAK,CAAC;AACzD,UAAM,KAAK,OAAO,SAAS;AAC3B,WAAO,KAAK,QAAQ,OAAO,cAAc,KAAK,IAAI,EAAE,KAAK,EAAE,EAAE;AAAA,EAC/D;AAAA,EAEA,MAAM,SAAS,SAAmC;AAChD,WAAO,KAAK,QAAQ,OAAO,eAAe,mBAAmB,OAAO,CAAC,EAAE;AAAA,EACzE;AAAA,EAEA,MAAM,YAAY,SAAmC;AACnD,WAAO,KAAK,QAAQ,QAAQ,eAAe,mBAAmB,OAAO,CAAC,SAAS;AAAA,EACjF;AAAA;AAAA,EAIA,MAAM,UAA4B;AAChC,WAAO,KAAK,QAAQ,OAAO,WAAW;AAAA,EACxC;AAAA,EAEA,MAAM,UAAU,MAA8E;AAC5F,WAAO,KAAK,QAAQ,QAAQ,aAAa,IAAI;AAAA,EAC/C;AAAA,EAEA,MAAM,eAAe,QAAgB,MAAqD;AACxF,WAAO,KAAK,QAAQ,SAAS,aAAa,mBAAmB,MAAM,CAAC,IAAI,IAAI;AAAA,EAC9E;AAAA,EAEA,MAAM,eAAe,QAAkC;AACrD,WAAO,KAAK,QAAQ,UAAU,aAAa,mBAAmB,MAAM,CAAC,EAAE;AAAA,EACzE;AAAA,EAEA,MAAM,YAA8B;AAClC,WAAO,KAAK,QAAQ,UAAU,WAAW;AAAA,EAC3C;AAAA;AAAA,EAIA,MAAM,cAAc,OAA6D;AAC/E,UAAM,SAAS,IAAI,gBAAgB;AACnC,QAAI,OAAO,KAAM,QAAO,IAAI,QAAQ,OAAO,MAAM,IAAI,CAAC;AACtD,QAAI,OAAO,MAAO,QAAO,IAAI,SAAS,OAAO,MAAM,KAAK,CAAC;AACzD,UAAM,KAAK,OAAO,SAAS;AAC3B,WAAO,KAAK,QAAQ,OAAO,iBAAiB,KAAK,IAAI,EAAE,KAAK,EAAE,EAAE;AAAA,EAClE;AAAA,EAEA,MAAM,YAAY,SAAmC;AACnD,WAAO,KAAK,QAAQ,QAAQ,kBAAkB,mBAAmB,OAAO,CAAC,EAAE;AAAA,EAC7E;AAAA,EAEA,MAAM,eAAe,SAAmC;AACtD,WAAO,KAAK,QAAQ,UAAU,kBAAkB,mBAAmB,OAAO,CAAC,EAAE;AAAA,EAC/E;AAAA;AAAA,EAIA,MAAM,SAA2B;AAC/B,WAAO,KAAK,QAAQ,OAAO,eAAe,QAAW,KAAK;AAAA,EAC5D;AAAA;AAAA,EAIA,MAAM,cAAgC;AACpC,WAAO,KAAK,QAAQ,OAAO,sBAAsB,QAAW,KAAK;AAAA,EACnE;AAAA,EAEA,MAAM,aAAa,MAAgC;AACjD,WAAO,KAAK,QAAQ,OAAO,yBAAyB,UAAU,IAAI,CAAC,IAAI,QAAW,KAAK;AAAA,EACzF;AAAA,EAEA,MAAM,WAAW,OAAiC;AAChD,UAAM,SAAS,IAAI,gBAAgB,EAAE,GAAG,MAAM,CAAC;AAC/C,WAAO,KAAK,QAAQ,OAAO,wBAAwB,OAAO,SAAS,CAAC,IAAI,QAAW,KAAK;AAAA,EAC1F;AAAA,EAEA,MAAM,OAAO,IAA8B;AACzC,WAAO,KAAK,QAAQ,OAAO,iBAAiB,mBAAmB,EAAE,CAAC,IAAI,QAAW,KAAK;AAAA,EACxF;AAAA,EAEA,MAAM,UAAU,MAA4H;AAC1I,WAAO,KAAK,QAAQ,QAAQ,iBAAiB,IAAI;AAAA,EACnD;AAAA,EAEA,MAAM,UAAU,IAAY,MAAsF;AAChH,WAAO,KAAK,QAAQ,SAAS,iBAAiB,mBAAmB,EAAE,CAAC,IAAI,IAAI;AAAA,EAC9E;AAAA,EAEA,MAAM,UAAU,IAA8B;AAC5C,WAAO,KAAK,QAAQ,UAAU,iBAAiB,mBAAmB,EAAE,CAAC,EAAE;AAAA,EACzE;AAAA,EAEA,MAAM,WAAW,IAA8B;AAC7C,WAAO,KAAK,QAAQ,QAAQ,iBAAiB,mBAAmB,EAAE,CAAC,UAAU;AAAA,EAC/E;AAAA,EAEA,MAAM,aAAa,IAA8B;AAC/C,WAAO,KAAK,QAAQ,QAAQ,iBAAiB,mBAAmB,EAAE,CAAC,YAAY;AAAA,EACjF;AAAA;AAAA,EAIA,MAAc,QAAiB,QAAgB,MAAc,MAAgB,cAAuB,MAAkB;AACpH,UAAM,MAAM,GAAG,KAAK,OAAO,MAAM,GAAG,IAAI;AACxC,UAAM,UAAkC,CAAC;AAEzC,QAAI,SAAS,QAAW;AACtB,cAAQ,cAAc,IAAI;AAAA,IAC5B;AAEA,QAAI,aAAa;AACf,UAAI,KAAK,oBAAoB;AAC3B,gBAAQ,eAAe,IAAI,UAAU,KAAK,kBAAkB;AAAA,MAC9D,WAAW,KAAK,OAAO,OAAO;AAC5B,gBAAQ,eAAe,IAAI,UAAU,KAAK,OAAO,KAAK;AAAA,MACxD,WAAW,KAAK,OAAO,QAAQ;AAC7B,gBAAQ,WAAW,IAAI,KAAK,OAAO;AAAA,MACrC,OAAO;AACL,cAAM,IAAI,MAAM,qDAAqD;AAAA,MACvE;AAAA,IACF;AAEA,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC;AAAA,MACA;AAAA,MACA,MAAM,OAAO,KAAK,UAAU,IAAI,IAAI;AAAA,IACtC,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,UAAU,MAAM,SAAS,KAAK,EAAE,MAAM,OAAO,EAAE,SAAS,SAAS,WAAW,EAAE;AACpF,YAAM,IAAI,MAAM,aAAa,SAAS,MAAM,KAAK,QAAQ,SAAS,KAAK,KAAK,UAAU,OAAO,CAAC,EAAE;AAAA,IAClG;AAEA,WAAO,SAAS,KAAK;AAAA,EACvB;AACF;;;AC/UA,SAAS,cAAc,eAAe,WAAW,YAAY,kBAAkB;AAC/E,SAAS,YAAY;AACrB,SAAS,eAAe;AAYxB,IAAM,iBAAiC;AAAA,EACrC,QAAQ;AAAA,EACR,OAAO;AACT;AAEO,SAAS,eAAuB;AACrC,SAAO,KAAK,QAAQ,GAAG,WAAW;AACpC;AAEA,SAAS,oBAA4B;AACnC,SAAO,KAAK,aAAa,GAAG,aAAa;AAC3C;AAEO,SAAS,gBAAwB;AACtC,SAAO,kBAAkB;AAC3B;AAEO,SAAS,aAA6B;AAC3C,MAAI,aAAsC,CAAC;AAE3C,QAAM,aAAa,kBAAkB;AACrC,MAAI,WAAW,UAAU,GAAG;AAC1B,QAAI;AACF,YAAM,MAAM,aAAa,YAAY,OAAO;AAC5C,mBAAa,KAAK,MAAM,GAAG;AAAA,IAC7B,QAAQ;AAAA,IAER;AAAA,EACF;AAIA,MAAI,WAAW,QAAQ,SAAS,WAAW,KAAK,WAAW,OAAO,SAAS,WAAW,GAAG;AACvF,WAAO,WAAW;AAClB,WAAO,WAAW;AAElB,QAAI;AACF,YAAM,UAAU,EAAE,GAAG,WAAW;AAChC,oBAAc,YAAY,KAAK,UAAU,SAAS,MAAM,CAAC,GAAG,OAAO;AAAA,IACrE,QAAQ;AAAA,IAER;AAAA,EACF;AAGA,QAAM,SAAyB;AAAA,IAC7B,GAAG;AAAA,IACH,GAAG;AAAA,EACL;AAGA,QAAM,YAAY,QAAQ,IAAI,kBAAkB;AAChD,QAAM,WAAW,QAAQ,IAAI,iBAAiB;AAC9C,QAAM,WAAW,QAAQ,IAAI,gBAAgB;AAC7C,QAAM,YAAY,QAAQ,IAAI,kBAAkB;AAChD,QAAM,YAAY,QAAQ,IAAI,kBAAkB;AAEhD,MAAI,UAAW,QAAO,SAAS;AAC/B,MAAI,SAAU,QAAO,QAAQ;AAC7B,MAAI,SAAU,QAAO,QAAQ;AAC7B,MAAI,UAAW,QAAO,SAAS;AAC/B,MAAI,UAAW,QAAO,SAAS;AAE/B,SAAO;AACT;AAEO,SAAS,WAAW,SAAwC;AACjE,QAAM,YAAY,aAAa;AAC/B,MAAI,CAAC,WAAW,SAAS,GAAG;AAC1B,cAAU,WAAW,EAAE,WAAW,KAAK,CAAC;AAAA,EAC1C;AAEA,MAAI,WAAoC,CAAC;AACzC,QAAM,aAAa,kBAAkB;AACrC,MAAI,WAAW,UAAU,GAAG;AAC1B,QAAI;AACF,iBAAW,KAAK,MAAM,aAAa,YAAY,OAAO,CAAC;AAAA,IACzD,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,QAAM,SAAS,EAAE,GAAG,UAAU,GAAG,QAAQ;AACzC,gBAAc,YAAY,KAAK,UAAU,QAAQ,MAAM,CAAC,GAAG,OAAO;AACpE;AAEO,SAAS,cAAoB;AAClC,QAAM,aAAa,kBAAkB;AACrC,MAAI,WAAW,UAAU,GAAG;AAC1B,eAAW,UAAU;AAAA,EACvB;AACF;;;ACzGA,SAAS,oBAAoB;AAC7B,OAAO,eAAe;AAMtB,IAAM,uBAAuB,oBAAI,IAAI,CAAC,KAAM,MAAM,MAAM,MAAM,IAAI,CAAC;AAc5D,IAAM,iBAAN,cAA6B,aAAa;AAAA,EACvC,WAAW,oBAAI,IAA+B;AAAA,EAC9C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACD;AAAA,EAEP,YACE,OACA,oBAAoB,MACpB,oBAAoB,KACpB,uBAAuB,GACvB;AACA,UAAM;AACN,SAAK,QAAQ;AACb,SAAK,oBAAoB;AACzB,SAAK,oBAAoB;AACzB,SAAK,uBAAuB;AAAA,EAC9B;AAAA;AAAA,EAGA,QAAQ,WAAmB,cAA4B;AACrD,QAAI,KAAK,SAAS,IAAI,SAAS,GAAG;AAChC;AAAA,IACF;AAEA,UAAM,MAAM,GAAG,KAAK,KAAK,yBAAyB,SAAS,UAAU,YAAY;AACjF,UAAM,KAAK,IAAI,UAAU,GAAG;AAE5B,UAAM,OAA0B;AAAA,MAC9B;AAAA,MACA;AAAA,MACA;AAAA,MACA,gBAAgB;AAAA,MAChB,mBAAmB;AAAA,IACrB;AAEA,SAAK,SAAS,IAAI,WAAW,IAAI;AAEjC,OAAG,GAAG,QAAQ,MAAM;AAClB,WAAK,oBAAoB;AACzB,WAAK,iBAAiB,YAAY,MAAM;AACtC,YAAI,GAAG,eAAe,UAAU,MAAM;AACpC,aAAG,KAAK,KAAK,UAAU,EAAE,MAAM,oBAAoB,SAAS,CAAC,EAAE,CAAC,CAAC;AAAA,QACnE;AAAA,MACF,GAAG,KAAK,iBAAiB;AAEzB,WAAK,KAAK,qBAAqB,SAAS;AAAA,IAC1C,CAAC;AAED,OAAG,GAAG,WAAW,CAAC,QAAQ;AACxB,UAAI;AACF,cAAM,UAAU,KAAK,MAAM,IAAI,SAAS,CAAC;AAEzC,YAAI,QAAQ,MAAM,MAAM,uBAAwB;AAEhD,aAAK,KAAK,mBAAmB,WAAW,OAAO;AAAA,MACjD,QAAQ;AAAA,MAER;AAAA,IACF,CAAC;AAED,OAAG,GAAG,SAAS,CAAC,MAAM,WAAW;AAC/B,WAAK,eAAe,IAAI;AAIxB,UAAI,qBAAqB,IAAI,IAAI,GAAG;AAClC,aAAK,SAAS,OAAO,SAAS;AAC9B,aAAK,KAAK,gBAAgB,WAAW,0BAA0B,IAAI,KAAK,OAAO,SAAS,CAAC,GAAG;AAC5F;AAAA,MACF;AAEA,UAAI,SAAS,KAAM;AAEjB,YAAI,KAAK,qBAAqB,KAAK,sBAAsB;AACvD,eAAK,SAAS,OAAO,SAAS;AAC9B,eAAK,KAAK,gBAAgB,WAAW,2BAA2B,KAAK,oBAAoB,WAAW;AACpG;AAAA,QACF;AACA,cAAM,QAAQ,KAAK;AAAA,UACjB,MAAO,KAAK,IAAI,GAAG,KAAK,iBAAiB;AAAA,UACzC,KAAK;AAAA,QACP;AACA,aAAK;AAEL,aAAK,KAAK,wBAAwB,WAAW,KAAK;AAElD,mBAAW,MAAM;AACf,eAAK,SAAS,OAAO,SAAS;AAC9B,eAAK,QAAQ,WAAW,YAAY;AAAA,QACtC,GAAG,KAAK;AAAA,MACV,OAAO;AACL,aAAK,SAAS,OAAO,SAAS;AAC9B,aAAK,KAAK,wBAAwB,WAAW,OAAO,SAAS,CAAC;AAAA,MAChE;AAAA,IACF,CAAC;AAED,OAAG,GAAG,SAAS,CAAC,QAAQ;AACtB,WAAK,KAAK,iBAAiB,WAAW,GAAG;AAAA,IAC3C,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,KAAK,WAAmB,SAA2C;AACjE,UAAM,OAAO,KAAK,SAAS,IAAI,SAAS;AACxC,QAAI,CAAC,QAAQ,KAAK,GAAG,eAAe,UAAU,MAAM;AAClD,aAAO;AAAA,IACT;AAEA,UAAM,WAAW;AAAA,MACf,IAAI,QAAQ,IAAI,KAAK,OAAO,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAAA,MAC7F,WAAW,QAAQ,WAAW,KAAK;AAAA,MACnC,WAAW,QAAQ,WAAW,KAAK,KAAK,IAAI;AAAA,MAC5C,QAAQ,QAAQ,QAAQ,KAAK,EAAE,MAAM,YAAY,SAAS,KAAK,WAAW,UAAU;AAAA,MACpF,MAAM,QAAQ,MAAM,KAAK;AAAA,MACzB,SAAS,QAAQ,SAAS,KAAK,CAAC;AAAA,IAClC;AACA,SAAK,GAAG,KAAK,KAAK,UAAU,QAAQ,CAAC;AACrC,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,WAAW,WAAyB;AAClC,UAAM,OAAO,KAAK,SAAS,IAAI,SAAS;AACxC,QAAI,CAAC,KAAM;AAEX,SAAK,eAAe,IAAI;AACxB,QAAI,KAAK,GAAG,eAAe,UAAU,QAAQ,KAAK,GAAG,eAAe,UAAU,YAAY;AACxF,WAAK,GAAG,MAAM,KAAM,wBAAwB;AAAA,IAC9C;AACA,SAAK,SAAS,OAAO,SAAS;AAAA,EAChC;AAAA;AAAA,EAGA,gBAAsB;AACpB,eAAW,aAAa,KAAK,SAAS,KAAK,GAAG;AAC5C,WAAK,WAAW,SAAS;AAAA,IAC3B;AAAA,EACF;AAAA;AAAA,EAGA,IAAI,cAAsB;AACxB,WAAO,KAAK,SAAS;AAAA,EACvB;AAAA;AAAA,EAGA,YAAY,WAA4B;AACtC,UAAM,OAAO,KAAK,SAAS,IAAI,SAAS;AACxC,WAAO,MAAM,GAAG,eAAe,UAAU;AAAA,EAC3C;AAAA,EAEQ,eAAe,MAA+B;AACpD,QAAI,KAAK,gBAAgB;AACvB,oBAAc,KAAK,cAAc;AACjC,WAAK,iBAAiB;AAAA,IACxB;AAAA,EACF;AACF;;;ACpLA,SAAS,gBAAAA,eAAc,iBAAAC,gBAAe,aAAAC,YAAW,cAAAC,mBAAkB;AACnE,SAAS,eAAe;AASjB,IAAM,sBAAN,MAAiD;AAAA,EAC9C,MAAM,oBAAI,IAAoB;AAAA,EACtC,IAAI,WAAkC;AACpC,WAAO,KAAK,IAAI,IAAI,SAAS,KAAK;AAAA,EACpC;AAAA,EACA,IAAI,WAAmB,WAAyB;AAC9C,UAAM,OAAO,KAAK,IAAI,IAAI,SAAS;AACnC,QAAI,SAAS,UAAa,YAAY,KAAM,MAAK,IAAI,IAAI,WAAW,SAAS;AAAA,EAC/E;AACF;AAEO,IAAM,kBAAN,MAA6C;AAAA,EAElD,YAA6B,MAAc;AAAd;AAAA,EAAe;AAAA,EAAf;AAAA,EADrB,QAAoC;AAAA,EAGpC,OAA4B;AAClC,QAAI,KAAK,MAAO,QAAO,KAAK;AAC5B,QAAI,CAACA,YAAW,KAAK,IAAI,GAAG;AAC1B,WAAK,QAAQ,oBAAI,IAAI;AACrB,aAAO,KAAK;AAAA,IACd;AACA,UAAM,MAAMH,cAAa,KAAK,MAAM,MAAM;AAC1C,QAAI;AACF,WAAK,QAAQ,IAAI,IAAI,OAAO,QAAQ,KAAK,MAAM,GAAG,CAAC,CAAC;AAAA,IACtD,QAAQ;AACN,WAAK,QAAQ,oBAAI,IAAI;AAAA,IACvB;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,UAAgB;AACtB,QAAI,CAAC,KAAK,MAAO;AACjB,IAAAE,WAAU,QAAQ,KAAK,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AACjD,IAAAD,eAAc,KAAK,MAAM,KAAK,UAAU,OAAO,YAAY,KAAK,KAAK,GAAG,MAAM,CAAC,GAAG,MAAM;AAAA,EAC1F;AAAA,EAEA,IAAI,WAAkC;AACpC,WAAO,KAAK,KAAK,EAAE,IAAI,SAAS,KAAK;AAAA,EACvC;AAAA,EACA,IAAI,WAAmB,WAAyB;AAC9C,UAAM,IAAI,KAAK,KAAK;AACpB,UAAM,OAAO,EAAE,IAAI,SAAS;AAC5B,QAAI,SAAS,UAAa,YAAY,MAAM;AAC1C,QAAE,IAAI,WAAW,SAAS;AAC1B,WAAK,QAAQ;AAAA,IACf;AAAA,EACF;AACF;;;AC7CA,eAAsB,qBACpB,QACA,gBAC0B;AAC1B,QAAM,MAAO,MAAM,OAAO,YAAY,EAAE,MAAM,YAAY,QAAQ,SAAS,CAAC;AAG5E,QAAM,OAAO,KAAK,QAAQ,CAAC;AAC3B,QAAM,WAA4B,CAAC;AACnC,aAAW,KAAK,MAAM;AACpB,UAAM,YAAY,EAAE,WAAW,KAAK,EAAE,IAAI;AAC1C,UAAM,eAAe,EAAE,cAAc;AACrC,QAAI,OAAO,cAAc,YAAY,OAAO,iBAAiB,SAAU;AACvE,aAAS,KAAK;AAAA,MACZ;AAAA,MACA;AAAA,MACA,iBAAiB,OAAO,EAAE,iBAAiB,MAAM,WAAW,EAAE,iBAAiB,IAAI;AAAA,MACnF,gBAAgB,OAAO,EAAE,gBAAgB,MAAM,WAAW,EAAE,gBAAgB,IAAI;AAAA,MAChF,WAAW,OAAO,EAAE,WAAW,MAAM,WAAW,EAAE,WAAW,IAAI;AAAA,IACnE,CAAC;AACD,mBAAe,QAAQ,WAAW,YAAY;AAAA,EAChD;AACA,SAAO;AACT;AASO,SAAS,kBAAkB,MAAwB,MAAqC;AAC7F,QAAM,UAAU,IAAI,IAAI,KAAK,IAAI,CAAC,MAAgC,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC;AACnF,QAAM,UAAU,IAAI,IAAI,KAAK,IAAI,CAAC,MAAgC,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC;AACnF,QAAM,aAA+B,CAAC;AACtC,QAAM,YAA8B,CAAC;AACrC,QAAM,QAA0B,CAAC;AAEjC,aAAW,CAAC,IAAI,CAAC,KAAK,SAAS;AAC7B,UAAM,IAAI,QAAQ,IAAI,EAAE;AACxB,QAAI,CAAC,GAAG;AACN,UAAI,EAAE,WAAW,mBAAoB,YAAW,KAAK,CAAC;AAAA,IACxD,WAAW,EAAE,WAAW,sBAAsB,EAAE,WAAW,UAAU;AACnE,gBAAU,KAAK,CAAC;AAAA,IAClB;AAAA,EACF;AACA,aAAW,CAAC,IAAI,CAAC,KAAK,SAAS;AAC7B,QAAI,CAAC,QAAQ,IAAI,EAAE,EAAG,OAAM,KAAK,CAAC;AAAA,EACpC;AACA,SAAO,EAAE,YAAY,WAAW,MAAM;AACxC;;;AC/DA,SAAS,gBAAAG,qBAAoB;AAC7B,OAAOC,gBAAe;AACtB,SAAS,mBAAmB,iCAA2D;AAavF,IAAM,6BAA6B,oBAAI,IAAI,CAAC,KAAM,IAAI,CAAC;AAgDhD,IAAM,iBAAN,cAA6BC,cAAa;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAET,yBAAyB;AAAA,EACzB,sBAA4D;AAAA,EAC5D;AAAA,EACA,UAAyB;AAAA,EACzB,UAA4B;AAAA,EAC5B,iBAAwC;AAAA,EACxC,iBAAwD;AAAA,EACxD,WAAW;AAAA,EACX,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA,EAKX,mBAAmB;AAAA,EACV,iBAAiB,oBAAI,IAA2B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUhD,WAAW,oBAAI,IAA2B;AAAA;AAAA,EAEnD,iBAA2C;AAAA;AAAA;AAAA;AAAA,EAIlC,iBAAiB,oBAAI,IAAoB;AAAA;AAAA;AAAA;AAAA,EAIlD;AAAA,EACA;AAAA,EACS,kBAAiC,IAAI,QAAQ,CAAC,SAAS,WAAW;AACjF,SAAK,yBAAyB;AAC9B,SAAK,wBAAwB;AAAA,EAC/B,CAAC;AAAA,EAED,YAAY,MAA6B;AACvC,UAAM;AACN,UAAM,SAAyB;AAAA,MAC7B,QAAQ,KAAK,UAAU;AAAA,MACvB,OAAO,KAAK,SAAS;AAAA,IACvB;AACA,SAAK,SAAS,IAAI,UAAU,MAAM;AAClC,SAAK,OAAO,cAAc,KAAK,UAAU;AACzC,SAAK,aAAa,KAAK;AACvB,SAAK,SAAS,KAAK,eAAe,IAAI,oBAAoB;AAC1D,SAAK,sBAAsB,KAAK,uBAAuB;AACvD,SAAK,uBAAuB,KAAK,wBAAwB;AACzD,SAAK,cAAc,KAAK,eAAe;AACvC,SAAK,qBAAqB,KAAK,sBAAsB;AACrD,SAAK,sBAAsB,KAAK,uBAAuB;AACvD,SAAK,uBAAuB,KAAK;AACjC,SAAK,0BAA0B,KAAK,2BAA2B;AAC/D,SAAK,2BAA2B,KAAK,4BAA4B;AAAA,EACnE;AAAA,EAEA,IAAI,UAAmB;AAAE,WAAO,KAAK;AAAA,EAAU;AAAA,EAC/C,IAAI,iBAAgC;AAAE,WAAO,KAAK;AAAA,EAAS;AAAA;AAAA,EAE3D,IAAI,cAA2B;AAAE,WAAO,KAAK;AAAA,EAAQ;AAAA;AAAA,EAErD,IAAI,gBAAyB;AAAE,WAAO,KAAK;AAAA,EAAa;AAAA,EAExD,MAAM,MAAM,WAA6C;AACvD,QAAI,KAAK,SAAU,OAAM,IAAI,MAAM,gCAAgC;AAInE,QAAI,UAAU,SAAS;AACrB,WAAK,UAAU,UAAU;AAAA,IAC3B,OAAO;AACL,YAAM,KAAK,MAAM,KAAK;AAAA,QACpB,MAAM,KAAK,OAAO,WAAW;AAAA,QAC7B;AAAA,UACE,WAAW,KAAK;AAAA,UAChB,YAAY,KAAK;AAAA,UACjB,aAAa,KAAK;AAAA,UAClB,aAAa,MAAM,KAAK;AAAA,UACxB,SAAS,CAAC,GAAG,KAAK,UAAU,KAAK,KAAK,iBAAiB,sBAAsB,CAAC,YAAa,IAAc,OAAO,cAAc,KAAK,IAAI;AAAA,QACzI;AAAA,MACF;AACA,WAAK,UAAW,GAAG,IAAI,KAAiB,GAAG,SAAS,KAAgB;AAAA,IACtE;AACA,QAAI,CAAC,KAAK,QAAS,OAAM,IAAI,MAAM,6EAA6E;AAGhH,SAAK,iBAAiB,IAAI,eAAe,KAAK,OAAO,OAAO,KAAK,qBAAqB,KAAQ,KAAK,oBAAoB;AACvH,SAAK,eAAe,UAAU,KAAK;AACnC,SAAK,mBAAmB,SAAS;AAIjC,UAAM,KAAK,aAAa;AAKxB,UAAM,KAAK;AAEX,SAAK,WAAW;AAChB,SAAK,KAAK,iBAAiB,KAAK,OAAO;AAGvC,SAAK,KAAK,aAAa,SAAS;AAAA,EAClC;AAAA,EAEQ,mBAAmB,WAAoC;AAC7D,SAAK,iBAAiB;AACtB,UAAM,KAAK,KAAK;AAChB,QAAI,CAAC,GAAI;AACT,OAAG,GAAG,qBAAqB,CAAC,QAAgB,KAAK,KAAK,qBAAqB,GAAG,CAAC;AAC/E,OAAG,GAAG,wBAAwB,CAAC,KAAa,WAAmB,KAAK,KAAK,wBAAwB,KAAK,MAAM,CAAC;AAC7G,OAAG,GAAG,mBAAmB,CAAC,KAAa,YAAqC;AAO1E,YAAM,OAAO,KAAK,SAAS,IAAI,GAAG,KAAK,QAAQ,QAAQ;AACvD,YAAM,OAAO,KACV,KAAK,MAAM,KAAK,qBAAqB,KAAK,OAAO,CAAC,EAClD,MAAM,SAAO;AAAE,aAAK,KAAK,iBAAiB,KAAK,GAAG;AAAA,MAAG,CAAC;AACzD,WAAK,SAAS,IAAI,KAAK,IAAI;AAC3B,WAAK,QAAQ,MAAM;AACjB,YAAI,KAAK,SAAS,IAAI,GAAG,MAAM,KAAM,MAAK,SAAS,OAAO,GAAG;AAAA,MAC/D,CAAC;AAAA,IACH,CAAC;AACD,OAAG,GAAG,gBAAgB,CAAC,KAAa,WAAmB;AACrD,YAAM,SAAS,KAAK,eAAe,IAAI,GAAG,KAAK,EAAE,WAAW,KAAK,cAAc,GAAG;AAClF,WAAK,eAAe,OAAO,GAAG;AAC9B,gBAAU,iBAAiB,QAAQ,MAAM;AAAA,IAC3C,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,aAAa,WAA6C;AACtE,QAAI,CAAC,KAAK,eAAgB;AAC1B,QAAI;AACF,YAAM,WAAW,MAAM,qBAAqB,KAAK,QAAQ,KAAK,cAAc;AAC5E,iBAAW,KAAK,UAAU;AACxB,aAAK,eAAe,IAAI,EAAE,WAAW,CAAC;AACtC,kBAAU,eAAe,CAAC;AAC1B,aAAK,KAAK,sBAAsB,EAAE,SAAS;AAAA,MAC7C;AAAA,IACF,SAAS,KAAK;AACZ,WAAK,KAAK,iBAAiB,kBAAmB,IAAc,OAAO,EAAE;AAAA,IACvE;AAAA,EACF;AAAA,EAEQ,eAA8B;AACpC,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,YAAM,MAAM,GAAG,KAAK,OAAO,KAAK,mBAAmB,mBAAmB,KAAK,UAAU,CAAC;AACtF,YAAM,KAAK,IAAIC,WAAU,GAAG;AAC5B,WAAK,UAAU;AACf,SAAG,GAAG,QAAQ,MAAM;AAClB,aAAK,iBAAiB,YAAY,MAAM;AACtC,cAAI,GAAG,eAAeA,WAAU,MAAM;AACpC,eAAG,KAAK,KAAK,UAAU,EAAE,MAAM,oBAAoB,SAAS,CAAC,EAAE,CAAC,CAAC;AAAA,UACnE;AAAA,QACF,GAAG,KAAK,mBAAmB;AAC3B,aAAK,KAAK,iBAAiB;AAC3B,aAAK,mBAAmB;AACxB,aAAK,yBAAyB;AAC9B,aAAK,KAAK,kBAAkB;AAC5B,gBAAQ;AAAA,MACV,CAAC;AACD,SAAG,GAAG,SAAS,SAAO;AACpB,YAAI,CAAC,KAAK,iBAAkB,QAAO,GAAG;AAAA,MACxC,CAAC;AACD,SAAG,GAAG,SAAS,CAAC,MAAM,WAAW;AAC/B,aAAK,eAAe;AACpB,aAAK,KAAK,sBAAsB,MAAM,OAAO,SAAS,CAAC;AACvD,YAAI,KAAK,SAAU;AACnB,YAAI,2BAA2B,IAAI,IAAI,GAAG;AACxC,eAAK,WAAW;AAChB,eAAK,KAAK,cAAc,KAAK,SAAS,kBAAkB,IAAI,KAAK,OAAO,SAAS,CAAC,EAAE;AACpF;AAAA,QACF;AACA,aAAK,uBAAuB;AAAA,MAC9B,CAAC;AACD,SAAG,GAAG,WAAW,SAAO;AACtB,aAAK,KAAK,mBAAmB,GAAG,EAAE,MAAM,SAAO;AAC7C,eAAK,KAAK,iBAAiB,iCAAkC,IAAc,OAAO,EAAE;AAAA,QACtF,CAAC;AAAA,MACH,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,yBAA+B;AACrC,QAAI,KAAK,SAAU;AACnB,UAAM,QAAQ,KAAK;AAAA,MACjB,KAAK,0BAA0B,KAAK,KAAK;AAAA,MACzC,KAAK;AAAA,IACP;AACA,SAAK;AACL,SAAK,KAAK,sBAAsB,KAAK;AACrC,SAAK,sBAAsB,WAAW,MAAM;AAC1C,WAAK,sBAAsB;AAC3B,UAAI,KAAK,SAAU;AAEnB,WAAK,KAAK,aAAa,EAAE,MAAM,MAAM;AAAA,MAAkC,CAAC;AAAA,IAC1E,GAAG,KAAK;AAAA,EACV;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,MAAc,mBAAmB,KAAuC;AACtE,QAAI;AACJ,QAAI;AACF,cAAQ,KAAK,MAAM,IAAI,SAAS,CAAC;AAAA,IACnC,QAAQ;AACN;AAAA,IACF;AACA,QAAI,OAAO,UAAU,YAAY,UAAU,KAAM;AACjD,UAAM,OAAQ,MAAkC,MAAM;AAGtD,QAAI,SAAS,iBAAiB,SAAS,oBAAoB;AACzD,UAAI;AACJ,UAAI;AACF,iBAAS,0BAA0B,MAAM,KAAK;AAAA,MAChD,QAAQ;AACN;AAAA,MACF;AACA,UAAI,OAAO,SAAS,eAAe;AACjC,cAAM,KAAK,aAAa,OAAO,OAAO;AAAA,MACxC,OAAO;AACL,aAAK,kBAAkB,OAAO,OAAO;AAAA,MACvC;AACA;AAAA,IACF;AAGA,UAAM,UAAW,MAAkC,SAAS;AAC5D,YAAQ,MAAM;AAAA,MACZ,KAAK;AACH;AAAA;AAAA,MACF,KAAK;AACH,aAAK,KAAK,iBAAiB,iBAAiB,KAAK,UAAU,OAAO,KAAK,YAAY,EAAE;AACrF;AAAA,MACF,KAAK;AACH,aAAK,KAAK,mBAAmB,OAAO;AACpC;AAAA,MACF,KAAK;AACH,aAAK,KAAK,gBAAgB,OAAO;AACjC;AAAA,MACF;AAEE;AAAA,IACJ;AAAA,EACF;AAAA;AAAA,EAGA,MAAc,aACZ,SACe;AACf,UAAM,YAAY,QAAQ;AAC1B,UAAM,eAAe,QAAQ;AAC7B,UAAM,SAAwB;AAAA,MAC5B;AAAA,MACA,cAAc,gBAAgB;AAAA,MAC9B,iBAAiB,QAAQ;AAAA,MACzB,gBAAgB,QAAQ;AAAA,MACxB,mBAAmB,QAAQ;AAAA,IAC7B;AACA,SAAK,eAAe,IAAI,WAAW,MAAM;AACzC,SAAK,gBAAgB,eAAe,MAAM;AAC1C,SAAK,KAAK,eAAe,MAAM;AAG/B,UAAM,gBAAgB,KAAK,cACvB,OACA,KAAK,gBAAgB,oBACnB,MAAM,KAAK,eAAe,kBAAkB,MAAM,IAClD;AACN,QAAI,CAAC,cAAe;AAEpB,QAAI,KAAK,aAAa;AACpB,UAAI;AACF,cAAM,KAAK,OAAO,eAAe,SAAS;AAAA,MAC5C,SAAS,KAAK;AACZ,aAAK,KAAK,iBAAiB,sBAAsB,SAAS,KAAM,IAAc,OAAO,EAAE;AACvF;AAAA,MACF;AAAA,IACF;AAGA,QAAI,cAAc;AAChB,WAAK,gBAAgB,QAAQ,WAAW,YAAY;AAAA,IACtD,OAAO;AACL,WAAK,KAAK,iBAAiB,mBAAmB,SAAS,gFAAgF;AAAA,IACzI;AAAA,EACF;AAAA;AAAA,EAGQ,kBACN,SACM;AACN,UAAM,YAAY,QAAQ;AAC1B,UAAM,eAAe,QAAQ;AAC7B,UAAM,WAAW,KAAK,eAAe,IAAI,SAAS;AAClD,UAAM,SAAwB,YAAY;AAAA,MACxC;AAAA,MACA,cAAc,gBAAgB;AAAA,IAChC;AACA,QAAI,aAAc,QAAO,eAAe;AACxC,SAAK,eAAe,IAAI,WAAW,MAAM;AACzC,SAAK,KAAK,oBAAoB,MAAM;AACpC,QAAI,cAAc;AAChB,WAAK,gBAAgB,QAAQ,WAAW,YAAY;AAAA,IACtD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqBA,MAAM,qBAAqB,WAAmB,SAAiD;AAC7F,UAAM,YAAY,KAAK,gBAAgB;AACvC,QAAI,CAAC,UAAW;AAEhB,UAAM,OAAO,QAAQ,OAAO;AAC5B,UAAM,SAAS,MAAM;AACrB,UAAM,QAAQ,QAAQ,WAAW;AACjC,UAAM,YACJ,OAAO,WAAW,WACd,SACA,OAAO,UAAU,WACf,IAAI,KAAK,KAAK,EAAE,YAAY,KAC5B,oBAAI,KAAK,GAAE,YAAY;AAE/B,UAAM,OAAO,KAAK,OAAO,IAAI,SAAS;AACtC,QAAI,QAAQ,aAAa,KAAM;AAE/B,UAAM,UAAU,KAAK,eAAe,IAAI,SAAS,KAAK,EAAE,WAAW,cAAc,GAAG;AACpF,QAAI;AACF,YAAM,UAAU,SAAS,OAAO;AAAA,IAClC,SAAS,KAAK;AAGZ,WAAK,KAAK,iBAAiB,WAAW,GAAG;AACzC;AAAA,IACF;AACA,SAAK,OAAO,IAAI,WAAW,SAAS;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,KACJ,WACA,SACiC;AAGjC,UAAM,KAAK,KAAK;AAChB,QAAI,IAAI,YAAY,SAAS,GAAG;AAC9B,YAAM,KAAK,GAAG,KAAK,WAAW,OAAO;AACrC,UAAI,GAAI,QAAO,EAAE,KAAK,KAAK;AAAA,IAC7B;AAEA,UAAM,KAAK,OAAO,mBAAmB,WAAW,OAAO;AACvD,WAAO,EAAE,KAAK,OAAO;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,WAAW,WAA4B;AACrC,UAAM,KAAK,KAAK;AAChB,QAAI,CAAC,IAAI,YAAY,SAAS,EAAG,QAAO;AACxC,UAAM,MAAM,KAAK,IAAI;AACrB,UAAM,OAAO,KAAK,eAAe,IAAI,SAAS,KAAK;AACnD,QAAI,MAAM,OAAO,IAAK,QAAO;AAC7B,SAAK,eAAe,IAAI,WAAW,GAAG;AACtC,WAAO,GAAG,KAAK,WAAW,EAAE,MAAM,kBAAkB,iBAAiB,SAAS,CAAC,EAAE,CAAC;AAAA,EACpF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBA,MAAM,iBACJ,IACA,MAOY;AACZ,QAAI,UAAU;AAEd,WAAO,KAAK,gBAAgB,UAAa,UAAU,KAAK,aAAa;AACnE,UAAI,KAAK,cAAc,EAAG,OAAM,IAAI,MAAM,WAAW;AACrD,UAAI;AACF,eAAO,MAAM,GAAG;AAAA,MAClB,SAAS,KAAK;AACZ;AACA,YAAI,KAAK,oBAAoB,GAAG,EAAG,OAAM;AACzC,YAAI,KAAK,gBAAgB,UAAa,WAAW,KAAK,YAAa,OAAM;AACzE,cAAM,QAAQ,KAAK,IAAI,KAAK,YAAY,MAAM,UAAU,IAAI,KAAK,UAAU;AAC3E,aAAK,UAAU,SAAS,KAAK,KAAK;AAClC,cAAM,IAAI,QAAQ,OAAK,WAAW,GAAG,KAAK,CAAC;AAAA,MAC7C;AAAA,IACF;AAEA,UAAM,IAAI,MAAM,6BAA6B;AAAA,EAC/C;AAAA;AAAA,EAGQ,oBAAoB,KAAuB;AACjD,QAAI,EAAE,eAAe,OAAQ,QAAO;AACpC,UAAM,IAAI,IAAI,QAAQ,MAAM,mBAAmB;AAC/C,QAAI,CAAC,EAAG,QAAO;AACf,UAAM,SAAS,OAAO,EAAE,CAAC,CAAC;AAC1B,WAAO,UAAU,OAAO,SAAS,OAAO,WAAW;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAc,oBAAmC;AAC/C,QAAI,CAAC,KAAK,QAAS;AACnB,QAAI;AACF,YAAM,KAAK;AAAA,QACT,MAAM,KAAK,OAAO,cAAc,KAAK,OAAQ;AAAA,QAC7C;AAAA,UACE,WAAW,KAAK;AAAA,UAChB,YAAY,KAAK;AAAA,UACjB,aAAa,KAAK;AAAA,UAClB,aAAa,MAAM,KAAK;AAAA,UACxB,SAAS,CAAC,GAAG,KAAK,UAAU,KAAK,KAAK,iBAAiB,sBAAsB,CAAC,YAAa,IAAc,OAAO,cAAc,KAAK,IAAI;AAAA,QACzI;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AACZ,UAAI,KAAK,SAAU;AACnB,WAAK,KAAK,2BAA2B,KAAK,SAAS,GAAG;AACtD,UAAI,CAAC,KAAK,SAAU,MAAK,sBAAsB,GAAG;AAClD;AAAA,IACF;AACA,SAAK,KAAK,mBAAmB,KAAK,OAAO;AACzC,QAAI,CAAC,KAAK,SAAU,MAAK,uBAAuB;AAAA,EAClD;AAAA,EAEQ,iBAAuB;AAC7B,QAAI,KAAK,gBAAgB;AAAE,oBAAc,KAAK,cAAc;AAAG,WAAK,iBAAiB;AAAA,IAAM;AAAA,EAC7F;AAAA,EAEA,OAAa;AACX,SAAK,WAAW;AAChB,SAAK,WAAW;AAChB,QAAI,KAAK,qBAAqB;AAAE,mBAAa,KAAK,mBAAmB;AAAG,WAAK,sBAAsB;AAAA,IAAM;AACzG,SAAK,sBAAsB,IAAI,MAAM,kBAAkB,CAAC;AACxD,SAAK,eAAe;AACpB,SAAK,gBAAgB,cAAc;AACnC,QAAI,KAAK,SAAS;AAAE,WAAK,QAAQ,MAAM,KAAM,mBAAmB;AAAG,WAAK,UAAU;AAAA,IAAM;AACxF,SAAK,eAAe,MAAM;AAC1B,SAAK,OAAO,cAAc,IAAI;AAC9B,SAAK,KAAK,SAAS;AAAA,EACrB;AACF;;;ACnmBO,IAAM,2BAA2B;","names":["readFileSync","writeFileSync","mkdirSync","existsSync","EventEmitter","WebSocket","EventEmitter","WebSocket"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clawrent/provider",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"ws": "^8.18.0",
|
|
21
|
-
"@clawrent/protocol": "0.3.
|
|
21
|
+
"@clawrent/protocol": "0.3.2",
|
|
22
22
|
"@clawrent/shared-types": "0.2.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|