clixad 0.0.1-beta.1 → 0.0.1-beta.3

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.
Files changed (2) hide show
  1. package/dist/clixad.mjs +200 -93
  2. package/package.json +1 -1
package/dist/clixad.mjs CHANGED
@@ -210,14 +210,18 @@ var init_client = __esm({
210
210
  if (!res.ok) throw new Error(`checkout failed: ${res.status} ${await res.text()}`);
211
211
  return res.json();
212
212
  }
213
- async models() {
214
- const res = await fetch(`${this.config.gatewayUrl}/v1/models`);
213
+ // Both take an optional signal for the REPL's sake: they are awaited while the
214
+ // input box is locked, and a gateway that is cold-starting (Render's free tier,
215
+ // the better part of a minute) would otherwise be indistinguishable from a
216
+ // hung terminal. Nothing else passes one — a one-shot CLI command has Ctrl+C.
217
+ async models(signal) {
218
+ const res = await fetch(`${this.config.gatewayUrl}/v1/models`, { signal });
215
219
  if (!res.ok) throw new Error(`models failed: ${res.status}`);
216
220
  const data = await res.json();
217
221
  return data.data;
218
222
  }
219
- async wallet() {
220
- const res = await fetch(`${this.config.gatewayUrl}/v1/wallet`, { headers: this.headers() });
223
+ async wallet(signal) {
224
+ const res = await fetch(`${this.config.gatewayUrl}/v1/wallet`, { headers: this.headers(), signal });
221
225
  if (res.status === 401) throw await authFailure(res, "wallet");
222
226
  if (!res.ok) throw new Error(`wallet failed: ${res.status}`);
223
227
  return res.json();
@@ -1483,7 +1487,9 @@ import { spawn as spawn3 } from "node:child_process";
1483
1487
  function openBrowser(url) {
1484
1488
  const cmd = process.platform === "win32" ? "cmd" : process.platform === "darwin" ? "open" : "xdg-open";
1485
1489
  const args = process.platform === "win32" ? ["/c", "start", "", url] : [url];
1486
- spawn3(cmd, args, { detached: true, stdio: "ignore", windowsHide: true }).unref();
1490
+ const child = spawn3(cmd, args, { detached: true, stdio: "ignore", windowsHide: true });
1491
+ child.on("error", () => void 0);
1492
+ child.unref();
1487
1493
  }
1488
1494
  var init_browser = __esm({
1489
1495
  "src/browser.ts"() {
@@ -1491,6 +1497,26 @@ var init_browser = __esm({
1491
1497
  }
1492
1498
  });
1493
1499
 
1500
+ // src/version.ts
1501
+ import { readFileSync as readFileSync5 } from "node:fs";
1502
+ function readVersion() {
1503
+ try {
1504
+ const url = new URL("../package.json", import.meta.url);
1505
+ const pkg = JSON.parse(readFileSync5(url, "utf8"));
1506
+ return typeof pkg.version === "string" && pkg.version ? pkg.version : "unknown";
1507
+ } catch {
1508
+ return "unknown";
1509
+ }
1510
+ }
1511
+ var VERSION, VERSION_LABEL;
1512
+ var init_version = __esm({
1513
+ "src/version.ts"() {
1514
+ "use strict";
1515
+ VERSION = readVersion();
1516
+ VERSION_LABEL = `v${VERSION}`;
1517
+ }
1518
+ });
1519
+
1494
1520
  // src/compact.ts
1495
1521
  function estimateTokens(text) {
1496
1522
  return Math.ceil(text.length / 4);
@@ -2096,7 +2122,7 @@ function App({ client, config, wallet, session, initialTask }) {
2096
2122
  earnedUsdToday: wallet?.earned_usd_today ?? 0,
2097
2123
  maxRewardUsd: wallet?.max_reward_usd_per_day ?? 0,
2098
2124
  cwd: process.cwd(),
2099
- version: "v0.0.1"
2125
+ version: VERSION_LABEL
2100
2126
  })
2101
2127
  }
2102
2128
  ]);
@@ -2118,11 +2144,13 @@ function App({ client, config, wallet, session, initialTask }) {
2118
2144
  const [tick, setTick] = useState(0);
2119
2145
  const [startedAt, setStartedAt] = useState(0);
2120
2146
  const [quitHint, setQuitHint] = useState(false);
2147
+ const [busyLabel, setBusyLabel] = useState(WORKING);
2121
2148
  const [sponsor, setSponsor] = useState(null);
2122
2149
  const messagesRef = useRef(messages);
2123
2150
  messagesRef.current = messages;
2124
2151
  const permRef = useRef(createState("normal"));
2125
2152
  const abortRef = useRef(null);
2153
+ const busyAbortRef = useRef(null);
2126
2154
  const filesRef = useRef(null);
2127
2155
  const ctrlCRef = useRef(0);
2128
2156
  const sessionRef = useRef(session ?? { id: newSessionId(), started: (/* @__PURE__ */ new Date()).toISOString() });
@@ -2324,6 +2352,30 @@ function App({ client, config, wallet, session, initialTask }) {
2324
2352
  },
2325
2353
  [client, contextWindow, handleEvent, model, nextSponsor, permit, push, root, session?.title]
2326
2354
  );
2355
+ const stopCurrent = useCallback(() => {
2356
+ abortRef.current?.abort();
2357
+ busyAbortRef.current?.abort();
2358
+ }, []);
2359
+ const runBusy = useCallback(
2360
+ async (label, fn) => {
2361
+ const ac = new AbortController();
2362
+ busyAbortRef.current = ac;
2363
+ setBusy(true);
2364
+ setBusyLabel(label);
2365
+ setStartedAt(Date.now());
2366
+ try {
2367
+ await fn(ac.signal);
2368
+ } catch (err) {
2369
+ if (ac.signal.aborted) push({ kind: "notice", tone: "warn", text: " (stopped)" });
2370
+ else push({ kind: "notice", tone: "error", text: ` ${err.message}` });
2371
+ } finally {
2372
+ busyAbortRef.current = null;
2373
+ setBusyLabel(WORKING);
2374
+ setBusy(false);
2375
+ }
2376
+ },
2377
+ [push]
2378
+ );
2327
2379
  const runAdWall = useCallback(async () => {
2328
2380
  const task = pendingTaskRef.current;
2329
2381
  pendingTaskRef.current = null;
@@ -2337,18 +2389,28 @@ function App({ client, config, wallet, session, initialTask }) {
2337
2389
  ` : ` opened ${base} \u2014 paste your token there; waiting for the reward\u2026
2338
2390
  `) + ` Credits land on completion; being screened out of an offer pays nothing and is normal.`
2339
2391
  });
2340
- setBusy(true);
2341
- const deadline = Date.now() + 5 * 6e4;
2342
2392
  let credited = false;
2343
- while (Date.now() < deadline && !credited) {
2344
- await new Promise((r) => setTimeout(r, 3e3));
2345
- const w = await client.wallet().catch(() => void 0);
2346
- if (w && w.balance > before) {
2347
- setBalance(w.balance);
2348
- credited = true;
2393
+ let stopped = false;
2394
+ await runBusy(WAITING_FOR_REWARD, async (signal) => {
2395
+ const deadline = Date.now() + 5 * 6e4;
2396
+ while (Date.now() < deadline && !credited && !signal.aborted) {
2397
+ await sleep(3e3, signal);
2398
+ if (signal.aborted) break;
2399
+ const w = await client.wallet(signal).catch(() => void 0);
2400
+ if (w && w.balance > before) {
2401
+ setBalance(w.balance);
2402
+ credited = true;
2403
+ }
2349
2404
  }
2350
- }
2351
- setBusy(false);
2405
+ stopped = signal.aborted;
2406
+ });
2407
+ if (!credited) pendingTaskRef.current = task;
2408
+ if (stopped)
2409
+ return push({
2410
+ kind: "notice",
2411
+ tone: "warn",
2412
+ text: " stopped waiting. A reward still lands whenever the offer clears \u2014\n /wallet checks the balance, /earn opens the wall again." + (task ? "\n Your last request is still queued: press enter to retry it." : "")
2413
+ });
2352
2414
  if (!credited)
2353
2415
  return push({
2354
2416
  kind: "notice",
@@ -2357,7 +2419,7 @@ function App({ client, config, wallet, session, initialTask }) {
2357
2419
  });
2358
2420
  push({ kind: "notice", tone: "good", text: " credits added \u2014 continuing" });
2359
2421
  if (task) await runTurn2(task);
2360
- }, [balance, client, config.dashboardUrl, push, runTurn2]);
2422
+ }, [balance, client, config.dashboardUrl, push, runBusy, runTurn2]);
2361
2423
  const runCommand = useCallback(
2362
2424
  async (line2) => {
2363
2425
  const [cmd, ...rest] = line2.slice(1).split(" ");
@@ -2390,83 +2452,74 @@ function App({ client, config, wallet, session, initialTask }) {
2390
2452
  push({ kind: "notice", text: ` mode \u2192 ${MODE_LABEL[permRef.current.mode]}` });
2391
2453
  return;
2392
2454
  }
2393
- case "compact": {
2394
- setBusy(true);
2395
- try {
2396
- const res = await compact(client, model, [
2397
- { role: "system", content: contextRef.current.systemPrompt },
2398
- ...messagesRef.current
2399
- ]);
2400
- if (!res) push({ kind: "notice", text: " nothing to compact yet" });
2401
- else {
2402
- setMessages(res.messages.slice(1));
2403
- setBalance(res.balance);
2404
- setSpent((s) => s + res.creditsCharged);
2405
- push({
2406
- kind: "notice",
2407
- text: ` compacted: ~${Math.round(res.before / 1e3)}k \u2192 ~${Math.round(res.after / 1e3)}k tokens (${res.creditsCharged} credits)`
2408
- });
2409
- }
2410
- } catch (err) {
2411
- push({ kind: "notice", tone: "error", text: ` ${err.message}` });
2412
- }
2413
- setBusy(false);
2455
+ // A model call like any other, so esc has to stop it like any other —
2456
+ // and stopping it costs nothing, since the summary only replaces the
2457
+ // conversation once the call has come back whole.
2458
+ case "compact":
2459
+ await runBusy(COMPACTING, async (signal) => {
2460
+ const res = await compact(
2461
+ client,
2462
+ model,
2463
+ [{ role: "system", content: contextRef.current.systemPrompt }, ...messagesRef.current],
2464
+ { signal }
2465
+ );
2466
+ if (!res) return push({ kind: "notice", text: " nothing to compact yet" });
2467
+ setMessages(res.messages.slice(1));
2468
+ setBalance(res.balance);
2469
+ setSpent((s) => s + res.creditsCharged);
2470
+ push({
2471
+ kind: "notice",
2472
+ text: ` compacted: ~${Math.round(res.before / 1e3)}k \u2192 ~${Math.round(res.after / 1e3)}k tokens (${res.creditsCharged} credits)`
2473
+ });
2474
+ });
2414
2475
  return;
2415
- }
2416
2476
  case "init":
2417
2477
  await runTurn2(INIT_PROMPT);
2418
2478
  return;
2419
2479
  // Always the picker — an id you have to remember and type is exactly
2420
2480
  // what a picker is for. A typed id only preselects a row.
2421
- case "model": {
2422
- setBusy(true);
2423
- const models = catalogRef.current.length ? catalogRef.current : await client.models().catch(() => []);
2424
- catalogRef.current = models;
2425
- setBusy(false);
2426
- if (!models.length) return push({ kind: "notice", tone: "error", text: " could not load the model list" });
2427
- if (arg && !models.some((m) => m.id === arg)) {
2428
- push({ kind: "notice", tone: "warn", text: ` unknown model: ${arg}` });
2429
- }
2430
- const items = models.map((m) => ({
2431
- value: m.id,
2432
- label: m.id,
2433
- hint: `${m.tier.padEnd(8)}${adsPerTaskLabel(m.est_ads_per_task)}`,
2434
- current: m.id === model
2435
- }));
2436
- const preselect = items.findIndex((i) => i.value === arg);
2437
- setPickerSel(preselect >= 0 ? preselect : Math.max(0, items.findIndex((i) => i.current)));
2438
- setPicker({
2439
- title: "Select model",
2440
- subtitle: "Applies to this session and is saved as your default.",
2441
- items,
2442
- onPick: (choice) => {
2443
- config.model = choice.value;
2444
- saveConfig(config);
2445
- setModel2(choice.value);
2446
- push({ kind: "notice", text: ` model \u2192 ${choice.value}` });
2481
+ case "model":
2482
+ await runBusy(LOADING, async (signal) => {
2483
+ const models = catalogRef.current.length ? catalogRef.current : await client.models(signal);
2484
+ catalogRef.current = models;
2485
+ if (!models.length) return push({ kind: "notice", tone: "error", text: " could not load the model list" });
2486
+ if (arg && !models.some((m) => m.id === arg)) {
2487
+ push({ kind: "notice", tone: "warn", text: ` unknown model: ${arg}` });
2447
2488
  }
2489
+ const items = models.map((m) => ({
2490
+ value: m.id,
2491
+ label: m.id,
2492
+ hint: `${m.tier.padEnd(8)}${adsPerTaskLabel(m.est_ads_per_task)}`,
2493
+ current: m.id === model
2494
+ }));
2495
+ const preselect = items.findIndex((i) => i.value === arg);
2496
+ setPickerSel(preselect >= 0 ? preselect : Math.max(0, items.findIndex((i) => i.current)));
2497
+ setPicker({
2498
+ title: "Select model",
2499
+ subtitle: "Applies to this session and is saved as your default.",
2500
+ items,
2501
+ onPick: (choice) => {
2502
+ config.model = choice.value;
2503
+ saveConfig(config);
2504
+ setModel2(choice.value);
2505
+ push({ kind: "notice", text: ` model \u2192 ${choice.value}` });
2506
+ }
2507
+ });
2448
2508
  });
2449
2509
  return;
2450
- }
2451
- case "models": {
2452
- setBusy(true);
2453
- try {
2454
- const ms = await client.models();
2510
+ case "models":
2511
+ await runBusy(LOADING, async (signal) => {
2512
+ const ms = await client.models(signal);
2455
2513
  catalogRef.current = ms;
2456
2514
  push({
2457
2515
  kind: "notice",
2458
2516
  text: ms.map((m) => ` ${m.id.padEnd(24)} ${adsPerTaskLabel(m.est_ads_per_task)}`).join("\n")
2459
2517
  });
2460
- } catch (err) {
2461
- push({ kind: "notice", tone: "error", text: ` ${err.message}` });
2462
- }
2463
- setBusy(false);
2518
+ });
2464
2519
  return;
2465
- }
2466
- case "wallet": {
2467
- setBusy(true);
2468
- try {
2469
- const w = await client.wallet();
2520
+ case "wallet":
2521
+ await runBusy(LOADING, async (signal) => {
2522
+ const w = await client.wallet(signal);
2470
2523
  setBalance(w.balance);
2471
2524
  const reversals = w.ledger.filter((e) => e.reason === "ad_reversal");
2472
2525
  const reversed = reversals.reduce((sum, e) => sum + Math.abs(e.delta), 0);
@@ -2475,12 +2528,8 @@ function App({ client, config, wallet, session, initialTask }) {
2475
2528
  text: ` balance ${w.balance.toLocaleString("en-US")} credits \xB7 ${w.ads_today} offers today \xB7 $${w.earned_usd_today.toFixed(2)}/$${w.max_reward_usd_per_day.toFixed(2)} earned` + (reversals.length ? `
2476
2529
  recently: ${reversed.toLocaleString("en-US")} credits from ${reversals.length} offer${reversals.length === 1 ? "" : "s"} were reversed by the provider. Run \`clixad wallet\` for the full ledger.` : "")
2477
2530
  });
2478
- } catch (err) {
2479
- push({ kind: "notice", tone: "error", text: ` ${err.message}` });
2480
- }
2481
- setBusy(false);
2531
+ });
2482
2532
  return;
2483
- }
2484
2533
  // The same browser handoff the paywall takes, rather than a second way of
2485
2534
  // doing it: /earn used to call the dev-only /v1/ads/reward simulator, so
2486
2535
  // in production the slash command the paywall itself recommends was a 404.
@@ -2491,7 +2540,7 @@ function App({ client, config, wallet, session, initialTask }) {
2491
2540
  push({ kind: "notice", tone: "warn", text: ` unknown command: /${cmd} \u2014 try /help` });
2492
2541
  }
2493
2542
  },
2494
- [client, config, cycleMode, exit, model, push, runTurn2]
2543
+ [client, config, cycleMode, exit, model, push, runAdWall, runBusy, runTurn2]
2495
2544
  );
2496
2545
  const submit = useCallback(
2497
2546
  async (raw) => {
@@ -2540,7 +2589,7 @@ function App({ client, config, wallet, session, initialTask }) {
2540
2589
  );
2541
2590
  useInput((ch, key) => {
2542
2591
  if (key.ctrl && ch === "c") {
2543
- if (busy) return abortRef.current?.abort();
2592
+ if (busy) return stopCurrent();
2544
2593
  if (!isEmpty(editor)) return setEditor(EMPTY);
2545
2594
  if (Date.now() - ctrlCRef.current < 2e3) return exit();
2546
2595
  ctrlCRef.current = Date.now();
@@ -2579,7 +2628,7 @@ function App({ client, config, wallet, session, initialTask }) {
2579
2628
  return;
2580
2629
  }
2581
2630
  if (busy) {
2582
- if (key.escape) abortRef.current?.abort();
2631
+ if (key.escape) stopCurrent();
2583
2632
  return;
2584
2633
  }
2585
2634
  if (key.tab && key.shift) return cycleMode();
@@ -2675,7 +2724,9 @@ function App({ client, config, wallet, session, initialTask }) {
2675
2724
  /* @__PURE__ */ jsx2(Text2, { color: MANGO_BRIGHT, children: "\u276F " }),
2676
2725
  busy ? /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
2677
2726
  spinner,
2678
- " working\u2026 ",
2727
+ " ",
2728
+ busyLabel,
2729
+ " ",
2679
2730
  elapsed,
2680
2731
  "s \xB7 esc to stop"
2681
2732
  ] }) : /* @__PURE__ */ jsx2(Text2, { children: renderInput(editor) })
@@ -2702,6 +2753,18 @@ function App({ client, config, wallet, session, initialTask }) {
2702
2753
  ] })
2703
2754
  ] });
2704
2755
  }
2756
+ function sleep(ms, signal) {
2757
+ return new Promise((resolve2) => {
2758
+ if (signal.aborted) return resolve2();
2759
+ const done = () => {
2760
+ clearTimeout(timer);
2761
+ signal.removeEventListener("abort", done);
2762
+ resolve2();
2763
+ };
2764
+ const timer = setTimeout(done, ms);
2765
+ signal.addEventListener("abort", done, { once: true });
2766
+ });
2767
+ }
2705
2768
  function renderInput(state) {
2706
2769
  return state.lines.map((line2, row) => {
2707
2770
  const prefix = row === 0 ? "" : "\n";
@@ -2762,7 +2825,7 @@ function tailLines(text, max) {
2762
2825
  const lines = text.split("\n");
2763
2826
  return lines.length <= max ? text : lines.slice(-max).join("\n");
2764
2827
  }
2765
- var SPINNER, LIVE_OUTPUT_LINES, COMMITTED_OUTPUT_LINES;
2828
+ var SPINNER, WORKING, WAITING_FOR_REWARD, LOADING, COMPACTING, LIVE_OUTPUT_LINES, COMMITTED_OUTPUT_LINES;
2766
2829
  var init_app = __esm({
2767
2830
  "src/tui/app.tsx"() {
2768
2831
  "use strict";
@@ -2774,6 +2837,7 @@ var init_app = __esm({
2774
2837
  init_compact();
2775
2838
  init_kimi();
2776
2839
  init_browser();
2840
+ init_version();
2777
2841
  init_tools();
2778
2842
  init_permissions();
2779
2843
  init_session();
@@ -2785,6 +2849,10 @@ var init_app = __esm({
2785
2849
  init_suggest();
2786
2850
  init_views();
2787
2851
  SPINNER = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
2852
+ WORKING = "working\u2026";
2853
+ WAITING_FOR_REWARD = "waiting for the offer\u2026";
2854
+ LOADING = "loading\u2026";
2855
+ COMPACTING = "compacting\u2026";
2788
2856
  LIVE_OUTPUT_LINES = 5;
2789
2857
  COMMITTED_OUTPUT_LINES = 4;
2790
2858
  }
@@ -2819,6 +2887,35 @@ init_session();
2819
2887
  init_kimi();
2820
2888
  init_banner();
2821
2889
  init_browser();
2890
+
2891
+ // src/title.ts
2892
+ var APP_TITLE = "Clixad";
2893
+ function titleEnabled({ isTTY, env }) {
2894
+ const flag = env.CLIXAD_TITLE?.trim().toLowerCase();
2895
+ if (flag === "0" || flag === "false" || flag === "off" || flag === "no") return false;
2896
+ if (!isTTY) return false;
2897
+ if (env.TERM === "dumb") return false;
2898
+ if (env.CI !== void 0 && env.CI !== "") return false;
2899
+ return true;
2900
+ }
2901
+ function titleSequence(title) {
2902
+ return `\x1B]0;${title.replace(/[\x00-\x1f\x7f]/g, " ").trim()}\x07`;
2903
+ }
2904
+ function titleStream(streams = [process.stdout, process.stderr]) {
2905
+ return streams.find((s) => s?.isTTY);
2906
+ }
2907
+ function setTerminalTitle(title = APP_TITLE, out = titleStream()) {
2908
+ process.title = title.toLowerCase();
2909
+ if (!out || !titleEnabled({ isTTY: out.isTTY, env: process.env })) return;
2910
+ out.write(titleSequence(title));
2911
+ }
2912
+ function clearTerminalTitle(out = titleStream()) {
2913
+ if (!out || !titleEnabled({ isTTY: out.isTTY, env: process.env })) return;
2914
+ out.write(titleSequence(""));
2915
+ }
2916
+
2917
+ // src/main.ts
2918
+ init_version();
2822
2919
  var c = {
2823
2920
  cyan: (s) => `\x1B[36m${s}\x1B[0m`,
2824
2921
  green: (s) => `\x1B[32m${s}\x1B[0m`,
@@ -2828,6 +2925,8 @@ var c = {
2828
2925
  bold: (s) => `\x1B[1m${s}\x1B[0m`
2829
2926
  };
2830
2927
  async function main() {
2928
+ setTerminalTitle();
2929
+ process.on("exit", () => clearTerminalTitle());
2831
2930
  const [cmd, ...rest] = process.argv.slice(2);
2832
2931
  const config = loadConfig();
2833
2932
  const client = new GatewayClient(config);
@@ -2866,6 +2965,13 @@ async function main() {
2866
2965
  case "--help":
2867
2966
  case "-h":
2868
2967
  return printHelp();
2968
+ // The first thing anyone types after an install, and it used to land in
2969
+ // `unknown command` and print the help with exit code 1. Bare, no "clixad"
2970
+ // prefix and no colour: it gets piped into scripts and issue reports.
2971
+ case "version":
2972
+ case "--version":
2973
+ case "-v":
2974
+ return void console.log(VERSION);
2869
2975
  case void 0:
2870
2976
  return repl(client, config);
2871
2977
  default:
@@ -2925,7 +3031,7 @@ async function githubLogin(client, config, start, invite) {
2925
3031
  const deadline = Date.now() + start.expires_in * 1e3;
2926
3032
  let interval = Math.max(start.interval, 1);
2927
3033
  while (Date.now() < deadline) {
2928
- await sleep(interval * 1e3);
3034
+ await sleep2(interval * 1e3);
2929
3035
  process.stdout.write(c.dim("."));
2930
3036
  const poll = await client.devicePoll(start.session, invite);
2931
3037
  if (poll.status === "pending") {
@@ -2976,7 +3082,7 @@ async function devLogin(client, config, email, invite) {
2976
3082
  console.log(` balance: ${c.bold(String(res.balance))} credits (signup bonus)`);
2977
3083
  console.log(c.dim(` token stored in ${configPath()}`));
2978
3084
  }
2979
- var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
3085
+ var sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
2980
3086
  function logout(config) {
2981
3087
  delete config.token;
2982
3088
  delete config.userId;
@@ -3052,7 +3158,7 @@ async function earn(client, config) {
3052
3158
  process.stdout.write(c.dim(" waiting for an offer to clear"));
3053
3159
  const deadline = Date.now() + 5 * 60 * 1e3;
3054
3160
  while (Date.now() < deadline) {
3055
- await sleep(3e3);
3161
+ await sleep2(3e3);
3056
3162
  process.stdout.write(c.dim("."));
3057
3163
  const balance = (await safeWallet(client))?.balance ?? before;
3058
3164
  if (balance > before) {
@@ -3097,7 +3203,7 @@ async function buyCmd(client, config, pack) {
3097
3203
  process.stdout.write(c.dim(" waiting for payment to clear"));
3098
3204
  const deadline = Date.now() + 5 * 60 * 1e3;
3099
3205
  while (Date.now() < deadline) {
3100
- await sleep(3e3);
3206
+ await sleep2(3e3);
3101
3207
  process.stdout.write(c.dim("."));
3102
3208
  const balance = (await safeWallet(client))?.balance ?? before;
3103
3209
  if (balance > before) {
@@ -3266,6 +3372,7 @@ function printHelp() {
3266
3372
  ${c.cyan("code")} ["<task>"] launch the full Kimi CLI coding agent on the current dir
3267
3373
  ${c.cyan("--continue")} resume the last session in this directory
3268
3374
  ${c.cyan("--resume")} [id] list saved sessions, or resume one
3375
+ ${c.cyan("--version")} print the version and exit
3269
3376
  (no command) interactive coding REPL`);
3270
3377
  }
3271
3378
  main().catch((err) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clixad",
3
- "version": "0.0.1-beta.1",
3
+ "version": "0.0.1-beta.3",
4
4
  "description": "Free AI coding agent in your terminal, funded by rewarded ads.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",