@clawrent/cli 0.4.3 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +73 -470
- package/dist/index.js.map +1 -1
- package/dist/lib.d.ts +1 -204
- package/dist/lib.js +9 -431
- package/dist/lib.js.map +1 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -1,326 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { readFileSync as
|
|
5
|
-
import { dirname, join as
|
|
4
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
5
|
+
import { dirname, join as join2 } from "path";
|
|
6
6
|
import { fileURLToPath } from "url";
|
|
7
7
|
import { Command } from "commander";
|
|
8
8
|
|
|
9
9
|
// src/commands/auth.ts
|
|
10
10
|
import { createInterface } from "readline";
|
|
11
|
-
|
|
12
|
-
// src/config.ts
|
|
13
|
-
import { readFileSync, writeFileSync, mkdirSync, unlinkSync, existsSync } from "fs";
|
|
14
|
-
import { join } from "path";
|
|
15
|
-
import { homedir } from "os";
|
|
16
|
-
var DEFAULT_CONFIG = {
|
|
17
|
-
apiUrl: "https://clawrent.cloud",
|
|
18
|
-
wsUrl: "wss://clawrent.cloud"
|
|
19
|
-
};
|
|
20
|
-
function getConfigDir() {
|
|
21
|
-
return join(homedir(), ".clawrent");
|
|
22
|
-
}
|
|
23
|
-
function getConfigFilePath() {
|
|
24
|
-
return join(getConfigDir(), "config.json");
|
|
25
|
-
}
|
|
26
|
-
function getConfigPath() {
|
|
27
|
-
return getConfigFilePath();
|
|
28
|
-
}
|
|
29
|
-
function loadConfig() {
|
|
30
|
-
let fileConfig = {};
|
|
31
|
-
const configPath = getConfigFilePath();
|
|
32
|
-
if (existsSync(configPath)) {
|
|
33
|
-
try {
|
|
34
|
-
const raw = readFileSync(configPath, "utf-8");
|
|
35
|
-
fileConfig = JSON.parse(raw);
|
|
36
|
-
} catch {
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
if (fileConfig.apiUrl?.includes("localhost") || fileConfig.wsUrl?.includes("localhost")) {
|
|
40
|
-
delete fileConfig.apiUrl;
|
|
41
|
-
delete fileConfig.wsUrl;
|
|
42
|
-
try {
|
|
43
|
-
const cleaned = { ...fileConfig };
|
|
44
|
-
writeFileSync(configPath, JSON.stringify(cleaned, null, 2), "utf-8");
|
|
45
|
-
} catch {
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
const config = {
|
|
49
|
-
...DEFAULT_CONFIG,
|
|
50
|
-
...fileConfig
|
|
51
|
-
};
|
|
52
|
-
const envApiUrl = process.env["CLAWRENT_API_URL"];
|
|
53
|
-
const envWsUrl = process.env["CLAWRENT_WS_URL"];
|
|
54
|
-
const envToken = process.env["CLAWRENT_TOKEN"];
|
|
55
|
-
const envApiKey = process.env["CLAWRENT_API_KEY"];
|
|
56
|
-
const envUserId = process.env["CLAWRENT_USER_ID"];
|
|
57
|
-
if (envApiUrl) config.apiUrl = envApiUrl;
|
|
58
|
-
if (envWsUrl) config.wsUrl = envWsUrl;
|
|
59
|
-
if (envToken) config.token = envToken;
|
|
60
|
-
if (envApiKey) config.apiKey = envApiKey;
|
|
61
|
-
if (envUserId) config.userId = envUserId;
|
|
62
|
-
return config;
|
|
63
|
-
}
|
|
64
|
-
function saveConfig(partial) {
|
|
65
|
-
const configDir = getConfigDir();
|
|
66
|
-
if (!existsSync(configDir)) {
|
|
67
|
-
mkdirSync(configDir, { recursive: true });
|
|
68
|
-
}
|
|
69
|
-
let existing = {};
|
|
70
|
-
const configPath = getConfigFilePath();
|
|
71
|
-
if (existsSync(configPath)) {
|
|
72
|
-
try {
|
|
73
|
-
existing = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
74
|
-
} catch {
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
const merged = { ...existing, ...partial };
|
|
78
|
-
writeFileSync(configPath, JSON.stringify(merged, null, 2), "utf-8");
|
|
79
|
-
}
|
|
80
|
-
function clearConfig() {
|
|
81
|
-
const configPath = getConfigFilePath();
|
|
82
|
-
if (existsSync(configPath)) {
|
|
83
|
-
unlinkSync(configPath);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// src/api-client.ts
|
|
88
|
-
var ApiClient = class {
|
|
89
|
-
config;
|
|
90
|
-
/** When set (e.g. by ProviderAgent.start), overrides config.token for REST auth. */
|
|
91
|
-
agentTokenOverride = null;
|
|
92
|
-
constructor(config) {
|
|
93
|
-
this.config = config;
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Set a token that overrides config.token for subsequent REST requests.
|
|
97
|
-
* Used by the in-process provider agent: once serving with an agentToken,
|
|
98
|
-
* provider REST calls (approve/list/end + internal autoApprove) authenticate
|
|
99
|
-
* as the agent owner via this token, so they work without a separate user
|
|
100
|
-
* JWT login. The backend's resolveAuth accepts the agt_clawrent_* prefix.
|
|
101
|
-
* Pass null to clear (e.g. on stop_serving).
|
|
102
|
-
*/
|
|
103
|
-
setAgentToken(token) {
|
|
104
|
-
this.agentTokenOverride = token;
|
|
105
|
-
}
|
|
106
|
-
get apiUrl() {
|
|
107
|
-
return this.config.apiUrl;
|
|
108
|
-
}
|
|
109
|
-
get wsUrl() {
|
|
110
|
-
return this.config.wsUrl;
|
|
111
|
-
}
|
|
112
|
-
get userId() {
|
|
113
|
-
return this.config.userId;
|
|
114
|
-
}
|
|
115
|
-
// --- Auth (no auth needed) ---
|
|
116
|
-
async sendVerification(email) {
|
|
117
|
-
return this.request("POST", "/api/auth/send-verification", { email }, false);
|
|
118
|
-
}
|
|
119
|
-
async registerUser(input) {
|
|
120
|
-
return this.request("POST", "/api/auth/register", input, false);
|
|
121
|
-
}
|
|
122
|
-
async login(email, password) {
|
|
123
|
-
return this.request("POST", "/api/auth/login", { email, password }, false);
|
|
124
|
-
}
|
|
125
|
-
async getMe() {
|
|
126
|
-
return this.request("GET", "/api/auth/me");
|
|
127
|
-
}
|
|
128
|
-
// --- Marketplace ---
|
|
129
|
-
async browse(query) {
|
|
130
|
-
const params = new URLSearchParams();
|
|
131
|
-
if (query?.search) params.set("search", query.search);
|
|
132
|
-
if (query?.category) params.set("category", query.category);
|
|
133
|
-
if (query?.page) params.set("page", String(query.page));
|
|
134
|
-
if (query?.limit) params.set("limit", String(query.limit));
|
|
135
|
-
const qs = params.toString();
|
|
136
|
-
return this.request("GET", `/api/marketplace/browse${qs ? `?${qs}` : ""}`);
|
|
137
|
-
}
|
|
138
|
-
async getAgent(slug) {
|
|
139
|
-
return this.request("GET", `/api/marketplace/agents/${encodeURIComponent(slug)}`);
|
|
140
|
-
}
|
|
141
|
-
// --- Sessions ---
|
|
142
|
-
async rent(options) {
|
|
143
|
-
return this.request("POST", "/api/sessions", {
|
|
144
|
-
agentId: options.agentId,
|
|
145
|
-
taskDescription: options.taskDescription,
|
|
146
|
-
grantedPermissions: options.grantedPermissions ?? {}
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
async getSessions(query) {
|
|
150
|
-
const params = new URLSearchParams();
|
|
151
|
-
if (query?.role) params.set("role", query.role);
|
|
152
|
-
if (query?.status) params.set("status", query.status);
|
|
153
|
-
if (query?.page) params.set("page", String(query.page));
|
|
154
|
-
if (query?.limit) params.set("limit", String(query.limit));
|
|
155
|
-
const qs = params.toString();
|
|
156
|
-
return this.request("GET", `/api/sessions${qs ? `?${qs}` : ""}`);
|
|
157
|
-
}
|
|
158
|
-
async getSession(sessionId) {
|
|
159
|
-
return this.request("GET", `/api/sessions/${encodeURIComponent(sessionId)}`);
|
|
160
|
-
}
|
|
161
|
-
async getSessionMessages(sessionId) {
|
|
162
|
-
return this.request("GET", `/api/sessions/${encodeURIComponent(sessionId)}/messages`);
|
|
163
|
-
}
|
|
164
|
-
async endSession(sessionId) {
|
|
165
|
-
return this.request("POST", `/api/sessions/${encodeURIComponent(sessionId)}/end`);
|
|
166
|
-
}
|
|
167
|
-
async approveSession(sessionId) {
|
|
168
|
-
return this.request("POST", `/api/sessions/${encodeURIComponent(sessionId)}/approve`);
|
|
169
|
-
}
|
|
170
|
-
// --- Billing ---
|
|
171
|
-
async getBalance() {
|
|
172
|
-
return this.request("GET", "/api/billing/wallet");
|
|
173
|
-
}
|
|
174
|
-
async topUp(amount) {
|
|
175
|
-
return this.request("POST", "/api/billing/wallet/topup", { amount });
|
|
176
|
-
}
|
|
177
|
-
// --- Provider: Agents ---
|
|
178
|
-
async registerAgent(data) {
|
|
179
|
-
return this.request("POST", "/api/agents", data);
|
|
180
|
-
}
|
|
181
|
-
async getMyAgents(query) {
|
|
182
|
-
const params = new URLSearchParams();
|
|
183
|
-
if (query?.page) params.set("page", String(query.page));
|
|
184
|
-
if (query?.limit) params.set("limit", String(query.limit));
|
|
185
|
-
if (query?.roles) params.set("roles", query.roles);
|
|
186
|
-
const qs = params.toString();
|
|
187
|
-
return this.request("GET", `/api/agents/my${qs ? `?${qs}` : ""}`);
|
|
188
|
-
}
|
|
189
|
-
/** Resolve the current agent from agentToken. Requires agt_clawrent_ token auth. */
|
|
190
|
-
async getMyAgent() {
|
|
191
|
-
return this.request("GET", "/api/agents/me/agent");
|
|
192
|
-
}
|
|
193
|
-
async applyProvider(agentId, data) {
|
|
194
|
-
return this.request("POST", `/api/agents/${encodeURIComponent(agentId)}/apply-provider`, data);
|
|
195
|
-
}
|
|
196
|
-
/** Publish agent — simplified apply-provider with defaults, submits for admin review */
|
|
197
|
-
async publishAgent(agentId, data) {
|
|
198
|
-
return this.request("POST", `/api/agents/${encodeURIComponent(agentId)}/publish`, data ?? {});
|
|
199
|
-
}
|
|
200
|
-
/** Activate agent — verify admin-approved + WebSocket connected, then go online */
|
|
201
|
-
async activateAgent(agentId) {
|
|
202
|
-
return this.request("POST", `/api/agents/${encodeURIComponent(agentId)}/activate`);
|
|
203
|
-
}
|
|
204
|
-
async setOnlineStatus(agentId, onlineStatus) {
|
|
205
|
-
return this.request("PATCH", `/api/agents/${encodeURIComponent(agentId)}/status`, { onlineStatus });
|
|
206
|
-
}
|
|
207
|
-
async generateAgentToken(agentId) {
|
|
208
|
-
return this.request("POST", `/api/agents/${encodeURIComponent(agentId)}/token`);
|
|
209
|
-
}
|
|
210
|
-
async revokeAgentToken(agentId) {
|
|
211
|
-
return this.request("DELETE", `/api/agents/${encodeURIComponent(agentId)}/token`);
|
|
212
|
-
}
|
|
213
|
-
// --- Orders ---
|
|
214
|
-
async createOrder(data) {
|
|
215
|
-
return this.request("POST", "/api/orders", data);
|
|
216
|
-
}
|
|
217
|
-
async getOrders(query) {
|
|
218
|
-
const params = new URLSearchParams();
|
|
219
|
-
if (query?.status) params.set("status", query.status);
|
|
220
|
-
if (query?.page) params.set("page", String(query.page));
|
|
221
|
-
if (query?.limit) params.set("limit", String(query.limit));
|
|
222
|
-
const qs = params.toString();
|
|
223
|
-
return this.request("GET", `/api/orders${qs ? `?${qs}` : ""}`);
|
|
224
|
-
}
|
|
225
|
-
async getOrder(orderId) {
|
|
226
|
-
return this.request("GET", `/api/orders/${encodeURIComponent(orderId)}`);
|
|
227
|
-
}
|
|
228
|
-
async cancelOrder(orderId) {
|
|
229
|
-
return this.request("POST", `/api/orders/${encodeURIComponent(orderId)}/cancel`);
|
|
230
|
-
}
|
|
231
|
-
// --- Cart ---
|
|
232
|
-
async getCart() {
|
|
233
|
-
return this.request("GET", "/api/cart");
|
|
234
|
-
}
|
|
235
|
-
async addToCart(data) {
|
|
236
|
-
return this.request("POST", "/api/cart", data);
|
|
237
|
-
}
|
|
238
|
-
async updateCartItem(itemId, data) {
|
|
239
|
-
return this.request("PATCH", `/api/cart/${encodeURIComponent(itemId)}`, data);
|
|
240
|
-
}
|
|
241
|
-
async removeFromCart(itemId) {
|
|
242
|
-
return this.request("DELETE", `/api/cart/${encodeURIComponent(itemId)}`);
|
|
243
|
-
}
|
|
244
|
-
async clearCart() {
|
|
245
|
-
return this.request("DELETE", "/api/cart");
|
|
246
|
-
}
|
|
247
|
-
// --- Favorites ---
|
|
248
|
-
async listFavorites(query) {
|
|
249
|
-
const params = new URLSearchParams();
|
|
250
|
-
if (query?.page) params.set("page", String(query.page));
|
|
251
|
-
if (query?.limit) params.set("limit", String(query.limit));
|
|
252
|
-
const qs = params.toString();
|
|
253
|
-
return this.request("GET", `/api/favorites${qs ? `?${qs}` : ""}`);
|
|
254
|
-
}
|
|
255
|
-
async addFavorite(agentId) {
|
|
256
|
-
return this.request("POST", `/api/favorites/${encodeURIComponent(agentId)}`);
|
|
257
|
-
}
|
|
258
|
-
async removeFavorite(agentId) {
|
|
259
|
-
return this.request("DELETE", `/api/favorites/${encodeURIComponent(agentId)}`);
|
|
260
|
-
}
|
|
261
|
-
// --- Health ---
|
|
262
|
-
async health() {
|
|
263
|
-
return this.request("GET", "/api/health", void 0, false);
|
|
264
|
-
}
|
|
265
|
-
// --- Docs (MCP interface) ---
|
|
266
|
-
async getDocsTree() {
|
|
267
|
-
return this.request("GET", "/api/mcp/docs/tree", void 0, false);
|
|
268
|
-
}
|
|
269
|
-
async getDocByPath(path) {
|
|
270
|
-
return this.request("GET", `/api/mcp/docs/by-path/${encodeURI(path)}`, void 0, false);
|
|
271
|
-
}
|
|
272
|
-
async searchDocs(query) {
|
|
273
|
-
const params = new URLSearchParams({ q: query });
|
|
274
|
-
return this.request("GET", `/api/mcp/docs/search?${params.toString()}`, void 0, false);
|
|
275
|
-
}
|
|
276
|
-
async getDoc(id) {
|
|
277
|
-
return this.request("GET", `/api/mcp/docs/${encodeURIComponent(id)}`, void 0, false);
|
|
278
|
-
}
|
|
279
|
-
async createDoc(data) {
|
|
280
|
-
return this.request("POST", "/api/mcp/docs", data);
|
|
281
|
-
}
|
|
282
|
-
async updateDoc(id, data) {
|
|
283
|
-
return this.request("PATCH", `/api/mcp/docs/${encodeURIComponent(id)}`, data);
|
|
284
|
-
}
|
|
285
|
-
async deleteDoc(id) {
|
|
286
|
-
return this.request("DELETE", `/api/mcp/docs/${encodeURIComponent(id)}`);
|
|
287
|
-
}
|
|
288
|
-
async publishDoc(id) {
|
|
289
|
-
return this.request("POST", `/api/mcp/docs/${encodeURIComponent(id)}/publish`);
|
|
290
|
-
}
|
|
291
|
-
async unpublishDoc(id) {
|
|
292
|
-
return this.request("POST", `/api/mcp/docs/${encodeURIComponent(id)}/unpublish`);
|
|
293
|
-
}
|
|
294
|
-
// --- Private ---
|
|
295
|
-
async request(method, path, body, requireAuth = true) {
|
|
296
|
-
const url = `${this.config.apiUrl}${path}`;
|
|
297
|
-
const headers = {};
|
|
298
|
-
if (body !== void 0) {
|
|
299
|
-
headers["Content-Type"] = "application/json";
|
|
300
|
-
}
|
|
301
|
-
if (requireAuth) {
|
|
302
|
-
if (this.agentTokenOverride) {
|
|
303
|
-
headers["Authorization"] = `Bearer ${this.agentTokenOverride}`;
|
|
304
|
-
} else if (this.config.token) {
|
|
305
|
-
headers["Authorization"] = `Bearer ${this.config.token}`;
|
|
306
|
-
} else if (this.config.apiKey) {
|
|
307
|
-
headers["x-api-key"] = this.config.apiKey;
|
|
308
|
-
} else {
|
|
309
|
-
throw new Error("Not authenticated. Run `clawrent auth login` first.");
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
const response = await fetch(url, {
|
|
313
|
-
method,
|
|
314
|
-
headers,
|
|
315
|
-
body: body ? JSON.stringify(body) : void 0
|
|
316
|
-
});
|
|
317
|
-
if (!response.ok) {
|
|
318
|
-
const errBody = await response.json().catch(() => ({ message: response.statusText }));
|
|
319
|
-
throw new Error(`API error ${response.status}: ${errBody["message"] ?? JSON.stringify(errBody)}`);
|
|
320
|
-
}
|
|
321
|
-
return response.json();
|
|
322
|
-
}
|
|
323
|
-
};
|
|
11
|
+
import { ApiClient, loadConfig, saveConfig, clearConfig, getConfigPath } from "@clawrent/provider";
|
|
324
12
|
|
|
325
13
|
// src/output.ts
|
|
326
14
|
function printJson(data) {
|
|
@@ -487,10 +175,11 @@ function registerAuthCommand(program2) {
|
|
|
487
175
|
}
|
|
488
176
|
|
|
489
177
|
// src/commands/browse.ts
|
|
178
|
+
import { ApiClient as ApiClient2, loadConfig as loadConfig2 } from "@clawrent/provider";
|
|
490
179
|
function registerBrowseCommand(program2) {
|
|
491
180
|
program2.command("browse").description("Browse available agents on the marketplace").option("-s, --search <query>", "Search by name").option("-c, --category <category>", "Filter by category").option("-p, --page <number>", "Page number", "1").option("-l, --limit <number>", "Results per page", "20").action(async (opts) => {
|
|
492
181
|
try {
|
|
493
|
-
const client = new
|
|
182
|
+
const client = new ApiClient2(loadConfig2());
|
|
494
183
|
const result = await client.browse({
|
|
495
184
|
search: opts.search,
|
|
496
185
|
category: opts.category,
|
|
@@ -506,10 +195,11 @@ function registerBrowseCommand(program2) {
|
|
|
506
195
|
}
|
|
507
196
|
|
|
508
197
|
// src/commands/agent.ts
|
|
198
|
+
import { ApiClient as ApiClient3, loadConfig as loadConfig3 } from "@clawrent/provider";
|
|
509
199
|
function registerAgentCommand(program2) {
|
|
510
200
|
program2.command("agent <slug>").description("Get agent details by slug").action(async (slug) => {
|
|
511
201
|
try {
|
|
512
|
-
const client = new
|
|
202
|
+
const client = new ApiClient3(loadConfig3());
|
|
513
203
|
const result = await client.getAgent(slug);
|
|
514
204
|
printJson(result);
|
|
515
205
|
} catch (err) {
|
|
@@ -520,10 +210,11 @@ function registerAgentCommand(program2) {
|
|
|
520
210
|
}
|
|
521
211
|
|
|
522
212
|
// src/commands/sessions.ts
|
|
213
|
+
import { ApiClient as ApiClient4, loadConfig as loadConfig4 } from "@clawrent/provider";
|
|
523
214
|
function registerSessionsCommand(program2) {
|
|
524
215
|
program2.command("sessions").description("List your sessions").option("-r, --role <role>", "Filter by role (consumer/provider)").option("-s, --status <status>", "Filter by status").option("-p, --page <number>", "Page number", "1").option("-l, --limit <number>", "Results per page", "20").action(async (opts) => {
|
|
525
216
|
try {
|
|
526
|
-
const client = new
|
|
217
|
+
const client = new ApiClient4(loadConfig4());
|
|
527
218
|
const result = await client.getSessions({
|
|
528
219
|
role: opts.role,
|
|
529
220
|
status: opts.status,
|
|
@@ -539,10 +230,11 @@ function registerSessionsCommand(program2) {
|
|
|
539
230
|
}
|
|
540
231
|
|
|
541
232
|
// src/commands/balance.ts
|
|
233
|
+
import { ApiClient as ApiClient5, loadConfig as loadConfig5 } from "@clawrent/provider";
|
|
542
234
|
function registerBalanceCommand(program2) {
|
|
543
235
|
program2.command("balance").description("Check wallet balance").action(async () => {
|
|
544
236
|
try {
|
|
545
|
-
const client = new
|
|
237
|
+
const client = new ApiClient5(loadConfig5());
|
|
546
238
|
const result = await client.getBalance();
|
|
547
239
|
printJson(result);
|
|
548
240
|
} catch (err) {
|
|
@@ -553,10 +245,11 @@ function registerBalanceCommand(program2) {
|
|
|
553
245
|
}
|
|
554
246
|
|
|
555
247
|
// src/commands/topup.ts
|
|
248
|
+
import { ApiClient as ApiClient6, loadConfig as loadConfig6 } from "@clawrent/provider";
|
|
556
249
|
function registerTopupCommand(program2) {
|
|
557
250
|
program2.command("topup <amount>").description("Top up wallet balance").action(async (amount) => {
|
|
558
251
|
try {
|
|
559
|
-
const client = new
|
|
252
|
+
const client = new ApiClient6(loadConfig6());
|
|
560
253
|
const result = await client.topUp(amount);
|
|
561
254
|
printJson(result);
|
|
562
255
|
} catch (err) {
|
|
@@ -567,10 +260,11 @@ function registerTopupCommand(program2) {
|
|
|
567
260
|
}
|
|
568
261
|
|
|
569
262
|
// src/commands/health.ts
|
|
263
|
+
import { ApiClient as ApiClient7, loadConfig as loadConfig7 } from "@clawrent/provider";
|
|
570
264
|
function registerHealthCommand(program2) {
|
|
571
265
|
program2.command("health").description("Check platform health").action(async () => {
|
|
572
266
|
try {
|
|
573
|
-
const client = new
|
|
267
|
+
const client = new ApiClient7(loadConfig7());
|
|
574
268
|
const result = await client.health();
|
|
575
269
|
printJson(result);
|
|
576
270
|
} catch (err) {
|
|
@@ -581,6 +275,7 @@ function registerHealthCommand(program2) {
|
|
|
581
275
|
}
|
|
582
276
|
|
|
583
277
|
// src/commands/rent.ts
|
|
278
|
+
import { ApiClient as ApiClient8, loadConfig as loadConfig8 } from "@clawrent/provider";
|
|
584
279
|
function registerRentCommand(program2) {
|
|
585
280
|
program2.command("rent").description("Rent an agent (create a session)").requiredOption("--agent-id <id>", "Agent ID to rent").requiredOption("--task <description>", "Task description").option("--permissions <json>", "Granted permissions as JSON string", "{}").action(async (opts) => {
|
|
586
281
|
try {
|
|
@@ -591,7 +286,7 @@ function registerRentCommand(program2) {
|
|
|
591
286
|
printError("Invalid JSON for --permissions");
|
|
592
287
|
process.exit(1);
|
|
593
288
|
}
|
|
594
|
-
const client = new
|
|
289
|
+
const client = new ApiClient8(loadConfig8());
|
|
595
290
|
const result = await client.rent({
|
|
596
291
|
agentId: opts.agentId,
|
|
597
292
|
taskDescription: opts.task,
|
|
@@ -606,10 +301,11 @@ function registerRentCommand(program2) {
|
|
|
606
301
|
}
|
|
607
302
|
|
|
608
303
|
// src/commands/end.ts
|
|
304
|
+
import { ApiClient as ApiClient9, loadConfig as loadConfig9 } from "@clawrent/provider";
|
|
609
305
|
function registerEndCommand(program2) {
|
|
610
306
|
program2.command("end <sessionId>").description("End a session").action(async (sessionId) => {
|
|
611
307
|
try {
|
|
612
|
-
const client = new
|
|
308
|
+
const client = new ApiClient9(loadConfig9());
|
|
613
309
|
const result = await client.endSession(sessionId);
|
|
614
310
|
printJson(result);
|
|
615
311
|
} catch (err) {
|
|
@@ -621,11 +317,12 @@ function registerEndCommand(program2) {
|
|
|
621
317
|
|
|
622
318
|
// src/commands/send.ts
|
|
623
319
|
import WebSocket from "ws";
|
|
320
|
+
import { ApiClient as ApiClient10, loadConfig as loadConfig10 } from "@clawrent/provider";
|
|
624
321
|
function registerSendCommand(program2) {
|
|
625
322
|
program2.command("send <sessionId>").description("Send a message to a session via WebSocket").requiredOption("--content <text>", "Message content").option("--type <messageType>", "Message type", "dialogue.message").option("--token <sessionToken>", "Session token (auto-fetched if not provided)").option("--slot <index>", "Slot index for consumer role (default: 0)", "0").option("--wait <ms>", "Wait for response (milliseconds)").action(async (sessionId, opts) => {
|
|
626
323
|
try {
|
|
627
|
-
const config =
|
|
628
|
-
const client = new
|
|
324
|
+
const config = loadConfig10();
|
|
325
|
+
const client = new ApiClient10(config);
|
|
629
326
|
let sessionToken = opts.token;
|
|
630
327
|
let role = "consumer";
|
|
631
328
|
if (!sessionToken) {
|
|
@@ -700,6 +397,7 @@ function registerSendCommand(program2) {
|
|
|
700
397
|
}
|
|
701
398
|
|
|
702
399
|
// src/commands/provider/index.ts
|
|
400
|
+
import { ApiClient as ApiClient11, loadConfig as loadConfig11 } from "@clawrent/provider";
|
|
703
401
|
function registerProviderCommands(program2) {
|
|
704
402
|
const provider = program2.command("provider").description("Provider operations");
|
|
705
403
|
const agent = provider.command("agent").description("Manage your agents");
|
|
@@ -727,7 +425,7 @@ function registerProviderCommands(program2) {
|
|
|
727
425
|
process.exit(1);
|
|
728
426
|
}
|
|
729
427
|
}
|
|
730
|
-
const client = new
|
|
428
|
+
const client = new ApiClient11(loadConfig11());
|
|
731
429
|
const result = await client.registerAgent(data);
|
|
732
430
|
printJson(result);
|
|
733
431
|
} catch (err) {
|
|
@@ -737,7 +435,7 @@ function registerProviderCommands(program2) {
|
|
|
737
435
|
});
|
|
738
436
|
agent.command("list").description("List your agents").option("-r, --roles <roles>", "Filter by roles (consumer, both)").option("-p, --page <number>", "Page number", "1").option("-l, --limit <number>", "Results per page", "20").action(async (opts) => {
|
|
739
437
|
try {
|
|
740
|
-
const client = new
|
|
438
|
+
const client = new ApiClient11(loadConfig11());
|
|
741
439
|
const result = await client.getMyAgents({
|
|
742
440
|
roles: opts.roles,
|
|
743
441
|
page: parseInt(opts.page, 10),
|
|
@@ -751,7 +449,7 @@ function registerProviderCommands(program2) {
|
|
|
751
449
|
});
|
|
752
450
|
agent.command("apply-provider <agentId>").description("Apply for provider role on an agent").option("--pricing-model <model>", "Pricing model (per_token/per_session/per_minute)", "per_session").option("--price <amount>", "Price amount", "1.00").option("--currency <cur>", "Currency (CNY/USD)", "CNY").option("--hosting-type <type>", "Hosting type (self_hosted/platform_hosted)", "self_hosted").option("--approval-mode <mode>", "Session approval mode (manual/auto)", "manual").option("--max-concurrent <n>", "Max concurrent sessions", "5").option("--max-slots <n>", "Max consumer slots per session", "1").action(async (agentId, opts) => {
|
|
753
451
|
try {
|
|
754
|
-
const client = new
|
|
452
|
+
const client = new ApiClient11(loadConfig11());
|
|
755
453
|
const result = await client.applyProvider(agentId, {
|
|
756
454
|
pricingModel: opts.pricingModel,
|
|
757
455
|
priceAmount: opts.price,
|
|
@@ -770,7 +468,7 @@ function registerProviderCommands(program2) {
|
|
|
770
468
|
});
|
|
771
469
|
agent.command("status <agentId>").description("Set agent online status").requiredOption("--status <status>", "Online status (online/offline/busy)").action(async (agentId, opts) => {
|
|
772
470
|
try {
|
|
773
|
-
const client = new
|
|
471
|
+
const client = new ApiClient11(loadConfig11());
|
|
774
472
|
const result = await client.setOnlineStatus(agentId, opts.status);
|
|
775
473
|
printSuccess(`Agent status set to ${opts.status}.`);
|
|
776
474
|
printJson(result);
|
|
@@ -781,7 +479,7 @@ function registerProviderCommands(program2) {
|
|
|
781
479
|
});
|
|
782
480
|
provider.command("sessions").description("List provider sessions").option("-s, --status <status>", "Filter by status").option("-p, --page <number>", "Page number", "1").option("-l, --limit <number>", "Results per page", "20").action(async (opts) => {
|
|
783
481
|
try {
|
|
784
|
-
const client = new
|
|
482
|
+
const client = new ApiClient11(loadConfig11());
|
|
785
483
|
const result = await client.getSessions({
|
|
786
484
|
role: "provider",
|
|
787
485
|
status: opts.status,
|
|
@@ -796,7 +494,7 @@ function registerProviderCommands(program2) {
|
|
|
796
494
|
});
|
|
797
495
|
provider.command("approve <sessionId>").description("Approve a pending session").action(async (sessionId) => {
|
|
798
496
|
try {
|
|
799
|
-
const client = new
|
|
497
|
+
const client = new ApiClient11(loadConfig11());
|
|
800
498
|
const result = await client.approveSession(sessionId);
|
|
801
499
|
printSuccess("Session approved.");
|
|
802
500
|
printJson(result);
|
|
@@ -808,21 +506,23 @@ function registerProviderCommands(program2) {
|
|
|
808
506
|
}
|
|
809
507
|
|
|
810
508
|
// src/serve/index.ts
|
|
811
|
-
import
|
|
509
|
+
import WebSocket2 from "ws";
|
|
510
|
+
import { ApiClient as ApiClient12, loadConfig as loadConfig12, SessionManager, resumeActiveSessions } from "@clawrent/provider";
|
|
812
511
|
|
|
813
512
|
// src/daemon.ts
|
|
814
|
-
import { readFileSync
|
|
815
|
-
import { join
|
|
513
|
+
import { readFileSync, writeFileSync, unlinkSync, openSync, closeSync, mkdirSync, existsSync, readdirSync } from "fs";
|
|
514
|
+
import { join, basename } from "path";
|
|
816
515
|
import { spawn } from "child_process";
|
|
516
|
+
import { getConfigDir } from "@clawrent/provider";
|
|
817
517
|
function getPidFilePath(agentId) {
|
|
818
|
-
return
|
|
518
|
+
return join(getConfigDir(), `serve-${agentId}.pid`);
|
|
819
519
|
}
|
|
820
520
|
function getLogFilePath(agentId) {
|
|
821
|
-
return
|
|
521
|
+
return join(getConfigDir(), `serve-${agentId}.log`);
|
|
822
522
|
}
|
|
823
523
|
function readPid(agentId) {
|
|
824
524
|
try {
|
|
825
|
-
const content =
|
|
525
|
+
const content = readFileSync(getPidFilePath(agentId), "utf-8").trim();
|
|
826
526
|
const pid = parseInt(content, 10);
|
|
827
527
|
return Number.isFinite(pid) && pid > 0 ? pid : null;
|
|
828
528
|
} catch {
|
|
@@ -831,14 +531,14 @@ function readPid(agentId) {
|
|
|
831
531
|
}
|
|
832
532
|
function writePid(agentId, pid) {
|
|
833
533
|
const dir = getConfigDir();
|
|
834
|
-
if (!
|
|
835
|
-
|
|
534
|
+
if (!existsSync(dir)) {
|
|
535
|
+
mkdirSync(dir, { recursive: true });
|
|
836
536
|
}
|
|
837
|
-
|
|
537
|
+
writeFileSync(getPidFilePath(agentId), String(pid), "utf-8");
|
|
838
538
|
}
|
|
839
539
|
function removePidFile(agentId) {
|
|
840
540
|
try {
|
|
841
|
-
|
|
541
|
+
unlinkSync(getPidFilePath(agentId));
|
|
842
542
|
} catch {
|
|
843
543
|
}
|
|
844
544
|
}
|
|
@@ -861,7 +561,7 @@ function isDaemonRunning(agentId) {
|
|
|
861
561
|
}
|
|
862
562
|
function listRunningDaemons() {
|
|
863
563
|
const dir = getConfigDir();
|
|
864
|
-
if (!
|
|
564
|
+
if (!existsSync(dir)) return [];
|
|
865
565
|
const results = [];
|
|
866
566
|
for (const file of readdirSync(dir)) {
|
|
867
567
|
const match = /^serve-(.+)\.pid$/.exec(basename(file));
|
|
@@ -877,8 +577,8 @@ function listRunningDaemons() {
|
|
|
877
577
|
function spawnDaemon(agentId, args) {
|
|
878
578
|
const logFile = getLogFilePath(agentId);
|
|
879
579
|
const dir = getConfigDir();
|
|
880
|
-
if (!
|
|
881
|
-
|
|
580
|
+
if (!existsSync(dir)) {
|
|
581
|
+
mkdirSync(dir, { recursive: true });
|
|
882
582
|
}
|
|
883
583
|
const logFd = openSync(logFile, "a");
|
|
884
584
|
const child = spawn(process.argv[0], [process.argv[1], ...args], {
|
|
@@ -950,125 +650,6 @@ var StdioBridge = class {
|
|
|
950
650
|
}
|
|
951
651
|
};
|
|
952
652
|
|
|
953
|
-
// src/serve/session-manager.ts
|
|
954
|
-
import { EventEmitter } from "events";
|
|
955
|
-
import WebSocket2 from "ws";
|
|
956
|
-
var SessionManager = class extends EventEmitter {
|
|
957
|
-
sessions = /* @__PURE__ */ new Map();
|
|
958
|
-
wsUrl;
|
|
959
|
-
heartbeatInterval;
|
|
960
|
-
maxReconnectDelay;
|
|
961
|
-
agentId;
|
|
962
|
-
constructor(wsUrl, heartbeatInterval = 25e3, maxReconnectDelay = 3e4) {
|
|
963
|
-
super();
|
|
964
|
-
this.wsUrl = wsUrl;
|
|
965
|
-
this.heartbeatInterval = heartbeatInterval;
|
|
966
|
-
this.maxReconnectDelay = maxReconnectDelay;
|
|
967
|
-
}
|
|
968
|
-
/** Connect to a session via WebSocket as provider */
|
|
969
|
-
connect(sessionId, sessionToken) {
|
|
970
|
-
if (this.sessions.has(sessionId)) {
|
|
971
|
-
return;
|
|
972
|
-
}
|
|
973
|
-
const url = `${this.wsUrl}/ws/session?sessionId=${sessionId}&token=${sessionToken}&role=provider`;
|
|
974
|
-
const ws = new WebSocket2(url);
|
|
975
|
-
const conn = {
|
|
976
|
-
sessionId,
|
|
977
|
-
sessionToken,
|
|
978
|
-
ws,
|
|
979
|
-
heartbeatTimer: null,
|
|
980
|
-
reconnectAttempts: 0
|
|
981
|
-
};
|
|
982
|
-
this.sessions.set(sessionId, conn);
|
|
983
|
-
ws.on("open", () => {
|
|
984
|
-
conn.reconnectAttempts = 0;
|
|
985
|
-
conn.heartbeatTimer = setInterval(() => {
|
|
986
|
-
if (ws.readyState === WebSocket2.OPEN) {
|
|
987
|
-
ws.send(JSON.stringify({ type: "system.heartbeat", payload: {} }));
|
|
988
|
-
}
|
|
989
|
-
}, this.heartbeatInterval);
|
|
990
|
-
this.emit("session:connected", sessionId);
|
|
991
|
-
});
|
|
992
|
-
ws.on("message", (raw) => {
|
|
993
|
-
try {
|
|
994
|
-
const message = JSON.parse(raw.toString());
|
|
995
|
-
if (message["type"] === "system.heartbeat_ack") return;
|
|
996
|
-
this.emit("session:message", sessionId, message);
|
|
997
|
-
} catch {
|
|
998
|
-
}
|
|
999
|
-
});
|
|
1000
|
-
ws.on("close", (code, reason) => {
|
|
1001
|
-
this.clearHeartbeat(conn);
|
|
1002
|
-
if (code !== 1e3) {
|
|
1003
|
-
const delay = Math.min(
|
|
1004
|
-
1e3 * Math.pow(2, conn.reconnectAttempts),
|
|
1005
|
-
this.maxReconnectDelay
|
|
1006
|
-
);
|
|
1007
|
-
conn.reconnectAttempts++;
|
|
1008
|
-
this.emit("session:reconnecting", sessionId, delay);
|
|
1009
|
-
setTimeout(() => {
|
|
1010
|
-
this.sessions.delete(sessionId);
|
|
1011
|
-
this.connect(sessionId, sessionToken);
|
|
1012
|
-
}, delay);
|
|
1013
|
-
} else {
|
|
1014
|
-
this.sessions.delete(sessionId);
|
|
1015
|
-
this.emit("session:disconnected", sessionId, reason.toString());
|
|
1016
|
-
}
|
|
1017
|
-
});
|
|
1018
|
-
ws.on("error", (err) => {
|
|
1019
|
-
this.emit("session:error", sessionId, err);
|
|
1020
|
-
});
|
|
1021
|
-
}
|
|
1022
|
-
/** Send a message to a specific session, auto-wrapping with protocol envelope */
|
|
1023
|
-
send(sessionId, message) {
|
|
1024
|
-
const conn = this.sessions.get(sessionId);
|
|
1025
|
-
if (!conn || conn.ws.readyState !== WebSocket2.OPEN) {
|
|
1026
|
-
return false;
|
|
1027
|
-
}
|
|
1028
|
-
const envelope = {
|
|
1029
|
-
id: message["id"] ?? `msg_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`,
|
|
1030
|
-
sessionId: message["sessionId"] ?? sessionId,
|
|
1031
|
-
timestamp: message["timestamp"] ?? Date.now(),
|
|
1032
|
-
sender: message["sender"] ?? { role: "provider", agentId: this.agentId ?? "unknown" },
|
|
1033
|
-
type: message["type"] ?? "result.success",
|
|
1034
|
-
payload: message["payload"] ?? {}
|
|
1035
|
-
};
|
|
1036
|
-
conn.ws.send(JSON.stringify(envelope));
|
|
1037
|
-
return true;
|
|
1038
|
-
}
|
|
1039
|
-
/** Disconnect a specific session */
|
|
1040
|
-
disconnect(sessionId) {
|
|
1041
|
-
const conn = this.sessions.get(sessionId);
|
|
1042
|
-
if (!conn) return;
|
|
1043
|
-
this.clearHeartbeat(conn);
|
|
1044
|
-
if (conn.ws.readyState === WebSocket2.OPEN || conn.ws.readyState === WebSocket2.CONNECTING) {
|
|
1045
|
-
conn.ws.close(1e3, "Provider disconnecting");
|
|
1046
|
-
}
|
|
1047
|
-
this.sessions.delete(sessionId);
|
|
1048
|
-
}
|
|
1049
|
-
/** Disconnect all sessions */
|
|
1050
|
-
disconnectAll() {
|
|
1051
|
-
for (const sessionId of this.sessions.keys()) {
|
|
1052
|
-
this.disconnect(sessionId);
|
|
1053
|
-
}
|
|
1054
|
-
}
|
|
1055
|
-
/** Get active session count */
|
|
1056
|
-
get activeCount() {
|
|
1057
|
-
return this.sessions.size;
|
|
1058
|
-
}
|
|
1059
|
-
/** Check if a session is connected */
|
|
1060
|
-
isConnected(sessionId) {
|
|
1061
|
-
const conn = this.sessions.get(sessionId);
|
|
1062
|
-
return conn?.ws.readyState === WebSocket2.OPEN;
|
|
1063
|
-
}
|
|
1064
|
-
clearHeartbeat(conn) {
|
|
1065
|
-
if (conn.heartbeatTimer) {
|
|
1066
|
-
clearInterval(conn.heartbeatTimer);
|
|
1067
|
-
conn.heartbeatTimer = null;
|
|
1068
|
-
}
|
|
1069
|
-
}
|
|
1070
|
-
};
|
|
1071
|
-
|
|
1072
653
|
// src/serve/protocol.ts
|
|
1073
654
|
var correlationCounter = 0;
|
|
1074
655
|
function createCorrelationId() {
|
|
@@ -1089,9 +670,9 @@ function registerServeCommand(program2) {
|
|
|
1089
670
|
program2.command("serve").description("Start serve daemon - bridge WebSocket sessions to stdin/stdout").requiredOption("--agent-token <token>", "Agent token (agt_clawrent_*) for authentication").option("--auto-approve", "Automatically approve incoming sessions", false).option("--poll-interval <ms>", "Polling interval for pending sessions (ms)", "5000").option("-d, --daemon", "Run in background as a daemon process", false).action(async (opts) => {
|
|
1090
671
|
try {
|
|
1091
672
|
if (opts.daemon) {
|
|
1092
|
-
const config =
|
|
673
|
+
const config = loadConfig12();
|
|
1093
674
|
config.token = opts.agentToken;
|
|
1094
|
-
const client = new
|
|
675
|
+
const client = new ApiClient12(config);
|
|
1095
676
|
let agentId;
|
|
1096
677
|
try {
|
|
1097
678
|
const agent = await client.getMyAgent();
|
|
@@ -1122,9 +703,9 @@ Logs: ${getLogFilePath(agentId)}`);
|
|
|
1122
703
|
});
|
|
1123
704
|
}
|
|
1124
705
|
async function runDaemon(opts) {
|
|
1125
|
-
const config =
|
|
706
|
+
const config = loadConfig12();
|
|
1126
707
|
config.token = opts.agentToken;
|
|
1127
|
-
const client = new
|
|
708
|
+
const client = new ApiClient12(config);
|
|
1128
709
|
const bridge = new StdioBridge();
|
|
1129
710
|
const sessionManager = new SessionManager(config.wsUrl);
|
|
1130
711
|
const pollInterval = parseInt(opts.pollInterval, 10);
|
|
@@ -1233,11 +814,11 @@ async function runDaemon(opts) {
|
|
|
1233
814
|
function connectAgentWs(token) {
|
|
1234
815
|
const wsBase = config.wsUrl ?? config.apiUrl.replace(/^http/, "ws");
|
|
1235
816
|
const url = `${wsBase}/ws/agent?token=${token}`;
|
|
1236
|
-
agentWs = new
|
|
817
|
+
agentWs = new WebSocket2(url);
|
|
1237
818
|
agentWs.on("open", () => {
|
|
1238
819
|
bridge.writeNotification("agent.connected", { agentId });
|
|
1239
820
|
agentHeartbeatTimer = setInterval(() => {
|
|
1240
|
-
if (agentWs && agentWs.readyState ===
|
|
821
|
+
if (agentWs && agentWs.readyState === WebSocket2.OPEN) {
|
|
1241
822
|
agentWs.send(JSON.stringify({ type: "system.heartbeat", payload: {} }));
|
|
1242
823
|
}
|
|
1243
824
|
}, 25e3);
|
|
@@ -1326,6 +907,28 @@ async function runDaemon(opts) {
|
|
|
1326
907
|
}, pollInterval);
|
|
1327
908
|
}
|
|
1328
909
|
connectAgentWs(opts.agentToken);
|
|
910
|
+
void (async () => {
|
|
911
|
+
try {
|
|
912
|
+
const resumed = await resumeActiveSessions(client, sessionManager);
|
|
913
|
+
for (const s of resumed) {
|
|
914
|
+
if (activeSessions.has(s.sessionId) || knownPendingSessions.has(s.sessionId)) continue;
|
|
915
|
+
activeSessions.add(s.sessionId);
|
|
916
|
+
knownPendingSessions.add(s.sessionId);
|
|
917
|
+
bridge.writeNotification("session.new", {
|
|
918
|
+
sessionId: s.sessionId,
|
|
919
|
+
sessionToken: s.sessionToken,
|
|
920
|
+
taskDescription: s.taskDescription ?? "",
|
|
921
|
+
consumerUserId: s.consumerUserId ?? "",
|
|
922
|
+
slotIndex: s.slotIndex ?? 0,
|
|
923
|
+
reattached: true
|
|
924
|
+
});
|
|
925
|
+
}
|
|
926
|
+
} catch (err) {
|
|
927
|
+
bridge.writeNotification("session.reattach_failed", {
|
|
928
|
+
error: err instanceof Error ? err.message : String(err)
|
|
929
|
+
});
|
|
930
|
+
}
|
|
931
|
+
})();
|
|
1329
932
|
const shutdown = async () => {
|
|
1330
933
|
if (pollTimer) clearInterval(pollTimer);
|
|
1331
934
|
if (agentHeartbeatTimer) clearInterval(agentHeartbeatTimer);
|
|
@@ -1458,7 +1061,7 @@ function registerStatusCommand(program2) {
|
|
|
1458
1061
|
|
|
1459
1062
|
// src/index.ts
|
|
1460
1063
|
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
1461
|
-
var pkg = JSON.parse(
|
|
1064
|
+
var pkg = JSON.parse(readFileSync2(join2(__dirname, "..", "package.json"), "utf-8"));
|
|
1462
1065
|
var program = new Command();
|
|
1463
1066
|
program.name("clawrent").description("ClawRent CLI - Agent capability rental platform").version(pkg.version);
|
|
1464
1067
|
registerAuthCommand(program);
|