clixad 0.0.1-beta.41 → 0.0.1-beta.43

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.
@@ -214,6 +214,11 @@ function usd(v) {
214
214
  function packsFromClause(cheapestUsd) {
215
215
  return typeof cheapestUsd === "number" && cheapestUsd > 0 ? `, from ${usd(cheapestUsd)}` : "";
216
216
  }
217
+ function rewardedAdLine(offer) {
218
+ if (!offer) return "";
219
+ return ` Or watch a short ad on the earn page (/earn): ${offer.credits.toLocaleString("en-US")} credits for watching one to the end, ${offer.leftToday} left today.
220
+ `;
221
+ }
217
222
  function parseSpendable(raw) {
218
223
  if (!raw || typeof raw !== "object") return void 0;
219
224
  const r = raw;
@@ -291,6 +296,7 @@ var LEDGER_REASONS = {
291
296
  own_survey_reward: "Clixad survey",
292
297
  ad_screenout_bonus: "screenout bonus (didn't qualify)",
293
298
  ad_sponsor_impression: "sponsored line shown",
299
+ ad_rewarded_view: "ad watched",
294
300
  ad_reversal: "offer reward reversed by the provider",
295
301
  purchase: "credits purchased",
296
302
  usage: "model usage",
@@ -368,7 +374,7 @@ var SignupClosedError = class extends Error {
368
374
  waitlistUrl;
369
375
  };
370
376
  var PaywallError = class extends Error {
371
- constructor(balance, estimatedCost, grantPerAd, freeModels = [], cheapestPackUsd = null, ownSurvey = null) {
377
+ constructor(balance, estimatedCost, grantPerAd, freeModels = [], cheapestPackUsd = null, ownSurvey = null, rewardedAd = null) {
372
378
  super("Out of credits");
373
379
  this.balance = balance;
374
380
  this.estimatedCost = estimatedCost;
@@ -376,6 +382,7 @@ var PaywallError = class extends Error {
376
382
  this.freeModels = freeModels;
377
383
  this.cheapestPackUsd = cheapestPackUsd;
378
384
  this.ownSurvey = ownSurvey;
385
+ this.rewardedAd = rewardedAd;
379
386
  this.name = "PaywallError";
380
387
  }
381
388
  balance;
@@ -384,9 +391,10 @@ var PaywallError = class extends Error {
384
391
  freeModels;
385
392
  cheapestPackUsd;
386
393
  ownSurvey;
394
+ rewardedAd;
387
395
  };
388
396
  var PremiumLockedError = class extends Error {
389
- constructor(message, model, neededCredits, premiumCredits, unlockUsd, grantPerAd, freeModels, spendable) {
397
+ constructor(message, model, neededCredits, premiumCredits, unlockUsd, grantPerAd, freeModels, spendable, rewardedAd = null) {
390
398
  super(message);
391
399
  this.model = model;
392
400
  this.neededCredits = neededCredits;
@@ -395,6 +403,7 @@ var PremiumLockedError = class extends Error {
395
403
  this.grantPerAd = grantPerAd;
396
404
  this.freeModels = freeModels;
397
405
  this.spendable = spendable;
406
+ this.rewardedAd = rewardedAd;
398
407
  this.name = "PremiumLockedError";
399
408
  }
400
409
  model;
@@ -404,6 +413,7 @@ var PremiumLockedError = class extends Error {
404
413
  grantPerAd;
405
414
  freeModels;
406
415
  spendable;
416
+ rewardedAd;
407
417
  };
408
418
  var LimitRefusalError = class extends Error {
409
419
  constructor(message, type, spendable) {
@@ -447,7 +457,8 @@ function premiumLockedError(message, model, body, spendable) {
447
457
  typeof body?.unlock_usd === "number" && body.unlock_usd > 0 ? body.unlock_usd : null,
448
458
  num(body?.grant_per_ad),
449
459
  freeAlternatives(body?.free_models),
450
- spendable
460
+ spendable,
461
+ ownSurveyOffer(body?.rewarded_ad)
451
462
  );
452
463
  }
453
464
  function shortfallHeadline(err, model) {
@@ -463,7 +474,9 @@ function paywallError(body) {
463
474
  body.grant_per_ad,
464
475
  freeAlternatives(body.free_models),
465
476
  typeof pack === "number" && Number.isFinite(pack) && pack > 0 ? pack : null,
466
- ownSurveyOffer(body.own_survey)
477
+ ownSurveyOffer(body.own_survey),
478
+ // The same shape, `{ credits, left_today }`, and the same defensive read.
479
+ ownSurveyOffer(body.rewarded_ad)
467
480
  );
468
481
  }
469
482
  function ownSurveyOffer(raw) {
@@ -2306,6 +2319,94 @@ function diffStat(lines) {
2306
2319
  }
2307
2320
  return { added, removed };
2308
2321
  }
2322
+ var MAX_VIEW_ROWS = 2e3;
2323
+ function diffView(path, before, after, opts = {}) {
2324
+ const context = opts.context ?? 3;
2325
+ if (opts.created) {
2326
+ const lines2 = splitLines(after);
2327
+ const rows2 = lines2.slice(0, MAX_VIEW_ROWS).map((text, i) => ({ kind: "add", line: i + 1, text }));
2328
+ if (lines2.length > MAX_VIEW_ROWS) rows2.push({ kind: "gap", count: lines2.length - MAX_VIEW_ROWS });
2329
+ return { kind: "diff", path, created: true, added: after === "" ? 0 : lines2.length, removed: 0, rows: rows2 };
2330
+ }
2331
+ const lines = diffLines(splitLines(before), splitLines(after));
2332
+ const { added, removed } = diffStat(lines);
2333
+ const keep = new Array(lines.length).fill(false);
2334
+ lines.forEach((l, i) => {
2335
+ if (l.kind === "ctx") return;
2336
+ for (let k = Math.max(0, i - context); k <= Math.min(lines.length - 1, i + context); k++) keep[k] = true;
2337
+ });
2338
+ const rows = [];
2339
+ let skipped = 0;
2340
+ for (let i = 0; i < lines.length; i++) {
2341
+ if (!keep[i]) {
2342
+ skipped++;
2343
+ continue;
2344
+ }
2345
+ if (skipped > 0 && rows.length > 0) rows.push({ kind: "gap", count: skipped });
2346
+ skipped = 0;
2347
+ if (rows.length >= MAX_VIEW_ROWS) {
2348
+ rows.push({ kind: "gap", count: lines.length - i });
2349
+ break;
2350
+ }
2351
+ rows.push({ ...lines[i] });
2352
+ }
2353
+ return { kind: "diff", path, created: false, added, removed, rows };
2354
+ }
2355
+ function diffTint(env = process.env) {
2356
+ if (env.NO_COLOR) return "none";
2357
+ if (env.COLORTERM === "truecolor" || env.COLORTERM === "24bit") return "truecolor";
2358
+ if (/256/.test(env.TERM ?? "")) return "256";
2359
+ if (env.TERM === "dumb") return "none";
2360
+ return "basic";
2361
+ }
2362
+ var TINTS = {
2363
+ truecolor: {
2364
+ add: "\x1B[48;2;28;62;38m",
2365
+ del: "\x1B[48;2;78;32;36m",
2366
+ addSign: "\x1B[38;2;126;231;135m",
2367
+ delSign: "\x1B[38;2;255;123;114m",
2368
+ off: R
2369
+ },
2370
+ "256": { add: "\x1B[48;5;22m", del: "\x1B[48;5;52m", addSign: "\x1B[92m", delSign: "\x1B[91m", off: R },
2371
+ basic: { add: GREEN, del: RED, addSign: "", delSign: "", off: R },
2372
+ none: { add: "", del: "", addSign: "", delSign: "", off: "" }
2373
+ };
2374
+ function renderDiffRows(view, width, opts) {
2375
+ const tint = TINTS[opts.tint ?? "basic"];
2376
+ const max = opts.maxRows ?? Number.POSITIVE_INFINITY;
2377
+ const numbers = view.rows.filter((r) => r.kind !== "gap");
2378
+ const gutter = Math.max(3, ...numbers.map((r) => String(r.line).length));
2379
+ const fit = (text) => {
2380
+ const cut2 = opts.measure(text) > width ? opts.cut(text, width) : text;
2381
+ return cut2 + " ".repeat(Math.max(0, width - opts.measure(cut2)));
2382
+ };
2383
+ const rows = [];
2384
+ let more = 0;
2385
+ for (const row of view.rows) {
2386
+ if (rows.length >= max) {
2387
+ if (row.kind !== "gap") more++;
2388
+ continue;
2389
+ }
2390
+ if (row.kind === "gap") {
2391
+ const dim = tint === TINTS.none ? "" : DIM;
2392
+ rows.push(`${dim}${opts.cut(`${" ".repeat(gutter)} \u22EF ${row.count} unchanged line${row.count === 1 ? "" : "s"}`, width)}${tint.off}`);
2393
+ continue;
2394
+ }
2395
+ const text = row.text.replace(/\t/g, " ");
2396
+ const no = String(row.line).padStart(gutter);
2397
+ if (row.kind === "ctx") {
2398
+ rows.push(`${tint === TINTS.none ? "" : DIM}${opts.cut(`${no} ${text}`, width)}${tint.off}`);
2399
+ continue;
2400
+ }
2401
+ const sign = row.kind === "add" ? "+" : "-";
2402
+ const bg2 = row.kind === "add" ? tint.add : tint.del;
2403
+ const signColor = row.kind === "add" ? tint.addSign : tint.delSign;
2404
+ const body = fit(`${no} ${sign} ${text}`);
2405
+ const at = gutter + 1;
2406
+ rows.push(`${bg2}${body.slice(0, at)}${signColor}${sign}${signColor ? "\x1B[39m" : ""}${body.slice(at + 1)}${tint.off}`);
2407
+ }
2408
+ return { rows, more };
2409
+ }
2309
2410
  function renderDiff(oldText, newText, opts = {}) {
2310
2411
  const context = opts.context ?? 3;
2311
2412
  const maxLines = opts.maxLines ?? 40;
@@ -3605,13 +3706,16 @@ ${body2}` + (pdf.text.length > MAX_FILE_BYTES ? "\n\u2026 [truncated]" : "");
3605
3706
  const abs = safeResolve(ctx.root, requireString(args.path, "write_file", "path"));
3606
3707
  const content = requireString(args.content, "write_file", "content");
3607
3708
  const name = rel(ctx.root, abs);
3608
- const before = existsSync2(abs) ? fsCall(`cannot write ${name}`, () => readFileSync3(abs, "utf8")) : "";
3709
+ const existed = existsSync2(abs);
3710
+ const before = existed ? fsCall(`cannot write ${name}`, () => readFileSync3(abs, "utf8")) : "";
3609
3711
  const preview = renderDiff(before, content) || "(no change)";
3712
+ const view = diffView(name, before, content, { created: !existed });
3610
3713
  await gate(ctx, {
3611
3714
  tool: "write_file",
3612
3715
  signature: `write:${name}`,
3613
3716
  summary: `${before ? "overwrite" : "create"} ${name}`,
3614
3717
  preview,
3718
+ view,
3615
3719
  path: name,
3616
3720
  root: ctx.root
3617
3721
  });
@@ -3619,6 +3723,7 @@ ${body2}` + (pdf.text.length > MAX_FILE_BYTES ? "\n\u2026 [truncated]" : "");
3619
3723
  mkdirSync2(dirname2(abs), { recursive: true });
3620
3724
  writeFileSync2(abs, content, "utf8");
3621
3725
  });
3726
+ ctx.present?.(view);
3622
3727
  return `wrote ${content.length} bytes to ${name}`;
3623
3728
  },
3624
3729
  /**
@@ -3648,15 +3753,18 @@ ${body2}` + (pdf.text.length > MAX_FILE_BYTES ? "\n\u2026 [truncated]" : "");
3648
3753
  }
3649
3754
  const after = before.split(oldString).join(newString);
3650
3755
  const preview = renderDiff(before, after) || "(no change)";
3756
+ const view = diffView(name, before, after);
3651
3757
  await gate(ctx, {
3652
3758
  tool: "edit_file",
3653
3759
  signature: `write:${name}`,
3654
3760
  summary: `edit ${name}`,
3655
3761
  preview,
3762
+ view,
3656
3763
  path: name,
3657
3764
  root: ctx.root
3658
3765
  });
3659
3766
  fsCall(`cannot edit ${name}`, () => writeFileSync2(abs, after, "utf8"));
3767
+ ctx.present?.(view);
3660
3768
  return `edited ${name} (${count > 1 ? `${count} occurrences` : "1 occurrence"})`;
3661
3769
  },
3662
3770
  /**
@@ -5303,6 +5411,9 @@ async function runAgent(client, task, opts) {
5303
5411
  mcp: opts.mcp,
5304
5412
  shells: opts.shells,
5305
5413
  attach: (image) => pendingImages.push(image),
5414
+ // A placeholder that says writes are shown at this depth; each call gets
5415
+ // its own (`executeToolCall`), which puts the view on its result event.
5416
+ ...depth === 0 ? { present: () => void 0 } : {},
5306
5417
  // The recursion guard, and the whole of it: a sub-agent runs at depth 1 and
5307
5418
  // is handed no way to start another.
5308
5419
  ...depth === 0 ? { spawn: runSubAgent } : {}
@@ -5498,9 +5609,13 @@ async function executeToolCall(ctx, call, emit) {
5498
5609
  }
5499
5610
  emit({ type: "tool_call", id, name, args });
5500
5611
  const search = ctx.webSearch;
5612
+ let view;
5501
5613
  const scoped = {
5502
5614
  ...ctx,
5503
5615
  onOutput: (chunk) => emit({ type: "tool_output", id, chunk }),
5616
+ // Only where something draws it: a sub-agent's writes are not shown, and
5617
+ // `ctx.present` is how this run says whether anybody is watching.
5618
+ ...ctx.present ? { present: (v) => view = v } : {},
5504
5619
  // Reported against this call the moment it is charged, so the row says
5505
5620
  // what it cost and the balance on screen moves with it.
5506
5621
  ...search ? {
@@ -5520,7 +5635,7 @@ async function executeToolCall(ctx, call, emit) {
5520
5635
  };
5521
5636
  try {
5522
5637
  const result = await dispatch(scoped, name, args);
5523
- emit({ type: "tool_result", id, name, result, ok: true });
5638
+ emit({ type: "tool_result", id, name, result, ok: true, ...view ? { view } : {} });
5524
5639
  return result;
5525
5640
  } catch (err) {
5526
5641
  if (err instanceof ToolError) {
@@ -6410,6 +6525,7 @@ export {
6410
6525
  NO_PREMIUM_CREDITS,
6411
6526
  usd,
6412
6527
  packsFromClause,
6528
+ rewardedAdLine,
6413
6529
  parseSpendable,
6414
6530
  adsPerTaskLabel,
6415
6531
  grantLabel,
@@ -6443,6 +6559,8 @@ export {
6443
6559
  webSearchCostLine,
6444
6560
  freeHelpLine,
6445
6561
  freeAlternativeLine,
6562
+ diffTint,
6563
+ renderDiffRows,
6446
6564
  shells,
6447
6565
  TodoList,
6448
6566
  loadMcpConfig,
package/dist/clixad.mjs CHANGED
@@ -53,7 +53,7 @@ import {
53
53
  takeConfigNotices,
54
54
  toolSchemaFor,
55
55
  usd
56
- } from "./chunk-AOKPITZW.mjs";
56
+ } from "./chunk-T7SUUKJC.mjs";
57
57
 
58
58
  // src/tui/load.ts
59
59
  import * as nodeModule from "node:module";
@@ -132,7 +132,7 @@ async function withProductionReact(load) {
132
132
  }
133
133
  function loadTui() {
134
134
  boundInkCaches();
135
- return withProductionReact(() => import("./tui-FSKTJFDL.mjs"));
135
+ return withProductionReact(() => import("./tui-773NJ4FQ.mjs"));
136
136
  }
137
137
 
138
138
  // src/title.ts