clawmoney 0.15.30 → 0.15.31
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/commands/relay-setup.js +35 -28
- package/dist/commands/relay.js +47 -18
- package/package.json +1 -1
|
@@ -290,34 +290,38 @@ export async function relaySetupCommand() {
|
|
|
290
290
|
const failures = [];
|
|
291
291
|
const regSpin = spinner();
|
|
292
292
|
regSpin.start(`Registering ${registrations.length} providers...`);
|
|
293
|
-
|
|
293
|
+
// Parallel registration — each request creates a distinct RelayProvider
|
|
294
|
+
// row so there's no write contention, and the backend's insert path is
|
|
295
|
+
// idempotent on (agent_id, cli_type, model). Sequential registration
|
|
296
|
+
// was costing ~1 RTT per row, which on a high-latency link (e.g. from
|
|
297
|
+
// China) added up to 7-10s of visible wait for 7 providers.
|
|
298
|
+
await Promise.all(registrations.map(async (r) => {
|
|
299
|
+
const body = {
|
|
300
|
+
cli_type: r.cli,
|
|
301
|
+
model: r.model,
|
|
302
|
+
mode: "chat",
|
|
303
|
+
concurrency,
|
|
304
|
+
daily_limit_usd: dailyLimit,
|
|
305
|
+
price_input_per_m: r.input,
|
|
306
|
+
price_output_per_m: r.output,
|
|
307
|
+
};
|
|
294
308
|
try {
|
|
295
|
-
const body = {
|
|
296
|
-
cli_type: r.cli,
|
|
297
|
-
model: r.model,
|
|
298
|
-
mode: "chat",
|
|
299
|
-
concurrency,
|
|
300
|
-
daily_limit_usd: dailyLimit,
|
|
301
|
-
price_input_per_m: r.input,
|
|
302
|
-
price_output_per_m: r.output,
|
|
303
|
-
};
|
|
304
309
|
const resp = await apiPost("/api/v1/relay/providers", body, config.api_key);
|
|
305
310
|
if (resp.ok) {
|
|
306
311
|
succeeded++;
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
const raw = resp.data && typeof resp.data === "object" && "detail" in resp.data
|
|
315
|
+
? resp.data.detail
|
|
316
|
+
: resp.data;
|
|
317
|
+
const detail = typeof raw === "string" ? raw : JSON.stringify(raw);
|
|
318
|
+
// Already-registered is a soft success — idempotent re-run.
|
|
319
|
+
if (detail.includes("Already registered")) {
|
|
320
|
+
succeeded++;
|
|
307
321
|
}
|
|
308
322
|
else {
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
: resp.data;
|
|
312
|
-
const detail = typeof raw === "string" ? raw : JSON.stringify(raw);
|
|
313
|
-
// Already-registered is a soft success — idempotent re-run.
|
|
314
|
-
if (detail.includes("Already registered")) {
|
|
315
|
-
succeeded++;
|
|
316
|
-
}
|
|
317
|
-
else {
|
|
318
|
-
failed++;
|
|
319
|
-
failures.push({ cli: r.cli, model: r.model, error: detail });
|
|
320
|
-
}
|
|
323
|
+
failed++;
|
|
324
|
+
failures.push({ cli: r.cli, model: r.model, error: detail });
|
|
321
325
|
}
|
|
322
326
|
}
|
|
323
327
|
catch (err) {
|
|
@@ -325,7 +329,7 @@ export async function relaySetupCommand() {
|
|
|
325
329
|
failed++;
|
|
326
330
|
failures.push({ cli: r.cli, model: r.model, error: msg });
|
|
327
331
|
}
|
|
328
|
-
}
|
|
332
|
+
}));
|
|
329
333
|
if (failed === 0) {
|
|
330
334
|
regSpin.stop(`${chalk.green(`✓ ${succeeded} providers registered`)} ` +
|
|
331
335
|
chalk.dim(`(${limitLabel[dailyLimit] ?? `$${dailyLimit}`} quota share · you earn ~${earnPct}%)`));
|
|
@@ -362,11 +366,14 @@ export async function relaySetupCommand() {
|
|
|
362
366
|
outro(chalk.yellow("Setup complete (daemon not started)"));
|
|
363
367
|
return;
|
|
364
368
|
}
|
|
365
|
-
log.message
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
log.message(
|
|
369
|
-
|
|
369
|
+
// One multi-line log.message renders each line with a `│` prefix
|
|
370
|
+
// but without clack's inter-call gap — 3 bullets fit in 3 lines
|
|
371
|
+
// instead of 6.
|
|
372
|
+
log.message(chalk.dim("Next:") +
|
|
373
|
+
"\n" +
|
|
374
|
+
` ${chalk.cyan("clawmoney relay status")} daemon health + providers\n` +
|
|
375
|
+
` ${chalk.cyan("clawmoney relay credits")} earnings + balance\n` +
|
|
376
|
+
` ${chalk.cyan("clawmoney relay stop")} stop daemon`);
|
|
370
377
|
const cliLabel = uniqueClis.length === 1
|
|
371
378
|
? `${uniqueClis[0]} daemon running`
|
|
372
379
|
: `daemon serving ${uniqueClis.join(" + ")}`;
|
package/dist/commands/relay.js
CHANGED
|
@@ -206,36 +206,65 @@ export async function relayStatusCommand() {
|
|
|
206
206
|
else {
|
|
207
207
|
console.log(chalk.dim(" Local process: not running"));
|
|
208
208
|
}
|
|
209
|
-
// Remote status
|
|
209
|
+
// Remote status. /api/v1/relay/providers/me returns a LIST of
|
|
210
|
+
// RelayProviderPublic (one row per registered model), so we can't
|
|
211
|
+
// treat the body as a single object. For multi-cli providers the
|
|
212
|
+
// list can easily be 7-10 rows — render them as a table with one
|
|
213
|
+
// line per row instead of 14 labeled lines for a single picked row.
|
|
210
214
|
const spinner = ora("Fetching relay provider status...").start();
|
|
211
215
|
try {
|
|
212
216
|
const resp = await apiGet("/api/v1/relay/providers/me", config.api_key);
|
|
213
217
|
if (!resp.ok) {
|
|
214
218
|
if (resp.status === 404) {
|
|
215
219
|
spinner.info("Not registered as relay provider yet.");
|
|
216
|
-
console.log(chalk.dim(` Run "clawmoney relay
|
|
220
|
+
console.log(chalk.dim(` Run "clawmoney relay setup" to get started.`));
|
|
217
221
|
return;
|
|
218
222
|
}
|
|
219
|
-
const detail = resp.data?.detail ?? resp.status;
|
|
223
|
+
const detail = resp.data?.detail ?? String(resp.status);
|
|
220
224
|
spinner.fail(chalk.red(`Failed to fetch status: ${detail}`));
|
|
221
225
|
process.exit(1);
|
|
222
226
|
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
227
|
+
// Normalize: backend currently returns a list, but guard against
|
|
228
|
+
// a single-object shape in case someone points the CLI at an older
|
|
229
|
+
// Hub build.
|
|
230
|
+
const providers = Array.isArray(resp.data)
|
|
231
|
+
? resp.data
|
|
232
|
+
: resp.data
|
|
233
|
+
? [resp.data]
|
|
234
|
+
: [];
|
|
235
|
+
if (providers.length === 0) {
|
|
236
|
+
spinner.info("No providers registered yet.");
|
|
237
|
+
console.log(chalk.dim(` Run "clawmoney relay setup" to get started.`));
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
spinner.succeed(`Relay Providers (${providers.length})`);
|
|
226
241
|
console.log("");
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
console.log(
|
|
236
|
-
console.log(
|
|
237
|
-
|
|
238
|
-
|
|
242
|
+
// Aggregate stats across all rows since users think of earnings /
|
|
243
|
+
// spend as account-level, not per-model.
|
|
244
|
+
const totalEarned = providers.reduce((s, p) => s + (p.total_earned_usd ?? 0), 0);
|
|
245
|
+
const totalRequests = providers.reduce((s, p) => s + (p.total_requests ?? 0), 0);
|
|
246
|
+
const totalDailySpent = providers.reduce((s, p) => s + (p.daily_spent_usd ?? 0), 0);
|
|
247
|
+
const totalDailyLimit = providers.reduce((s, p) => s + (p.daily_limit_usd ?? 0), 0);
|
|
248
|
+
// Per-provider rows — compact table with status/cli/model/load.
|
|
249
|
+
const header = ` ${"STATUS".padEnd(9)} ${"CLI".padEnd(12)} ${"MODEL".padEnd(30)} ${"LOAD".padEnd(8)} ${"EARNED".padEnd(10)}`;
|
|
250
|
+
console.log(chalk.bold(header));
|
|
251
|
+
console.log(chalk.dim(" " + "─".repeat(75)));
|
|
252
|
+
for (const p of providers) {
|
|
253
|
+
const statusRaw = (p.status ?? "-").padEnd(9);
|
|
254
|
+
const statusColored = p.status === "online"
|
|
255
|
+
? chalk.green(statusRaw)
|
|
256
|
+
: p.status === "offline"
|
|
257
|
+
? chalk.dim(statusRaw)
|
|
258
|
+
: chalk.yellow(statusRaw);
|
|
259
|
+
const cli = (p.cli_type ?? "-").padEnd(12);
|
|
260
|
+
const model = (p.model ?? "-").padEnd(30);
|
|
261
|
+
const load = `${p.current_load ?? 0}/${p.concurrency ?? "-"}`.padEnd(8);
|
|
262
|
+
const earned = `$${(p.total_earned_usd ?? 0).toFixed(2)}`.padEnd(10);
|
|
263
|
+
console.log(` ${statusColored} ${cli} ${model} ${load} ${earned}`);
|
|
264
|
+
}
|
|
265
|
+
console.log("");
|
|
266
|
+
console.log(` ${chalk.bold("Daily quota:")} $${totalDailySpent.toFixed(2)} / $${totalDailyLimit.toFixed(2)}`);
|
|
267
|
+
console.log(` ${chalk.bold("Total earned:")} $${totalEarned.toFixed(2)} (${totalRequests} requests)`);
|
|
239
268
|
}
|
|
240
269
|
catch (err) {
|
|
241
270
|
spinner.fail(chalk.red("Failed to fetch status"));
|