@clawrent/cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/lib.js ADDED
@@ -0,0 +1,372 @@
1
+ // src/api-client.ts
2
+ var ApiClient = class {
3
+ config;
4
+ constructor(config) {
5
+ this.config = config;
6
+ }
7
+ get apiUrl() {
8
+ return this.config.apiUrl;
9
+ }
10
+ get wsUrl() {
11
+ return this.config.wsUrl;
12
+ }
13
+ get userId() {
14
+ return this.config.userId;
15
+ }
16
+ // --- Auth (no auth needed) ---
17
+ async login(email, password) {
18
+ return this.request("POST", "/api/auth/login", { email, password }, false);
19
+ }
20
+ async getMe() {
21
+ return this.request("GET", "/api/auth/me");
22
+ }
23
+ // --- Marketplace ---
24
+ async browse(query) {
25
+ const params = new URLSearchParams();
26
+ if (query?.search) params.set("search", query.search);
27
+ if (query?.category) params.set("category", query.category);
28
+ if (query?.page) params.set("page", String(query.page));
29
+ if (query?.limit) params.set("limit", String(query.limit));
30
+ const qs = params.toString();
31
+ return this.request("GET", `/api/marketplace/browse${qs ? `?${qs}` : ""}`);
32
+ }
33
+ async getAgent(slug) {
34
+ return this.request("GET", `/api/marketplace/agents/${encodeURIComponent(slug)}`);
35
+ }
36
+ // --- Sessions ---
37
+ async rent(options) {
38
+ return this.request("POST", "/api/sessions", {
39
+ agentId: options.agentId,
40
+ taskDescription: options.taskDescription,
41
+ grantedPermissions: options.grantedPermissions ?? {}
42
+ });
43
+ }
44
+ async getSessions(query) {
45
+ const params = new URLSearchParams();
46
+ if (query?.role) params.set("role", query.role);
47
+ if (query?.status) params.set("status", query.status);
48
+ if (query?.page) params.set("page", String(query.page));
49
+ if (query?.limit) params.set("limit", String(query.limit));
50
+ const qs = params.toString();
51
+ return this.request("GET", `/api/sessions${qs ? `?${qs}` : ""}`);
52
+ }
53
+ async getSession(sessionId) {
54
+ return this.request("GET", `/api/sessions/${encodeURIComponent(sessionId)}`);
55
+ }
56
+ async getSessionMessages(sessionId) {
57
+ return this.request("GET", `/api/sessions/${encodeURIComponent(sessionId)}/messages`);
58
+ }
59
+ async endSession(sessionId) {
60
+ return this.request("POST", `/api/sessions/${encodeURIComponent(sessionId)}/end`);
61
+ }
62
+ async approveSession(sessionId) {
63
+ return this.request("POST", `/api/sessions/${encodeURIComponent(sessionId)}/approve`);
64
+ }
65
+ // --- Billing ---
66
+ async getBalance() {
67
+ return this.request("GET", "/api/billing/wallet");
68
+ }
69
+ async topUp(amount) {
70
+ return this.request("POST", "/api/billing/wallet/topup", { amount });
71
+ }
72
+ // --- Provider: Agents ---
73
+ async registerAgent(data) {
74
+ return this.request("POST", "/api/agents", data);
75
+ }
76
+ async getMyAgents(query) {
77
+ const params = new URLSearchParams();
78
+ if (query?.page) params.set("page", String(query.page));
79
+ if (query?.limit) params.set("limit", String(query.limit));
80
+ if (query?.status) params.set("status", query.status);
81
+ const qs = params.toString();
82
+ return this.request("GET", `/api/agents/my${qs ? `?${qs}` : ""}`);
83
+ }
84
+ async publishAgent(agentId) {
85
+ return this.request("POST", `/api/agents/${encodeURIComponent(agentId)}/publish`);
86
+ }
87
+ async activateAgent(agentId) {
88
+ return this.request("POST", `/api/agents/${encodeURIComponent(agentId)}/activate`);
89
+ }
90
+ async setOnlineStatus(agentId, onlineStatus) {
91
+ return this.request("PATCH", `/api/agents/${encodeURIComponent(agentId)}/status`, { onlineStatus });
92
+ }
93
+ async generateAgentToken(agentId) {
94
+ return this.request("POST", `/api/agents/${encodeURIComponent(agentId)}/token`);
95
+ }
96
+ async revokeAgentToken(agentId) {
97
+ return this.request("DELETE", `/api/agents/${encodeURIComponent(agentId)}/token`);
98
+ }
99
+ // --- Orders ---
100
+ async createOrder(data) {
101
+ return this.request("POST", "/api/orders", data);
102
+ }
103
+ async getOrders(query) {
104
+ const params = new URLSearchParams();
105
+ if (query?.status) params.set("status", query.status);
106
+ if (query?.page) params.set("page", String(query.page));
107
+ if (query?.limit) params.set("limit", String(query.limit));
108
+ const qs = params.toString();
109
+ return this.request("GET", `/api/orders${qs ? `?${qs}` : ""}`);
110
+ }
111
+ async getOrder(orderId) {
112
+ return this.request("GET", `/api/orders/${encodeURIComponent(orderId)}`);
113
+ }
114
+ async cancelOrder(orderId) {
115
+ return this.request("POST", `/api/orders/${encodeURIComponent(orderId)}/cancel`);
116
+ }
117
+ // --- Cart ---
118
+ async getCart() {
119
+ return this.request("GET", "/api/cart");
120
+ }
121
+ async addToCart(data) {
122
+ return this.request("POST", "/api/cart", data);
123
+ }
124
+ async updateCartItem(itemId, data) {
125
+ return this.request("PATCH", `/api/cart/${encodeURIComponent(itemId)}`, data);
126
+ }
127
+ async removeFromCart(itemId) {
128
+ return this.request("DELETE", `/api/cart/${encodeURIComponent(itemId)}`);
129
+ }
130
+ async clearCart() {
131
+ return this.request("DELETE", "/api/cart");
132
+ }
133
+ // --- Favorites ---
134
+ async listFavorites(query) {
135
+ const params = new URLSearchParams();
136
+ if (query?.page) params.set("page", String(query.page));
137
+ if (query?.limit) params.set("limit", String(query.limit));
138
+ const qs = params.toString();
139
+ return this.request("GET", `/api/favorites${qs ? `?${qs}` : ""}`);
140
+ }
141
+ async addFavorite(agentId) {
142
+ return this.request("POST", `/api/favorites/${encodeURIComponent(agentId)}`);
143
+ }
144
+ async removeFavorite(agentId) {
145
+ return this.request("DELETE", `/api/favorites/${encodeURIComponent(agentId)}`);
146
+ }
147
+ // --- Health ---
148
+ async health() {
149
+ return this.request("GET", "/api/health", void 0, false);
150
+ }
151
+ // --- Private ---
152
+ async request(method, path, body, requireAuth = true) {
153
+ const url = `${this.config.apiUrl}${path}`;
154
+ const headers = {};
155
+ if (body !== void 0) {
156
+ headers["Content-Type"] = "application/json";
157
+ }
158
+ if (requireAuth) {
159
+ if (this.config.token) {
160
+ headers["Authorization"] = `Bearer ${this.config.token}`;
161
+ } else if (this.config.apiKey) {
162
+ headers["x-api-key"] = this.config.apiKey;
163
+ } else {
164
+ throw new Error("Not authenticated. Run `clawrent auth login` first.");
165
+ }
166
+ }
167
+ const response = await fetch(url, {
168
+ method,
169
+ headers,
170
+ body: body ? JSON.stringify(body) : void 0
171
+ });
172
+ if (!response.ok) {
173
+ const errBody = await response.json().catch(() => ({ message: response.statusText }));
174
+ throw new Error(`API error ${response.status}: ${errBody["message"] ?? JSON.stringify(errBody)}`);
175
+ }
176
+ return response.json();
177
+ }
178
+ };
179
+
180
+ // src/config.ts
181
+ import { readFileSync, writeFileSync, mkdirSync, unlinkSync, existsSync } from "fs";
182
+ import { join } from "path";
183
+ import { homedir } from "os";
184
+ var DEFAULT_CONFIG = {
185
+ apiUrl: "http://localhost:3001",
186
+ wsUrl: "ws://localhost:3001"
187
+ };
188
+ function getConfigDir() {
189
+ return join(homedir(), ".clawrent");
190
+ }
191
+ function getConfigFilePath() {
192
+ return join(getConfigDir(), "config.json");
193
+ }
194
+ function getConfigPath() {
195
+ return getConfigFilePath();
196
+ }
197
+ function loadConfig() {
198
+ let fileConfig = {};
199
+ const configPath = getConfigFilePath();
200
+ if (existsSync(configPath)) {
201
+ try {
202
+ const raw = readFileSync(configPath, "utf-8");
203
+ fileConfig = JSON.parse(raw);
204
+ } catch {
205
+ }
206
+ }
207
+ const config = {
208
+ ...DEFAULT_CONFIG,
209
+ ...fileConfig
210
+ };
211
+ const envApiUrl = process.env["CLAWRENT_API_URL"];
212
+ const envWsUrl = process.env["CLAWRENT_WS_URL"];
213
+ const envToken = process.env["CLAWRENT_TOKEN"];
214
+ const envApiKey = process.env["CLAWRENT_API_KEY"];
215
+ const envUserId = process.env["CLAWRENT_USER_ID"];
216
+ if (envApiUrl) config.apiUrl = envApiUrl;
217
+ if (envWsUrl) config.wsUrl = envWsUrl;
218
+ if (envToken) config.token = envToken;
219
+ if (envApiKey) config.apiKey = envApiKey;
220
+ if (envUserId) config.userId = envUserId;
221
+ return config;
222
+ }
223
+ function saveConfig(partial) {
224
+ const configDir = getConfigDir();
225
+ if (!existsSync(configDir)) {
226
+ mkdirSync(configDir, { recursive: true });
227
+ }
228
+ let existing = {};
229
+ const configPath = getConfigFilePath();
230
+ if (existsSync(configPath)) {
231
+ try {
232
+ existing = JSON.parse(readFileSync(configPath, "utf-8"));
233
+ } catch {
234
+ }
235
+ }
236
+ const merged = { ...existing, ...partial };
237
+ writeFileSync(configPath, JSON.stringify(merged, null, 2), "utf-8");
238
+ }
239
+ function clearConfig() {
240
+ const configPath = getConfigFilePath();
241
+ if (existsSync(configPath)) {
242
+ unlinkSync(configPath);
243
+ }
244
+ }
245
+
246
+ // src/serve/session-manager.ts
247
+ import { EventEmitter } from "events";
248
+ import WebSocket from "ws";
249
+ var SessionManager = class extends EventEmitter {
250
+ sessions = /* @__PURE__ */ new Map();
251
+ wsUrl;
252
+ heartbeatInterval;
253
+ maxReconnectDelay;
254
+ agentId;
255
+ constructor(wsUrl, heartbeatInterval = 25e3, maxReconnectDelay = 3e4) {
256
+ super();
257
+ this.wsUrl = wsUrl;
258
+ this.heartbeatInterval = heartbeatInterval;
259
+ this.maxReconnectDelay = maxReconnectDelay;
260
+ }
261
+ /** Connect to a session via WebSocket as provider */
262
+ connect(sessionId, sessionToken) {
263
+ if (this.sessions.has(sessionId)) {
264
+ return;
265
+ }
266
+ const url = `${this.wsUrl}/ws/session?sessionId=${sessionId}&token=${sessionToken}&role=provider`;
267
+ const ws = new WebSocket(url);
268
+ const conn = {
269
+ sessionId,
270
+ sessionToken,
271
+ ws,
272
+ heartbeatTimer: null,
273
+ reconnectAttempts: 0
274
+ };
275
+ this.sessions.set(sessionId, conn);
276
+ ws.on("open", () => {
277
+ conn.reconnectAttempts = 0;
278
+ conn.heartbeatTimer = setInterval(() => {
279
+ if (ws.readyState === WebSocket.OPEN) {
280
+ ws.send(JSON.stringify({ type: "system.heartbeat", payload: {} }));
281
+ }
282
+ }, this.heartbeatInterval);
283
+ this.emit("session:connected", sessionId);
284
+ });
285
+ ws.on("message", (raw) => {
286
+ try {
287
+ const message = JSON.parse(raw.toString());
288
+ if (message["type"] === "system.heartbeat_ack") return;
289
+ this.emit("session:message", sessionId, message);
290
+ } catch {
291
+ }
292
+ });
293
+ ws.on("close", (code, reason) => {
294
+ this.clearHeartbeat(conn);
295
+ if (code !== 1e3) {
296
+ const delay = Math.min(
297
+ 1e3 * Math.pow(2, conn.reconnectAttempts),
298
+ this.maxReconnectDelay
299
+ );
300
+ conn.reconnectAttempts++;
301
+ this.emit("session:reconnecting", sessionId, delay);
302
+ setTimeout(() => {
303
+ this.sessions.delete(sessionId);
304
+ this.connect(sessionId, sessionToken);
305
+ }, delay);
306
+ } else {
307
+ this.sessions.delete(sessionId);
308
+ this.emit("session:disconnected", sessionId, reason.toString());
309
+ }
310
+ });
311
+ ws.on("error", (err) => {
312
+ this.emit("session:error", sessionId, err);
313
+ });
314
+ }
315
+ /** Send a message to a specific session, auto-wrapping with protocol envelope */
316
+ send(sessionId, message) {
317
+ const conn = this.sessions.get(sessionId);
318
+ if (!conn || conn.ws.readyState !== WebSocket.OPEN) {
319
+ return false;
320
+ }
321
+ const envelope = {
322
+ id: message["id"] ?? `msg_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`,
323
+ sessionId: message["sessionId"] ?? sessionId,
324
+ timestamp: message["timestamp"] ?? Date.now(),
325
+ sender: message["sender"] ?? { role: "provider", agentId: this.agentId ?? "unknown" },
326
+ type: message["type"] ?? "result.success",
327
+ payload: message["payload"] ?? {}
328
+ };
329
+ conn.ws.send(JSON.stringify(envelope));
330
+ return true;
331
+ }
332
+ /** Disconnect a specific session */
333
+ disconnect(sessionId) {
334
+ const conn = this.sessions.get(sessionId);
335
+ if (!conn) return;
336
+ this.clearHeartbeat(conn);
337
+ if (conn.ws.readyState === WebSocket.OPEN || conn.ws.readyState === WebSocket.CONNECTING) {
338
+ conn.ws.close(1e3, "Provider disconnecting");
339
+ }
340
+ this.sessions.delete(sessionId);
341
+ }
342
+ /** Disconnect all sessions */
343
+ disconnectAll() {
344
+ for (const sessionId of this.sessions.keys()) {
345
+ this.disconnect(sessionId);
346
+ }
347
+ }
348
+ /** Get active session count */
349
+ get activeCount() {
350
+ return this.sessions.size;
351
+ }
352
+ /** Check if a session is connected */
353
+ isConnected(sessionId) {
354
+ const conn = this.sessions.get(sessionId);
355
+ return conn?.ws.readyState === WebSocket.OPEN;
356
+ }
357
+ clearHeartbeat(conn) {
358
+ if (conn.heartbeatTimer) {
359
+ clearInterval(conn.heartbeatTimer);
360
+ conn.heartbeatTimer = null;
361
+ }
362
+ }
363
+ };
364
+ export {
365
+ ApiClient,
366
+ SessionManager,
367
+ clearConfig,
368
+ getConfigPath,
369
+ loadConfig,
370
+ saveConfig
371
+ };
372
+ //# sourceMappingURL=lib.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/api-client.ts","../src/config.ts","../src/serve/session-manager.ts"],"sourcesContent":["import type { ClawRentConfig } from './config.js';\r\n\r\nexport class ApiClient {\r\n private config: ClawRentConfig;\r\n\r\n constructor(config: ClawRentConfig) {\r\n this.config = config;\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 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(sessionId: string): Promise<unknown> {\r\n return this.request('GET', `/api/sessions/${encodeURIComponent(sessionId)}/messages`);\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; status?: 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?.status) params.set('status', query.status);\r\n const qs = params.toString();\r\n return this.request('GET', `/api/agents/my${qs ? `?${qs}` : ''}`);\r\n }\r\n\r\n async publishAgent(agentId: string): Promise<unknown> {\r\n return this.request('POST', `/api/agents/${encodeURIComponent(agentId)}/publish`);\r\n }\r\n\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 // --- 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.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: 'http://localhost:3001',\r\n wsUrl: 'ws://localhost:3001',\r\n};\r\n\r\nfunction 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 // 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\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 public agentId?: string;\r\n\r\n constructor(wsUrl: string, heartbeatInterval = 25_000, maxReconnectDelay = 30_000) {\r\n super();\r\n this.wsUrl = wsUrl;\r\n this.heartbeatInterval = heartbeatInterval;\r\n this.maxReconnectDelay = maxReconnectDelay;\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 if (code !== 1000) {\r\n // Abnormal close — try reconnect\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"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@clawrent/cli",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "main": "./dist/lib.js",
6
+ "types": "./dist/lib.d.ts",
7
+ "bin": {
8
+ "clawrent": "./dist/index.js"
9
+ },
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/lib.d.ts",
13
+ "import": "./dist/lib.js"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "publishConfig": {
20
+ "access": "public"
21
+ },
22
+ "dependencies": {
23
+ "commander": "^13.0.0",
24
+ "ws": "^8.18.0",
25
+ "@clawrent/shared-types": "0.1.0",
26
+ "@clawrent/protocol": "0.1.0"
27
+ },
28
+ "devDependencies": {
29
+ "@types/node": "^22.0.0",
30
+ "@types/ws": "^8.5.0",
31
+ "tsup": "^8.3.0",
32
+ "typescript": "^5.7.0",
33
+ "@clawrent/config": "0.1.0"
34
+ },
35
+ "scripts": {
36
+ "build": "tsup",
37
+ "dev": "tsup --watch",
38
+ "typecheck": "tsc --noEmit",
39
+ "lint": "eslint src/"
40
+ }
41
+ }