@clawrent/provider 0.1.1 → 0.1.2
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 +4 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { EventEmitter } from 'node:events';
|
|
2
2
|
import WebSocket from 'ws';
|
|
3
|
+
import { GuardrailDecision } from '@clawrent/protocol';
|
|
3
4
|
|
|
4
5
|
interface ClawRentConfig {
|
|
5
6
|
apiUrl: string;
|
|
@@ -238,6 +239,8 @@ interface ActiveSession {
|
|
|
238
239
|
taskDescription?: string;
|
|
239
240
|
consumerUserId?: string;
|
|
240
241
|
slotIndex?: number;
|
|
242
|
+
/** 平台护栏决策(R3b/R1,来自 session.new 事件):block/advisory/未设置 */
|
|
243
|
+
guardrailDecision?: GuardrailDecision;
|
|
241
244
|
}
|
|
242
245
|
interface SessionSummary {
|
|
243
246
|
sessionId: string;
|
|
@@ -417,6 +420,6 @@ declare class ProviderClient extends EventEmitter {
|
|
|
417
420
|
stop(): void;
|
|
418
421
|
}
|
|
419
422
|
|
|
420
|
-
declare const PROVIDER_PACKAGE_VERSION = "0.1.
|
|
423
|
+
declare const PROVIDER_PACKAGE_VERSION = "0.1.2";
|
|
421
424
|
|
|
422
425
|
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
|
@@ -755,7 +755,8 @@ var ProviderClient = class extends EventEmitter2 {
|
|
|
755
755
|
sessionId,
|
|
756
756
|
sessionToken: sessionToken ?? "",
|
|
757
757
|
taskDescription: payload.taskDescription,
|
|
758
|
-
consumerUserId: payload.consumerUserId
|
|
758
|
+
consumerUserId: payload.consumerUserId,
|
|
759
|
+
guardrailDecision: payload.guardrailDecision
|
|
759
760
|
};
|
|
760
761
|
this.activeSessions.set(sessionId, active);
|
|
761
762
|
this.boundCallbacks?.onSessionNew?.(active);
|
|
@@ -890,7 +891,7 @@ var ProviderClient = class extends EventEmitter2 {
|
|
|
890
891
|
};
|
|
891
892
|
|
|
892
893
|
// src/index.ts
|
|
893
|
-
var PROVIDER_PACKAGE_VERSION = "0.1.
|
|
894
|
+
var PROVIDER_PACKAGE_VERSION = "0.1.2";
|
|
894
895
|
export {
|
|
895
896
|
ApiClient,
|
|
896
897
|
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\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 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 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.2';\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.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"ws": "^8.18.0",
|
|
21
|
-
"@clawrent/protocol": "0.3.
|
|
21
|
+
"@clawrent/protocol": "0.3.2",
|
|
22
22
|
"@clawrent/shared-types": "0.2.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|