@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 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.1.1";
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.client.getMyAgent();
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
- try {
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", reject);
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
- stop() {
876
- this._running = false;
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.1.1";
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":"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","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.1.1",
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.1",
21
+ "@clawrent/protocol": "0.3.2",
22
22
  "@clawrent/shared-types": "0.2.0"
23
23
  },
24
24
  "devDependencies": {