clawmoney 0.15.13 → 0.15.15

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.
@@ -2,7 +2,7 @@ import { execSync } from "node:child_process";
2
2
  import { existsSync } from "node:fs";
3
3
  import { homedir } from "node:os";
4
4
  import { join } from "node:path";
5
- import { intro, outro, multiselect, confirm, text, spinner, isCancel, cancel, log, } from "@clack/prompts";
5
+ import { intro, outro, multiselect, confirm, select, spinner, isCancel, cancel, log, } from "@clack/prompts";
6
6
  import chalk from "chalk";
7
7
  import { apiPost } from "../utils/api.js";
8
8
  import { requireConfig } from "../utils/config.js";
@@ -224,48 +224,61 @@ export async function relaySetupCommand() {
224
224
  cancel("No models selected — nothing to register");
225
225
  process.exit(0);
226
226
  }
227
- // ── Step 4: global concurrency + daily budget ──
228
- const concurrencyAns = await text({
229
- message: "Concurrency cap per provider? (1-5 recommended; higher looks less like a single power user to upstream fingerprint detection)",
230
- placeholder: "5",
231
- defaultValue: "5",
232
- validate: (v) => {
233
- const n = parseInt(v || "5", 10);
234
- if (Number.isNaN(n) || n < 1 || n > 20) {
235
- return "Must be a number between 1 and 20";
236
- }
237
- return undefined;
238
- },
239
- });
240
- if (isCancel(concurrencyAns)) {
241
- cancel("Setup cancelled");
242
- process.exit(0);
243
- }
244
- const dailyLimitAns = await text({
245
- message: "Daily API spend cap per provider in USD? (the daemon stops accepting requests when exceeded)",
246
- placeholder: "15",
247
- defaultValue: "15",
248
- validate: (v) => {
249
- const n = parseFloat(v || "15");
250
- if (Number.isNaN(n) || n < 0) {
251
- return "Must be a non-negative number";
252
- }
253
- return undefined;
254
- },
227
+ // ── Step 4: daily budget (the only product-level decision) ──
228
+ //
229
+ // Concurrency is silent (5, the "single power user" cap explained
230
+ // in the file header). daily_limit is the one variable that's a
231
+ // product decision, not a technical one: it directly controls how
232
+ // much you can earn (and how much subscription quota the relay
233
+ // burns through per day). We offer three presets calibrated to
234
+ // common provider postures, plus the implicit fall-through of
235
+ // editing config.yaml after start for advanced overrides.
236
+ //
237
+ // Earning math per provider (assuming 100% utilization):
238
+ // max_earn_per_day = daily_limit × RELAY_DISCOUNT × (1 - PLATFORM_FEE)
239
+ // = daily_limit × 0.20 × 0.90 = daily_limit × 0.18
240
+ // max_earn_per_month max_earn_per_day × 30
241
+ const concurrency = 5;
242
+ const earnPerMonth = (cap) => Math.round(cap * RELAY_DISCOUNT * (1 - PLATFORM_FEE) * 30);
243
+ const dailyLimitChoice = await select({
244
+ message: "Daily API budget per provider? (caps how much subscription quota the relay burns through per day; higher = more earnings, but closer to relay-farm signal)",
245
+ options: [
246
+ {
247
+ value: 5,
248
+ label: "Conservative $5/day cap",
249
+ hint: `up to ~$${earnPerMonth(5)}/month earnings · safest fingerprint, near-zero ban risk`,
250
+ },
251
+ {
252
+ value: 15,
253
+ label: "Balanced — $15/day cap",
254
+ hint: `up to ~$${earnPerMonth(15)}/month earnings · matches a heavy individual user · low ban risk (recommended)`,
255
+ },
256
+ {
257
+ value: 30,
258
+ label: "Aggressive — $30/day cap",
259
+ hint: `up to ~$${earnPerMonth(30)}/month earnings · power-user upper bound · moderate ban risk`,
260
+ },
261
+ {
262
+ value: 60,
263
+ label: "Maximize — $60/day cap",
264
+ hint: `up to ~$${earnPerMonth(60)}/month earnings · clearly above single-user usage · higher ban risk, recommended only if you're willing to rotate accounts`,
265
+ },
266
+ ],
267
+ initialValue: 15,
255
268
  });
256
- if (isCancel(dailyLimitAns)) {
269
+ if (isCancel(dailyLimitChoice)) {
257
270
  cancel("Setup cancelled");
258
271
  process.exit(0);
259
272
  }
260
- const concurrency = parseInt(concurrencyAns, 10);
261
- const dailyLimit = parseFloat(dailyLimitAns);
273
+ const dailyLimit = dailyLimitChoice;
262
274
  // ── Step 5: confirmation summary ──
263
275
  log.step(chalk.bold("Summary"));
264
276
  for (const r of registrations) {
265
277
  log.message(` ${chalk.cyan(r.cli + "/" + r.model).padEnd(50)} ${chalk.dim(formatBuyerPrice(r.input, r.output))}`);
266
278
  }
267
- log.message(chalk.dim(` ${registrations.length} providers · concurrency=${concurrency} · daily_limit=$${dailyLimit}`));
279
+ log.message(chalk.dim(` ${registrations.length} provider(s) · concurrency=${concurrency}/provider · daily_limit=$${dailyLimit}/provider`));
268
280
  log.message(chalk.dim(` You earn ~${Math.round((1 - PLATFORM_FEE) * 100)}% of what buyers pay (after platform fee)`));
281
+ log.message(chalk.dim(` To customize: edit ~/.clawmoney/config.yaml after start, or re-register a single model via "clawmoney relay register --cli X --model Y --concurrency N --daily-limit M"`));
269
282
  const proceed = await confirm({
270
283
  message: `Register all ${registrations.length} providers now?`,
271
284
  initialValue: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clawmoney",
3
- "version": "0.15.13",
3
+ "version": "0.15.15",
4
4
  "description": "ClawMoney CLI -- Earn rewards with your AI agent",
5
5
  "type": "module",
6
6
  "bin": {