clixad 0.0.1-beta.23 → 0.0.1-beta.25
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 +259 -28
- package/package.json +1 -1
package/dist/clixad.mjs
CHANGED
|
@@ -94,14 +94,62 @@ var init_estimate = __esm({
|
|
|
94
94
|
});
|
|
95
95
|
|
|
96
96
|
// src/sponsor/formats.ts
|
|
97
|
-
|
|
97
|
+
function isAdFormat(value) {
|
|
98
|
+
return typeof value === "string" && AD_FORMATS.includes(value);
|
|
99
|
+
}
|
|
100
|
+
var AD_FORMATS, EXTRA_AD_FORMATS;
|
|
98
101
|
var init_formats = __esm({
|
|
99
102
|
"src/sponsor/formats.ts"() {
|
|
100
103
|
"use strict";
|
|
104
|
+
AD_FORMATS = ["top_bar", "sidebar_card", "status_bar"];
|
|
101
105
|
EXTRA_AD_FORMATS = ["sidebar_card", "status_bar"];
|
|
102
106
|
}
|
|
103
107
|
});
|
|
104
108
|
|
|
109
|
+
// src/sponsor/direct.ts
|
|
110
|
+
function sanitizeAdText(raw) {
|
|
111
|
+
return raw.replace(/\u001b\[[0-?]*[ -/]*[@-~]/g, "").replace(/\u001b\][^\u0007\u001b]*(?:\u0007|\u001b\\)?/g, "").replace(/[\u0000-\u001f\u007f-\u009f]/g, " ").replace(/[--]/g, "").replace(/[-]/g, "").replace(/\s+/g, " ").trim();
|
|
112
|
+
}
|
|
113
|
+
function parseDirectLines(body) {
|
|
114
|
+
const raw = body?.lines;
|
|
115
|
+
if (!Array.isArray(raw)) return [];
|
|
116
|
+
const out = [];
|
|
117
|
+
const seen = /* @__PURE__ */ new Set();
|
|
118
|
+
for (const item of raw) {
|
|
119
|
+
if (!item || typeof item !== "object") continue;
|
|
120
|
+
const e = item;
|
|
121
|
+
if (!isAdFormat(e.format) || seen.has(e.format)) continue;
|
|
122
|
+
if (e.hold === true) {
|
|
123
|
+
out.push({ format: e.format, hold: true });
|
|
124
|
+
seen.add(e.format);
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (typeof e.text !== "string" || typeof e.serve_token !== "string" || typeof e.click_url !== "string") continue;
|
|
128
|
+
const text = sanitizeAdText(e.text).slice(0, MAX_TEXT);
|
|
129
|
+
if (!text || !e.serve_token || e.serve_token.length > 2e3) continue;
|
|
130
|
+
let clickUrl;
|
|
131
|
+
try {
|
|
132
|
+
const url = new URL(e.click_url);
|
|
133
|
+
if (url.protocol !== "https:" && url.protocol !== "http:") continue;
|
|
134
|
+
clickUrl = url.toString();
|
|
135
|
+
} catch {
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
out.push({ format: e.format, text, serveToken: e.serve_token, clickUrl });
|
|
139
|
+
seen.add(e.format);
|
|
140
|
+
}
|
|
141
|
+
return out;
|
|
142
|
+
}
|
|
143
|
+
var DIRECT_ASK_TIMEOUT_MS, MAX_TEXT;
|
|
144
|
+
var init_direct = __esm({
|
|
145
|
+
"src/sponsor/direct.ts"() {
|
|
146
|
+
"use strict";
|
|
147
|
+
init_formats();
|
|
148
|
+
DIRECT_ASK_TIMEOUT_MS = 1500;
|
|
149
|
+
MAX_TEXT = 200;
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
|
|
105
153
|
// src/edge.ts
|
|
106
154
|
function detectEdgeBlock(status, headers, body) {
|
|
107
155
|
if (status !== 403) return void 0;
|
|
@@ -327,6 +375,13 @@ function extraFormatIds(raw) {
|
|
|
327
375
|
function imagePart(image) {
|
|
328
376
|
return { type: "image_url", image_url: { url: `data:${image.mimeType};base64,${image.data}` } };
|
|
329
377
|
}
|
|
378
|
+
function withoutReasoning(messages) {
|
|
379
|
+
return messages.map((message) => {
|
|
380
|
+
if (!message.reasoning_details) return message;
|
|
381
|
+
const { reasoning_details: _dropped, ...rest } = message;
|
|
382
|
+
return rest;
|
|
383
|
+
});
|
|
384
|
+
}
|
|
330
385
|
function messageText(message) {
|
|
331
386
|
const content = message.content;
|
|
332
387
|
if (typeof content === "string") return content;
|
|
@@ -447,6 +502,26 @@ function accumulateToolCall(calls, part, fallbackIndex) {
|
|
|
447
502
|
if (part.function?.arguments) current.function.arguments += part.function.arguments;
|
|
448
503
|
calls.set(index, current);
|
|
449
504
|
}
|
|
505
|
+
function mergeReasoningDetails(acc, delta) {
|
|
506
|
+
if (!Array.isArray(delta)) return;
|
|
507
|
+
for (const piece of delta) {
|
|
508
|
+
if (!piece || typeof piece !== "object") continue;
|
|
509
|
+
const part = piece;
|
|
510
|
+
const existing = typeof part.index === "number" ? acc.find((block) => block.index === part.index) : void 0;
|
|
511
|
+
if (!existing) {
|
|
512
|
+
acc.push({ ...part });
|
|
513
|
+
continue;
|
|
514
|
+
}
|
|
515
|
+
for (const [key, value] of Object.entries(part)) {
|
|
516
|
+
if (value === null || value === void 0) continue;
|
|
517
|
+
if ((key === "text" || key === "summary" || key === "data") && typeof value === "string") {
|
|
518
|
+
existing[key] = `${typeof existing[key] === "string" ? existing[key] : ""}${value}`;
|
|
519
|
+
} else {
|
|
520
|
+
existing[key] = value;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
450
525
|
async function* parseSSE(body) {
|
|
451
526
|
const reader = body.getReader();
|
|
452
527
|
const decoder = new TextDecoder();
|
|
@@ -471,6 +546,7 @@ var init_client = __esm({
|
|
|
471
546
|
"use strict";
|
|
472
547
|
init_estimate();
|
|
473
548
|
init_formats();
|
|
549
|
+
init_direct();
|
|
474
550
|
init_edge();
|
|
475
551
|
CHAT_ENCODED_CONTENT_TYPE = "application/vnd.clixad.chat+gzip";
|
|
476
552
|
LEDGER_REASONS = {
|
|
@@ -618,6 +694,7 @@ var init_client = __esm({
|
|
|
618
694
|
return { status: "closed", message: closed.message, waitlistUrl: closed.waitlist_url };
|
|
619
695
|
}
|
|
620
696
|
if (!res.ok && !("status" in data && data.status)) {
|
|
697
|
+
if (res.status >= 500 || res.status === 429) return { status: "unavailable", error: `http ${res.status}` };
|
|
621
698
|
return { status: "error", error: `http ${res.status}` };
|
|
622
699
|
}
|
|
623
700
|
return data;
|
|
@@ -954,6 +1031,51 @@ var init_client = __esm({
|
|
|
954
1031
|
return 0;
|
|
955
1032
|
}
|
|
956
1033
|
}
|
|
1034
|
+
/**
|
|
1035
|
+
* Ask for booked lines (step 2): one ask per model call, naming the slots
|
|
1036
|
+
* that fit the terminal now. See `sponsor/direct.ts` for the contract.
|
|
1037
|
+
*
|
|
1038
|
+
* Never throws, for `sponsorConfig`'s reason. A 404 means a gateway that
|
|
1039
|
+
* does not know the route, so `supported: false` tells the caller to stop
|
|
1040
|
+
* asking for the rest of the session; every other failure (a timeout, a 429,
|
|
1041
|
+
* a 5xx, a malformed body) is simply "nothing booked" this time.
|
|
1042
|
+
*/
|
|
1043
|
+
async directSponsor(formats, cols, signal) {
|
|
1044
|
+
try {
|
|
1045
|
+
const res = await gatewayFetch(`${this.config.gatewayUrl}/v1/sponsor/direct`, {
|
|
1046
|
+
method: "POST",
|
|
1047
|
+
headers: this.headers(),
|
|
1048
|
+
...signal ? { signal } : {},
|
|
1049
|
+
body: JSON.stringify({ formats, cols })
|
|
1050
|
+
});
|
|
1051
|
+
if (res.status === 404) return { supported: false, lines: [] };
|
|
1052
|
+
if (!res.ok) return { supported: true, lines: [] };
|
|
1053
|
+
return { supported: true, lines: parseDirectLines(await res.json()) };
|
|
1054
|
+
} catch {
|
|
1055
|
+
return { supported: true, lines: [] };
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
/**
|
|
1059
|
+
* Report the booked lines a turn drew, in one call, after the turn is over.
|
|
1060
|
+
* Never to `/v1/sponsor/impression`, which would credit them as ADtention's.
|
|
1061
|
+
* Never throws; answers what was credited, for the tally and for tests.
|
|
1062
|
+
*/
|
|
1063
|
+
async reportDirectImpressions(impressions, signal) {
|
|
1064
|
+
if (impressions.length === 0) return 0;
|
|
1065
|
+
try {
|
|
1066
|
+
const res = await gatewayFetch(`${this.config.gatewayUrl}/v1/sponsor/direct/impression`, {
|
|
1067
|
+
method: "POST",
|
|
1068
|
+
headers: this.headers(),
|
|
1069
|
+
...signal ? { signal } : {},
|
|
1070
|
+
body: JSON.stringify({ impressions: impressions.map((i) => ({ format: i.format, serve_token: i.serveToken })) })
|
|
1071
|
+
});
|
|
1072
|
+
if (!res.ok) return 0;
|
|
1073
|
+
const body = await res.json();
|
|
1074
|
+
return typeof body.credited === "number" ? body.credited : 0;
|
|
1075
|
+
} catch {
|
|
1076
|
+
return 0;
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
957
1079
|
/**
|
|
958
1080
|
* Search the web, through the gateway.
|
|
959
1081
|
*
|
|
@@ -1150,6 +1272,7 @@ var init_client = __esm({
|
|
|
1150
1272
|
let balance = 0;
|
|
1151
1273
|
let streamError;
|
|
1152
1274
|
const calls = /* @__PURE__ */ new Map();
|
|
1275
|
+
const reasoning = [];
|
|
1153
1276
|
for await (const evt of parseSSE(res.body)) {
|
|
1154
1277
|
if (evt === "[DONE]") break;
|
|
1155
1278
|
let json;
|
|
@@ -1167,6 +1290,7 @@ var init_client = __esm({
|
|
|
1167
1290
|
for (const [index, part] of (choice?.delta?.tool_calls ?? []).entries()) {
|
|
1168
1291
|
accumulateToolCall(calls, part, index);
|
|
1169
1292
|
}
|
|
1293
|
+
mergeReasoningDetails(reasoning, choice?.delta?.reasoning_details);
|
|
1170
1294
|
if (choice?.finish_reason) finishReason = choice.finish_reason;
|
|
1171
1295
|
if (json.error) streamError = json.error.message || "the model stream failed";
|
|
1172
1296
|
if (json.clixad) {
|
|
@@ -1179,6 +1303,7 @@ var init_client = __esm({
|
|
|
1179
1303
|
const message = { role: "assistant", content: content || null };
|
|
1180
1304
|
if (calls.size > 0) {
|
|
1181
1305
|
message.tool_calls = [...calls.entries()].sort(([a], [b]) => a - b).map(([, c2]) => c2);
|
|
1306
|
+
if (reasoning.length) message.reasoning_details = reasoning;
|
|
1182
1307
|
}
|
|
1183
1308
|
return { message, finishReason, creditsCharged, balance, ...free };
|
|
1184
1309
|
}
|
|
@@ -1413,11 +1538,24 @@ async function githubLogin(client, config, start, invite, report, signal) {
|
|
|
1413
1538
|
openBrowser(start.verification_uri);
|
|
1414
1539
|
const deadline = Date.now() + start.expires_in * 1e3;
|
|
1415
1540
|
let interval = Math.max(start.interval, 1);
|
|
1541
|
+
let unavailableSince;
|
|
1416
1542
|
while (Date.now() < deadline) {
|
|
1417
1543
|
await sleep2(interval * 1e3, signal);
|
|
1418
1544
|
if (signal?.aborted) return { status: "aborted" };
|
|
1419
1545
|
report.tick?.();
|
|
1420
|
-
|
|
1546
|
+
let poll;
|
|
1547
|
+
try {
|
|
1548
|
+
poll = await client.devicePoll(start.session, invite);
|
|
1549
|
+
} catch (err) {
|
|
1550
|
+
if (!(err instanceof GatewayUnreachableError)) throw err;
|
|
1551
|
+
poll = { status: "unavailable", error: err.message };
|
|
1552
|
+
}
|
|
1553
|
+
if (poll.status === "unavailable") {
|
|
1554
|
+
unavailableSince ??= Date.now();
|
|
1555
|
+
if (Date.now() - unavailableSince > UNAVAILABLE_GIVE_UP_MS) return { status: "failed", error: poll.error };
|
|
1556
|
+
continue;
|
|
1557
|
+
}
|
|
1558
|
+
unavailableSince = void 0;
|
|
1421
1559
|
if (poll.status === "pending") {
|
|
1422
1560
|
if (poll.interval) interval = poll.interval;
|
|
1423
1561
|
continue;
|
|
@@ -1445,10 +1583,19 @@ async function githubLogin(client, config, start, invite, report, signal) {
|
|
|
1445
1583
|
}
|
|
1446
1584
|
};
|
|
1447
1585
|
}
|
|
1448
|
-
return { status: "failed", error: poll.error ?? poll.status };
|
|
1586
|
+
return { status: "failed", error: describePollError(poll.error ?? poll.status) };
|
|
1449
1587
|
}
|
|
1450
1588
|
return { status: "timeout" };
|
|
1451
1589
|
}
|
|
1590
|
+
function describePollError(error) {
|
|
1591
|
+
if (error === "unknown_session") {
|
|
1592
|
+
return "the server restarted while you were signing in, so this code no longer works. Sign in again.";
|
|
1593
|
+
}
|
|
1594
|
+
if (error === "login_unavailable") {
|
|
1595
|
+
return "GitHub approved the sign-in, but the server could not finish it. Try again in a minute.";
|
|
1596
|
+
}
|
|
1597
|
+
return error;
|
|
1598
|
+
}
|
|
1452
1599
|
async function devLogin(client, config, email, invite) {
|
|
1453
1600
|
let res;
|
|
1454
1601
|
try {
|
|
@@ -1487,7 +1634,7 @@ function sleep2(ms, signal) {
|
|
|
1487
1634
|
signal.addEventListener("abort", done, { once: true });
|
|
1488
1635
|
});
|
|
1489
1636
|
}
|
|
1490
|
-
var TERMS_URL, PRIVACY_URL, TERMS_NOTICE;
|
|
1637
|
+
var TERMS_URL, PRIVACY_URL, TERMS_NOTICE, UNAVAILABLE_GIVE_UP_MS;
|
|
1491
1638
|
var init_login = __esm({
|
|
1492
1639
|
"src/login.ts"() {
|
|
1493
1640
|
"use strict";
|
|
@@ -1499,6 +1646,7 @@ var init_login = __esm({
|
|
|
1499
1646
|
TERMS_NOTICE = `By creating an account you confirm that you are at least 18 and that you agree to
|
|
1500
1647
|
the Terms \u2014 ${TERMS_URL}
|
|
1501
1648
|
and the Privacy Policy \u2014 ${PRIVACY_URL}`;
|
|
1649
|
+
UNAVAILABLE_GIVE_UP_MS = 18e4;
|
|
1502
1650
|
}
|
|
1503
1651
|
});
|
|
1504
1652
|
|
|
@@ -4060,6 +4208,19 @@ ${NO_SEARCH_INSTRUCTION}`,
|
|
|
4060
4208
|
|
|
4061
4209
|
(the sub-agent hit its step limit \u2014 this answer may be incomplete)` : answer;
|
|
4062
4210
|
}
|
|
4211
|
+
function emitUsage(turn) {
|
|
4212
|
+
emit({
|
|
4213
|
+
type: "usage",
|
|
4214
|
+
creditsCharged: turn.creditsCharged,
|
|
4215
|
+
balance: turn.balance,
|
|
4216
|
+
...turn.free ? {
|
|
4217
|
+
free: true,
|
|
4218
|
+
creditsWaived: turn.creditsWaived ?? 0,
|
|
4219
|
+
freeCreditsLeft: turn.freeCreditsLeft ?? 0
|
|
4220
|
+
} : {}
|
|
4221
|
+
});
|
|
4222
|
+
}
|
|
4223
|
+
let retriedEmpty = false;
|
|
4063
4224
|
for (let step = 0; step < maxSteps; step++) {
|
|
4064
4225
|
if (opts.signal?.aborted) return stop("aborted");
|
|
4065
4226
|
let turn;
|
|
@@ -4077,23 +4238,27 @@ ${NO_SEARCH_INSTRUCTION}`,
|
|
|
4077
4238
|
creditsWaived += turn.creditsWaived ?? 0;
|
|
4078
4239
|
if (turn.freeCreditsLeft !== void 0) freeCreditsLeft = turn.freeCreditsLeft;
|
|
4079
4240
|
balance = turn.balance;
|
|
4080
|
-
|
|
4081
|
-
type: "usage",
|
|
4082
|
-
creditsCharged: turn.creditsCharged,
|
|
4083
|
-
balance: turn.balance,
|
|
4084
|
-
...turn.free ? {
|
|
4085
|
-
free: true,
|
|
4086
|
-
creditsWaived: turn.creditsWaived ?? 0,
|
|
4087
|
-
freeCreditsLeft: turn.freeCreditsLeft ?? 0
|
|
4088
|
-
} : {}
|
|
4089
|
-
});
|
|
4090
|
-
messages.push(turn.message);
|
|
4241
|
+
emitUsage(turn);
|
|
4091
4242
|
const content = messageText(turn.message);
|
|
4092
|
-
if (content) lastText = content;
|
|
4093
4243
|
const calls = turn.message.tool_calls ?? [];
|
|
4244
|
+
if (calls.length === 0 && !content.trim() && !retriedEmpty) {
|
|
4245
|
+
retriedEmpty = true;
|
|
4246
|
+
continue;
|
|
4247
|
+
}
|
|
4248
|
+
retriedEmpty = false;
|
|
4249
|
+
messages.push(turn.message);
|
|
4250
|
+
if (content) lastText = content;
|
|
4094
4251
|
if (calls.length === 0) {
|
|
4095
4252
|
emit({ type: "final", content, creditsCharged, balance });
|
|
4096
|
-
return {
|
|
4253
|
+
return {
|
|
4254
|
+
content,
|
|
4255
|
+
messages: withoutReasoning(messages),
|
|
4256
|
+
creditsCharged,
|
|
4257
|
+
balance,
|
|
4258
|
+
creditsWaived,
|
|
4259
|
+
freeCreditsLeft,
|
|
4260
|
+
steps: step + 1
|
|
4261
|
+
};
|
|
4097
4262
|
}
|
|
4098
4263
|
if (content) emit({ type: "message", content });
|
|
4099
4264
|
pendingImages = [];
|
|
@@ -4117,7 +4282,7 @@ ${NO_SEARCH_INSTRUCTION}`,
|
|
|
4117
4282
|
emit({ type: "max_steps" });
|
|
4118
4283
|
return {
|
|
4119
4284
|
content: lastText || "(stopped: reached max steps)",
|
|
4120
|
-
messages,
|
|
4285
|
+
messages: withoutReasoning(messages),
|
|
4121
4286
|
creditsCharged,
|
|
4122
4287
|
balance,
|
|
4123
4288
|
creditsWaived,
|
|
@@ -4127,7 +4292,16 @@ ${NO_SEARCH_INSTRUCTION}`,
|
|
|
4127
4292
|
};
|
|
4128
4293
|
function stop(reason) {
|
|
4129
4294
|
emit({ type: reason });
|
|
4130
|
-
return {
|
|
4295
|
+
return {
|
|
4296
|
+
content: lastText,
|
|
4297
|
+
messages: withoutReasoning(messages),
|
|
4298
|
+
creditsCharged,
|
|
4299
|
+
balance,
|
|
4300
|
+
creditsWaived,
|
|
4301
|
+
freeCreditsLeft,
|
|
4302
|
+
steps: 0,
|
|
4303
|
+
stopped: reason
|
|
4304
|
+
};
|
|
4131
4305
|
}
|
|
4132
4306
|
}
|
|
4133
4307
|
function toolMessage(call, content) {
|
|
@@ -4230,7 +4404,7 @@ var init_agent = __esm({
|
|
|
4230
4404
|
init_mcp();
|
|
4231
4405
|
init_client();
|
|
4232
4406
|
SUBAGENT_MAX_STEPS = 12;
|
|
4233
|
-
SYSTEM_PROMPT = "You are Clixad, a terminal coding agent. You can read, search, write and edit files and run shell commands, all confined to the user's workspace. Find your way around with glob and grep before reading whole files. Prefer edit_file over write_file for existing files. Make minimal correct edits, verify them when a test or build command is available, and stop when the task is complete. Keep your final message short: say what you did and why.\n\nNot every message is a task. If the user asks a question, or asks you to say something, answer in plain text and call no tools at all. Reach for a file or a command only when the request is actually about one, and when a message is ambiguous, prefer the reading of it that changes nothing.\n\nA tool call that was refused did not happen. Never describe it as done, and do not repeat it on a later message unless the user asks for it again.\n\nReach outside the workspace when the answer is outside it: web_search for current documentation, releases and error messages, then web_fetch to read the page. Do not guess at an API you could look up.\n\nStart anything that does not exit on its own \u2014 dev servers, watchers, tailed logs \u2014 with run_command background: true, and read it with read_output. A foreground command is killed after its timeout.\n\nWhen finding something out means opening many files, give it to task instead: the sub-agent reads them in its own context and reports back, which keeps this conversation short. Use todo_write for work with several distinct steps, and keep it current as you go.";
|
|
4407
|
+
SYSTEM_PROMPT = "You are Clixad, a terminal coding agent. You can read, search, write and edit files and run shell commands, all confined to the user's workspace. When someone asks who or what you are, answer that you are Clixad, in their language; do not introduce yourself as the underlying language model or as a product of the company that trained it. If asked which model you run on, say it is the one selected with /model, shown under the input box. Find your way around with glob and grep before reading whole files. Prefer edit_file over write_file for existing files. Make minimal correct edits, verify them when a test or build command is available, and stop when the task is complete. Keep your final message short: say what you did and why.\n\nNot every message is a task. If the user asks a question, or asks you to say something, answer in plain text and call no tools at all. Reach for a file or a command only when the request is actually about one, and when a message is ambiguous, prefer the reading of it that changes nothing.\n\nA tool call that was refused did not happen. Never describe it as done, and do not repeat it on a later message unless the user asks for it again.\n\nReach outside the workspace when the answer is outside it: web_search for current documentation, releases and error messages, then web_fetch to read the page. Do not guess at an API you could look up.\n\nStart anything that does not exit on its own \u2014 dev servers, watchers, tailed logs \u2014 with run_command background: true, and read it with read_output. A foreground command is killed after its timeout.\n\nWhen finding something out means opening many files, give it to task instead: the sub-agent reads them in its own context and reports back, which keeps this conversation short. Use todo_write for work with several distinct steps, and keep it current as you go.";
|
|
4234
4408
|
NO_SEARCH_INSTRUCTION = [
|
|
4235
4409
|
"# Web search is not available on this gateway",
|
|
4236
4410
|
"There is no web_search tool. web_fetch works normally and needs no key, so fetch a URL directly",
|
|
@@ -4620,7 +4794,7 @@ var init_kimi = __esm({
|
|
|
4620
4794
|
"gemini-3.8-flash": 1048576,
|
|
4621
4795
|
"kimi-k2.7-code": 262144,
|
|
4622
4796
|
"claude-haiku-4.5": 2e5,
|
|
4623
|
-
"claude-sonnet-5": 1e6,
|
|
4797
|
+
"claude-sonnet-5.5": 1e6,
|
|
4624
4798
|
"gpt-6-sol": 105e4,
|
|
4625
4799
|
"kimi-k3": 1048576,
|
|
4626
4800
|
"claude-opus-5.5": 1e6,
|
|
@@ -4634,7 +4808,9 @@ var init_kimi = __esm({
|
|
|
4634
4808
|
"gpt-5.2": 105e4,
|
|
4635
4809
|
"claude-opus-5": 1e6,
|
|
4636
4810
|
"gpt-5.5": 105e4,
|
|
4637
|
-
"gpt-5.2-pro": 105e4
|
|
4811
|
+
"gpt-5.2-pro": 105e4,
|
|
4812
|
+
// Retired on 2026-09-29 for Claude Sonnet 5.5, same window.
|
|
4813
|
+
"claude-sonnet-5": 1e6
|
|
4638
4814
|
};
|
|
4639
4815
|
DEFAULT_CONTEXT_TOKENS = 256e3;
|
|
4640
4816
|
INSTALL_HELP = `Kimi CLI is not installed (or not on PATH).
|
|
@@ -5751,7 +5927,7 @@ var init_views = __esm({
|
|
|
5751
5927
|
});
|
|
5752
5928
|
|
|
5753
5929
|
// src/tui/app.tsx
|
|
5754
|
-
import { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
5930
|
+
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
5755
5931
|
import { Box as Box2, Static, Text as Text2, useApp, useInput, usePaste, useStdout } from "ink";
|
|
5756
5932
|
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
5757
5933
|
function buyDeclarationLines(pack) {
|
|
@@ -5807,6 +5983,7 @@ function App({
|
|
|
5807
5983
|
notices: notices2,
|
|
5808
5984
|
sponsorServe,
|
|
5809
5985
|
sponsorFormats,
|
|
5986
|
+
sponsorDirect,
|
|
5810
5987
|
initHint
|
|
5811
5988
|
}) {
|
|
5812
5989
|
const { exit } = useApp();
|
|
@@ -5915,6 +6092,8 @@ function App({
|
|
|
5915
6092
|
const sponsorPrevRef = useRef(void 0);
|
|
5916
6093
|
const sponsorCallRef = useRef(0);
|
|
5917
6094
|
const pendingImpressionRef = useRef(/* @__PURE__ */ new Map());
|
|
6095
|
+
const pendingDirectRef = useRef(/* @__PURE__ */ new Map());
|
|
6096
|
+
const directSupportedRef = useRef(true);
|
|
5918
6097
|
const drawnRef = useRef(/* @__PURE__ */ new Set());
|
|
5919
6098
|
const sponsorSlotRef = useRef(
|
|
5920
6099
|
/* @__PURE__ */ new Map()
|
|
@@ -5965,6 +6144,9 @@ function App({
|
|
|
5965
6144
|
);
|
|
5966
6145
|
const tallyRef = useRef(createTally());
|
|
5967
6146
|
const heightCacheRef = useRef(/* @__PURE__ */ new Map());
|
|
6147
|
+
const screenRef = useRef(
|
|
6148
|
+
null
|
|
6149
|
+
);
|
|
5968
6150
|
const push = useCallback((e) => {
|
|
5969
6151
|
const id = idRef.current++;
|
|
5970
6152
|
setEntries((prev) => [...prev, { ...e, id }]);
|
|
@@ -6123,8 +6305,7 @@ function App({
|
|
|
6123
6305
|
} else {
|
|
6124
6306
|
setSponsor(null);
|
|
6125
6307
|
}
|
|
6126
|
-
|
|
6127
|
-
if (!adFitsFormat(format, colsRef.current)) continue;
|
|
6308
|
+
const fetchNetwork = (format) => {
|
|
6128
6309
|
void remoteSponsorRef.current[format].fetch().then((line2) => {
|
|
6129
6310
|
if (!line2 || call !== sponsorCallRef.current) return;
|
|
6130
6311
|
if (!adFitsFormat(format, colsRef.current)) return;
|
|
@@ -6142,15 +6323,55 @@ function App({
|
|
|
6142
6323
|
recordImpression(tallyRef.current, line2.id);
|
|
6143
6324
|
pendingImpressionRef.current.set(format, { call, impression: line2.impression });
|
|
6144
6325
|
});
|
|
6145
|
-
}
|
|
6326
|
+
};
|
|
6327
|
+
const paintDirect = (line2) => {
|
|
6328
|
+
const { format } = line2;
|
|
6329
|
+
if (call !== sponsorCallRef.current) return;
|
|
6330
|
+
if (!adFitsFormat(format, colsRef.current)) return;
|
|
6331
|
+
if (format !== "top_bar" && modalOpenRef.current) return;
|
|
6332
|
+
const drawnId = `direct:${call}:${format}`;
|
|
6333
|
+
if (format === "top_bar") {
|
|
6334
|
+
if (!sponsorRow(line2.text, colsRef.current, "network")) return;
|
|
6335
|
+
setSponsor({ text: line2.text, origin: "network", impressionId: drawnId });
|
|
6336
|
+
} else {
|
|
6337
|
+
setAdSlots((slots) => ({ ...slots, [format]: { text: line2.text, impressionId: drawnId } }));
|
|
6338
|
+
}
|
|
6339
|
+
pendingDirectRef.current.set(format, { call, serveToken: line2.serveToken, drawnId });
|
|
6340
|
+
};
|
|
6341
|
+
const fitting = AD_FORMATS.filter((format) => adFitsFormat(format, colsRef.current));
|
|
6342
|
+
void (async () => {
|
|
6343
|
+
let direct = [];
|
|
6344
|
+
if (directSupportedRef.current && fitting.length > 0) {
|
|
6345
|
+
const ask3 = sponsorDirect ?? ((formats, cols2, signal) => client.directSponsor(formats, cols2, signal));
|
|
6346
|
+
let answer = { supported: true, lines: [] };
|
|
6347
|
+
try {
|
|
6348
|
+
answer = await ask3(fitting, colsRef.current, AbortSignal.timeout(DIRECT_ASK_TIMEOUT_MS));
|
|
6349
|
+
} catch {
|
|
6350
|
+
}
|
|
6351
|
+
if (!answer.supported) directSupportedRef.current = false;
|
|
6352
|
+
direct = answer.lines;
|
|
6353
|
+
}
|
|
6354
|
+
if (call !== sponsorCallRef.current) return;
|
|
6355
|
+
for (const format of ["top_bar", ...EXTRA_AD_FORMATS]) {
|
|
6356
|
+
if (!adFitsFormat(format, colsRef.current)) continue;
|
|
6357
|
+
const booked = direct.find((line2) => line2.format === format);
|
|
6358
|
+
if (booked && "hold" in booked) continue;
|
|
6359
|
+
if (booked) paintDirect(booked);
|
|
6360
|
+
else fetchNetwork(format);
|
|
6361
|
+
}
|
|
6362
|
+
})();
|
|
6146
6363
|
},
|
|
6147
|
-
[config.sponsor, stdout, wallet]
|
|
6364
|
+
[config.sponsor, stdout, wallet, client, sponsorDirect]
|
|
6148
6365
|
);
|
|
6149
6366
|
const reportSponsor = useCallback(() => {
|
|
6150
6367
|
const pending = [...pendingImpressionRef.current.values()];
|
|
6368
|
+
const pendingDirect = [...pendingDirectRef.current.entries()];
|
|
6151
6369
|
const drawn = drawnRef.current;
|
|
6152
6370
|
pendingImpressionRef.current = /* @__PURE__ */ new Map();
|
|
6371
|
+
pendingDirectRef.current = /* @__PURE__ */ new Map();
|
|
6153
6372
|
drawnRef.current = /* @__PURE__ */ new Set();
|
|
6373
|
+
const directReports = pendingDirect.filter(([, p]) => p.call === sponsorCallRef.current && drawn.has(p.drawnId)).map(([format, p]) => ({ format, serveToken: p.serveToken }));
|
|
6374
|
+
if (directReports.length > 0) void client.reportDirectImpressions(directReports);
|
|
6154
6375
|
const reports = pending.filter((p) => p.call === sponsorCallRef.current).filter((p) => drawn.has(p.impression.impressionId)).map((p) => p.impression);
|
|
6155
6376
|
if (reports.length === 0) return;
|
|
6156
6377
|
void (async () => {
|
|
@@ -7469,7 +7690,16 @@ ${dropped.map((l) => ` \xB7 ${l}`).join("\n")}`
|
|
|
7469
7690
|
}, 0);
|
|
7470
7691
|
}, [entries, cols]);
|
|
7471
7692
|
const used = chromeHeight + menu.length + pickerHeight + askHeight + planHeight + buyHeight + busyHeight + liveHeight;
|
|
7472
|
-
const
|
|
7693
|
+
const lastScreen = screenRef.current;
|
|
7694
|
+
const freshScreen = !lastScreen || lastScreen.epoch !== staticEpoch || lastScreen.rows !== rows || lastScreen.cols !== cols || printed < lastScreen.printed;
|
|
7695
|
+
const onScreen = Math.max(
|
|
7696
|
+
0,
|
|
7697
|
+
Math.min(freshScreen ? printed : lastScreen.onScreen + (printed - lastScreen.printed), viewport - used)
|
|
7698
|
+
);
|
|
7699
|
+
const spacer = Math.max(0, viewport - onScreen - used);
|
|
7700
|
+
useLayoutEffect(() => {
|
|
7701
|
+
screenRef.current = { epoch: staticEpoch, rows, cols, printed, onScreen };
|
|
7702
|
+
});
|
|
7473
7703
|
const labelW = Math.min(
|
|
7474
7704
|
Math.max(1, Math.floor(cols * 0.5)),
|
|
7475
7705
|
menu.reduce((w, c2) => Math.max(w, visibleLength(c2.label)), 0)
|
|
@@ -7806,6 +8036,7 @@ var init_app = __esm({
|
|
|
7806
8036
|
init_provider();
|
|
7807
8037
|
init_network();
|
|
7808
8038
|
init_formats();
|
|
8039
|
+
init_direct();
|
|
7809
8040
|
init_render();
|
|
7810
8041
|
init_commands();
|
|
7811
8042
|
init_editor();
|