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.
- package/dist/clixad.mjs +200 -93
- 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
|
-
|
|
214
|
-
|
|
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 })
|
|
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:
|
|
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
|
-
|
|
2344
|
-
|
|
2345
|
-
const
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
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
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
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
|
-
|
|
2452
|
-
|
|
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
|
-
}
|
|
2461
|
-
push({ kind: "notice", tone: "error", text: ` ${err.message}` });
|
|
2462
|
-
}
|
|
2463
|
-
setBusy(false);
|
|
2518
|
+
});
|
|
2464
2519
|
return;
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
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
|
-
}
|
|
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
|
|
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)
|
|
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
|
-
"
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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) => {
|