kimiflare 0.34.1 → 0.36.0

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/index.js CHANGED
@@ -1,5 +1,11 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
4
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
5
+ }) : x)(function(x) {
6
+ if (typeof require !== "undefined") return require.apply(this, arguments);
7
+ throw Error('Dynamic require of "' + x + '" is not supported');
8
+ });
3
9
  var __esm = (fn, res) => function __init() {
4
10
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
5
11
  };
@@ -96,6 +102,31 @@ async function loadConfig() {
96
102
  const envCodeMode = readBooleanEnv("KIMIFLARE_CODE_MODE");
97
103
  const envCostAttribution = readBooleanEnv("KIMI_COST_ATTRIBUTION");
98
104
  const envFilePicker = readBooleanEnv("KIMIFLARE_FILE_PICKER");
105
+ const envCloudMode = readBooleanEnv("KIMIFLARE_CLOUD");
106
+ if (envCloudMode) {
107
+ return {
108
+ accountId: "",
109
+ apiToken: "",
110
+ model: envModel,
111
+ cloudMode: true,
112
+ reasoningEffort: envEffort,
113
+ coauthor: envCoauthor?.enabled ?? true,
114
+ coauthorName: envCoauthor?.name,
115
+ coauthorEmail: envCoauthor?.email,
116
+ cacheStablePrompts,
117
+ compiledContext,
118
+ imageHistoryTurns: Number.isNaN(imageHistoryTurns) ? void 0 : imageHistoryTurns,
119
+ memoryEnabled: envMemoryEnabled,
120
+ memoryDbPath: envMemoryDbPath,
121
+ memoryMaxAgeDays: envMemoryMaxAgeDays,
122
+ memoryMaxEntries: envMemoryMaxEntries,
123
+ memoryEmbeddingModel: envMemoryEmbeddingModel,
124
+ plumbingModel: envPlumbingModel,
125
+ codeMode: envCodeMode,
126
+ costAttribution: envCostAttribution ?? false,
127
+ filePicker: envFilePicker ?? true
128
+ };
129
+ }
99
130
  if (envAccount && envToken) {
100
131
  return {
101
132
  accountId: envAccount,
@@ -128,6 +159,31 @@ async function loadConfig() {
128
159
  try {
129
160
  const raw = await readFile(configPath(), "utf8");
130
161
  const parsed = JSON.parse(raw);
162
+ if (parsed.cloudMode) {
163
+ return {
164
+ accountId: envAccount ?? parsed.accountId ?? "",
165
+ apiToken: envToken ?? parsed.apiToken ?? "",
166
+ model: envModel ?? parsed.model ?? DEFAULT_MODEL,
167
+ cloudMode: true,
168
+ reasoningEffort: envEffort ?? parsed.reasoningEffort,
169
+ coauthor: envCoauthor?.enabled ?? parsed.coauthor ?? true,
170
+ coauthorName: envCoauthor?.name ?? parsed.coauthorName,
171
+ coauthorEmail: envCoauthor?.email ?? parsed.coauthorEmail,
172
+ mcpServers: parsed.mcpServers,
173
+ cacheStablePrompts: parsed.cacheStablePrompts ?? cacheStablePrompts,
174
+ compiledContext: parsed.compiledContext ?? compiledContext,
175
+ imageHistoryTurns: Number.isNaN(imageHistoryTurns) ? parsed.imageHistoryTurns : imageHistoryTurns,
176
+ memoryEnabled: envMemoryEnabled ?? parsed.memoryEnabled,
177
+ memoryDbPath: envMemoryDbPath ?? parsed.memoryDbPath,
178
+ memoryMaxAgeDays: envMemoryMaxAgeDays ?? parsed.memoryMaxAgeDays,
179
+ memoryMaxEntries: envMemoryMaxEntries ?? parsed.memoryMaxEntries,
180
+ memoryEmbeddingModel: envMemoryEmbeddingModel ?? parsed.memoryEmbeddingModel,
181
+ plumbingModel: envPlumbingModel ?? parsed.plumbingModel,
182
+ codeMode: envCodeMode ?? parsed.codeMode,
183
+ costAttribution: envCostAttribution ?? parsed.costAttribution ?? false,
184
+ filePicker: envFilePicker ?? parsed.filePicker ?? true
185
+ };
186
+ }
131
187
  if (parsed.accountId && parsed.apiToken) {
132
188
  return {
133
189
  accountId: envAccount ?? parsed.accountId,
@@ -155,7 +211,8 @@ async function loadConfig() {
155
211
  memoryExtractionModel: envMemoryExtractionModel ?? parsed.memoryExtractionModel,
156
212
  codeMode: envCodeMode ?? parsed.codeMode ?? true,
157
213
  costAttribution: envCostAttribution ?? parsed.costAttribution ?? true,
158
- filePicker: envFilePicker ?? parsed.filePicker ?? true
214
+ filePicker: envFilePicker ?? parsed.filePicker ?? true,
215
+ cloudMode: envCloudMode ?? parsed.cloudMode
159
216
  };
160
217
  }
161
218
  } catch {
@@ -270,10 +327,8 @@ async function* readSSE(stream, signal) {
270
327
  const decoder = new TextDecoder("utf-8");
271
328
  let buffer = "";
272
329
  const onAbort = () => {
273
- try {
274
- reader.cancel(new DOMException("aborted", "AbortError"));
275
- } catch {
276
- }
330
+ reader.cancel(new DOMException("aborted", "AbortError")).catch(() => {
331
+ });
277
332
  };
278
333
  signal?.addEventListener("abort", onAbort, { once: true });
279
334
  try {
@@ -443,7 +498,7 @@ async function* runKimi(opts2) {
443
498
  let res;
444
499
  try {
445
500
  const headers = {
446
- Authorization: `Bearer ${opts2.apiToken}`,
501
+ Authorization: `Bearer ${opts2.cloudMode && opts2.cloudToken ? opts2.cloudToken : opts2.apiToken}`,
447
502
  "Content-Type": "application/json",
448
503
  "User-Agent": getUserAgent(),
449
504
  ...gatewayHeaders
@@ -500,6 +555,12 @@ function validateModelId(model) {
500
555
  }
501
556
  function buildKimiRequestTarget(opts2) {
502
557
  validateModelId(opts2.model);
558
+ if (opts2.cloudMode) {
559
+ return {
560
+ url: "https://api.kimiflare.com/v1/chat",
561
+ headers: opts2.cloudToken ? { Authorization: `Bearer ${opts2.cloudToken}` } : {}
562
+ };
563
+ }
503
564
  if (!opts2.gateway?.id) {
504
565
  return {
505
566
  url: `https://api.cloudflare.com/client/v4/accounts/${encodeURIComponent(opts2.accountId)}/ai/run/${opts2.model}`,
@@ -1326,6 +1387,8 @@ var init_api_generator = __esm({
1326
1387
  });
1327
1388
 
1328
1389
  // src/code-mode/sandbox.ts
1390
+ import { join as join6, dirname as dirname3 } from "path";
1391
+ import { pathToFileURL } from "url";
1329
1392
  function stripTypescript(code) {
1330
1393
  let js = code;
1331
1394
  js = js.replace(/interface\s+\w+\s*\{[\s\S]*?\n\}/g, "");
@@ -1342,6 +1405,41 @@ function stripTypescript(code) {
1342
1405
  js = js.replace(/\n{3,}/g, "\n\n");
1343
1406
  return js.trim();
1344
1407
  }
1408
+ async function loadTypescript(cwd) {
1409
+ try {
1410
+ const tsPath = await import.meta.resolve("typescript");
1411
+ return await import(tsPath);
1412
+ } catch {
1413
+ }
1414
+ let dir = cwd;
1415
+ while (dir !== dirname3(dir)) {
1416
+ try {
1417
+ const tsPath = join6(dir, "node_modules", "typescript", "lib", "typescript.js");
1418
+ return await import(pathToFileURL(tsPath).href);
1419
+ } catch {
1420
+ }
1421
+ dir = dirname3(dir);
1422
+ }
1423
+ return null;
1424
+ }
1425
+ async function transpileOrStrip(code, cwd) {
1426
+ const ts = await loadTypescript(cwd);
1427
+ if (ts) {
1428
+ const result = ts.transpileModule(code, {
1429
+ compilerOptions: {
1430
+ module: ts.ModuleKind.ES2022,
1431
+ target: ts.ScriptTarget.ES2022,
1432
+ esModuleInterop: true,
1433
+ isolatedModules: true
1434
+ }
1435
+ });
1436
+ return { js: result.outputText, warnings: [] };
1437
+ }
1438
+ return {
1439
+ js: stripTypescript(code),
1440
+ warnings: ["TypeScript not found in node_modules. Using fallback parser; install typescript for reliable transpilation."]
1441
+ };
1442
+ }
1345
1443
  async function runWithIsolatedVm(opts2) {
1346
1444
  const { Isolate } = await import("isolated-vm");
1347
1445
  const isolate = new Isolate({ memoryLimit: opts2.memoryLimitMB ?? 128 });
@@ -1389,7 +1487,7 @@ async function runWithIsolatedVm(opts2) {
1389
1487
  await context.eval(`var api = {
1390
1488
  ${apiMethods}
1391
1489
  };`);
1392
- const jsCode = stripTypescript(opts2.code);
1490
+ const { js: jsCode, warnings } = await transpileOrStrip(opts2.code, opts2.ctx.cwd);
1393
1491
  const wrapped = `(async function() {
1394
1492
  ${jsCode}
1395
1493
  })();`;
@@ -1400,11 +1498,11 @@ ${jsCode}
1400
1498
  await new Promise((r) => setTimeout(r, 10));
1401
1499
  } catch (err) {
1402
1500
  const message2 = err instanceof Error ? err.message : String(err);
1403
- return { output: "", logs, error: message2, toolCalls };
1501
+ return { output: "", logs, error: message2, toolCalls, warnings };
1404
1502
  } finally {
1405
1503
  isolate.dispose();
1406
1504
  }
1407
- return { output: logs.join("\n"), logs, toolCalls };
1505
+ return { output: logs.join("\n"), logs, toolCalls, warnings };
1408
1506
  }
1409
1507
  async function runWithNodeVm(opts2) {
1410
1508
  const { runInNewContext } = await import("vm");
@@ -1472,7 +1570,7 @@ async function runWithNodeVm(opts2) {
1472
1570
  return result.content;
1473
1571
  };
1474
1572
  }
1475
- const jsCode = stripTypescript(opts2.code);
1573
+ const { js: jsCode, warnings } = await transpileOrStrip(opts2.code, opts2.ctx.cwd);
1476
1574
  const wrapped = `"use strict";
1477
1575
  (async function() {
1478
1576
  ${jsCode}
@@ -1483,9 +1581,9 @@ ${jsCode}
1483
1581
  await new Promise((r) => setTimeout(r, 10));
1484
1582
  } catch (err) {
1485
1583
  const message2 = err instanceof Error ? err.message : String(err);
1486
- return { output: "", logs, error: message2, toolCalls };
1584
+ return { output: "", logs, error: message2, toolCalls, warnings };
1487
1585
  }
1488
- return { output: logs.join("\n"), logs, toolCalls };
1586
+ return { output: logs.join("\n"), logs, toolCalls, warnings };
1489
1587
  }
1490
1588
  async function runInSandbox(opts2) {
1491
1589
  try {
@@ -1580,7 +1678,18 @@ Use console.log() to return results. Only console.log output will be sent back t
1580
1678
  });
1581
1679
  }
1582
1680
  if (iter >= max) {
1583
- if (opts2.continueOnLimit) {
1681
+ if (opts2.callbacks.onToolLimitReached) {
1682
+ const decision = await opts2.callbacks.onToolLimitReached();
1683
+ if (decision === "continue") {
1684
+ opts2.messages.push({
1685
+ role: "system",
1686
+ content: "You have reached the tool-call limit for this session. The counter has been reset so you can continue working. Please proceed with your task."
1687
+ });
1688
+ iter = 0;
1689
+ } else {
1690
+ return;
1691
+ }
1692
+ } else if (opts2.continueOnLimit) {
1584
1693
  opts2.messages.push({
1585
1694
  role: "system",
1586
1695
  content: "You have reached the tool-call limit for this session. The counter has been reset so you can continue working. Please proceed with your task."
@@ -1646,7 +1755,9 @@ Use console.log() to return results. Only console.log output will be sent back t
1646
1755
  maxCompletionTokens: opts2.maxCompletionTokens,
1647
1756
  reasoningEffort: opts2.reasoningEffort,
1648
1757
  sessionId: opts2.sessionId,
1649
- gateway: opts2.gateway
1758
+ gateway: opts2.gateway,
1759
+ cloudMode: opts2.cloudMode,
1760
+ cloudToken: opts2.cloudToken
1650
1761
  });
1651
1762
  for await (const ev of events) {
1652
1763
  switch (ev.type) {
@@ -1825,10 +1936,13 @@ Use console.log() to return results. Only console.log output will be sent back t
1825
1936
  toolResults.push(toolResult);
1826
1937
  opts2.callbacks.onToolResult?.(toolResult);
1827
1938
  }
1828
- const resultContent = sandboxResult.error ? `Error: ${sandboxResult.error}
1939
+ const warningPrefix = sandboxResult.warnings?.length ? `Warning: ${sandboxResult.warnings.join(" ")}
1940
+
1941
+ ` : "";
1942
+ const resultContent = sandboxResult.error ? `${warningPrefix}Error: ${sandboxResult.error}
1829
1943
 
1830
1944
  Output:
1831
- ${sandboxResult.output}` : sandboxResult.output;
1945
+ ${sandboxResult.output}` : `${warningPrefix}${sandboxResult.output}`;
1832
1946
  const result = {
1833
1947
  tool_call_id: tc.id,
1834
1948
  name: "execute_code",
@@ -2180,11 +2294,11 @@ var init_mode = __esm({
2180
2294
 
2181
2295
  // src/agent/system-prompt.ts
2182
2296
  import { platform, release, homedir as homedir3 } from "os";
2183
- import { basename, join as join6 } from "path";
2297
+ import { basename, join as join7 } from "path";
2184
2298
  import { readFileSync as readFileSync2, statSync } from "fs";
2185
2299
  function loadContextFile(cwd) {
2186
2300
  for (const name of CONTEXT_FILENAMES) {
2187
- const path = join6(cwd, name);
2301
+ const path = join7(cwd, name);
2188
2302
  try {
2189
2303
  const s = statSync(path);
2190
2304
  if (!s.isFile() || s.size > MAX_CONTEXT_BYTES) continue;
@@ -2339,7 +2453,7 @@ var init_read = __esm({
2339
2453
 
2340
2454
  // src/tools/write.ts
2341
2455
  import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile3 } from "fs/promises";
2342
- import { dirname as dirname3 } from "path";
2456
+ import { dirname as dirname4 } from "path";
2343
2457
  var writeTool;
2344
2458
  var init_write = __esm({
2345
2459
  "src/tools/write.ts"() {
@@ -2369,7 +2483,7 @@ var init_write = __esm({
2369
2483
  before = await readFile4(abs, "utf8");
2370
2484
  } catch {
2371
2485
  }
2372
- await mkdir4(dirname3(abs), { recursive: true });
2486
+ await mkdir4(dirname4(abs), { recursive: true });
2373
2487
  await writeFile3(abs, args.content, "utf8");
2374
2488
  const verb = before ? "Overwrote" : "Created";
2375
2489
  return `${verb} ${args.path} (${args.content.length} chars).`;
@@ -2436,7 +2550,7 @@ var init_edit = __esm({
2436
2550
  // src/tools/bash.ts
2437
2551
  import { spawn } from "child_process";
2438
2552
  import { tmpdir } from "os";
2439
- import { join as join7 } from "path";
2553
+ import { join as join8 } from "path";
2440
2554
  function formatBashTitle(raw) {
2441
2555
  let cmd = (raw ?? "").trim();
2442
2556
  const m = cmd.match(/^cd\s+([^\s&;]+)\s*(?:&&|;)\s*(.*)$/);
@@ -2454,7 +2568,7 @@ function injectCoauthor(command, coauthor) {
2454
2568
  const mentionsGit = /\bgit\b/.test(trimmed);
2455
2569
  if (!createsCommit && !isRebaseContinue && !mentionsGit) return command;
2456
2570
  if (movesHeadOnly) return command;
2457
- const tmpFile = join7(tmpdir(), `kf-coauthor-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`);
2571
+ const tmpFile = join8(tmpdir(), `kf-coauthor-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`);
2458
2572
  const amendBlock = `
2459
2573
  if ! git log -1 --pretty=%B 2>/dev/null | grep -qF "${trailer}"; then
2460
2574
  git log -1 --pretty=%B | git interpret-trailers --trailer "${trailer}" > "${tmpFile}" && git commit --amend -F "${tmpFile}" --no-edit && rm -f "${tmpFile}"
@@ -3618,16 +3732,16 @@ var init_executor = __esm({
3618
3732
  // src/util/update-check.ts
3619
3733
  import { readFile as readFile7, writeFile as writeFile5, mkdir as mkdir5 } from "fs/promises";
3620
3734
  import { homedir as homedir5 } from "os";
3621
- import { join as join8, dirname as dirname4 } from "path";
3735
+ import { join as join9, dirname as dirname5 } from "path";
3622
3736
  import { fileURLToPath as fileURLToPath2 } from "url";
3623
3737
  function cachePath() {
3624
- const xdg = process.env.XDG_CONFIG_HOME || join8(homedir5(), ".config");
3625
- return join8(xdg, "kimiflare", "update-check.json");
3738
+ const xdg = process.env.XDG_CONFIG_HOME || join9(homedir5(), ".config");
3739
+ return join9(xdg, "kimiflare", "update-check.json");
3626
3740
  }
3627
3741
  async function findPackageJson(startDir) {
3628
3742
  let dir = startDir;
3629
3743
  while (true) {
3630
- const candidate = join8(dir, "package.json");
3744
+ const candidate = join9(dir, "package.json");
3631
3745
  try {
3632
3746
  const raw = await readFile7(candidate, "utf8");
3633
3747
  const parsed = JSON.parse(raw);
@@ -3636,14 +3750,14 @@ async function findPackageJson(startDir) {
3636
3750
  }
3637
3751
  } catch {
3638
3752
  }
3639
- const parent = dirname4(dir);
3753
+ const parent = dirname5(dir);
3640
3754
  if (parent === dir) break;
3641
3755
  dir = parent;
3642
3756
  }
3643
3757
  return null;
3644
3758
  }
3645
3759
  async function readLocalVersion() {
3646
- const here = dirname4(fileURLToPath2(import.meta.url));
3760
+ const here = dirname5(fileURLToPath2(import.meta.url));
3647
3761
  const found = await findPackageJson(here);
3648
3762
  return found?.version ?? null;
3649
3763
  }
@@ -3660,7 +3774,7 @@ async function readCache() {
3660
3774
  }
3661
3775
  async function writeCache(entry) {
3662
3776
  const p = cachePath();
3663
- await mkdir5(dirname4(p), { recursive: true });
3777
+ await mkdir5(dirname5(p), { recursive: true });
3664
3778
  await writeFile5(p, JSON.stringify(entry), "utf8");
3665
3779
  }
3666
3780
  async function fetchLatestVersion() {
@@ -3720,20 +3834,20 @@ var init_update_check = __esm({
3720
3834
  // src/remote/session-store.ts
3721
3835
  import { readFile as readFile8, writeFile as writeFile6, mkdir as mkdir6, readdir as readdir2 } from "fs/promises";
3722
3836
  import { homedir as homedir6 } from "os";
3723
- import { join as join9 } from "path";
3837
+ import { join as join10 } from "path";
3724
3838
  function remoteDir() {
3725
- const xdg = process.env.XDG_DATA_HOME || join9(homedir6(), ".config");
3726
- return join9(xdg, "kimiflare", "remote");
3839
+ const xdg = process.env.XDG_DATA_HOME || join10(homedir6(), ".config");
3840
+ return join10(xdg, "kimiflare", "remote");
3727
3841
  }
3728
3842
  async function saveRemoteSession(session) {
3729
3843
  const dir = remoteDir();
3730
3844
  await mkdir6(dir, { recursive: true });
3731
- const path = join9(dir, `${session.sessionId}.json`);
3845
+ const path = join10(dir, `${session.sessionId}.json`);
3732
3846
  await writeFile6(path, JSON.stringify(session, null, 2) + "\n", "utf8");
3733
3847
  }
3734
3848
  async function loadRemoteSession(sessionId) {
3735
3849
  try {
3736
- const path = join9(remoteDir(), `${sessionId}.json`);
3850
+ const path = join10(remoteDir(), `${sessionId}.json`);
3737
3851
  const raw = await readFile8(path, "utf8");
3738
3852
  return JSON.parse(raw);
3739
3853
  } catch {
@@ -3748,7 +3862,7 @@ async function listRemoteSessions() {
3748
3862
  for (const file of files) {
3749
3863
  if (!file.endsWith(".json")) continue;
3750
3864
  try {
3751
- const raw = await readFile8(join9(dir, file), "utf8");
3865
+ const raw = await readFile8(join10(dir, file), "utf8");
3752
3866
  sessions.push(JSON.parse(raw));
3753
3867
  } catch {
3754
3868
  }
@@ -3770,7 +3884,7 @@ var init_session_store = __esm({
3770
3884
 
3771
3885
  // src/remote/deploy.ts
3772
3886
  import { execSync } from "child_process";
3773
- import { join as join10, dirname as dirname5 } from "path";
3887
+ import { join as join11, dirname as dirname6 } from "path";
3774
3888
  import { fileURLToPath as fileURLToPath3 } from "url";
3775
3889
  import { randomBytes } from "crypto";
3776
3890
  function generateSecret() {
@@ -3805,7 +3919,7 @@ async function* deployForTui() {
3805
3919
  yield { message: "Docker OK" };
3806
3920
  yield { message: "Building remote agent bundle..." };
3807
3921
  try {
3808
- runCapture("npm run build:remote-agent", join10(REMOTE_DIR, ".."));
3922
+ runCapture("npm run build:remote-agent", join11(REMOTE_DIR, ".."));
3809
3923
  yield { message: "Agent bundle built" };
3810
3924
  } catch (err) {
3811
3925
  yield { message: `Build failed: ${err instanceof Error ? err.message : String(err)}`, error: true };
@@ -3934,9 +4048,9 @@ var init_deploy = __esm({
3934
4048
  "src/remote/deploy.ts"() {
3935
4049
  "use strict";
3936
4050
  init_config();
3937
- __dirname = dirname5(fileURLToPath3(import.meta.url));
3938
- REMOTE_DIR = join10(__dirname, "..", "..", "..", "remote");
3939
- WORKER_DIR = join10(REMOTE_DIR, "worker");
4051
+ __dirname = dirname6(fileURLToPath3(import.meta.url));
4052
+ REMOTE_DIR = join11(__dirname, "..", "..", "..", "remote");
4053
+ WORKER_DIR = join11(REMOTE_DIR, "worker");
3940
4054
  }
3941
4055
  });
3942
4056
 
@@ -4360,11 +4474,11 @@ var init_heuristic = __esm({
4360
4474
 
4361
4475
  // src/cost-attribution/classify-from-session.ts
4362
4476
  import { readFile as readFile9 } from "fs/promises";
4363
- import { join as join11 } from "path";
4477
+ import { join as join12 } from "path";
4364
4478
  import { homedir as homedir7 } from "os";
4365
4479
  function sessionsDir() {
4366
- const xdg = process.env.XDG_DATA_HOME || join11(homedir7(), ".local", "share");
4367
- return join11(xdg, "kimiflare", "sessions");
4480
+ const xdg = process.env.XDG_DATA_HOME || join12(homedir7(), ".local", "share");
4481
+ return join12(xdg, "kimiflare", "sessions");
4368
4482
  }
4369
4483
  function parseToolCalls(calls) {
4370
4484
  return calls.map((c) => {
@@ -4378,7 +4492,7 @@ function parseToolCalls(calls) {
4378
4492
  }
4379
4493
  async function classifyFromSessionFile(sessionId) {
4380
4494
  try {
4381
- const raw = await readFile9(join11(sessionsDir(), `${sessionId}.json`), "utf8");
4495
+ const raw = await readFile9(join12(sessionsDir(), `${sessionId}.json`), "utf8");
4382
4496
  const session = JSON.parse(raw);
4383
4497
  const messages = session.messages ?? [];
4384
4498
  const turns = [];
@@ -4412,14 +4526,14 @@ __export(cli_exports, {
4412
4526
  runCostCommand: () => runCostCommand
4413
4527
  });
4414
4528
  import { readFile as readFile10 } from "fs/promises";
4415
- import { join as join12 } from "path";
4529
+ import { join as join13 } from "path";
4416
4530
  import { homedir as homedir8 } from "os";
4417
4531
  function usageDir() {
4418
- const xdg = process.env.XDG_DATA_HOME || join12(homedir8(), ".local", "share");
4419
- return join12(xdg, "kimiflare");
4532
+ const xdg = process.env.XDG_DATA_HOME || join13(homedir8(), ".local", "share");
4533
+ return join13(xdg, "kimiflare");
4420
4534
  }
4421
4535
  function usagePath() {
4422
- return join12(usageDir(), "usage.json");
4536
+ return join13(usageDir(), "usage.json");
4423
4537
  }
4424
4538
  function today() {
4425
4539
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
@@ -4517,6 +4631,124 @@ var init_cli = __esm({
4517
4631
  }
4518
4632
  });
4519
4633
 
4634
+ // src/cloud/auth.ts
4635
+ var auth_exports = {};
4636
+ __export(auth_exports, {
4637
+ CLOUD_API_URL: () => CLOUD_API_URL,
4638
+ POLL_INTERVAL_MS: () => POLL_INTERVAL_MS,
4639
+ POLL_TIMEOUT_MS: () => POLL_TIMEOUT_MS,
4640
+ authenticateDevice: () => authenticateDevice,
4641
+ clearCloudCredentials: () => clearCloudCredentials,
4642
+ fetchCloudUsage: () => fetchCloudUsage,
4643
+ generateDeviceCodes: () => generateDeviceCodes,
4644
+ loadCloudCredentials: () => loadCloudCredentials,
4645
+ pollForToken: () => pollForToken,
4646
+ registerDevice: () => registerDevice,
4647
+ saveCloudCredentials: () => saveCloudCredentials
4648
+ });
4649
+ import { readFile as readFile11, writeFile as writeFile7 } from "fs/promises";
4650
+ import { homedir as homedir9 } from "os";
4651
+ import { join as join14 } from "path";
4652
+ function cloudCredPath() {
4653
+ const xdg = process.env.XDG_CONFIG_HOME || join14(homedir9(), ".config");
4654
+ return join14(xdg, "kimiflare", "cloud.json");
4655
+ }
4656
+ function generateCode() {
4657
+ const chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
4658
+ let out = "";
4659
+ for (let i = 0; i < 8; i++) {
4660
+ out += chars[Math.floor(Math.random() * chars.length)];
4661
+ }
4662
+ return out;
4663
+ }
4664
+ function generateDeviceCodes() {
4665
+ const deviceCode = `device-${generateCode()}-${Date.now()}`;
4666
+ const userCode = `${generateCode()}-${generateCode()}`;
4667
+ const authUrl = `${CLOUD_API_URL}/auth/github?code=${encodeURIComponent(userCode)}`;
4668
+ return { deviceCode, userCode, authUrl };
4669
+ }
4670
+ async function registerDevice(codes) {
4671
+ const registerRes = await fetch(`${CLOUD_API_URL}/auth/device`, {
4672
+ method: "POST",
4673
+ headers: { "Content-Type": "application/json" },
4674
+ body: JSON.stringify({ device_code: codes.deviceCode, user_code: codes.userCode })
4675
+ });
4676
+ if (!registerRes.ok) {
4677
+ const err = await registerRes.json().catch(() => ({}));
4678
+ throw new Error(`Failed to register device: ${err.error || registerRes.statusText}`);
4679
+ }
4680
+ }
4681
+ async function pollForToken(deviceCode) {
4682
+ const pollRes = await fetch(`${CLOUD_API_URL}/auth/poll`, {
4683
+ method: "POST",
4684
+ headers: { "Content-Type": "application/json" },
4685
+ body: JSON.stringify({ device_code: deviceCode })
4686
+ });
4687
+ if (!pollRes.ok) return null;
4688
+ const pollData = await pollRes.json();
4689
+ if (pollData.status === "approved" && pollData.access_token) {
4690
+ const creds = {
4691
+ accessToken: pollData.access_token,
4692
+ expiresAt: Math.floor(Date.now() / 1e3) + 7 * 24 * 60 * 60
4693
+ // 7 days
4694
+ };
4695
+ await saveCloudCredentials(creds);
4696
+ return creds;
4697
+ }
4698
+ return null;
4699
+ }
4700
+ async function fetchCloudUsage(token) {
4701
+ const res = await fetch(`${CLOUD_API_URL}/v1/usage`, {
4702
+ headers: { Authorization: `Bearer ${token}` }
4703
+ });
4704
+ if (!res.ok) return null;
4705
+ return await res.json();
4706
+ }
4707
+ async function loadCloudCredentials() {
4708
+ try {
4709
+ const raw = await readFile11(cloudCredPath(), "utf8");
4710
+ const parsed = JSON.parse(raw);
4711
+ if (parsed.expiresAt && parsed.expiresAt > Date.now() / 1e3) {
4712
+ return parsed;
4713
+ }
4714
+ } catch {
4715
+ }
4716
+ return null;
4717
+ }
4718
+ async function saveCloudCredentials(creds) {
4719
+ const p = cloudCredPath();
4720
+ await writeFile7(p, JSON.stringify(creds, null, 2), "utf8");
4721
+ }
4722
+ async function clearCloudCredentials() {
4723
+ try {
4724
+ const { unlink: unlink4 } = await import("fs/promises");
4725
+ await unlink4(cloudCredPath());
4726
+ } catch {
4727
+ }
4728
+ }
4729
+ async function authenticateDevice(onStatus) {
4730
+ const codes = generateDeviceCodes();
4731
+ await registerDevice(codes);
4732
+ onStatus({ url: codes.authUrl, userCode: codes.userCode, polling: false });
4733
+ const startTime = Date.now();
4734
+ while (Date.now() - startTime < POLL_TIMEOUT_MS) {
4735
+ await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
4736
+ onStatus({ url: codes.authUrl, userCode: codes.userCode, polling: true });
4737
+ const creds = await pollForToken(codes.deviceCode);
4738
+ if (creds) return creds;
4739
+ }
4740
+ throw new Error("Authentication timed out. Please try again.");
4741
+ }
4742
+ var CLOUD_API_URL, POLL_INTERVAL_MS, POLL_TIMEOUT_MS;
4743
+ var init_auth = __esm({
4744
+ "src/cloud/auth.ts"() {
4745
+ "use strict";
4746
+ CLOUD_API_URL = "https://api.kimiflare.com";
4747
+ POLL_INTERVAL_MS = 5e3;
4748
+ POLL_TIMEOUT_MS = 15 * 60 * 1e3;
4749
+ }
4750
+ });
4751
+
4520
4752
  // src/remote/tui-auth.ts
4521
4753
  var tui_auth_exports = {};
4522
4754
  __export(tui_auth_exports, {
@@ -5426,9 +5658,9 @@ var init_connection = __esm({
5426
5658
  });
5427
5659
 
5428
5660
  // src/lsp/protocol.ts
5429
- import { pathToFileURL, fileURLToPath as fileURLToPath4 } from "url";
5661
+ import { pathToFileURL as pathToFileURL2, fileURLToPath as fileURLToPath4 } from "url";
5430
5662
  function toUri(path) {
5431
- return pathToFileURL(path).href;
5663
+ return pathToFileURL2(path).href;
5432
5664
  }
5433
5665
  function fromUri(uri) {
5434
5666
  return fileURLToPath4(uri);
@@ -6568,7 +6800,7 @@ import { useEffect, useState } from "react";
6568
6800
  import { Box as Box5, Text as Text5 } from "ink";
6569
6801
  import Spinner3 from "ink-spinner";
6570
6802
  import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
6571
- function StatusBar({ model, usage, sessionUsage, thinking, turnStartedAt, mode, effort, contextLimit, hasUpdate, latestVersion, gatewayMeta, codeMode }) {
6803
+ function StatusBar({ model, usage, sessionUsage, thinking, turnStartedAt, mode, effort, contextLimit, hasUpdate, latestVersion, gatewayMeta, codeMode, cloudMode, cloudBudget }) {
6572
6804
  const theme = useTheme();
6573
6805
  const [now2, setNow] = useState(Date.now());
6574
6806
  const modeColor = mode === "plan" ? theme.modeBadge.plan : mode === "auto" ? theme.modeBadge.auto : theme.modeBadge.edit;
@@ -6580,6 +6812,7 @@ function StatusBar({ model, usage, sessionUsage, thinking, turnStartedAt, mode,
6580
6812
  }, [thinking, turnStartedAt]);
6581
6813
  const elapsed = turnStartedAt !== null ? formatElapsed(now2 - turnStartedAt) : null;
6582
6814
  const leftParts = [`${shortModel(model)}`, effort];
6815
+ if (cloudMode) leftParts.push("CLOUD");
6583
6816
  if (codeMode) leftParts.push("CODE");
6584
6817
  return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
6585
6818
  /* @__PURE__ */ jsxs5(Box5, { children: [
@@ -6600,7 +6833,7 @@ function StatusBar({ model, usage, sessionUsage, thinking, turnStartedAt, mode,
6600
6833
  ] })
6601
6834
  ] }),
6602
6835
  usage && /* @__PURE__ */ jsxs5(Box5, { children: [
6603
- /* @__PURE__ */ jsx6(Text5, { color: theme.info.color, children: buildRightParts(usage, contextLimit, sessionUsage, gatewayMeta).join(" \xB7 ") }),
6836
+ /* @__PURE__ */ jsx6(Text5, { color: theme.info.color, children: buildRightParts(usage, contextLimit, sessionUsage, gatewayMeta, cloudMode, cloudBudget).join(" \xB7 ") }),
6604
6837
  warn ? /* @__PURE__ */ jsxs5(Text5, { color: theme.warn, bold: true, children: [
6605
6838
  " \xB7 ",
6606
6839
  "/compact recommended"
@@ -6614,7 +6847,7 @@ function StatusBar({ model, usage, sessionUsage, thinking, turnStartedAt, mode,
6614
6847
  ] })
6615
6848
  ] });
6616
6849
  }
6617
- function buildRightParts(usage, contextLimit, sessionUsage, gatewayMeta) {
6850
+ function buildRightParts(usage, contextLimit, sessionUsage, gatewayMeta, cloudMode, cloudBudget) {
6618
6851
  const pct = Math.round(usage.prompt_tokens / contextLimit * 100);
6619
6852
  const parts = [];
6620
6853
  if (sessionUsage) {
@@ -6622,19 +6855,35 @@ function buildRightParts(usage, contextLimit, sessionUsage, gatewayMeta) {
6622
6855
  parts.push(`in ${sessionUsage.promptTokens}${cached ? ` (${cached} cached)` : ""}`);
6623
6856
  parts.push(`out ${sessionUsage.completionTokens}`);
6624
6857
  parts.push(`ctx ${pct}%`);
6625
- parts.push(`$${sessionUsage.cost.toFixed(5)}`);
6858
+ if (cloudMode) {
6859
+ parts.push(`\x1B[9m${sessionUsage.cost.toFixed(5)}\x1B[29m`);
6860
+ } else {
6861
+ parts.push(`${sessionUsage.cost.toFixed(5)}`);
6862
+ }
6626
6863
  } else {
6627
6864
  const cached = usage.prompt_tokens_details?.cached_tokens ?? 0;
6628
6865
  const cost = calculateCost(usage.prompt_tokens, usage.completion_tokens, cached);
6629
6866
  parts.push(`in ${usage.prompt_tokens}${cached ? ` (${cached} cached)` : ""}`);
6630
6867
  parts.push(`out ${usage.completion_tokens}`);
6631
6868
  parts.push(`ctx ${pct}%`);
6632
- parts.push(`$${cost.total.toFixed(5)}`);
6869
+ if (cloudMode) {
6870
+ parts.push(`\x1B[9m${cost.total.toFixed(5)}\x1B[29m`);
6871
+ } else {
6872
+ parts.push(`${cost.total.toFixed(5)}`);
6873
+ }
6874
+ }
6875
+ if (cloudMode && cloudBudget) {
6876
+ parts.push(`${formatTokens(cloudBudget.remaining)}/${formatTokens(cloudBudget.limit)} tokens`);
6633
6877
  }
6634
6878
  const gatewayCache = formatGatewayCacheStatus(gatewayMeta);
6635
6879
  if (gatewayCache) parts.push(gatewayCache);
6636
6880
  return parts;
6637
6881
  }
6882
+ function formatTokens(n) {
6883
+ if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
6884
+ if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
6885
+ return String(n);
6886
+ }
6638
6887
  function formatGatewayCacheStatus(gatewayMeta) {
6639
6888
  const status = gatewayMeta?.cacheStatus?.trim();
6640
6889
  return status ? `AI Gateway \xB7 cache ${status.toLowerCase()}` : null;
@@ -6695,11 +6944,48 @@ var init_permission = __esm({
6695
6944
  }
6696
6945
  });
6697
6946
 
6698
- // src/ui/resume-picker.tsx
6699
- import { useState as useState2 } from "react";
6700
- import { Box as Box7, Text as Text7, useWindowSize } from "ink";
6947
+ // src/ui/limit-modal.tsx
6948
+ import { Box as Box7, Text as Text7 } from "ink";
6701
6949
  import SelectInput2 from "ink-select-input";
6702
6950
  import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
6951
+ function LimitModal({ limit, onDecide }) {
6952
+ const theme = useTheme();
6953
+ const items = [
6954
+ { label: "Continue", value: "continue" },
6955
+ { label: "Stop", value: "stop" }
6956
+ ];
6957
+ return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", borderStyle: "round", borderColor: theme.error, paddingX: 1, children: [
6958
+ /* @__PURE__ */ jsxs7(Text7, { color: theme.error, bold: true, children: [
6959
+ "Tool-call limit reached (",
6960
+ limit,
6961
+ ")"
6962
+ ] }),
6963
+ /* @__PURE__ */ jsxs7(Text7, { dimColor: true, children: [
6964
+ "This session has made ",
6965
+ limit,
6966
+ " tool calls. What would you like to do?"
6967
+ ] }),
6968
+ /* @__PURE__ */ jsx8(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx8(
6969
+ SelectInput2,
6970
+ {
6971
+ items,
6972
+ onSelect: (item) => onDecide(item.value)
6973
+ }
6974
+ ) })
6975
+ ] });
6976
+ }
6977
+ var init_limit_modal = __esm({
6978
+ "src/ui/limit-modal.tsx"() {
6979
+ "use strict";
6980
+ init_theme_context();
6981
+ }
6982
+ });
6983
+
6984
+ // src/ui/resume-picker.tsx
6985
+ import { useState as useState2 } from "react";
6986
+ import { Box as Box8, Text as Text8, useWindowSize } from "ink";
6987
+ import SelectInput3 from "ink-select-input";
6988
+ import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
6703
6989
  function ResumePicker({ sessions, onPick }) {
6704
6990
  const theme = useTheme();
6705
6991
  const { rows } = useWindowSize();
@@ -6708,11 +6994,11 @@ function ResumePicker({ sessions, onPick }) {
6708
6994
  const totalPages = Math.max(1, Math.ceil(sessions.length / pageSize));
6709
6995
  const safePage = Math.min(page, totalPages - 1);
6710
6996
  if (sessions.length === 0) {
6711
- return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
6712
- /* @__PURE__ */ jsx8(Text7, { color: theme.accent, bold: true, children: "Resume a session" }),
6713
- /* @__PURE__ */ jsx8(Text7, { color: theme.info.color, children: "No saved sessions yet. Press Enter to dismiss." }),
6714
- /* @__PURE__ */ jsx8(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx8(
6715
- SelectInput2,
6997
+ return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
6998
+ /* @__PURE__ */ jsx9(Text8, { color: theme.accent, bold: true, children: "Resume a session" }),
6999
+ /* @__PURE__ */ jsx9(Text8, { color: theme.info.color, children: "No saved sessions yet. Press Enter to dismiss." }),
7000
+ /* @__PURE__ */ jsx9(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx9(
7001
+ SelectInput3,
6716
7002
  {
6717
7003
  items: [{ label: "(back)", value: "__cancel__" }],
6718
7004
  onSelect: () => onPick(null)
@@ -6734,9 +7020,9 @@ function ResumePicker({ sessions, onPick }) {
6734
7020
  items.push({ label: "\u2192 next page", value: "__next__" });
6735
7021
  }
6736
7022
  items.push({ label: "(cancel)", value: "__cancel__" });
6737
- return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
6738
- /* @__PURE__ */ jsx8(Text7, { color: theme.accent, bold: true, children: "Resume a session" }),
6739
- /* @__PURE__ */ jsxs7(Text7, { color: theme.info.color, children: [
7023
+ return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
7024
+ /* @__PURE__ */ jsx9(Text8, { color: theme.accent, bold: true, children: "Resume a session" }),
7025
+ /* @__PURE__ */ jsxs8(Text8, { color: theme.info.color, children: [
6740
7026
  "Arrow keys to select, Enter to confirm. Page ",
6741
7027
  safePage + 1,
6742
7028
  " of ",
@@ -6745,8 +7031,8 @@ function ResumePicker({ sessions, onPick }) {
6745
7031
  sessions.length,
6746
7032
  " total)"
6747
7033
  ] }),
6748
- /* @__PURE__ */ jsx8(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx8(
6749
- SelectInput2,
7034
+ /* @__PURE__ */ jsx9(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx9(
7035
+ SelectInput3,
6750
7036
  {
6751
7037
  items,
6752
7038
  onSelect: (item) => {
@@ -6786,9 +7072,9 @@ var init_resume_picker = __esm({
6786
7072
 
6787
7073
  // src/ui/task-list.tsx
6788
7074
  import { useEffect as useEffect2, useRef, useState as useState3 } from "react";
6789
- import { Box as Box8, Text as Text8 } from "ink";
7075
+ import { Box as Box9, Text as Text9 } from "ink";
6790
7076
  import Spinner4 from "ink-spinner";
6791
- import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
7077
+ import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
6792
7078
  function TaskList({ tasks, startedAt, tokensDelta }) {
6793
7079
  const theme = useTheme();
6794
7080
  const [now2, setNow] = useState3(Date.now());
@@ -6812,21 +7098,21 @@ function TaskList({ tasks, startedAt, tokensDelta }) {
6812
7098
  const allDone = done === total;
6813
7099
  const header = active ? active.title : allDone ? `${total} tasks done` : `${done}/${total}`;
6814
7100
  const elapsed = startedAt ? formatElapsed2(now2 - startedAt) : null;
6815
- const headerStats = [elapsed, tokensDelta > 0 ? `\u2191 ${formatTokens(tokensDelta)} tokens` : null].filter(Boolean).join(" \xB7 ");
7101
+ const headerStats = [elapsed, tokensDelta > 0 ? `\u2191 ${formatTokens2(tokensDelta)} tokens` : null].filter(Boolean).join(" \xB7 ");
6816
7102
  const visibleTasks = tasks.slice(0, MAX_VISIBLE);
6817
7103
  const hiddenPending = Math.max(0, tasks.length - visibleTasks.length);
6818
- return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", marginBottom: 1, children: [
6819
- /* @__PURE__ */ jsxs8(Box8, { children: [
6820
- /* @__PURE__ */ jsx9(Text8, { color: allDone ? "green" : theme.accent, bold: true, children: header }),
6821
- headerStats && /* @__PURE__ */ jsxs8(Text8, { color: theme.info.color, children: [
7104
+ return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", marginBottom: 1, children: [
7105
+ /* @__PURE__ */ jsxs9(Box9, { children: [
7106
+ /* @__PURE__ */ jsx10(Text9, { color: allDone ? "green" : theme.accent, bold: true, children: header }),
7107
+ headerStats && /* @__PURE__ */ jsxs9(Text9, { color: theme.info.color, children: [
6822
7108
  " ",
6823
7109
  "(",
6824
7110
  headerStats,
6825
7111
  ")"
6826
7112
  ] })
6827
7113
  ] }),
6828
- visibleTasks.map((t) => /* @__PURE__ */ jsx9(TaskRow, { task: t }, t.id)),
6829
- hiddenPending > 0 && /* @__PURE__ */ jsxs8(Text8, { color: theme.info.color, children: [
7114
+ visibleTasks.map((t) => /* @__PURE__ */ jsx10(TaskRow, { task: t }, t.id)),
7115
+ hiddenPending > 0 && /* @__PURE__ */ jsxs9(Text9, { color: theme.info.color, children: [
6830
7116
  " ",
6831
7117
  "\u2026 +",
6832
7118
  hiddenPending,
@@ -6837,21 +7123,21 @@ function TaskList({ tasks, startedAt, tokensDelta }) {
6837
7123
  function TaskRow({ task }) {
6838
7124
  const theme = useTheme();
6839
7125
  if (task.status === "completed") {
6840
- return /* @__PURE__ */ jsxs8(Text8, { color: theme.info.color, children: [
7126
+ return /* @__PURE__ */ jsxs9(Text9, { color: theme.info.color, children: [
6841
7127
  " ",
6842
7128
  "\u2713 ",
6843
- /* @__PURE__ */ jsx9(Text8, { strikethrough: true, children: task.title })
7129
+ /* @__PURE__ */ jsx10(Text9, { strikethrough: true, children: task.title })
6844
7130
  ] });
6845
7131
  }
6846
7132
  if (task.status === "in_progress") {
6847
- return /* @__PURE__ */ jsxs8(Text8, { color: theme.accent, bold: true, children: [
7133
+ return /* @__PURE__ */ jsxs9(Text9, { color: theme.accent, bold: true, children: [
6848
7134
  " ",
6849
- /* @__PURE__ */ jsx9(Spinner4, { type: "dots" }),
7135
+ /* @__PURE__ */ jsx10(Spinner4, { type: "dots" }),
6850
7136
  " ",
6851
7137
  task.title
6852
7138
  ] });
6853
7139
  }
6854
- return /* @__PURE__ */ jsxs8(Text8, { color: theme.info.color, children: [
7140
+ return /* @__PURE__ */ jsxs9(Text9, { color: theme.info.color, children: [
6855
7141
  " ",
6856
7142
  "\u2610 ",
6857
7143
  task.title
@@ -6864,7 +7150,7 @@ function formatElapsed2(ms) {
6864
7150
  if (m === 0) return `${s}s`;
6865
7151
  return `${m}m ${s}s`;
6866
7152
  }
6867
- function formatTokens(n) {
7153
+ function formatTokens2(n) {
6868
7154
  if (n < 1e3) return String(n);
6869
7155
  return `${(n / 1e3).toFixed(1)}k`;
6870
7156
  }
@@ -7399,8 +7685,8 @@ var init_source = __esm({
7399
7685
 
7400
7686
  // src/ui/text-input.tsx
7401
7687
  import { useState as useState4, useEffect as useEffect3, useRef as useRef2 } from "react";
7402
- import { Text as Text9, useInput } from "ink";
7403
- import { jsx as jsx10 } from "react/jsx-runtime";
7688
+ import { Text as Text10, useInput } from "ink";
7689
+ import { jsx as jsx11 } from "react/jsx-runtime";
7404
7690
  function shouldTreatAsPaste(input) {
7405
7691
  if (input.length >= PASTE_CHAR_THRESHOLD) return true;
7406
7692
  const newlines = (input.match(/\n/g) ?? []).length;
@@ -7610,7 +7896,7 @@ function CustomTextInput({
7610
7896
  } else if (cursorOffset === displayValue.length) {
7611
7897
  renderedValue += source_default.inverse(" ");
7612
7898
  }
7613
- return /* @__PURE__ */ jsx10(Text9, { children: renderedValue });
7899
+ return /* @__PURE__ */ jsx11(Text10, { children: renderedValue });
7614
7900
  }
7615
7901
  function findPasteTokenEndingAt(value, pos, pastes) {
7616
7902
  if (pos <= 0 || value[pos - 1] !== "]") return -1;
@@ -7632,17 +7918,138 @@ var init_text_input = __esm({
7632
7918
  });
7633
7919
 
7634
7920
  // src/ui/onboarding.tsx
7635
- import { useState as useState5 } from "react";
7636
- import { Box as Box9, Text as Text10 } from "ink";
7637
- import { Fragment, jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
7638
- function Onboarding({ onDone }) {
7921
+ import { useState as useState5, useEffect as useEffect4, useCallback } from "react";
7922
+ import { Box as Box10, Text as Text11, useInput as useInput2 } from "ink";
7923
+ import SelectInput4 from "ink-select-input";
7924
+ import Spinner5 from "ink-spinner";
7925
+ import { exec } from "child_process";
7926
+ import { promisify as promisify2 } from "util";
7927
+ import { Fragment, jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
7928
+ function openBrowser(url) {
7929
+ const platform3 = process.platform;
7930
+ const cmd = platform3 === "darwin" ? `open "${url}"` : platform3 === "win32" ? `start "" "${url}"` : `xdg-open "${url}"`;
7931
+ exec(cmd, (err) => {
7932
+ if (err) {
7933
+ }
7934
+ });
7935
+ }
7936
+ function formatRemaining(ms) {
7937
+ const totalSeconds = Math.ceil(ms / 1e3);
7938
+ const mins = Math.floor(totalSeconds / 60);
7939
+ const secs = totalSeconds % 60;
7940
+ return `${mins}:${secs.toString().padStart(2, "0")}`;
7941
+ }
7942
+ function Onboarding({ onDone, onCancel }) {
7639
7943
  const theme = useTheme();
7640
- const [step, setStep] = useState5("accountId");
7944
+ const [step, setStep] = useState5("mode");
7945
+ const [mode, setMode] = useState5("byok");
7641
7946
  const [accountId, setAccountId] = useState5("");
7642
7947
  const [apiToken, setApiToken] = useState5("");
7643
7948
  const [model, setModel] = useState5(DEFAULT_MODEL);
7644
7949
  const [savedPath, setSavedPath] = useState5(null);
7645
- const stepIndex = STEPS.indexOf(step) + 1;
7950
+ const [cloudAuth, setCloudAuth] = useState5(null);
7951
+ const [pollTick, setPollTick] = useState5(0);
7952
+ useEffect4(() => {
7953
+ if (step !== "cloudAuth" || !cloudAuth) return;
7954
+ if (cloudAuth.phase !== "polling") return;
7955
+ let cancelled = false;
7956
+ const tick = setInterval(() => {
7957
+ setPollTick((t) => t + 1);
7958
+ }, 1e3);
7959
+ const poll = async () => {
7960
+ while (!cancelled) {
7961
+ const elapsed = Date.now() - cloudAuth.startTime;
7962
+ if (elapsed >= POLL_TIMEOUT_MS) {
7963
+ if (!cancelled) {
7964
+ setCloudAuth({ phase: "error", message: "Authentication timed out. Please try again." });
7965
+ }
7966
+ return;
7967
+ }
7968
+ try {
7969
+ const creds = await pollForToken(cloudAuth.codes.deviceCode);
7970
+ if (creds && !cancelled) {
7971
+ const usage = await fetchCloudUsage(creds.accessToken);
7972
+ if (usage && !cancelled) {
7973
+ setCloudAuth({
7974
+ phase: "success",
7975
+ creds,
7976
+ usage
7977
+ });
7978
+ } else if (!cancelled) {
7979
+ setCloudAuth({ phase: "error", message: "Authenticated but failed to fetch usage." });
7980
+ }
7981
+ return;
7982
+ }
7983
+ } catch {
7984
+ }
7985
+ await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
7986
+ }
7987
+ };
7988
+ poll();
7989
+ return () => {
7990
+ cancelled = true;
7991
+ clearInterval(tick);
7992
+ };
7993
+ }, [step, cloudAuth]);
7994
+ useInput2(
7995
+ useCallback(
7996
+ (_input, key) => {
7997
+ if (key.escape && onCancel) {
7998
+ onCancel();
7999
+ }
8000
+ },
8001
+ [onCancel]
8002
+ )
8003
+ );
8004
+ const startCloudAuth = useCallback(async () => {
8005
+ try {
8006
+ const codes = generateDeviceCodes();
8007
+ await registerDevice(codes);
8008
+ setCloudAuth({ phase: "ready", codes });
8009
+ setStep("cloudAuth");
8010
+ } catch (err) {
8011
+ setCloudAuth({
8012
+ phase: "error",
8013
+ message: err instanceof Error ? err.message : "Failed to start authentication"
8014
+ });
8015
+ setStep("cloudAuth");
8016
+ }
8017
+ }, []);
8018
+ const handleModeSelect = (item) => {
8019
+ if (item.value === "cloud") {
8020
+ setMode("cloud");
8021
+ void startCloudAuth();
8022
+ } else {
8023
+ setMode("byok");
8024
+ setStep("accountId");
8025
+ }
8026
+ };
8027
+ const handleOpenBrowser = () => {
8028
+ if (cloudAuth?.phase === "ready") {
8029
+ openBrowser(cloudAuth.codes.authUrl);
8030
+ setCloudAuth({ phase: "polling", codes: cloudAuth.codes, startTime: Date.now() });
8031
+ }
8032
+ };
8033
+ const handleCloudSuccess = async () => {
8034
+ if (cloudAuth?.phase !== "success") return;
8035
+ const cfg = { accountId: "", apiToken: "", model: DEFAULT_MODEL, cloudMode: true };
8036
+ try {
8037
+ const path = await saveConfig(cfg);
8038
+ setSavedPath(path);
8039
+ onDone(cfg);
8040
+ } catch (e) {
8041
+ setSavedPath(`error: ${e.message}`);
8042
+ }
8043
+ };
8044
+ const handleCloudRetry = () => {
8045
+ setCloudAuth(null);
8046
+ void startCloudAuth();
8047
+ };
8048
+ const handleCloudSwitchToByok = () => {
8049
+ setCloudAuth(null);
8050
+ setMode("byok");
8051
+ setStep("accountId");
8052
+ };
7646
8053
  const handleAccountIdSubmit = (value) => {
7647
8054
  const trimmed = value.trim();
7648
8055
  if (!trimmed) return;
@@ -7670,26 +8077,133 @@ function Onboarding({ onDone }) {
7670
8077
  setSavedPath(`error: ${e.message}`);
7671
8078
  }
7672
8079
  };
7673
- return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", paddingY: 1, children: [
7674
- /* @__PURE__ */ jsxs9(Box9, { marginBottom: 1, children: [
7675
- /* @__PURE__ */ jsx11(Text10, { bold: true, color: theme.palette.primary, children: "kimiflare" }),
7676
- /* @__PURE__ */ jsxs9(Text10, { color: theme.info.color, children: [
8080
+ const byokSteps = ["accountId", "apiToken", "model", "confirm"];
8081
+ const stepIndex = step === "mode" ? 1 : step === "cloudAuth" ? 2 : byokSteps.indexOf(step) + 2;
8082
+ const totalSteps = mode === "cloud" ? 2 : byokSteps.length + 1;
8083
+ return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", paddingY: 1, children: [
8084
+ /* @__PURE__ */ jsxs10(Box10, { marginBottom: 1, children: [
8085
+ /* @__PURE__ */ jsx12(Text11, { bold: true, color: theme.palette.primary, children: "kimiflare" }),
8086
+ /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
7677
8087
  " ",
7678
8088
  "Terminal coding agent"
7679
8089
  ] })
7680
8090
  ] }),
7681
- /* @__PURE__ */ jsxs9(Text10, { color: theme.info.color, children: [
8091
+ /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
7682
8092
  "Step ",
7683
8093
  stepIndex,
7684
8094
  " of ",
7685
- STEPS.length
8095
+ totalSteps
7686
8096
  ] }),
7687
- /* @__PURE__ */ jsxs9(Box9, { marginTop: 1, flexDirection: "column", children: [
7688
- step === "accountId" && /* @__PURE__ */ jsxs9(Fragment, { children: [
7689
- /* @__PURE__ */ jsx11(Text10, { children: "Enter your Cloudflare Account ID" }),
7690
- /* @__PURE__ */ jsxs9(Box9, { marginTop: 1, children: [
7691
- /* @__PURE__ */ jsx11(Text10, { color: theme.palette.primary, children: "\u203A " }),
7692
- /* @__PURE__ */ jsx11(
8097
+ /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, flexDirection: "column", children: [
8098
+ step === "mode" && /* @__PURE__ */ jsxs10(Fragment, { children: [
8099
+ /* @__PURE__ */ jsx12(Text11, { children: "How do you want to connect?" }),
8100
+ /* @__PURE__ */ jsx12(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx12(
8101
+ SelectInput4,
8102
+ {
8103
+ items: [
8104
+ { label: "Cloud (managed) \u2014 no API key needed", value: "cloud" },
8105
+ { label: "BYOK \u2014 bring your own Cloudflare key", value: "byok" }
8106
+ ],
8107
+ onSelect: handleModeSelect
8108
+ }
8109
+ ) })
8110
+ ] }),
8111
+ step === "cloudAuth" && cloudAuth?.phase === "ready" && /* @__PURE__ */ jsxs10(Fragment, { children: [
8112
+ /* @__PURE__ */ jsx12(Text11, { children: "Authenticating with Kimiflare Cloud..." }),
8113
+ /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, flexDirection: "column", children: [
8114
+ /* @__PURE__ */ jsx12(Text11, { children: "1. Open this URL in your browser:" }),
8115
+ /* @__PURE__ */ jsx12(Text11, { color: theme.palette.primary, children: cloudAuth.codes.authUrl })
8116
+ ] }),
8117
+ /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
8118
+ /* @__PURE__ */ jsx12(Text11, { children: "2. " }),
8119
+ /* @__PURE__ */ jsx12(Text11, { bold: true, children: "[Press Enter to open browser]" })
8120
+ ] }),
8121
+ /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
8122
+ /* @__PURE__ */ jsx12(Text11, { color: theme.palette.primary, children: "\u203A " }),
8123
+ /* @__PURE__ */ jsx12(
8124
+ CustomTextInput,
8125
+ {
8126
+ value: "",
8127
+ onChange: () => {
8128
+ },
8129
+ onSubmit: handleOpenBrowser
8130
+ }
8131
+ )
8132
+ ] })
8133
+ ] }),
8134
+ step === "cloudAuth" && cloudAuth?.phase === "polling" && /* @__PURE__ */ jsxs10(Fragment, { children: [
8135
+ /* @__PURE__ */ jsxs10(Text11, { children: [
8136
+ /* @__PURE__ */ jsx12(Text11, { color: theme.spinner, children: /* @__PURE__ */ jsx12(Spinner5, { type: "dots" }) }),
8137
+ " ",
8138
+ "Waiting for authentication..."
8139
+ ] }),
8140
+ /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
8141
+ "Expires in ",
8142
+ formatRemaining(POLL_TIMEOUT_MS - (Date.now() - cloudAuth.startTime))
8143
+ ] }),
8144
+ /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
8145
+ "URL: ",
8146
+ cloudAuth.codes.authUrl
8147
+ ] })
8148
+ ] }),
8149
+ step === "cloudAuth" && cloudAuth?.phase === "success" && /* @__PURE__ */ jsxs10(Fragment, { children: [
8150
+ /* @__PURE__ */ jsx12(Text11, { color: theme.palette.success, children: "Authenticated!" }),
8151
+ /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, flexDirection: "column", children: [
8152
+ /* @__PURE__ */ jsxs10(Text11, { children: [
8153
+ "Token budget:",
8154
+ " ",
8155
+ /* @__PURE__ */ jsxs10(Text11, { bold: true, children: [
8156
+ cloudAuth.usage.remaining.toLocaleString(),
8157
+ " /",
8158
+ " ",
8159
+ cloudAuth.usage.input_token_limit.toLocaleString()
8160
+ ] }),
8161
+ " ",
8162
+ "remaining"
8163
+ ] }),
8164
+ /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
8165
+ "Grant expires: ",
8166
+ cloudAuth.usage.expires_at
8167
+ ] })
8168
+ ] }),
8169
+ /* @__PURE__ */ jsx12(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text11, { children: "[Press Enter to continue]" }) }),
8170
+ /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
8171
+ /* @__PURE__ */ jsx12(Text11, { color: theme.palette.primary, children: "\u203A " }),
8172
+ /* @__PURE__ */ jsx12(
8173
+ CustomTextInput,
8174
+ {
8175
+ value: "",
8176
+ onChange: () => {
8177
+ },
8178
+ onSubmit: handleCloudSuccess
8179
+ }
8180
+ )
8181
+ ] })
8182
+ ] }),
8183
+ step === "cloudAuth" && cloudAuth?.phase === "error" && /* @__PURE__ */ jsxs10(Fragment, { children: [
8184
+ /* @__PURE__ */ jsx12(Text11, { color: theme.palette.error, children: "Authentication failed" }),
8185
+ /* @__PURE__ */ jsx12(Text11, { color: theme.info.color, children: cloudAuth.message }),
8186
+ /* @__PURE__ */ jsx12(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx12(
8187
+ SelectInput4,
8188
+ {
8189
+ items: [
8190
+ { label: "Retry", value: "retry" },
8191
+ { label: "Switch to BYOK", value: "byok" },
8192
+ { label: "Cancel", value: "cancel" }
8193
+ ],
8194
+ onSelect: (item) => {
8195
+ if (item.value === "retry") handleCloudRetry();
8196
+ else if (item.value === "byok") handleCloudSwitchToByok();
8197
+ else if (onCancel) onCancel();
8198
+ }
8199
+ }
8200
+ ) })
8201
+ ] }),
8202
+ step === "accountId" && /* @__PURE__ */ jsxs10(Fragment, { children: [
8203
+ /* @__PURE__ */ jsx12(Text11, { children: "Enter your Cloudflare Account ID" }),
8204
+ /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
8205
+ /* @__PURE__ */ jsx12(Text11, { color: theme.palette.primary, children: "\u203A " }),
8206
+ /* @__PURE__ */ jsx12(
7693
8207
  CustomTextInput,
7694
8208
  {
7695
8209
  value: accountId,
@@ -7699,12 +8213,12 @@ function Onboarding({ onDone }) {
7699
8213
  )
7700
8214
  ] })
7701
8215
  ] }),
7702
- step === "apiToken" && /* @__PURE__ */ jsxs9(Fragment, { children: [
7703
- /* @__PURE__ */ jsx11(Text10, { children: "Enter your Cloudflare API Token" }),
7704
- /* @__PURE__ */ jsx11(Text10, { color: theme.info.color, children: "Create one at https://dash.cloudflare.com/profile/api-tokens" }),
7705
- /* @__PURE__ */ jsxs9(Box9, { marginTop: 1, children: [
7706
- /* @__PURE__ */ jsx11(Text10, { color: theme.palette.primary, children: "\u203A " }),
7707
- /* @__PURE__ */ jsx11(
8216
+ step === "apiToken" && /* @__PURE__ */ jsxs10(Fragment, { children: [
8217
+ /* @__PURE__ */ jsx12(Text11, { children: "Enter your Cloudflare API Token" }),
8218
+ /* @__PURE__ */ jsx12(Text11, { color: theme.info.color, children: "Create one at https://dash.cloudflare.com/profile/api-tokens" }),
8219
+ /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
8220
+ /* @__PURE__ */ jsx12(Text11, { color: theme.palette.primary, children: "\u203A " }),
8221
+ /* @__PURE__ */ jsx12(
7708
8222
  CustomTextInput,
7709
8223
  {
7710
8224
  value: apiToken,
@@ -7715,15 +8229,15 @@ function Onboarding({ onDone }) {
7715
8229
  )
7716
8230
  ] })
7717
8231
  ] }),
7718
- step === "model" && /* @__PURE__ */ jsxs9(Fragment, { children: [
7719
- /* @__PURE__ */ jsx11(Text10, { children: "Model ID (press Enter for default)" }),
7720
- /* @__PURE__ */ jsxs9(Text10, { color: theme.info.color, children: [
8232
+ step === "model" && /* @__PURE__ */ jsxs10(Fragment, { children: [
8233
+ /* @__PURE__ */ jsx12(Text11, { children: "Model ID (press Enter for default)" }),
8234
+ /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
7721
8235
  "default: ",
7722
8236
  DEFAULT_MODEL
7723
8237
  ] }),
7724
- /* @__PURE__ */ jsxs9(Box9, { marginTop: 1, children: [
7725
- /* @__PURE__ */ jsx11(Text10, { color: theme.palette.primary, children: "\u203A " }),
7726
- /* @__PURE__ */ jsx11(
8238
+ /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
8239
+ /* @__PURE__ */ jsx12(Text11, { color: theme.palette.primary, children: "\u203A " }),
8240
+ /* @__PURE__ */ jsx12(
7727
8241
  CustomTextInput,
7728
8242
  {
7729
8243
  value: model,
@@ -7733,10 +8247,10 @@ function Onboarding({ onDone }) {
7733
8247
  )
7734
8248
  ] })
7735
8249
  ] }),
7736
- step === "confirm" && /* @__PURE__ */ jsxs9(Fragment, { children: [
7737
- /* @__PURE__ */ jsx11(Text10, { children: "Ready to save configuration" }),
7738
- /* @__PURE__ */ jsxs9(
7739
- Box9,
8250
+ step === "confirm" && /* @__PURE__ */ jsxs10(Fragment, { children: [
8251
+ /* @__PURE__ */ jsx12(Text11, { children: "Ready to save configuration" }),
8252
+ /* @__PURE__ */ jsxs10(
8253
+ Box10,
7740
8254
  {
7741
8255
  flexDirection: "column",
7742
8256
  marginTop: 1,
@@ -7745,25 +8259,25 @@ function Onboarding({ onDone }) {
7745
8259
  borderColor: theme.info.color,
7746
8260
  paddingX: 1,
7747
8261
  children: [
7748
- /* @__PURE__ */ jsxs9(Text10, { color: theme.info.color, children: [
8262
+ /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
7749
8263
  "Account ID: ",
7750
8264
  accountId
7751
8265
  ] }),
7752
- /* @__PURE__ */ jsxs9(Text10, { color: theme.info.color, children: [
8266
+ /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
7753
8267
  "API Token: ",
7754
8268
  "\u2022".repeat(apiToken.length)
7755
8269
  ] }),
7756
- /* @__PURE__ */ jsxs9(Text10, { color: theme.info.color, children: [
8270
+ /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
7757
8271
  "Model: ",
7758
8272
  model
7759
8273
  ] })
7760
8274
  ]
7761
8275
  }
7762
8276
  ),
7763
- /* @__PURE__ */ jsx11(Text10, { children: "Press Enter to confirm, or Ctrl+C to cancel" }),
7764
- /* @__PURE__ */ jsxs9(Box9, { marginTop: 1, children: [
7765
- /* @__PURE__ */ jsx11(Text10, { color: theme.palette.primary, children: "\u203A " }),
7766
- /* @__PURE__ */ jsx11(
8277
+ /* @__PURE__ */ jsx12(Text11, { children: "Press Enter to confirm, or Ctrl+C to cancel" }),
8278
+ /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
8279
+ /* @__PURE__ */ jsx12(Text11, { color: theme.palette.primary, children: "\u203A " }),
8280
+ /* @__PURE__ */ jsx12(
7767
8281
  CustomTextInput,
7768
8282
  {
7769
8283
  value: "",
@@ -7774,53 +8288,54 @@ function Onboarding({ onDone }) {
7774
8288
  )
7775
8289
  ] })
7776
8290
  ] }),
7777
- savedPath && /* @__PURE__ */ jsxs9(Text10, { color: theme.palette.success, children: [
8291
+ savedPath && /* @__PURE__ */ jsxs10(Text11, { color: theme.palette.success, children: [
7778
8292
  "Config saved to ",
7779
8293
  savedPath
7780
8294
  ] })
7781
8295
  ] })
7782
8296
  ] });
7783
8297
  }
7784
- var STEPS;
8298
+ var execAsync;
7785
8299
  var init_onboarding = __esm({
7786
8300
  "src/ui/onboarding.tsx"() {
7787
8301
  "use strict";
7788
8302
  init_text_input();
7789
8303
  init_config();
7790
8304
  init_theme_context();
7791
- STEPS = ["accountId", "apiToken", "model", "confirm"];
8305
+ init_auth();
8306
+ execAsync = promisify2(exec);
7792
8307
  }
7793
8308
  });
7794
8309
 
7795
8310
  // src/ui/welcome.tsx
7796
- import { Box as Box10, Text as Text11 } from "ink";
7797
- import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
8311
+ import { Box as Box11, Text as Text12 } from "ink";
8312
+ import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
7798
8313
  function Welcome({ accountId }) {
7799
8314
  const theme = useTheme();
7800
- return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", marginBottom: 1, children: [
7801
- /* @__PURE__ */ jsxs10(Box10, { marginBottom: 1, children: [
7802
- /* @__PURE__ */ jsx12(Text11, { bold: true, color: theme.accent, children: "kimiflare" }),
7803
- /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
8315
+ return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", marginBottom: 1, children: [
8316
+ /* @__PURE__ */ jsxs11(Box11, { marginBottom: 1, children: [
8317
+ /* @__PURE__ */ jsx13(Text12, { bold: true, color: theme.accent, children: "kimiflare" }),
8318
+ /* @__PURE__ */ jsxs11(Text12, { color: theme.info.color, children: [
7804
8319
  " ",
7805
8320
  "Ready when you are."
7806
8321
  ] })
7807
8322
  ] }),
7808
- accountId && /* @__PURE__ */ jsx12(Box10, { marginBottom: 1, children: /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
8323
+ accountId && /* @__PURE__ */ jsx13(Box11, { marginBottom: 1, children: /* @__PURE__ */ jsxs11(Text12, { color: theme.info.color, children: [
7809
8324
  " ",
7810
8325
  "Check your Cloudflare billing: https://dash.cloudflare.com/",
7811
8326
  accountId,
7812
8327
  "/billing/billable-usage"
7813
8328
  ] }) }),
7814
- /* @__PURE__ */ jsx12(Box10, { flexDirection: "column", children: SUGGESTIONS.map((s, i) => /* @__PURE__ */ jsxs10(Box10, { children: [
7815
- /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
8329
+ /* @__PURE__ */ jsx13(Box11, { flexDirection: "column", children: SUGGESTIONS.map((s, i) => /* @__PURE__ */ jsxs11(Box11, { children: [
8330
+ /* @__PURE__ */ jsxs11(Text12, { color: theme.info.color, children: [
7816
8331
  " ",
7817
8332
  "\u203A",
7818
8333
  " "
7819
8334
  ] }),
7820
- /* @__PURE__ */ jsx12(Text11, { color: theme.user, children: s })
8335
+ /* @__PURE__ */ jsx13(Text12, { color: theme.user, children: s })
7821
8336
  ] }, i)) }),
7822
- /* @__PURE__ */ jsx12(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text11, { color: theme.info.color, children: "Type a message or /help for commands \xB7 ctrl-c to exit \xB7 shift+tab to cycle modes" }) }),
7823
- /* @__PURE__ */ jsx12(Box10, { children: /* @__PURE__ */ jsx12(Text11, { color: theme.info.color, children: "Tip: type /hello to send feedback to the creator" }) })
8337
+ /* @__PURE__ */ jsx13(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx13(Text12, { color: theme.info.color, children: "Type a message or /help for commands \xB7 ctrl-c to exit \xB7 shift+tab to cycle modes" }) }),
8338
+ /* @__PURE__ */ jsx13(Box11, { children: /* @__PURE__ */ jsx13(Text12, { color: theme.info.color, children: "Tip: type /hello to send feedback to the creator" }) })
7824
8339
  ] });
7825
8340
  }
7826
8341
  var SUGGESTIONS;
@@ -7838,14 +8353,14 @@ var init_welcome = __esm({
7838
8353
 
7839
8354
  // src/ui/help-menu.tsx
7840
8355
  import { useState as useState6 } from "react";
7841
- import { Box as Box11, Text as Text12, useInput as useInput2 } from "ink";
7842
- import SelectInput3 from "ink-select-input";
7843
- import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
7844
- function HelpMenu({ customCommands, costAttributionEnabled, onDone, onCommand }) {
8356
+ import { Box as Box12, Text as Text13, useInput as useInput3 } from "ink";
8357
+ import SelectInput5 from "ink-select-input";
8358
+ import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
8359
+ function HelpMenu({ customCommands, costAttributionEnabled, cloudMode, onDone, onCommand }) {
7845
8360
  const theme = useTheme();
7846
8361
  const [page, setPage] = useState6("main");
7847
8362
  const customs = customCommands ?? [];
7848
- useInput2((_input, key) => {
8363
+ useInput3((_input, key) => {
7849
8364
  if (key.escape) {
7850
8365
  if (page !== "main") {
7851
8366
  setPage("main");
@@ -7858,8 +8373,9 @@ function HelpMenu({ customCommands, costAttributionEnabled, onDone, onCommand })
7858
8373
  onCommand(command);
7859
8374
  onDone();
7860
8375
  };
8376
+ const categories = cloudMode ? CATEGORIES.filter((c) => c.key !== "gateway") : CATEGORIES;
7861
8377
  if (page === "main") {
7862
- const items2 = CATEGORIES.map((cat) => ({
8378
+ const items2 = categories.map((cat) => ({
7863
8379
  label: cat.label,
7864
8380
  value: cat.key,
7865
8381
  key: cat.key
@@ -7868,11 +8384,11 @@ function HelpMenu({ customCommands, costAttributionEnabled, onDone, onCommand })
7868
8384
  items2.push({ label: "Run custom commands", value: "custom", key: "custom" });
7869
8385
  }
7870
8386
  items2.push({ label: "(close)", value: "__close__", key: "__close__" });
7871
- return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
7872
- /* @__PURE__ */ jsx13(Text12, { color: theme.accent, bold: true, children: "Help" }),
7873
- /* @__PURE__ */ jsx13(Text12, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select, Esc to close." }),
7874
- /* @__PURE__ */ jsx13(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx13(
7875
- SelectInput3,
8387
+ return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
8388
+ /* @__PURE__ */ jsx14(Text13, { color: theme.accent, bold: true, children: "Help" }),
8389
+ /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select, Esc to close." }),
8390
+ /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(
8391
+ SelectInput5,
7876
8392
  {
7877
8393
  items: items2,
7878
8394
  onSelect: (item) => {
@@ -7884,8 +8400,8 @@ function HelpMenu({ customCommands, costAttributionEnabled, onDone, onCommand })
7884
8400
  }
7885
8401
  }
7886
8402
  ) }),
7887
- /* @__PURE__ */ jsx13(Box11, { marginTop: 1, flexDirection: "column", children: SINGLE_COMMANDS.map((cmd) => /* @__PURE__ */ jsx13(Text12, { color: theme.info.color, dimColor: false, children: ` ${cmd.command.padEnd(20)} ${cmd.description}` }, cmd.command)) }),
7888
- /* @__PURE__ */ jsx13(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx13(Text12, { color: theme.info.color, dimColor: false, children: "keys: ctrl-c interrupt/exit \xB7 ctrl-r toggle reasoning \xB7 ctrl-o verbose \xB7 shift+tab cycle mode \xB7 \u2191/\u2193 history" }) })
8403
+ /* @__PURE__ */ jsx14(Box12, { marginTop: 1, flexDirection: "column", children: SINGLE_COMMANDS.map((cmd) => /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, dimColor: false, children: ` ${cmd.command.padEnd(20)} ${cmd.description}` }, cmd.command)) }),
8404
+ /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, dimColor: false, children: "keys: ctrl-c interrupt/exit \xB7 ctrl-r toggle reasoning \xB7 ctrl-o verbose \xB7 shift+tab cycle mode \xB7 \u2191/\u2193 history" }) })
7889
8405
  ] });
7890
8406
  }
7891
8407
  if (page === "custom") {
@@ -7895,11 +8411,11 @@ function HelpMenu({ customCommands, costAttributionEnabled, onDone, onCommand })
7895
8411
  key: c.name
7896
8412
  }));
7897
8413
  items2.push({ label: "\u2190 Back", value: "__back__", key: "__back__" });
7898
- return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
7899
- /* @__PURE__ */ jsx13(Text12, { color: theme.accent, bold: true, children: "Custom commands" }),
7900
- /* @__PURE__ */ jsx13(Text12, { color: theme.info.color, dimColor: false, children: customs.length === 0 ? "no custom commands found in .kimiflare/commands/" : "Arrow keys to navigate, Enter to run, Esc to go back." }),
7901
- /* @__PURE__ */ jsx13(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx13(
7902
- SelectInput3,
8414
+ return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
8415
+ /* @__PURE__ */ jsx14(Text13, { color: theme.accent, bold: true, children: "Custom commands" }),
8416
+ /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, dimColor: false, children: customs.length === 0 ? "no custom commands found in .kimiflare/commands/" : "Arrow keys to navigate, Enter to run, Esc to go back." }),
8417
+ /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(
8418
+ SelectInput5,
7903
8419
  {
7904
8420
  items: items2,
7905
8421
  onSelect: (item) => {
@@ -7913,7 +8429,7 @@ function HelpMenu({ customCommands, costAttributionEnabled, onDone, onCommand })
7913
8429
  ) })
7914
8430
  ] });
7915
8431
  }
7916
- const category = CATEGORIES.find((c) => c.key === page);
8432
+ const category = categories.find((c) => c.key === page);
7917
8433
  const selectable = category.commands.filter((cmd) => cmd.selectable !== false);
7918
8434
  const staticCmds = category.commands.filter((cmd) => cmd.selectable === false);
7919
8435
  const items = selectable.map((cmd) => ({
@@ -7922,11 +8438,11 @@ function HelpMenu({ customCommands, costAttributionEnabled, onDone, onCommand })
7922
8438
  key: cmd.command
7923
8439
  }));
7924
8440
  items.push({ label: "\u2190 Back", value: "__back__", key: "__back__" });
7925
- return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
7926
- /* @__PURE__ */ jsx13(Text12, { color: theme.accent, bold: true, children: category.label }),
7927
- /* @__PURE__ */ jsx13(Text12, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to execute, Esc to go back." }),
7928
- /* @__PURE__ */ jsx13(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx13(
7929
- SelectInput3,
8441
+ return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
8442
+ /* @__PURE__ */ jsx14(Text13, { color: theme.accent, bold: true, children: category.label }),
8443
+ /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to execute, Esc to go back." }),
8444
+ /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(
8445
+ SelectInput5,
7930
8446
  {
7931
8447
  items,
7932
8448
  onSelect: (item) => {
@@ -7938,7 +8454,7 @@ function HelpMenu({ customCommands, costAttributionEnabled, onDone, onCommand })
7938
8454
  }
7939
8455
  }
7940
8456
  ) }),
7941
- staticCmds.length > 0 && /* @__PURE__ */ jsx13(Box11, { marginTop: 1, flexDirection: "column", children: staticCmds.map((cmd) => /* @__PURE__ */ jsx13(Text12, { color: theme.info.color, children: ` ${cmd.command.padEnd(28)} ${cmd.description}` }, cmd.command)) })
8457
+ staticCmds.length > 0 && /* @__PURE__ */ jsx14(Box12, { marginTop: 1, flexDirection: "column", children: staticCmds.map((cmd) => /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, children: ` ${cmd.command.padEnd(28)} ${cmd.description}` }, cmd.command)) })
7942
8458
  ] });
7943
8459
  }
7944
8460
  var CATEGORIES, SINGLE_COMMANDS;
@@ -8170,17 +8686,17 @@ var init_tui_deploy = __esm({
8170
8686
  });
8171
8687
 
8172
8688
  // src/ui/remote-dashboard.tsx
8173
- import { useEffect as useEffect4, useState as useState7 } from "react";
8174
- import { Box as Box12, Text as Text13, useInput as useInput3 } from "ink";
8175
- import SelectInput4 from "ink-select-input";
8176
- import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
8689
+ import { useEffect as useEffect5, useState as useState7 } from "react";
8690
+ import { Box as Box13, Text as Text14, useInput as useInput4 } from "ink";
8691
+ import SelectInput6 from "ink-select-input";
8692
+ import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
8177
8693
  function RemoteDashboard({ onSelect, onCancel }) {
8178
8694
  const theme = useTheme();
8179
8695
  const [sessions, setSessions] = useState7([]);
8180
8696
  const [loading, setLoading] = useState7(true);
8181
8697
  const [error, setError] = useState7(null);
8182
8698
  const [refreshing, setRefreshing] = useState7(false);
8183
- useEffect4(() => {
8699
+ useEffect5(() => {
8184
8700
  loadSessions();
8185
8701
  }, []);
8186
8702
  async function loadSessions() {
@@ -8216,7 +8732,7 @@ function RemoteDashboard({ onSelect, onCancel }) {
8216
8732
  setRefreshing(false);
8217
8733
  }
8218
8734
  }
8219
- useInput3((input, key) => {
8735
+ useInput4((input, key) => {
8220
8736
  if (input === "r" || input === "R") {
8221
8737
  void loadSessions();
8222
8738
  }
@@ -8229,31 +8745,31 @@ function RemoteDashboard({ onSelect, onCancel }) {
8229
8745
  value: s.sessionId
8230
8746
  }));
8231
8747
  if (loading) {
8232
- return /* @__PURE__ */ jsx14(Box12, { flexDirection: "column", padding: 1, children: /* @__PURE__ */ jsx14(Text13, { color: theme.accent, children: "Loading remote sessions..." }) });
8748
+ return /* @__PURE__ */ jsx15(Box13, { flexDirection: "column", padding: 1, children: /* @__PURE__ */ jsx15(Text14, { color: theme.accent, children: "Loading remote sessions..." }) });
8233
8749
  }
8234
8750
  if (error) {
8235
- return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", padding: 1, children: [
8236
- /* @__PURE__ */ jsxs12(Text13, { color: theme.error, children: [
8751
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", padding: 1, children: [
8752
+ /* @__PURE__ */ jsxs13(Text14, { color: theme.error, children: [
8237
8753
  "Error: ",
8238
8754
  error
8239
8755
  ] }),
8240
- /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "Press R to retry, Esc to close" })
8756
+ /* @__PURE__ */ jsx15(Text14, { dimColor: true, children: "Press R to retry, Esc to close" })
8241
8757
  ] });
8242
8758
  }
8243
8759
  if (sessions.length === 0) {
8244
- return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", padding: 1, children: [
8245
- /* @__PURE__ */ jsx14(Text13, { color: theme.accent, children: "No remote sessions yet." }),
8246
- /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "Type /remote <prompt> to start one." }),
8247
- /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "Press Esc to close" })
8760
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", padding: 1, children: [
8761
+ /* @__PURE__ */ jsx15(Text14, { color: theme.accent, children: "No remote sessions yet." }),
8762
+ /* @__PURE__ */ jsx15(Text14, { dimColor: true, children: "Type /remote <prompt> to start one." }),
8763
+ /* @__PURE__ */ jsx15(Text14, { dimColor: true, children: "Press Esc to close" })
8248
8764
  ] });
8249
8765
  }
8250
- return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", padding: 1, children: [
8251
- /* @__PURE__ */ jsxs12(Text13, { bold: true, color: theme.accent, children: [
8766
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", padding: 1, children: [
8767
+ /* @__PURE__ */ jsxs13(Text14, { bold: true, color: theme.accent, children: [
8252
8768
  "Recent remote tasks ",
8253
8769
  refreshing ? "(refreshing...)" : ""
8254
8770
  ] }),
8255
- /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(
8256
- SelectInput4,
8771
+ /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
8772
+ SelectInput6,
8257
8773
  {
8258
8774
  items,
8259
8775
  onSelect: (item) => {
@@ -8262,7 +8778,7 @@ function RemoteDashboard({ onSelect, onCancel }) {
8262
8778
  }
8263
8779
  }
8264
8780
  ) }),
8265
- /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "\u2191\u2193 navigate \u2022 Enter select \u2022 R refresh \u2022 Esc close" }) })
8781
+ /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(Text14, { dimColor: true, children: "\u2191\u2193 navigate \u2022 Enter select \u2022 R refresh \u2022 Esc close" }) })
8266
8782
  ] });
8267
8783
  }
8268
8784
  function formatSessionLine(s) {
@@ -8270,7 +8786,7 @@ function formatSessionLine(s) {
8270
8786
  const ago = formatAgo(new Date(s.updatedAt));
8271
8787
  const prompt = s.prompt.slice(0, 30) + (s.prompt.length > 30 ? "\u2026" : "");
8272
8788
  const outcome = s.prUrl ? `PR ${s.prUrl.split("/").pop()}` : s.status;
8273
- const cost = s.tokensUsed && s.tokensBudget ? ` (${formatTokens2(s.tokensUsed)}/${formatTokens2(s.tokensBudget)})` : s.tokensUsed ? ` (${formatTokens2(s.tokensUsed)})` : "";
8789
+ const cost = s.tokensUsed && s.tokensBudget ? ` (${formatTokens3(s.tokensUsed)}/${formatTokens3(s.tokensBudget)})` : s.tokensUsed ? ` (${formatTokens3(s.tokensUsed)})` : "";
8274
8790
  return `${icon} ${prompt} \u2192 ${outcome} ${ago}${cost}`;
8275
8791
  }
8276
8792
  function formatAgo(date) {
@@ -8283,7 +8799,7 @@ function formatAgo(date) {
8283
8799
  if (minutes > 0) return `${minutes}m ago`;
8284
8800
  return "just now";
8285
8801
  }
8286
- function formatTokens2(n) {
8802
+ function formatTokens3(n) {
8287
8803
  if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
8288
8804
  if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
8289
8805
  return String(n);
@@ -8295,7 +8811,7 @@ function RemoteSessionDetail({
8295
8811
  }) {
8296
8812
  const theme = useTheme();
8297
8813
  const [cancelling, setCancelling] = useState7(false);
8298
- useInput3((input, key) => {
8814
+ useInput4((input, key) => {
8299
8815
  if (key.escape) {
8300
8816
  onBack();
8301
8817
  }
@@ -8315,50 +8831,50 @@ function RemoteSessionDetail({
8315
8831
  }
8316
8832
  }
8317
8833
  const isRunning = session.status === "running" || session.status === "pending";
8318
- return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", padding: 1, children: [
8319
- /* @__PURE__ */ jsx14(Text13, { bold: true, color: theme.accent, children: "Remote Session" }),
8320
- /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "column", children: [
8321
- /* @__PURE__ */ jsxs12(Text13, { children: [
8834
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", padding: 1, children: [
8835
+ /* @__PURE__ */ jsx15(Text14, { bold: true, color: theme.accent, children: "Remote Session" }),
8836
+ /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "column", children: [
8837
+ /* @__PURE__ */ jsxs13(Text14, { children: [
8322
8838
  "ID: ",
8323
8839
  session.sessionId
8324
8840
  ] }),
8325
- /* @__PURE__ */ jsxs12(Text13, { children: [
8841
+ /* @__PURE__ */ jsxs13(Text14, { children: [
8326
8842
  "Repo: ",
8327
8843
  session.repo
8328
8844
  ] }),
8329
- /* @__PURE__ */ jsxs12(Text13, { children: [
8845
+ /* @__PURE__ */ jsxs13(Text14, { children: [
8330
8846
  "Status: ",
8331
8847
  session.status
8332
8848
  ] }),
8333
- /* @__PURE__ */ jsxs12(Text13, { children: [
8849
+ /* @__PURE__ */ jsxs13(Text14, { children: [
8334
8850
  "Prompt: ",
8335
8851
  session.prompt
8336
8852
  ] }),
8337
- session.prUrl && /* @__PURE__ */ jsxs12(Text13, { children: [
8853
+ session.prUrl && /* @__PURE__ */ jsxs13(Text14, { children: [
8338
8854
  "PR: ",
8339
8855
  session.prUrl
8340
8856
  ] }),
8341
- session.errorMessage && /* @__PURE__ */ jsxs12(Text13, { color: theme.error, children: [
8857
+ session.errorMessage && /* @__PURE__ */ jsxs13(Text14, { color: theme.error, children: [
8342
8858
  "Error: ",
8343
8859
  session.errorMessage
8344
8860
  ] }),
8345
- session.tokensUsed !== void 0 && /* @__PURE__ */ jsxs12(Text13, { children: [
8861
+ session.tokensUsed !== void 0 && /* @__PURE__ */ jsxs13(Text14, { children: [
8346
8862
  "Tokens: ",
8347
- formatTokens2(session.tokensUsed),
8348
- session.tokensBudget ? ` / ${formatTokens2(session.tokensBudget)}` : ""
8863
+ formatTokens3(session.tokensUsed),
8864
+ session.tokensBudget ? ` / ${formatTokens3(session.tokensBudget)}` : ""
8349
8865
  ] }),
8350
- /* @__PURE__ */ jsxs12(Text13, { children: [
8866
+ /* @__PURE__ */ jsxs13(Text14, { children: [
8351
8867
  "Created: ",
8352
8868
  new Date(session.createdAt).toLocaleString()
8353
8869
  ] }),
8354
- session.finishedAt && /* @__PURE__ */ jsxs12(Text13, { children: [
8870
+ session.finishedAt && /* @__PURE__ */ jsxs13(Text14, { children: [
8355
8871
  "Finished: ",
8356
8872
  new Date(session.finishedAt).toLocaleString()
8357
8873
  ] })
8358
8874
  ] }),
8359
- /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "row", gap: 2, children: [
8360
- isRunning && onCancel && /* @__PURE__ */ jsx14(Text13, { color: theme.error, children: cancelling ? "Cancelling..." : "[C] Cancel session" }),
8361
- /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "Esc back" })
8875
+ /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "row", gap: 2, children: [
8876
+ isRunning && onCancel && /* @__PURE__ */ jsx15(Text14, { color: theme.error, children: cancelling ? "Cancelling..." : "[C] Cancel session" }),
8877
+ /* @__PURE__ */ jsx15(Text14, { dimColor: true, children: "Esc back" })
8362
8878
  ] })
8363
8879
  ] });
8364
8880
  }
@@ -8424,12 +8940,12 @@ __export(sessions_exports, {
8424
8940
  pruneSessions: () => pruneSessions,
8425
8941
  saveSession: () => saveSession
8426
8942
  });
8427
- import { readFile as readFile11, writeFile as writeFile7, mkdir as mkdir7, readdir as readdir3, stat as stat4 } from "fs/promises";
8428
- import { homedir as homedir9 } from "os";
8429
- import { join as join13 } from "path";
8943
+ import { readFile as readFile12, writeFile as writeFile8, mkdir as mkdir7, readdir as readdir3, stat as stat4 } from "fs/promises";
8944
+ import { homedir as homedir10 } from "os";
8945
+ import { join as join15 } from "path";
8430
8946
  function sessionsDir2() {
8431
- const xdg = process.env.XDG_DATA_HOME || join13(homedir9(), ".local", "share");
8432
- return join13(xdg, "kimiflare", "sessions");
8947
+ const xdg = process.env.XDG_DATA_HOME || join15(homedir10(), ".local", "share");
8948
+ return join15(xdg, "kimiflare", "sessions");
8433
8949
  }
8434
8950
  function sanitize(text) {
8435
8951
  return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
@@ -8442,8 +8958,8 @@ function makeSessionId(firstPrompt) {
8442
8958
  async function saveSession(file) {
8443
8959
  const dir = sessionsDir2();
8444
8960
  await mkdir7(dir, { recursive: true });
8445
- const path = join13(dir, `${file.id}.json`);
8446
- await writeFile7(path, JSON.stringify(file, null, 2), "utf8");
8961
+ const path = join15(dir, `${file.id}.json`);
8962
+ await writeFile8(path, JSON.stringify(file, null, 2), "utf8");
8447
8963
  return path;
8448
8964
  }
8449
8965
  async function pruneSessions() {
@@ -8462,9 +8978,9 @@ async function listSessions(limit = 30, cwd) {
8462
8978
  const summaries = [];
8463
8979
  for (const name of entries) {
8464
8980
  if (!name.endsWith(".json")) continue;
8465
- const path = join13(dir, name);
8981
+ const path = join15(dir, name);
8466
8982
  try {
8467
- const [s, raw] = await Promise.all([stat4(path), readFile11(path, "utf8")]);
8983
+ const [s, raw] = await Promise.all([stat4(path), readFile12(path, "utf8")]);
8468
8984
  const parsed = JSON.parse(raw);
8469
8985
  if (cwd && parsed.cwd !== cwd) continue;
8470
8986
  const firstUser = parsed.messages.find((m) => m.role === "user");
@@ -8484,7 +9000,7 @@ async function listSessions(limit = 30, cwd) {
8484
9000
  return summaries.slice(0, limit);
8485
9001
  }
8486
9002
  async function loadSession(filePath) {
8487
- const raw = await readFile11(filePath, "utf8");
9003
+ const raw = await readFile12(filePath, "utf8");
8488
9004
  return JSON.parse(raw);
8489
9005
  }
8490
9006
  var init_sessions = __esm({
@@ -8495,10 +9011,10 @@ var init_sessions = __esm({
8495
9011
  });
8496
9012
 
8497
9013
  // src/util/image.ts
8498
- import { readFile as readFile12 } from "fs/promises";
9014
+ import { readFile as readFile13 } from "fs/promises";
8499
9015
  import { basename as basename3 } from "path";
8500
9016
  async function encodeImageFile(filePath) {
8501
- const buf = await readFile12(filePath);
9017
+ const buf = await readFile13(filePath);
8502
9018
  if (buf.byteLength > MAX_IMAGE_BYTES) {
8503
9019
  throw new Error(
8504
9020
  `image too large (${(buf.byteLength / 1024 / 1024).toFixed(1)} MB); max is ${MAX_IMAGE_BYTES / 1024 / 1024} MB`
@@ -8534,15 +9050,15 @@ var init_image = __esm({
8534
9050
  });
8535
9051
 
8536
9052
  // src/usage-tracker.ts
8537
- import { readFile as readFile13, writeFile as writeFile8, mkdir as mkdir8 } from "fs/promises";
8538
- import { homedir as homedir10 } from "os";
8539
- import { join as join14 } from "path";
9053
+ import { readFile as readFile14, writeFile as writeFile9, mkdir as mkdir8 } from "fs/promises";
9054
+ import { homedir as homedir11 } from "os";
9055
+ import { join as join16 } from "path";
8540
9056
  function usageDir2() {
8541
- const xdg = process.env.XDG_DATA_HOME || join14(homedir10(), ".local", "share");
8542
- return join14(xdg, "kimiflare");
9057
+ const xdg = process.env.XDG_DATA_HOME || join16(homedir11(), ".local", "share");
9058
+ return join16(xdg, "kimiflare");
8543
9059
  }
8544
9060
  function usagePath2() {
8545
- return join14(usageDir2(), "usage.json");
9061
+ return join16(usageDir2(), "usage.json");
8546
9062
  }
8547
9063
  function today2() {
8548
9064
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
@@ -8553,7 +9069,7 @@ function cutoffDate(daysBack) {
8553
9069
  }
8554
9070
  async function loadLog2() {
8555
9071
  try {
8556
- const raw = await readFile13(usagePath2(), "utf8");
9072
+ const raw = await readFile14(usagePath2(), "utf8");
8557
9073
  const parsed = JSON.parse(raw);
8558
9074
  if (parsed.version === LOG_VERSION2) return parsed;
8559
9075
  } catch {
@@ -8562,7 +9078,7 @@ async function loadLog2() {
8562
9078
  }
8563
9079
  async function saveLog(log) {
8564
9080
  await mkdir8(usageDir2(), { recursive: true });
8565
- await writeFile8(usagePath2(), JSON.stringify(log, null, 2), "utf8");
9081
+ await writeFile9(usagePath2(), JSON.stringify(log, null, 2), "utf8");
8566
9082
  }
8567
9083
  function getOrCreateDay(log, date) {
8568
9084
  let day = log.days.find((d) => d.date === date);
@@ -8768,7 +9284,7 @@ __export(db_exports, {
8768
9284
  updateMemoryEmbedding: () => updateMemoryEmbedding
8769
9285
  });
8770
9286
  import Database from "better-sqlite3";
8771
- import { dirname as dirname6 } from "path";
9287
+ import { dirname as dirname7 } from "path";
8772
9288
  import { mkdirSync, statSync as statSync2 } from "fs";
8773
9289
  function initSchema(db) {
8774
9290
  db.exec(`
@@ -8853,7 +9369,7 @@ function openMemoryDb(dbPath) {
8853
9369
  if (dbInstance) {
8854
9370
  dbInstance.close();
8855
9371
  }
8856
- mkdirSync(dirname6(dbPath), { recursive: true });
9372
+ mkdirSync(dirname7(dbPath), { recursive: true });
8857
9373
  dbInstance = new Database(dbPath);
8858
9374
  dbInstance.pragma("journal_mode = WAL");
8859
9375
  dbInstance.pragma("foreign_keys = ON");
@@ -9263,8 +9779,8 @@ function computeExactScore(memory, queryText, cwd) {
9263
9779
  let score = 0;
9264
9780
  const lowerQuery = queryText.toLowerCase();
9265
9781
  for (const file of memory.relatedFiles) {
9266
- const basename4 = file.split("/").pop() ?? file;
9267
- if (lowerQuery.includes(basename4.toLowerCase()) || basename4.toLowerCase().includes(lowerQuery)) {
9782
+ const basename5 = file.split("/").pop() ?? file;
9783
+ if (lowerQuery.includes(basename5.toLowerCase()) || basename5.toLowerCase().includes(lowerQuery)) {
9268
9784
  score += 0.3;
9269
9785
  }
9270
9786
  if (cwd && file.startsWith(cwd)) {
@@ -9792,16 +10308,16 @@ Context: This memory was explicitly provided by the user during a conversation.`
9792
10308
  });
9793
10309
 
9794
10310
  // src/util/state.ts
9795
- import { readFile as readFile14, writeFile as writeFile9, mkdir as mkdir9 } from "fs/promises";
9796
- import { homedir as homedir11 } from "os";
9797
- import { join as join16 } from "path";
10311
+ import { readFile as readFile15, writeFile as writeFile10, mkdir as mkdir9 } from "fs/promises";
10312
+ import { homedir as homedir12 } from "os";
10313
+ import { join as join18 } from "path";
9798
10314
  function statePath() {
9799
- const xdg = process.env.XDG_CONFIG_HOME || join16(homedir11(), ".config");
9800
- return join16(xdg, "kimiflare", "state.json");
10315
+ const xdg = process.env.XDG_CONFIG_HOME || join18(homedir12(), ".config");
10316
+ return join18(xdg, "kimiflare", "state.json");
9801
10317
  }
9802
10318
  async function readState() {
9803
10319
  try {
9804
- const raw = await readFile14(statePath(), "utf8");
10320
+ const raw = await readFile15(statePath(), "utf8");
9805
10321
  return JSON.parse(raw);
9806
10322
  } catch {
9807
10323
  return {};
@@ -9809,8 +10325,8 @@ async function readState() {
9809
10325
  }
9810
10326
  async function writeState(state) {
9811
10327
  const path = statePath();
9812
- await mkdir9(join16(path, ".."), { recursive: true });
9813
- await writeFile9(path, JSON.stringify(state, null, 2) + "\n", "utf8");
10328
+ await mkdir9(join18(path, ".."), { recursive: true });
10329
+ await writeFile10(path, JSON.stringify(state, null, 2) + "\n", "utf8");
9814
10330
  }
9815
10331
  async function markCreatorMessageSeen(version) {
9816
10332
  const state = await readState();
@@ -9883,15 +10399,15 @@ var init_frontmatter = __esm({
9883
10399
 
9884
10400
  // src/commands/loader.ts
9885
10401
  import { open, realpath } from "fs/promises";
9886
- import { homedir as homedir12 } from "os";
9887
- import { join as join17, relative as relative4, sep as sep2 } from "path";
10402
+ import { homedir as homedir13 } from "os";
10403
+ import { join as join19, relative as relative4, sep as sep2 } from "path";
9888
10404
  import fg3 from "fast-glob";
9889
10405
  function projectCommandsDir(cwd = process.cwd()) {
9890
- return join17(cwd, ".kimiflare", "commands");
10406
+ return join19(cwd, ".kimiflare", "commands");
9891
10407
  }
9892
10408
  function globalCommandsDir() {
9893
- const xdg = process.env.XDG_CONFIG_HOME || join17(homedir12(), ".config");
9894
- return join17(xdg, "kimiflare", "commands");
10409
+ const xdg = process.env.XDG_CONFIG_HOME || join19(homedir13(), ".config");
10410
+ return join19(xdg, "kimiflare", "commands");
9895
10411
  }
9896
10412
  async function loadCustomCommands(cwd = process.cwd()) {
9897
10413
  const warnings = [];
@@ -10042,10 +10558,10 @@ var init_loader = __esm({
10042
10558
  });
10043
10559
 
10044
10560
  // src/commands/renderer.ts
10045
- import { exec } from "child_process";
10561
+ import { exec as exec2 } from "child_process";
10046
10562
  import { open as open2, realpath as realpath2 } from "fs/promises";
10047
10563
  import { isAbsolute as isAbsolute2, relative as relative5, resolve as resolvePathJoin, basename as pathBasename } from "path";
10048
- import { promisify as promisify2 } from "util";
10564
+ import { promisify as promisify3 } from "util";
10049
10565
  function tokenizeArgs(s) {
10050
10566
  return [...s.matchAll(ARG_TOKEN_RE)].map((match) => {
10051
10567
  const token = match[0];
@@ -10112,7 +10628,7 @@ async function replaceShell(prompt, warnings, cmd, shellTimeoutMs) {
10112
10628
  matches.map(async (match) => {
10113
10629
  const command = match[1] ?? "";
10114
10630
  try {
10115
- const { stdout } = await execAsync(command, {
10631
+ const { stdout } = await execAsync2(command, {
10116
10632
  timeout: shellTimeoutMs,
10117
10633
  maxBuffer: 1024 * 1024
10118
10634
  });
@@ -10193,12 +10709,12 @@ async function replaceFiles(prompt, warnings, cmd, cwd, maxFileBytes) {
10193
10709
  function message(error) {
10194
10710
  return error instanceof Error ? error.message : String(error);
10195
10711
  }
10196
- var execAsync, ARG_TOKEN_RE, POSITIONAL_RE, HAS_POSITIONAL, SHELL_RE, FILE_RE, DEFAULT_MAX_FILE_BYTES, DEFAULT_SHELL_TIMEOUT_MS, SECRET_PATTERNS2;
10712
+ var execAsync2, ARG_TOKEN_RE, POSITIONAL_RE, HAS_POSITIONAL, SHELL_RE, FILE_RE, DEFAULT_MAX_FILE_BYTES, DEFAULT_SHELL_TIMEOUT_MS, SECRET_PATTERNS2;
10197
10713
  var init_renderer2 = __esm({
10198
10714
  "src/commands/renderer.ts"() {
10199
10715
  "use strict";
10200
10716
  init_paths();
10201
- execAsync = promisify2(exec);
10717
+ execAsync2 = promisify3(exec2);
10202
10718
  ARG_TOKEN_RE = /(?:"[^"]*"|'[^']*'|[^\s"']+)/g;
10203
10719
  POSITIONAL_RE = /\$(\d+)/g;
10204
10720
  HAS_POSITIONAL = /\$\d+/;
@@ -10267,8 +10783,8 @@ var init_builtins = __esm({
10267
10783
  });
10268
10784
 
10269
10785
  // src/commands/save.ts
10270
- import { mkdir as mkdir10, writeFile as writeFile10, unlink as unlink2 } from "fs/promises";
10271
- import { dirname as dirname7 } from "path";
10786
+ import { mkdir as mkdir10, writeFile as writeFile11, unlink as unlink2 } from "fs/promises";
10787
+ import { dirname as dirname8 } from "path";
10272
10788
  async function saveCustomCommand(opts2) {
10273
10789
  const dir = opts2.source === "project" ? projectCommandsDir(opts2.cwd) : globalCommandsDir();
10274
10790
  const filepath = `${dir}/${opts2.name}.md`;
@@ -10279,8 +10795,8 @@ async function saveCustomCommand(opts2) {
10279
10795
  if (opts2.effort) data.effort = opts2.effort;
10280
10796
  const frontmatter = serializeFrontmatter(data);
10281
10797
  const content = frontmatter + opts2.template;
10282
- await mkdir10(dirname7(filepath), { recursive: true });
10283
- await writeFile10(filepath, content, "utf8");
10798
+ await mkdir10(dirname8(filepath), { recursive: true });
10799
+ await writeFile11(filepath, content, "utf8");
10284
10800
  return { filepath };
10285
10801
  }
10286
10802
  async function deleteCustomCommand(cmd) {
@@ -10296,9 +10812,9 @@ var init_save = __esm({
10296
10812
 
10297
10813
  // src/ui/command-wizard.tsx
10298
10814
  import { useState as useState8 } from "react";
10299
- import { Box as Box13, Text as Text14, useInput as useInput4, useWindowSize as useWindowSize2 } from "ink";
10300
- import SelectInput5 from "ink-select-input";
10301
- import { Fragment as Fragment2, jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
10815
+ import { Box as Box14, Text as Text15, useInput as useInput5, useWindowSize as useWindowSize2 } from "ink";
10816
+ import SelectInput7 from "ink-select-input";
10817
+ import { Fragment as Fragment2, jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
10302
10818
  function CommandWizard({ mode, initial, existingNames, builtinNames, onDone, onSave }) {
10303
10819
  const theme = useTheme();
10304
10820
  const [step, setStep] = useState8("name");
@@ -10322,7 +10838,7 @@ function CommandWizard({ mode, initial, existingNames, builtinNames, onDone, onS
10322
10838
  if (existingNames.includes(trimmed) && !isEditingSelf(trimmed)) return `/${trimmed} already exists`;
10323
10839
  return null;
10324
10840
  };
10325
- useInput4((_input, key) => {
10841
+ useInput5((_input, key) => {
10326
10842
  if (key.escape) {
10327
10843
  onDone();
10328
10844
  }
@@ -10422,8 +10938,8 @@ ${template}`;
10422
10938
  const renderStep = () => {
10423
10939
  switch (step) {
10424
10940
  case "name":
10425
- return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10426
- /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
10941
+ return /* @__PURE__ */ jsxs14(Fragment2, { children: [
10942
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.accent, bold: true, children: [
10427
10943
  mode === "create" ? "Create" : "Edit",
10428
10944
  " custom command \u2014 Name (",
10429
10945
  stepIndex,
@@ -10431,8 +10947,8 @@ ${template}`;
10431
10947
  totalSteps,
10432
10948
  ")"
10433
10949
  ] }),
10434
- error && /* @__PURE__ */ jsx15(Text14, { color: theme.error, children: error }),
10435
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
10950
+ error && /* @__PURE__ */ jsx16(Text15, { color: theme.error, children: error }),
10951
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
10436
10952
  CustomTextInput,
10437
10953
  {
10438
10954
  value: name,
@@ -10441,11 +10957,11 @@ ${template}`;
10441
10957
  focus: true
10442
10958
  }
10443
10959
  ) }),
10444
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "letters, numbers, _ - / only; must start with a letter" })
10960
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "letters, numbers, _ - / only; must start with a letter" })
10445
10961
  ] });
10446
10962
  case "description":
10447
- return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10448
- /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
10963
+ return /* @__PURE__ */ jsxs14(Fragment2, { children: [
10964
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.accent, bold: true, children: [
10449
10965
  mode === "create" ? "Create" : "Edit",
10450
10966
  " custom command \u2014 Description (",
10451
10967
  stepIndex,
@@ -10453,7 +10969,7 @@ ${template}`;
10453
10969
  totalSteps,
10454
10970
  ")"
10455
10971
  ] }),
10456
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
10972
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
10457
10973
  CustomTextInput,
10458
10974
  {
10459
10975
  value: description,
@@ -10462,49 +10978,49 @@ ${template}`;
10462
10978
  focus: true
10463
10979
  }
10464
10980
  ) }),
10465
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Press Enter to skip" })
10981
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "Press Enter to skip" })
10466
10982
  ] });
10467
10983
  case "template": {
10468
- const guide = /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", paddingLeft: 1, children: [
10469
- /* @__PURE__ */ jsx15(Text14, { color: theme.accent, bold: true, children: "What is this?" }),
10470
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "A prompt template \u2014 instructions to the AI." }),
10471
- /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
10984
+ const guide = /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", paddingLeft: 1, children: [
10985
+ /* @__PURE__ */ jsx16(Text15, { color: theme.accent, bold: true, children: "What is this?" }),
10986
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "A prompt template \u2014 instructions to the AI." }),
10987
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
10472
10988
  "When you type /",
10473
10989
  name || "yourcommand",
10474
10990
  " later, this gets sent to the model."
10475
10991
  ] }),
10476
- /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "column", children: [
10477
- /* @__PURE__ */ jsx15(Text14, { color: theme.accent, bold: true, children: "Variables" }),
10478
- /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
10992
+ /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, flexDirection: "column", children: [
10993
+ /* @__PURE__ */ jsx16(Text15, { color: theme.accent, bold: true, children: "Variables" }),
10994
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
10479
10995
  " ",
10480
10996
  "$1, $2 ... \u2192 arguments you type"
10481
10997
  ] }),
10482
- /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
10998
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
10483
10999
  " ",
10484
11000
  "$ARGUMENTS \u2192 everything after the command"
10485
11001
  ] })
10486
11002
  ] }),
10487
- /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "column", children: [
10488
- /* @__PURE__ */ jsx15(Text14, { color: theme.accent, bold: true, children: "Dynamic inlines" }),
10489
- /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
11003
+ /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, flexDirection: "column", children: [
11004
+ /* @__PURE__ */ jsx16(Text15, { color: theme.accent, bold: true, children: "Dynamic inlines" }),
11005
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
10490
11006
  " ",
10491
11007
  "!`git diff` \u2192 shell output inlined"
10492
11008
  ] }),
10493
- /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
11009
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
10494
11010
  " ",
10495
11011
  "@README.md \u2192 file contents inlined"
10496
11012
  ] })
10497
11013
  ] }),
10498
- /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "column", children: [
10499
- /* @__PURE__ */ jsx15(Text14, { color: theme.accent, bold: true, children: "Example" }),
10500
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Review this PR diff:" }),
10501
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "!`git diff main...HEAD`" }),
10502
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Focus on: $1" })
11014
+ /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, flexDirection: "column", children: [
11015
+ /* @__PURE__ */ jsx16(Text15, { color: theme.accent, bold: true, children: "Example" }),
11016
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "Review this PR diff:" }),
11017
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "!`git diff main...HEAD`" }),
11018
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "Focus on: $1" })
10503
11019
  ] })
10504
11020
  ] });
10505
- const inputArea = /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", flexGrow: 1, children: [
10506
- error && /* @__PURE__ */ jsx15(Text14, { color: theme.error, children: error }),
10507
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
11021
+ const inputArea = /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", flexGrow: 1, children: [
11022
+ error && /* @__PURE__ */ jsx16(Text15, { color: theme.error, children: error }),
11023
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
10508
11024
  CustomTextInput,
10509
11025
  {
10510
11026
  value: template,
@@ -10514,13 +11030,13 @@ ${template}`;
10514
11030
  enablePaste: true
10515
11031
  }
10516
11032
  ) }),
10517
- columns < 100 && /* @__PURE__ */ jsxs13(Fragment2, { children: [
10518
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Paste multi-line templates with Ctrl+V." }),
10519
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Variables: $1 $2 ... $ARGUMENTS Shell: !`cmd` File: @path" })
11033
+ columns < 100 && /* @__PURE__ */ jsxs14(Fragment2, { children: [
11034
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "Paste multi-line templates with Ctrl+V." }),
11035
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "Variables: $1 $2 ... $ARGUMENTS Shell: !`cmd` File: @path" })
10520
11036
  ] })
10521
11037
  ] });
10522
- return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10523
- /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
11038
+ return /* @__PURE__ */ jsxs14(Fragment2, { children: [
11039
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.accent, bold: true, children: [
10524
11040
  mode === "create" ? "Create" : "Edit",
10525
11041
  " custom command \u2014 Template (",
10526
11042
  stepIndex,
@@ -10528,10 +11044,10 @@ ${template}`;
10528
11044
  totalSteps,
10529
11045
  ")"
10530
11046
  ] }),
10531
- columns >= 100 ? /* @__PURE__ */ jsxs13(Box13, { flexDirection: "row", marginTop: 1, children: [
10532
- /* @__PURE__ */ jsx15(Box13, { flexDirection: "column", width: "50%", children: inputArea }),
10533
- /* @__PURE__ */ jsx15(Box13, { flexDirection: "column", width: "50%", children: guide })
10534
- ] }) : /* @__PURE__ */ jsx15(Box13, { flexDirection: "column", marginTop: 1, children: inputArea })
11047
+ columns >= 100 ? /* @__PURE__ */ jsxs14(Box14, { flexDirection: "row", marginTop: 1, children: [
11048
+ /* @__PURE__ */ jsx16(Box14, { flexDirection: "column", width: "50%", children: inputArea }),
11049
+ /* @__PURE__ */ jsx16(Box14, { flexDirection: "column", width: "50%", children: guide })
11050
+ ] }) : /* @__PURE__ */ jsx16(Box14, { flexDirection: "column", marginTop: 1, children: inputArea })
10535
11051
  ] });
10536
11052
  }
10537
11053
  case "advanced": {
@@ -10540,8 +11056,8 @@ ${template}`;
10540
11056
  { label: "Skip", value: "skip", key: "skip" },
10541
11057
  { label: "\u2190 Cancel", value: "cancel", key: "cancel" }
10542
11058
  ];
10543
- return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10544
- /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
11059
+ return /* @__PURE__ */ jsxs14(Fragment2, { children: [
11060
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.accent, bold: true, children: [
10545
11061
  mode === "create" ? "Create" : "Edit",
10546
11062
  " custom command \u2014 Options (",
10547
11063
  stepIndex,
@@ -10549,8 +11065,8 @@ ${template}`;
10549
11065
  totalSteps,
10550
11066
  ")"
10551
11067
  ] }),
10552
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
10553
- SelectInput5,
11068
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
11069
+ SelectInput7,
10554
11070
  {
10555
11071
  items,
10556
11072
  onSelect: (item) => {
@@ -10569,17 +11085,17 @@ ${template}`;
10569
11085
  { label: cmdMode === "auto" ? "auto \xB7 current" : "auto", value: "auto", key: "auto" },
10570
11086
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
10571
11087
  ];
10572
- return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10573
- /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
11088
+ return /* @__PURE__ */ jsxs14(Fragment2, { children: [
11089
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.accent, bold: true, children: [
10574
11090
  "Mode override (",
10575
11091
  stepIndex,
10576
11092
  "/",
10577
11093
  totalSteps,
10578
11094
  ")"
10579
11095
  ] }),
10580
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Saved to file but not yet enforced at runtime" }),
10581
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
10582
- SelectInput5,
11096
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "Saved to file but not yet enforced at runtime" }),
11097
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
11098
+ SelectInput7,
10583
11099
  {
10584
11100
  items,
10585
11101
  onSelect: (item) => {
@@ -10598,16 +11114,16 @@ ${template}`;
10598
11114
  { label: cmdEffort === "high" ? "high \xB7 current" : "high", value: "high", key: "high" },
10599
11115
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
10600
11116
  ];
10601
- return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10602
- /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
11117
+ return /* @__PURE__ */ jsxs14(Fragment2, { children: [
11118
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.accent, bold: true, children: [
10603
11119
  "Reasoning effort (",
10604
11120
  stepIndex,
10605
11121
  "/",
10606
11122
  totalSteps,
10607
11123
  ")"
10608
11124
  ] }),
10609
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
10610
- SelectInput5,
11125
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
11126
+ SelectInput7,
10611
11127
  {
10612
11128
  items,
10613
11129
  onSelect: (item) => {
@@ -10619,15 +11135,15 @@ ${template}`;
10619
11135
  ] });
10620
11136
  }
10621
11137
  case "model":
10622
- return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10623
- /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
11138
+ return /* @__PURE__ */ jsxs14(Fragment2, { children: [
11139
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.accent, bold: true, children: [
10624
11140
  "Model override (",
10625
11141
  stepIndex,
10626
11142
  "/",
10627
11143
  totalSteps,
10628
11144
  ")"
10629
11145
  ] }),
10630
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
11146
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
10631
11147
  CustomTextInput,
10632
11148
  {
10633
11149
  value: cmdModel ?? "",
@@ -10636,7 +11152,7 @@ ${template}`;
10636
11152
  focus: true
10637
11153
  }
10638
11154
  ) }),
10639
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Press Enter to skip" })
11155
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "Press Enter to skip" })
10640
11156
  ] });
10641
11157
  case "location": {
10642
11158
  const items = [
@@ -10644,16 +11160,16 @@ ${template}`;
10644
11160
  { label: source === "global" ? "Global \xB7 current" : "Global", value: "global", key: "global" },
10645
11161
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
10646
11162
  ];
10647
- return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10648
- /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
11163
+ return /* @__PURE__ */ jsxs14(Fragment2, { children: [
11164
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.accent, bold: true, children: [
10649
11165
  "Save location (",
10650
11166
  stepIndex,
10651
11167
  "/",
10652
11168
  totalSteps,
10653
11169
  ")"
10654
11170
  ] }),
10655
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
10656
- SelectInput5,
11171
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
11172
+ SelectInput7,
10657
11173
  {
10658
11174
  items,
10659
11175
  onSelect: (item) => {
@@ -10662,7 +11178,7 @@ ${template}`;
10662
11178
  }
10663
11179
  }
10664
11180
  ) }),
10665
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Project: .kimiflare/commands/ Global: ~/.config/kimiflare/commands/" })
11181
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "Project: .kimiflare/commands/ Global: ~/.config/kimiflare/commands/" })
10666
11182
  ] });
10667
11183
  }
10668
11184
  case "confirm": {
@@ -10670,8 +11186,8 @@ ${template}`;
10670
11186
  { label: "Save", value: "save", key: "save" },
10671
11187
  { label: "Cancel", value: "cancel", key: "cancel" }
10672
11188
  ];
10673
- return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10674
- /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
11189
+ return /* @__PURE__ */ jsxs14(Fragment2, { children: [
11190
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.accent, bold: true, children: [
10675
11191
  mode === "create" ? "Create" : "Edit",
10676
11192
  " custom command \u2014 Confirm (",
10677
11193
  stepIndex,
@@ -10679,14 +11195,14 @@ ${template}`;
10679
11195
  totalSteps,
10680
11196
  ")"
10681
11197
  ] }),
10682
- /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
11198
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
10683
11199
  source === "project" ? ".kimiflare/commands/" : "~/.config/kimiflare/commands/",
10684
11200
  name,
10685
11201
  ".md"
10686
11202
  ] }),
10687
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, flexDirection: "column", children: previewContent().split("\n").map((line, i) => /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: line || " " }, i)) }),
10688
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
10689
- SelectInput5,
11203
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, flexDirection: "column", children: previewContent().split("\n").map((line, i) => /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: line || " " }, i)) }),
11204
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
11205
+ SelectInput7,
10690
11206
  {
10691
11207
  items,
10692
11208
  onSelect: (item) => handleConfirm(item.value)
@@ -10696,7 +11212,7 @@ ${template}`;
10696
11212
  }
10697
11213
  }
10698
11214
  };
10699
- return /* @__PURE__ */ jsx15(Box13, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: renderStep() });
11215
+ return /* @__PURE__ */ jsx16(Box14, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: renderStep() });
10700
11216
  }
10701
11217
  var NAME_RE;
10702
11218
  var init_command_wizard = __esm({
@@ -10708,10 +11224,442 @@ var init_command_wizard = __esm({
10708
11224
  }
10709
11225
  });
10710
11226
 
11227
+ // src/init/context-generator.ts
11228
+ import { existsSync as existsSync2, statSync as statSync3 } from "fs";
11229
+ import { join as join20 } from "path";
11230
+ function detectFlavor(cwd) {
11231
+ for (const [flavor, signatures] of Object.entries(FLAVOR_SIGNATURES)) {
11232
+ if (flavor === "generic") continue;
11233
+ for (const sig of signatures) {
11234
+ const path = join20(cwd, sig);
11235
+ if (sig.includes("*")) {
11236
+ try {
11237
+ const parts = sig.split("*");
11238
+ const prefix = parts[0] ?? "";
11239
+ const suffix = parts[1] ?? "";
11240
+ const entries = __require("fs").readdirSync(cwd);
11241
+ if (entries.some((e) => e.startsWith(prefix) && e.endsWith(suffix))) {
11242
+ return flavor;
11243
+ }
11244
+ } catch {
11245
+ }
11246
+ } else if (existsSync2(path)) {
11247
+ return flavor;
11248
+ }
11249
+ }
11250
+ }
11251
+ return "generic";
11252
+ }
11253
+ function findFile(cwd, candidates) {
11254
+ for (const c of candidates) {
11255
+ if (existsSync2(join20(cwd, c))) return c;
11256
+ }
11257
+ return null;
11258
+ }
11259
+ function findSourceRoots(cwd) {
11260
+ const roots = [];
11261
+ for (const r of SOURCE_ROOT_CANDIDATES) {
11262
+ const p = join20(cwd, r);
11263
+ try {
11264
+ const s = statSync3(p);
11265
+ if (s.isDirectory()) roots.push(r);
11266
+ } catch {
11267
+ }
11268
+ }
11269
+ return roots;
11270
+ }
11271
+ function findCiConfig(cwd) {
11272
+ for (const c of CI_PATHS) {
11273
+ if (existsSync2(join20(cwd, c))) {
11274
+ try {
11275
+ const s = statSync3(join20(cwd, c));
11276
+ return s.isDirectory() ? c : c;
11277
+ } catch {
11278
+ }
11279
+ }
11280
+ }
11281
+ return null;
11282
+ }
11283
+ function languageForFlavor(f) {
11284
+ const map = {
11285
+ node: "JavaScript / TypeScript",
11286
+ python: "Python",
11287
+ go: "Go",
11288
+ rust: "Rust",
11289
+ ruby: "Ruby",
11290
+ java: "Java / Kotlin",
11291
+ dotnet: "C# / F#",
11292
+ php: "PHP",
11293
+ elixir: "Elixir",
11294
+ haskell: "Haskell",
11295
+ c: "C",
11296
+ cpp: "C++",
11297
+ zig: "Zig",
11298
+ generic: "Unknown"
11299
+ };
11300
+ return map[f];
11301
+ }
11302
+ function analyzeProject(cwd) {
11303
+ const flavor = detectFlavor(cwd);
11304
+ const packageFiles = {
11305
+ node: ["package.json"],
11306
+ python: ["pyproject.toml", "setup.py", "setup.cfg"],
11307
+ go: ["go.mod"],
11308
+ rust: ["Cargo.toml"],
11309
+ ruby: ["Gemfile"],
11310
+ java: ["pom.xml", "build.gradle", "build.gradle.kts"],
11311
+ dotnet: ["*.csproj"],
11312
+ php: ["composer.json"],
11313
+ elixir: ["mix.exs"],
11314
+ haskell: ["package.yaml", "*.cabal"],
11315
+ c: ["Makefile", "CMakeLists.txt"],
11316
+ cpp: ["Makefile", "CMakeLists.txt"],
11317
+ zig: ["build.zig"],
11318
+ generic: []
11319
+ };
11320
+ const lockFiles = {
11321
+ node: ["package-lock.json", "yarn.lock", "pnpm-lock.yaml", "bun.lockb"],
11322
+ python: ["poetry.lock", "uv.lock", "Pipfile.lock"],
11323
+ go: ["go.sum"],
11324
+ rust: ["Cargo.lock"],
11325
+ ruby: ["Gemfile.lock"],
11326
+ java: [],
11327
+ dotnet: [],
11328
+ php: ["composer.lock"],
11329
+ elixir: ["mix.lock"],
11330
+ haskell: [],
11331
+ c: [],
11332
+ cpp: [],
11333
+ zig: [],
11334
+ generic: []
11335
+ };
11336
+ const buildFiles = {
11337
+ node: ["tsup.config.ts", "vite.config.ts", "webpack.config.js", "rollup.config.js", "esbuild.js", "next.config.js", "nuxt.config.ts", "astro.config.mjs", "svelte.config.js"],
11338
+ python: ["setup.py", "setup.cfg", "pyproject.toml"],
11339
+ go: ["Makefile"],
11340
+ rust: ["Cargo.toml"],
11341
+ ruby: ["Rakefile"],
11342
+ java: ["pom.xml", "build.gradle"],
11343
+ dotnet: ["*.sln"],
11344
+ php: [],
11345
+ elixir: ["mix.exs"],
11346
+ haskell: ["package.yaml", "*.cabal"],
11347
+ c: ["Makefile", "CMakeLists.txt"],
11348
+ cpp: ["Makefile", "CMakeLists.txt"],
11349
+ zig: ["build.zig"],
11350
+ generic: []
11351
+ };
11352
+ const testConfigs = {
11353
+ node: ["vitest.config.ts", "jest.config.js", "playwright.config.ts", "cypress.config.ts", "ava.config.js"],
11354
+ python: ["pytest.ini", "tox.ini", "setup.cfg"],
11355
+ go: [],
11356
+ rust: [],
11357
+ ruby: ["Rakefile", "spec_helper.rb"],
11358
+ java: [],
11359
+ dotnet: [],
11360
+ php: ["phpunit.xml"],
11361
+ elixir: ["test/test_helper.exs"],
11362
+ haskell: [],
11363
+ c: ["Makefile"],
11364
+ cpp: ["Makefile"],
11365
+ zig: [],
11366
+ generic: []
11367
+ };
11368
+ const lintConfigs = {
11369
+ node: [".eslintrc", ".eslintrc.js", ".eslintrc.json", ".prettierrc", "biome.json", "deno.json"],
11370
+ python: [".flake8", "pyproject.toml", "setup.cfg", ".pylintrc", "ruff.toml"],
11371
+ go: [],
11372
+ rust: ["rustfmt.toml", "clippy.toml"],
11373
+ ruby: [".rubocop.yml"],
11374
+ java: [],
11375
+ dotnet: [],
11376
+ php: [],
11377
+ elixir: [".formatter.exs"],
11378
+ haskell: [],
11379
+ c: [".clang-format", ".clang-tidy"],
11380
+ cpp: [".clang-format", ".clang-tidy"],
11381
+ zig: [],
11382
+ generic: []
11383
+ };
11384
+ const typeConfigs = {
11385
+ node: ["tsconfig.json", "jsconfig.json"],
11386
+ python: ["pyproject.toml", "setup.cfg", "mypy.ini"],
11387
+ go: [],
11388
+ rust: [],
11389
+ ruby: [],
11390
+ java: [],
11391
+ dotnet: [],
11392
+ php: [],
11393
+ elixir: [],
11394
+ haskell: [],
11395
+ c: [],
11396
+ cpp: [],
11397
+ zig: [],
11398
+ generic: []
11399
+ };
11400
+ return {
11401
+ flavor,
11402
+ primaryLanguage: languageForFlavor(flavor),
11403
+ packageFile: findFile(cwd, packageFiles[flavor]),
11404
+ lockFile: findFile(cwd, lockFiles[flavor]),
11405
+ buildFile: findFile(cwd, buildFiles[flavor]),
11406
+ testConfig: findFile(cwd, testConfigs[flavor]),
11407
+ lintConfig: findFile(cwd, lintConfigs[flavor]),
11408
+ typeConfig: findFile(cwd, typeConfigs[flavor]),
11409
+ ciConfig: findCiConfig(cwd),
11410
+ readme: findFile(cwd, ["README.md", "README.rst", "README.txt", "Readme.md"]),
11411
+ sourceRoots: findSourceRoots(cwd),
11412
+ hasGit: existsSync2(join20(cwd, ".git"))
11413
+ };
11414
+ }
11415
+ function bashDiscoveryCommands(profile) {
11416
+ const cmds = [];
11417
+ if (profile.hasGit) {
11418
+ cmds.push(
11419
+ "git log --oneline -20",
11420
+ "git branch -a | head -20"
11421
+ );
11422
+ }
11423
+ switch (profile.flavor) {
11424
+ case "node":
11425
+ cmds.push(
11426
+ `cat package.json | jq -r '.scripts | to_entries[] | "\\(.key): \\(.value)"' 2>/dev/null || node -e "const p=require('./package.json'); Object.entries(p.scripts||{}).forEach(([k,v])=>console.log(k+': '+v))"`,
11427
+ "ls -la node_modules/.bin 2>/dev/null | head -30 || true"
11428
+ );
11429
+ break;
11430
+ case "python":
11431
+ cmds.push(
11432
+ `python -c "import tomllib; f=open('pyproject.toml','rb'); d=tomllib.load(f); [print(f'{k}: {v}') for k,v in d.get('project',{}).get('scripts',{}).items()]" 2>/dev/null || true`,
11433
+ "make -p 2>/dev/null | grep -E '^[a-zA-Z_-]+:.*$' | head -20 || true"
11434
+ );
11435
+ break;
11436
+ case "go":
11437
+ cmds.push("go help 2>/dev/null | head -10 || true");
11438
+ break;
11439
+ case "rust":
11440
+ cmds.push("cargo --list 2>/dev/null | head -20 || true");
11441
+ break;
11442
+ case "ruby":
11443
+ cmds.push("bundle exec rake -T 2>/dev/null | head -20 || true");
11444
+ break;
11445
+ case "java":
11446
+ cmds.push("./mvnw help:describe -Dplugin=help 2>/dev/null | head -10 || true");
11447
+ break;
11448
+ }
11449
+ cmds.push("ls -la");
11450
+ return cmds;
11451
+ }
11452
+ function discoveryChecklist(profile) {
11453
+ const lines = [];
11454
+ lines.push("## PHASE 1: Project Identity & Configuration");
11455
+ lines.push("");
11456
+ if (profile.readme) {
11457
+ lines.push(`- [ ] Read \`${profile.readme}\` \u2014 extract project name, description, purpose.`);
11458
+ }
11459
+ if (profile.packageFile) {
11460
+ lines.push(`- [ ] Read \`${profile.packageFile}\` \u2014 extract dependencies, scripts, metadata.`);
11461
+ }
11462
+ if (profile.buildFile) {
11463
+ lines.push(`- [ ] Read \`${profile.buildFile}\` \u2014 understand build system and entry points.`);
11464
+ }
11465
+ if (profile.typeConfig) {
11466
+ lines.push(`- [ ] Read \`${profile.typeConfig}\` \u2014 note strictness, target, module system.`);
11467
+ }
11468
+ if (profile.testConfig) {
11469
+ lines.push(`- [ ] Read \`${profile.testConfig}\` \u2014 understand test runner and conventions.`);
11470
+ }
11471
+ if (profile.lintConfig) {
11472
+ lines.push(`- [ ] Read \`${profile.lintConfig}\` \u2014 note style rules and formatter.`);
11473
+ }
11474
+ if (profile.ciConfig) {
11475
+ lines.push(`- [ ] Inspect CI config in \`${profile.ciConfig}\` \u2014 note checks, matrix, deployment.`);
11476
+ }
11477
+ lines.push("");
11478
+ lines.push("## PHASE 2: Source Structure Discovery");
11479
+ lines.push("");
11480
+ for (const root of profile.sourceRoots) {
11481
+ lines.push(`- [ ] Use \`glob\` to list files in \`${root}/**/*\` (limit to ~50 files).`);
11482
+ lines.push(`- [ ] Read 3-5 representative files from \`${root}\` to understand code patterns.`);
11483
+ }
11484
+ if (profile.sourceRoots.length === 0) {
11485
+ lines.push("- [ ] Use `glob` to find source files (`**/*.{js,ts,py,go,rs,rb,java,cs,php,ex,hs,c,cpp,zig}`) \u2014 list top 50.");
11486
+ lines.push("- [ ] Read 3-5 representative source files to understand code patterns.");
11487
+ }
11488
+ lines.push("- [ ] Use `glob` to find test files and note their location/naming pattern.");
11489
+ lines.push("- [ ] Use `glob` to find config files at root level.");
11490
+ lines.push("");
11491
+ lines.push("## PHASE 3: Convention Extraction");
11492
+ lines.push("");
11493
+ lines.push("- [ ] Use `grep` to find import patterns (e.g., `import .* from` or `require(`).");
11494
+ lines.push("- [ ] Use `grep` to find export patterns (e.g., `export ` or `module.exports`).");
11495
+ lines.push("- [ ] Check for any `.editorconfig`, `.gitignore`, or `CONTRIBUTING.md`.");
11496
+ if (profile.hasGit) {
11497
+ lines.push("- [ ] Run `git log --oneline -20` to understand commit style and recent activity.");
11498
+ lines.push("- [ ] Run `git branch -a | head -20` to understand branching strategy.");
11499
+ }
11500
+ lines.push("");
11501
+ lines.push("## PHASE 4: Build & Development Workflow");
11502
+ lines.push("");
11503
+ const bashCmds = bashDiscoveryCommands(profile);
11504
+ for (const cmd of bashCmds) {
11505
+ lines.push(`- [ ] Run \`bash\` with: \`${cmd}\``);
11506
+ }
11507
+ lines.push("");
11508
+ lines.push("## PHASE 5: Architecture & Patterns (Deep Dive)");
11509
+ lines.push("");
11510
+ lines.push("- [ ] Identify the main entry point(s) of the application.");
11511
+ lines.push("- [ ] Identify the testing framework and how tests are organized.");
11512
+ lines.push("- [ ] Look for any architectural patterns: MVC, hexagonal, actor model, etc.");
11513
+ lines.push("- [ ] Note any code-generation, build-time transforms, or code-mod tools.");
11514
+ lines.push("- [ ] Check for Docker, docker-compose, or deployment configs.");
11515
+ lines.push("- [ ] Note any monorepo patterns (workspaces, turborepo, nx, etc.).");
11516
+ return lines.join("\n");
11517
+ }
11518
+ function sectionTemplate() {
11519
+ return `
11520
+ Generate the context document with these sections. Be concise but comprehensive.
11521
+ Aim for 100\u2013200 lines total. Use markdown tables where they save space.
11522
+
11523
+ ### Required Sections
11524
+
11525
+ 1. **Project** \u2014 One-line description + primary language/runtime + key frameworks.
11526
+
11527
+ 2. **Build / test / run** \u2014 Exact shell commands. Include:
11528
+ - Development server / watch mode
11529
+ - Production build
11530
+ - Test commands (unit, integration, e2e if separate)
11531
+ - Lint / format commands
11532
+ - Type-checking commands
11533
+ - Any setup / install commands
11534
+ Note which commands are slow or require special setup.
11535
+
11536
+ 3. **Layout** \u2014 Table of key directories AND a one-sentence rationale for each.
11537
+ Explain *why* things live where they do, not just *what* is there.
11538
+
11539
+ 4. **Conventions** \u2014 Cover:
11540
+ - Naming conventions (files, variables, types, tests)
11541
+ - Import style and path resolution quirks
11542
+ - File organization patterns
11543
+ - Commit message style (if discernible from git history)
11544
+ - Branching strategy
11545
+ - TypeScript / type system strictness rules
11546
+ - Testing conventions (naming, location, mocks)
11547
+ - Anything surprising or non-obvious
11548
+
11549
+ 5. **Dependencies** \u2014 Rules for adding dependencies:
11550
+ - Package manager commands
11551
+ - Dev vs runtime dependency conventions
11552
+ - Native deps that must stay external (if bundling)
11553
+ - Version pinning policy
11554
+
11555
+ 6. **Do / Don't** \u2014 Numbered list of hard rules:
11556
+ - Security rules (never commit secrets, etc.)
11557
+ - Performance rules (don't bundle X, etc.)
11558
+ - Style rules that aren't caught by linters
11559
+ - Common mistakes to avoid
11560
+ - Anything that would make a maintainer sad
11561
+
11562
+ 7. **Debugging & Troubleshooting** \u2014 Common issues:
11563
+ - How to run in debug mode
11564
+ - Common build failures and fixes
11565
+ - How to reset / clean the project
11566
+ - Where logs live
11567
+
11568
+ 8. **Architecture Notes** (if applicable) \u2014 Brief notes on:
11569
+ - Key abstractions and their responsibilities
11570
+ - Data flow
11571
+ - External integrations
11572
+ - State management approach
11573
+ `.trim();
11574
+ }
11575
+ function buildInitPrompt(cwd) {
11576
+ const existingName = ["KIMI.md", "KIMIFLARE.md", "AGENT.md"].find(
11577
+ (n) => existsSync2(join20(cwd, n))
11578
+ );
11579
+ const isRefresh = existingName !== void 0;
11580
+ const targetFilename = existingName ?? "KIMI.md";
11581
+ const profile = analyzeProject(cwd);
11582
+ const checklist = discoveryChecklist(profile);
11583
+ const sections = sectionTemplate();
11584
+ const promptParts = [
11585
+ isRefresh ? `Regenerate \`${targetFilename}\` at the repository root to refresh project context. The file already exists \u2014 read it first and preserve anything still accurate, updating only what has changed or is missing.` : `Generate a \`${targetFilename}\` at the repository root so future agents have comprehensive project context.`,
11586
+ "",
11587
+ "This is a **structured investigation**. Follow the checklist below systematically. Use the `glob`, `read`, `grep`, and `bash` tools to gather information. Do not skip steps.",
11588
+ "",
11589
+ `**Detected project profile:** ${profile.primaryLanguage} (${profile.flavor})`,
11590
+ profile.packageFile ? `- Package file: ${profile.packageFile}` : null,
11591
+ profile.buildFile ? `- Build file: ${profile.buildFile}` : null,
11592
+ profile.testConfig ? `- Test config: ${profile.testConfig}` : null,
11593
+ profile.typeConfig ? `- Type config: ${profile.typeConfig}` : null,
11594
+ profile.lintConfig ? `- Lint config: ${profile.lintConfig}` : null,
11595
+ profile.ciConfig ? `- CI config: ${profile.ciConfig}` : null,
11596
+ profile.sourceRoots.length > 0 ? `- Source roots: ${profile.sourceRoots.join(", ")}` : null,
11597
+ profile.hasGit ? `- Git repository: yes` : null,
11598
+ "",
11599
+ "---",
11600
+ "",
11601
+ checklist,
11602
+ "",
11603
+ "---",
11604
+ "",
11605
+ sections,
11606
+ "",
11607
+ isRefresh ? `After writing the file, re-read \`${targetFilename}\` and verify it is complete and accurate.` : "After writing the file, re-read it and verify all sections are present and accurate.",
11608
+ "",
11609
+ "Do not call `tasks_set` for this. Just follow the checklist, gather information, then write the file."
11610
+ ];
11611
+ const prompt = promptParts.filter((p) => p !== null).join("\n");
11612
+ return { prompt, targetFilename, isRefresh };
11613
+ }
11614
+ var FLAVOR_SIGNATURES, SOURCE_ROOT_CANDIDATES, CI_PATHS;
11615
+ var init_context_generator = __esm({
11616
+ "src/init/context-generator.ts"() {
11617
+ "use strict";
11618
+ FLAVOR_SIGNATURES = {
11619
+ node: ["package.json", "package-lock.json", "yarn.lock", "pnpm-lock.yaml", "bun.lockb", "node_modules"],
11620
+ python: ["pyproject.toml", "setup.py", "setup.cfg", "requirements.txt", "Pipfile", "poetry.lock", "uv.lock", "tox.ini"],
11621
+ go: ["go.mod", "go.sum"],
11622
+ rust: ["Cargo.toml", "Cargo.lock"],
11623
+ ruby: ["Gemfile", "Gemfile.lock", "*.gemspec"],
11624
+ java: ["pom.xml", "build.gradle", "build.gradle.kts"],
11625
+ dotnet: ["*.csproj", "*.fsproj", "*.sln"],
11626
+ php: ["composer.json", "composer.lock"],
11627
+ elixir: ["mix.exs", "mix.lock"],
11628
+ haskell: ["package.yaml", "*.cabal", "stack.yaml"],
11629
+ c: ["Makefile", "CMakeLists.txt", "configure.ac"],
11630
+ cpp: ["Makefile", "CMakeLists.txt", "configure.ac"],
11631
+ zig: ["build.zig", "build.zig.zon"],
11632
+ generic: []
11633
+ };
11634
+ SOURCE_ROOT_CANDIDATES = [
11635
+ "src",
11636
+ "lib",
11637
+ "app",
11638
+ "source",
11639
+ "Sources",
11640
+ "pkg",
11641
+ "internal",
11642
+ "cmd",
11643
+ "bin",
11644
+ "packages",
11645
+ "projects"
11646
+ ];
11647
+ CI_PATHS = [
11648
+ ".github/workflows",
11649
+ ".gitlab-ci.yml",
11650
+ ".circleci",
11651
+ "azure-pipelines.yml",
11652
+ "Jenkinsfile",
11653
+ ".buildkite",
11654
+ "cloudbuild.yaml"
11655
+ ];
11656
+ }
11657
+ });
11658
+
10711
11659
  // src/ui/command-picker.tsx
10712
- import { Box as Box14, Text as Text15 } from "ink";
10713
- import SelectInput6 from "ink-select-input";
10714
- import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
11660
+ import { Box as Box15, Text as Text16 } from "ink";
11661
+ import SelectInput8 from "ink-select-input";
11662
+ import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
10715
11663
  function CommandPicker({ commands, title, onPick }) {
10716
11664
  const theme = useTheme();
10717
11665
  const items = commands.map((cmd) => ({
@@ -10720,11 +11668,11 @@ function CommandPicker({ commands, title, onPick }) {
10720
11668
  key: cmd.name
10721
11669
  }));
10722
11670
  items.push({ label: "\u2190 Cancel", value: null, key: "__cancel__" });
10723
- return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10724
- /* @__PURE__ */ jsx16(Text15, { color: theme.accent, bold: true, children: title }),
10725
- /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select." }),
10726
- /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
10727
- SelectInput6,
11671
+ return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11672
+ /* @__PURE__ */ jsx17(Text16, { color: theme.accent, bold: true, children: title }),
11673
+ /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select." }),
11674
+ /* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
11675
+ SelectInput8,
10728
11676
  {
10729
11677
  items,
10730
11678
  onSelect: (item) => {
@@ -10746,64 +11694,64 @@ var init_command_picker = __esm({
10746
11694
  });
10747
11695
 
10748
11696
  // src/ui/command-list.tsx
10749
- import { Box as Box15, Text as Text16, useInput as useInput5 } from "ink";
10750
- import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
11697
+ import { Box as Box16, Text as Text17, useInput as useInput6 } from "ink";
11698
+ import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
10751
11699
  function CommandList({ commands, onDone }) {
10752
11700
  const theme = useTheme();
10753
- useInput5((_input, key) => {
11701
+ useInput6((_input, key) => {
10754
11702
  if (key.escape) {
10755
11703
  onDone();
10756
11704
  }
10757
11705
  });
10758
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10759
- /* @__PURE__ */ jsx17(Text16, { color: theme.accent, bold: true, children: "Custom commands" }),
10760
- /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, dimColor: false, children: "Esc to close." }),
10761
- /* @__PURE__ */ jsxs15(Box15, { marginTop: 1, flexDirection: "column", children: [
10762
- commands.length === 0 && /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, children: "No custom commands found." }),
10763
- commands.map((cmd) => /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", marginBottom: 1, children: [
10764
- /* @__PURE__ */ jsxs15(Text16, { color: theme.accent, bold: true, children: [
11706
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11707
+ /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Custom commands" }),
11708
+ /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Esc to close." }),
11709
+ /* @__PURE__ */ jsxs16(Box16, { marginTop: 1, flexDirection: "column", children: [
11710
+ commands.length === 0 && /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, children: "No custom commands found." }),
11711
+ commands.map((cmd) => /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", marginBottom: 1, children: [
11712
+ /* @__PURE__ */ jsxs16(Text17, { color: theme.accent, bold: true, children: [
10765
11713
  "/",
10766
11714
  cmd.name
10767
11715
  ] }),
10768
- /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
11716
+ /* @__PURE__ */ jsxs16(Text17, { color: theme.info.color, children: [
10769
11717
  " ",
10770
11718
  "source: ",
10771
11719
  cmd.source
10772
11720
  ] }),
10773
- /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
11721
+ /* @__PURE__ */ jsxs16(Text17, { color: theme.info.color, children: [
10774
11722
  " ",
10775
11723
  "path: ",
10776
11724
  cmd.filepath
10777
11725
  ] }),
10778
- cmd.description && /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
11726
+ cmd.description && /* @__PURE__ */ jsxs16(Text17, { color: theme.info.color, children: [
10779
11727
  " ",
10780
11728
  "desc: ",
10781
11729
  cmd.description
10782
11730
  ] }),
10783
- cmd.mode && /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
11731
+ cmd.mode && /* @__PURE__ */ jsxs16(Text17, { color: theme.info.color, children: [
10784
11732
  " ",
10785
11733
  "mode: ",
10786
11734
  cmd.mode
10787
11735
  ] }),
10788
- cmd.effort && /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
11736
+ cmd.effort && /* @__PURE__ */ jsxs16(Text17, { color: theme.info.color, children: [
10789
11737
  " ",
10790
11738
  "effort: ",
10791
11739
  cmd.effort
10792
11740
  ] }),
10793
- cmd.model && /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
11741
+ cmd.model && /* @__PURE__ */ jsxs16(Text17, { color: theme.info.color, children: [
10794
11742
  " ",
10795
11743
  "model: ",
10796
11744
  cmd.model
10797
11745
  ] }),
10798
- /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
11746
+ /* @__PURE__ */ jsxs16(Text17, { color: theme.info.color, children: [
10799
11747
  " ",
10800
11748
  "template:"
10801
11749
  ] }),
10802
- cmd.template.split("\n").slice(0, 5).map((line, i) => /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
11750
+ cmd.template.split("\n").slice(0, 5).map((line, i) => /* @__PURE__ */ jsxs16(Text17, { color: theme.info.color, children: [
10803
11751
  " ",
10804
11752
  line || " "
10805
11753
  ] }, i)),
10806
- cmd.template.split("\n").length > 5 && /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
11754
+ cmd.template.split("\n").length > 5 && /* @__PURE__ */ jsxs16(Text17, { color: theme.info.color, children: [
10807
11755
  " ",
10808
11756
  "..."
10809
11757
  ] })
@@ -10820,10 +11768,10 @@ var init_command_list = __esm({
10820
11768
 
10821
11769
  // src/ui/lsp-wizard.tsx
10822
11770
  import { useState as useState9 } from "react";
10823
- import { Box as Box16, Text as Text17 } from "ink";
10824
- import SelectInput7 from "ink-select-input";
11771
+ import { Box as Box17, Text as Text18 } from "ink";
11772
+ import SelectInput9 from "ink-select-input";
10825
11773
  import { spawn as spawn3 } from "child_process";
10826
- import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
11774
+ import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
10827
11775
  function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
10828
11776
  const theme = useTheme();
10829
11777
  const [page, setPage] = useState9("main");
@@ -10934,11 +11882,11 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
10934
11882
  { label: "(close)", value: "__close__", key: "__close__" }
10935
11883
  ];
10936
11884
  if (page === "main") {
10937
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10938
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "LSP Servers" }),
10939
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select." }),
10940
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
10941
- SelectInput7,
11885
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11886
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: "LSP Servers" }),
11887
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select." }),
11888
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
11889
+ SelectInput9,
10942
11890
  {
10943
11891
  items: mainItems,
10944
11892
  onSelect: (item) => {
@@ -10965,11 +11913,11 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
10965
11913
  }),
10966
11914
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
10967
11915
  ];
10968
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10969
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Add LSP Server" }),
10970
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Select a language server to configure." }),
10971
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
10972
- SelectInput7,
11916
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11917
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: "Add LSP Server" }),
11918
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, dimColor: false, children: "Select a language server to configure." }),
11919
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
11920
+ SelectInput9,
10973
11921
  {
10974
11922
  items,
10975
11923
  onSelect: (item) => {
@@ -10996,19 +11944,19 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
10996
11944
  { label: isSuccess ? "Save to config \u2713" : "Save anyway", value: "save", key: "save" },
10997
11945
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
10998
11946
  ];
10999
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11000
- /* @__PURE__ */ jsxs16(Text17, { color: theme.accent, bold: true, children: [
11947
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11948
+ /* @__PURE__ */ jsxs17(Text18, { color: theme.accent, bold: true, children: [
11001
11949
  "Install ",
11002
11950
  selectedPreset.name
11003
11951
  ] }),
11004
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: selectedPreset.installHint }),
11005
- /* @__PURE__ */ jsxs16(Box16, { marginTop: 1, flexDirection: "column", children: [
11006
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Command:" }),
11007
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, children: selectedPreset.installCommand || "(none required)" })
11952
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, dimColor: false, children: selectedPreset.installHint }),
11953
+ /* @__PURE__ */ jsxs17(Box17, { marginTop: 1, flexDirection: "column", children: [
11954
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, dimColor: false, children: "Command:" }),
11955
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, children: selectedPreset.installCommand || "(none required)" })
11008
11956
  ] }),
11009
- installState.output && /* @__PURE__ */ jsx18(Box16, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx18(Text17, { color: isSuccess ? theme.accent : theme.error, children: installState.output.slice(-500) }) }),
11010
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
11011
- SelectInput7,
11957
+ installState.output && /* @__PURE__ */ jsx19(Box17, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx19(Text18, { color: isSuccess ? theme.accent : theme.error, children: installState.output.slice(-500) }) }),
11958
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
11959
+ SelectInput9,
11012
11960
  {
11013
11961
  items,
11014
11962
  onSelect: (item) => {
@@ -11025,16 +11973,16 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
11025
11973
  }
11026
11974
  }
11027
11975
  ) }),
11028
- isSuccess && /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(Text17, { color: theme.accent, children: "Server saved. Run /lsp reload to start it." }) })
11976
+ isSuccess && /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(Text18, { color: theme.accent, children: "Server saved. Run /lsp reload to start it." }) })
11029
11977
  ] });
11030
11978
  }
11031
11979
  if (page === "custom-name") {
11032
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11033
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Custom LSP Server \u2014 Name" }),
11034
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Enter a name for this server (e.g., my-server)." }),
11035
- /* @__PURE__ */ jsxs16(Box16, { marginTop: 1, children: [
11036
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, children: "\u203A " }),
11037
- /* @__PURE__ */ jsx18(
11980
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11981
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: "Custom LSP Server \u2014 Name" }),
11982
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, dimColor: false, children: "Enter a name for this server (e.g., my-server)." }),
11983
+ /* @__PURE__ */ jsxs17(Box17, { marginTop: 1, children: [
11984
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, children: "\u203A " }),
11985
+ /* @__PURE__ */ jsx19(
11038
11986
  CustomTextInput,
11039
11987
  {
11040
11988
  value: customName,
@@ -11048,8 +11996,8 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
11048
11996
  }
11049
11997
  )
11050
11998
  ] }),
11051
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
11052
- SelectInput7,
11999
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
12000
+ SelectInput9,
11053
12001
  {
11054
12002
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
11055
12003
  onSelect: () => setPage("add")
@@ -11058,12 +12006,12 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
11058
12006
  ] });
11059
12007
  }
11060
12008
  if (page === "custom-command") {
11061
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11062
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Custom LSP Server \u2014 Command" }),
11063
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Enter the command to start the server (space-separated)." }),
11064
- /* @__PURE__ */ jsxs16(Box16, { marginTop: 1, children: [
11065
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, children: "\u203A " }),
11066
- /* @__PURE__ */ jsx18(
12009
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
12010
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: "Custom LSP Server \u2014 Command" }),
12011
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, dimColor: false, children: "Enter the command to start the server (space-separated)." }),
12012
+ /* @__PURE__ */ jsxs17(Box17, { marginTop: 1, children: [
12013
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, children: "\u203A " }),
12014
+ /* @__PURE__ */ jsx19(
11067
12015
  CustomTextInput,
11068
12016
  {
11069
12017
  value: customCommand,
@@ -11077,8 +12025,8 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
11077
12025
  }
11078
12026
  )
11079
12027
  ] }),
11080
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
11081
- SelectInput7,
12028
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
12029
+ SelectInput9,
11082
12030
  {
11083
12031
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
11084
12032
  onSelect: () => setPage("custom-name")
@@ -11101,11 +12049,11 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
11101
12049
  },
11102
12050
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
11103
12051
  ];
11104
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11105
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Save LSP Config" }),
11106
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Where should this server configuration be saved?" }),
11107
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
11108
- SelectInput7,
12052
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
12053
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: "Save LSP Config" }),
12054
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, dimColor: false, children: "Where should this server configuration be saved?" }),
12055
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
12056
+ SelectInput9,
11109
12057
  {
11110
12058
  items,
11111
12059
  onSelect: (item) => {
@@ -11123,11 +12071,11 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
11123
12071
  if (page === "edit") {
11124
12072
  const keys = Object.keys(servers);
11125
12073
  if (keys.length === 0) {
11126
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11127
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Edit LSP Server" }),
11128
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, children: "No servers configured." }),
11129
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
11130
- SelectInput7,
12074
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
12075
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: "Edit LSP Server" }),
12076
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, children: "No servers configured." }),
12077
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
12078
+ SelectInput9,
11131
12079
  {
11132
12080
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
11133
12081
  onSelect: () => setPage("main")
@@ -11147,11 +12095,11 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
11147
12095
  }),
11148
12096
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
11149
12097
  ];
11150
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11151
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Edit LSP Server" }),
11152
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Select a server to toggle enabled/disabled." }),
11153
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
11154
- SelectInput7,
12098
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
12099
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: "Edit LSP Server" }),
12100
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, dimColor: false, children: "Select a server to toggle enabled/disabled." }),
12101
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
12102
+ SelectInput9,
11155
12103
  {
11156
12104
  items,
11157
12105
  onSelect: (item) => {
@@ -11168,11 +12116,11 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
11168
12116
  if (page === "delete") {
11169
12117
  const keys = Object.keys(servers);
11170
12118
  if (keys.length === 0) {
11171
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11172
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Delete LSP Server" }),
11173
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, children: "No servers configured." }),
11174
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
11175
- SelectInput7,
12119
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
12120
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: "Delete LSP Server" }),
12121
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, children: "No servers configured." }),
12122
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
12123
+ SelectInput9,
11176
12124
  {
11177
12125
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
11178
12126
  onSelect: () => setPage("main")
@@ -11188,11 +12136,11 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
11188
12136
  })),
11189
12137
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
11190
12138
  ];
11191
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11192
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Delete LSP Server" }),
11193
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Select a server to remove from config." }),
11194
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
11195
- SelectInput7,
12139
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
12140
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: "Delete LSP Server" }),
12141
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, dimColor: false, children: "Select a server to remove from config." }),
12142
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
12143
+ SelectInput9,
11196
12144
  {
11197
12145
  items,
11198
12146
  onSelect: (item) => {
@@ -11208,15 +12156,15 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
11208
12156
  }
11209
12157
  if (page === "list") {
11210
12158
  const keys = Object.keys(servers);
11211
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11212
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Configured LSP Servers" }),
11213
- keys.length === 0 ? /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, children: "No servers configured." }) : /* @__PURE__ */ jsx18(Box16, { marginTop: 1, flexDirection: "column", children: keys.map((k) => {
12159
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
12160
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: "Configured LSP Servers" }),
12161
+ keys.length === 0 ? /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, children: "No servers configured." }) : /* @__PURE__ */ jsx19(Box17, { marginTop: 1, flexDirection: "column", children: keys.map((k) => {
11214
12162
  const s = servers[k];
11215
12163
  const status = s.enabled !== false ? "enabled" : "disabled";
11216
- return /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, children: ` ${k.padEnd(16)} ${status} ${s.command.join(" ")}` }, k);
12164
+ return /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, children: ` ${k.padEnd(16)} ${status} ${s.command.join(" ")}` }, k);
11217
12165
  }) }),
11218
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
11219
- SelectInput7,
12166
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
12167
+ SelectInput9,
11220
12168
  {
11221
12169
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
11222
12170
  onSelect: () => setPage("main")
@@ -11342,9 +12290,9 @@ var init_lsp_wizard = __esm({
11342
12290
  });
11343
12291
 
11344
12292
  // src/ui/theme-picker.tsx
11345
- import { Box as Box17, Text as Text18 } from "ink";
11346
- import SelectInput8 from "ink-select-input";
11347
- import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
12293
+ import { Box as Box18, Text as Text19 } from "ink";
12294
+ import SelectInput10 from "ink-select-input";
12295
+ import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
11348
12296
  function PaletteSwatches({ palette }) {
11349
12297
  const colors = [
11350
12298
  palette.primary,
@@ -11352,7 +12300,7 @@ function PaletteSwatches({ palette }) {
11352
12300
  palette.success,
11353
12301
  palette.error
11354
12302
  ];
11355
- return /* @__PURE__ */ jsx19(Box17, { children: colors.map((c, i) => /* @__PURE__ */ jsx19(Text18, { color: c, children: "\u2588" }, i)) });
12303
+ return /* @__PURE__ */ jsx20(Box18, { children: colors.map((c, i) => /* @__PURE__ */ jsx20(Text19, { color: c, children: "\u2588" }, i)) });
11356
12304
  }
11357
12305
  function ThemePicker({ themes, onPick, onPreview }) {
11358
12306
  const current = useTheme();
@@ -11360,10 +12308,10 @@ function ThemePicker({ themes, onPick, onPreview }) {
11360
12308
  ...themes.map((t) => ({ label: t.label, value: t.name })),
11361
12309
  { label: "< Back", value: "__back__" }
11362
12310
  ];
11363
- return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: current.accent, paddingX: 1, children: [
11364
- /* @__PURE__ */ jsx19(Text18, { color: current.accent, bold: true, children: "Pick a theme" }),
11365
- /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
11366
- SelectInput8,
12311
+ return /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", borderStyle: "round", borderColor: current.accent, paddingX: 1, children: [
12312
+ /* @__PURE__ */ jsx20(Text19, { color: current.accent, bold: true, children: "Pick a theme" }),
12313
+ /* @__PURE__ */ jsx20(Box18, { marginTop: 1, children: /* @__PURE__ */ jsx20(
12314
+ SelectInput10,
11367
12315
  {
11368
12316
  items,
11369
12317
  onHighlight: (item) => {
@@ -11382,9 +12330,9 @@ function ThemePicker({ themes, onPick, onPreview }) {
11382
12330
  itemComponent: ({ label, isSelected }) => {
11383
12331
  const t = themes.find((x) => x.label === label);
11384
12332
  const color = t?.accent ?? current.accent;
11385
- return /* @__PURE__ */ jsxs17(Box17, { children: [
11386
- /* @__PURE__ */ jsx19(Text18, { color, bold: isSelected, dimColor: !isSelected, children: label }),
11387
- t && /* @__PURE__ */ jsx19(Box17, { marginLeft: 1, children: /* @__PURE__ */ jsx19(PaletteSwatches, { palette: t.palette }) })
12333
+ return /* @__PURE__ */ jsxs18(Box18, { children: [
12334
+ /* @__PURE__ */ jsx20(Text19, { color, bold: isSelected, dimColor: !isSelected, children: label }),
12335
+ t && /* @__PURE__ */ jsx20(Box18, { marginLeft: 1, children: /* @__PURE__ */ jsx20(PaletteSwatches, { palette: t.palette }) })
11388
12336
  ] });
11389
12337
  }
11390
12338
  }
@@ -11528,8 +12476,8 @@ var init_lsp_nudge = __esm({
11528
12476
  });
11529
12477
 
11530
12478
  // src/ui/file-picker.tsx
11531
- import { Box as Box18, Text as Text19 } from "ink";
11532
- import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
12479
+ import { Box as Box19, Text as Text20 } from "ink";
12480
+ import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
11533
12481
  function FilePicker({ items, selectedIndex, query }) {
11534
12482
  const theme = useTheme();
11535
12483
  let startIndex = 0;
@@ -11539,12 +12487,12 @@ function FilePicker({ items, selectedIndex, query }) {
11539
12487
  const visible = items.slice(startIndex, startIndex + VISIBLE_LIMIT);
11540
12488
  const hasMoreAbove = startIndex > 0;
11541
12489
  const hasMoreBelow = items.length > startIndex + VISIBLE_LIMIT;
11542
- return /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11543
- /* @__PURE__ */ jsx20(Text19, { color: theme.accent, bold: true, children: query ? `Files matching "${query}"` : "Mention a file" }),
11544
- /* @__PURE__ */ jsx20(Text19, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select, Esc to cancel." }),
11545
- /* @__PURE__ */ jsxs18(Box18, { marginTop: 1, flexDirection: "column", children: [
11546
- visible.length === 0 && /* @__PURE__ */ jsx20(Text19, { color: theme.info.color, children: "No matches" }),
11547
- hasMoreAbove && /* @__PURE__ */ jsxs18(Text19, { color: theme.info.color, children: [
12490
+ return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
12491
+ /* @__PURE__ */ jsx21(Text20, { color: theme.accent, bold: true, children: query ? `Files matching "${query}"` : "Mention a file" }),
12492
+ /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select, Esc to cancel." }),
12493
+ /* @__PURE__ */ jsxs19(Box19, { marginTop: 1, flexDirection: "column", children: [
12494
+ visible.length === 0 && /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, children: "No matches" }),
12495
+ hasMoreAbove && /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
11548
12496
  "\u2026 ",
11549
12497
  startIndex,
11550
12498
  " more above"
@@ -11553,12 +12501,12 @@ function FilePicker({ items, selectedIndex, query }) {
11553
12501
  const actualIndex = startIndex + i;
11554
12502
  const isSelected = actualIndex === selectedIndex;
11555
12503
  const label = item.isDirectory ? `${item.name}/` : item.name;
11556
- return /* @__PURE__ */ jsxs18(Text19, { color: isSelected ? theme.accent : void 0, bold: isSelected, children: [
12504
+ return /* @__PURE__ */ jsxs19(Text20, { color: isSelected ? theme.accent : void 0, bold: isSelected, children: [
11557
12505
  isSelected ? "\u203A " : " ",
11558
12506
  label
11559
12507
  ] }, item.name);
11560
12508
  }),
11561
- hasMoreBelow && /* @__PURE__ */ jsxs18(Text19, { color: theme.info.color, children: [
12509
+ hasMoreBelow && /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
11562
12510
  "\u2026 ",
11563
12511
  items.length - (startIndex + VISIBLE_LIMIT),
11564
12512
  " more below"
@@ -11576,8 +12524,8 @@ var init_file_picker = __esm({
11576
12524
  });
11577
12525
 
11578
12526
  // src/ui/slash-picker.tsx
11579
- import { Box as Box19, Text as Text20 } from "ink";
11580
- import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
12527
+ import { Box as Box20, Text as Text21 } from "ink";
12528
+ import { jsx as jsx22, jsxs as jsxs20 } from "react/jsx-runtime";
11581
12529
  function sourceBadge(source) {
11582
12530
  if (source === "builtin") return "";
11583
12531
  if (source === "project") return "project";
@@ -11597,12 +12545,12 @@ function SlashPicker({ items, selectedIndex, query }) {
11597
12545
  const hasMoreBelow = items.length > startIndex + VISIBLE_LIMIT2;
11598
12546
  const longestLabel = visible.reduce((m, it) => Math.max(m, commandLabel(it).length), 0);
11599
12547
  const nameColWidth = Math.max(NAME_COL_MIN_WIDTH, longestLabel + NAME_DESC_GAP);
11600
- return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11601
- /* @__PURE__ */ jsx21(Text20, { color: theme.accent, bold: true, children: query ? `Commands matching "/${query}"` : "Slash commands" }),
11602
- /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, children: "Arrow keys to navigate, Enter to select, Esc to cancel." }),
11603
- /* @__PURE__ */ jsxs19(Box19, { marginTop: 1, flexDirection: "column", children: [
11604
- visible.length === 0 && /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, children: "No matches" }),
11605
- hasMoreAbove && /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
12548
+ return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
12549
+ /* @__PURE__ */ jsx22(Text21, { color: theme.accent, bold: true, children: query ? `Commands matching "/${query}"` : "Slash commands" }),
12550
+ /* @__PURE__ */ jsx22(Text21, { color: theme.info.color, children: "Arrow keys to navigate, Enter to select, Esc to cancel." }),
12551
+ /* @__PURE__ */ jsxs20(Box20, { marginTop: 1, flexDirection: "column", children: [
12552
+ visible.length === 0 && /* @__PURE__ */ jsx22(Text21, { color: theme.info.color, children: "No matches" }),
12553
+ hasMoreAbove && /* @__PURE__ */ jsxs20(Text21, { color: theme.info.color, children: [
11606
12554
  "\u2026 ",
11607
12555
  startIndex,
11608
12556
  " more above"
@@ -11612,16 +12560,16 @@ function SlashPicker({ items, selectedIndex, query }) {
11612
12560
  const isSelected = actualIndex === selectedIndex;
11613
12561
  const nameCol = commandLabel(item).padEnd(nameColWidth);
11614
12562
  const badge = sourceBadge(item.source);
11615
- return /* @__PURE__ */ jsxs19(Text20, { color: isSelected ? theme.accent : void 0, bold: isSelected, children: [
12563
+ return /* @__PURE__ */ jsxs20(Text21, { color: isSelected ? theme.accent : void 0, bold: isSelected, children: [
11616
12564
  isSelected ? "\u203A " : " ",
11617
12565
  nameCol,
11618
- /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
12566
+ /* @__PURE__ */ jsxs20(Text21, { color: theme.info.color, children: [
11619
12567
  item.description,
11620
12568
  badge && ` [${badge}]`
11621
12569
  ] })
11622
12570
  ] }, item.name);
11623
12571
  }),
11624
- hasMoreBelow && /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
12572
+ hasMoreBelow && /* @__PURE__ */ jsxs20(Text21, { color: theme.info.color, children: [
11625
12573
  "\u2026 ",
11626
12574
  items.length - (startIndex + VISIBLE_LIMIT2),
11627
12575
  " more below"
@@ -11701,15 +12649,15 @@ var tui_report_exports = {};
11701
12649
  __export(tui_report_exports, {
11702
12650
  getCategoryReportText: () => getCategoryReportText
11703
12651
  });
11704
- import { readFile as readFile15 } from "fs/promises";
11705
- import { join as join18 } from "path";
11706
- import { homedir as homedir13 } from "os";
12652
+ import { readFile as readFile16 } from "fs/promises";
12653
+ import { join as join21 } from "path";
12654
+ import { homedir as homedir14 } from "os";
11707
12655
  function usageDir3() {
11708
- const xdg = process.env.XDG_DATA_HOME || join18(homedir13(), ".local", "share");
11709
- return join18(xdg, "kimiflare");
12656
+ const xdg = process.env.XDG_DATA_HOME || join21(homedir14(), ".local", "share");
12657
+ return join21(xdg, "kimiflare");
11710
12658
  }
11711
12659
  function usagePath3() {
11712
- return join18(usageDir3(), "usage.json");
12660
+ return join21(usageDir3(), "usage.json");
11713
12661
  }
11714
12662
  function today3() {
11715
12663
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
@@ -11721,7 +12669,7 @@ function daysAgo2(n) {
11721
12669
  }
11722
12670
  async function loadLog3() {
11723
12671
  try {
11724
- const raw = await readFile15(usagePath3(), "utf8");
12672
+ const raw = await readFile16(usagePath3(), "utf8");
11725
12673
  return JSON.parse(raw);
11726
12674
  } catch {
11727
12675
  return { version: 1, days: [], sessions: [] };
@@ -11787,18 +12735,18 @@ __export(app_exports, {
11787
12735
  shouldOpenMentionPicker: () => shouldOpenMentionPicker,
11788
12736
  shouldOpenSlashPicker: () => shouldOpenSlashPicker
11789
12737
  });
11790
- import React14, { useState as useState10, useRef as useRef3, useEffect as useEffect5, useCallback } from "react";
11791
- import { Box as Box20, Text as Text21, useApp, useInput as useInput6, render } from "ink";
11792
- import SelectInput9 from "ink-select-input";
11793
- import { existsSync as existsSync2, statSync as statSync3 } from "fs";
11794
- import { join as join19 } from "path";
12738
+ import React14, { useState as useState10, useRef as useRef3, useEffect as useEffect6, useCallback as useCallback2 } from "react";
12739
+ import { Box as Box21, Text as Text22, useApp, useInput as useInput7, render } from "ink";
12740
+ import SelectInput11 from "ink-select-input";
12741
+ import { existsSync as existsSync3, statSync as statSync4 } from "fs";
12742
+ import { join as join22 } from "path";
11795
12743
  import { unlink as unlink3 } from "fs/promises";
11796
12744
  import { execSync as execSync2 } from "child_process";
11797
12745
  import { spawn as spawn4 } from "child_process";
11798
12746
  import { platform as platform2 } from "os";
11799
12747
  import fg4 from "fast-glob";
11800
12748
  import { readFileSync as readFileSync3 } from "fs";
11801
- import { jsx as jsx22, jsxs as jsxs20 } from "react/jsx-runtime";
12749
+ import { jsx as jsx23, jsxs as jsxs21 } from "react/jsx-runtime";
11802
12750
  function buildFilePickerIgnoreList(cwd) {
11803
12751
  const hardcoded = [
11804
12752
  // Dependencies
@@ -11869,8 +12817,8 @@ function buildFilePickerIgnoreList(cwd) {
11869
12817
  ];
11870
12818
  const gitignorePatterns = [];
11871
12819
  try {
11872
- const gitignorePath = join19(cwd, ".gitignore");
11873
- const stats = statSync3(gitignorePath);
12820
+ const gitignorePath = join22(cwd, ".gitignore");
12821
+ const stats = statSync4(gitignorePath);
11874
12822
  if (stats.size > MAX_GITIGNORE_SIZE) {
11875
12823
  return hardcoded;
11876
12824
  }
@@ -11938,7 +12886,7 @@ function gatewayUsageLookupFromConfig(cfg, meta) {
11938
12886
  meta
11939
12887
  };
11940
12888
  }
11941
- function openBrowser(url) {
12889
+ function openBrowser2(url) {
11942
12890
  const cmd = platform2() === "darwin" ? "open" : platform2() === "win32" ? "start" : "xdg-open";
11943
12891
  const child = spawn4(cmd, [url], { detached: true, stdio: "ignore" });
11944
12892
  child.unref();
@@ -11958,7 +12906,7 @@ function detectGitHubRepo(cachedRepo) {
11958
12906
  }
11959
12907
  return null;
11960
12908
  }
11961
- function formatTokens3(n) {
12909
+ function formatTokens4(n) {
11962
12910
  if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
11963
12911
  if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
11964
12912
  return String(n);
@@ -12003,7 +12951,7 @@ function findImagePaths(text) {
12003
12951
  let match;
12004
12952
  while ((match = quotedRegex.exec(text)) !== null) {
12005
12953
  const path = match[1] ?? match[2];
12006
- if (path && isImagePath(path) && existsSync2(path)) {
12954
+ if (path && isImagePath(path) && existsSync3(path)) {
12007
12955
  paths.push(path);
12008
12956
  }
12009
12957
  }
@@ -12012,7 +12960,7 @@ function findImagePaths(text) {
12012
12960
  const processed = remaining.replace(/\\ /g, ESCAPED_SPACE);
12013
12961
  for (const token of processed.split(/\s+/)) {
12014
12962
  const clean = token.replace(new RegExp(ESCAPED_SPACE, "g"), " ").replace(/^["']|["',;:!?]$/g, "").replace(/[.,;:!?]$/, "");
12015
- if (clean && isImagePath(clean) && existsSync2(clean) && !paths.includes(clean)) {
12963
+ if (clean && isImagePath(clean) && existsSync3(clean) && !paths.includes(clean)) {
12016
12964
  paths.push(clean);
12017
12965
  }
12018
12966
  }
@@ -12022,14 +12970,15 @@ function App({
12022
12970
  initialCfg,
12023
12971
  initialUpdateResult,
12024
12972
  initialLspScope,
12025
- initialLspProjectPath
12973
+ initialLspProjectPath,
12974
+ initialCloudToken
12026
12975
  }) {
12027
12976
  const { exit } = useApp();
12028
12977
  const [cfg, setCfg] = useState10(initialCfg);
12029
12978
  const [lspScope, setLspScope] = useState10(initialLspScope);
12030
12979
  const [lspProjectPath, setLspProjectPath] = useState10(initialLspProjectPath);
12031
12980
  const [events, setRawEvents] = useState10([]);
12032
- const setEvents = useCallback(
12981
+ const setEvents = useCallback2(
12033
12982
  (updater) => {
12034
12983
  setRawEvents((prev) => {
12035
12984
  const next = typeof updater === "function" ? updater(prev) : updater;
@@ -12043,8 +12992,10 @@ function App({
12043
12992
  const [usage, setUsage] = useState10(null);
12044
12993
  const [sessionUsage, setSessionUsage] = useState10(null);
12045
12994
  const [gatewayMeta, setGatewayMeta] = useState10(null);
12995
+ const [cloudBudget, setCloudBudget] = useState10(null);
12046
12996
  const [showReasoning, setShowReasoning] = useState10(false);
12047
12997
  const [perm, setPerm] = useState10(null);
12998
+ const [limitModal, setLimitModal] = useState10(null);
12048
12999
  const [queue, setQueue] = useState10([]);
12049
13000
  const [history, setHistory] = useState10([]);
12050
13001
  const [historyIndex, setHistoryIndex] = useState10(-1);
@@ -12074,6 +13025,21 @@ function App({
12074
13025
  const [theme, setTheme] = useState10(resolveTheme(initialCfg?.theme));
12075
13026
  const [showThemePicker, setShowThemePicker] = useState10(false);
12076
13027
  const [originalTheme, setOriginalTheme] = useState10(null);
13028
+ useEffect6(() => {
13029
+ if (!cfg?.cloudMode || !initialCloudToken) return;
13030
+ let cancelled = false;
13031
+ const fetchBudget = async () => {
13032
+ const { fetchCloudUsage: fetchCloudUsage2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
13033
+ const usage2 = await fetchCloudUsage2(initialCloudToken);
13034
+ if (usage2 && !cancelled) {
13035
+ setCloudBudget({ remaining: usage2.remaining, limit: usage2.input_token_limit });
13036
+ }
13037
+ };
13038
+ fetchBudget();
13039
+ return () => {
13040
+ cancelled = true;
13041
+ };
13042
+ }, [cfg?.cloudMode, initialCloudToken]);
12077
13043
  const [cursorOffset, setCursorOffset] = useState10(0);
12078
13044
  const [activePicker, setActivePicker] = useState10(null);
12079
13045
  const [filePickerItems, setFilePickerItems] = useState10([]);
@@ -12087,6 +13053,7 @@ function App({
12087
13053
  const activeAsstIdRef = useRef3(null);
12088
13054
  const activeControllerRef = useRef3(null);
12089
13055
  const permResolveRef = useRef3(null);
13056
+ const limitResolveRef = useRef3(null);
12090
13057
  const pendingToolCallsRef = useRef3(/* @__PURE__ */ new Map());
12091
13058
  const sessionIdRef = useRef3(null);
12092
13059
  const modeRef = useRef3(mode);
@@ -12108,12 +13075,16 @@ function App({
12108
13075
  const lspManagerRef = useRef3(new LspManager());
12109
13076
  const lspToolsRef = useRef3([]);
12110
13077
  const lspInitRef = useRef3(false);
13078
+ const busyRef = useRef3(busy);
12111
13079
  const memoryManagerRef = useRef3(null);
12112
13080
  const sessionStartRecallRef = useRef3(null);
12113
13081
  const pendingTextRef = useRef3(/* @__PURE__ */ new Map());
12114
13082
  const flushTimeoutRef = useRef3(null);
12115
13083
  const customCommandsRef = useRef3([]);
12116
13084
  const pickerCancelRef = useRef3(null);
13085
+ useEffect6(() => {
13086
+ busyRef.current = busy;
13087
+ }, [busy]);
12117
13088
  const pickerAnchor = activePicker?.anchor ?? null;
12118
13089
  const pickerKind = activePicker?.kind ?? null;
12119
13090
  const pickerQuery = React14.useMemo(() => {
@@ -12136,7 +13107,7 @@ function App({
12136
13107
  if (pickerKind !== "slash" || pickerQuery === null) return [];
12137
13108
  return fuzzyFilter(allSlashCommands, pickerQuery, (c) => c.name).slice(0, 50);
12138
13109
  }, [pickerKind, allSlashCommands, pickerQuery]);
12139
- useEffect5(() => {
13110
+ useEffect6(() => {
12140
13111
  if (activePicker !== null) {
12141
13112
  const trigger = activePicker.kind === "file" ? "@" : "/";
12142
13113
  if (cursorOffset < activePicker.anchor) {
@@ -12193,28 +13164,28 @@ function App({
12193
13164
  return;
12194
13165
  }
12195
13166
  }, [input, cursorOffset, activePicker, filePickerEnabled]);
12196
- useEffect5(() => {
13167
+ useEffect6(() => {
12197
13168
  if (activePicker?.kind !== "file") return;
12198
13169
  const max = Math.max(0, filteredFileItems.length - 1);
12199
13170
  if (activePicker.selected > max) {
12200
13171
  setActivePicker({ ...activePicker, selected: max });
12201
13172
  }
12202
13173
  }, [filteredFileItems.length, activePicker]);
12203
- useEffect5(() => {
13174
+ useEffect6(() => {
12204
13175
  if (activePicker?.kind !== "slash") return;
12205
13176
  const max = Math.max(0, filteredSlashItems.length - 1);
12206
13177
  if (activePicker.selected > max) {
12207
13178
  setActivePicker({ ...activePicker, selected: max });
12208
13179
  }
12209
13180
  }, [filteredSlashItems.length, activePicker]);
12210
- const handlePickerUp = useCallback(() => {
13181
+ const handlePickerUp = useCallback2(() => {
12211
13182
  setActivePicker((p) => {
12212
13183
  if (!p) return null;
12213
13184
  const next = Math.max(0, p.selected - 1);
12214
13185
  return next === p.selected ? p : { ...p, selected: next };
12215
13186
  });
12216
13187
  }, []);
12217
- const handlePickerDown = useCallback(() => {
13188
+ const handlePickerDown = useCallback2(() => {
12218
13189
  setActivePicker((p) => {
12219
13190
  if (!p) return null;
12220
13191
  const max = p.kind === "file" ? Math.max(0, filteredFileItems.length - 1) : Math.max(0, filteredSlashItems.length - 1);
@@ -12222,7 +13193,7 @@ function App({
12222
13193
  return next === p.selected ? p : { ...p, selected: next };
12223
13194
  });
12224
13195
  }, [filteredFileItems.length, filteredSlashItems.length]);
12225
- const handlePickerSelect = useCallback(() => {
13196
+ const handlePickerSelect = useCallback2(() => {
12226
13197
  if (!activePicker) return;
12227
13198
  if (activePicker.kind === "file") {
12228
13199
  const item2 = filteredFileItems[activePicker.selected];
@@ -12240,12 +13211,12 @@ function App({
12240
13211
  setActivePicker(null);
12241
13212
  submitRef.current(value);
12242
13213
  }, [activePicker, filteredFileItems, filteredSlashItems, input, cursorOffset]);
12243
- const handlePickerCancel = useCallback(() => {
13214
+ const handlePickerCancel = useCallback2(() => {
12244
13215
  pickerCancelRef.current = cursorOffset;
12245
13216
  setActivePicker(null);
12246
13217
  }, [cursorOffset]);
12247
- useEffect5(() => {
12248
- const modalActive = showHelpMenu || commandWizard !== null || commandPicker !== null || commandToDelete !== null || showCommandList || showLspWizard || resumeSessions !== null || perm !== null;
13218
+ useEffect6(() => {
13219
+ const modalActive = showHelpMenu || commandWizard !== null || commandPicker !== null || commandToDelete !== null || showCommandList || showLspWizard || resumeSessions !== null || perm !== null || limitModal !== null;
12249
13220
  if (modalActive && activePicker !== null) {
12250
13221
  setActivePicker(null);
12251
13222
  }
@@ -12258,9 +13229,10 @@ function App({
12258
13229
  showLspWizard,
12259
13230
  resumeSessions,
12260
13231
  perm,
13232
+ limitModal,
12261
13233
  activePicker
12262
13234
  ]);
12263
- useEffect5(() => {
13235
+ useEffect6(() => {
12264
13236
  if (!cfg) return;
12265
13237
  void Promise.resolve().then(() => (init_sessions(), sessions_exports)).then(
12266
13238
  ({ pruneSessions: pruneSessions2 }) => pruneSessions2().then((removed) => {
@@ -12286,7 +13258,7 @@ function App({
12286
13258
  }
12287
13259
  });
12288
13260
  if (cfg.memoryEnabled) {
12289
- const dbPath = cfg.memoryDbPath ?? join19(process.cwd(), ".kimiflare", "memory.db");
13261
+ const dbPath = cfg.memoryDbPath ?? join22(process.cwd(), ".kimiflare", "memory.db");
12290
13262
  const manager = new MemoryManager({
12291
13263
  dbPath,
12292
13264
  accountId: cfg.accountId,
@@ -12354,7 +13326,7 @@ function App({
12354
13326
  }
12355
13327
  });
12356
13328
  }, [cfg, setEvents]);
12357
- useEffect5(() => {
13329
+ useEffect6(() => {
12358
13330
  const id = setInterval(() => {
12359
13331
  try {
12360
13332
  performance.clearMarks();
@@ -12364,7 +13336,7 @@ function App({
12364
13336
  }, 3e5);
12365
13337
  return () => clearInterval(id);
12366
13338
  }, []);
12367
- const reloadCustomCommands = useCallback(async () => {
13339
+ const reloadCustomCommands = useCallback2(async () => {
12368
13340
  const { commands, warnings } = await loadCustomCommands(process.cwd());
12369
13341
  customCommandsRef.current = commands;
12370
13342
  setCustomCommandsVersion((v) => v + 1);
@@ -12379,7 +13351,7 @@ function App({
12379
13351
  ]);
12380
13352
  }
12381
13353
  }, [setEvents]);
12382
- useEffect5(() => {
13354
+ useEffect6(() => {
12383
13355
  if (!cfg || updateCheckedRef.current) return;
12384
13356
  updateCheckedRef.current = true;
12385
13357
  if (initialUpdateResult) {
@@ -12430,7 +13402,7 @@ function App({
12430
13402
  }
12431
13403
  });
12432
13404
  }, [cfg, initialUpdateResult]);
12433
- useEffect5(() => {
13405
+ useEffect6(() => {
12434
13406
  modeRef.current = mode;
12435
13407
  if (cacheStableRef.current) {
12436
13408
  messagesRef.current[1] = {
@@ -12457,10 +13429,10 @@ function App({
12457
13429
  executorRef.current.clearSessionPermissions();
12458
13430
  }
12459
13431
  }, [mode, cfg?.model]);
12460
- useEffect5(() => {
13432
+ useEffect6(() => {
12461
13433
  effortRef.current = effort;
12462
13434
  }, [effort]);
12463
- useEffect5(() => {
13435
+ useEffect6(() => {
12464
13436
  if (!cfg) return;
12465
13437
  const id = setInterval(() => {
12466
13438
  void checkForUpdate().then((result) => {
@@ -12491,7 +13463,7 @@ function App({
12491
13463
  }, 30 * 60 * 1e3);
12492
13464
  return () => clearInterval(id);
12493
13465
  }, [cfg]);
12494
- const initMcp = useCallback(async () => {
13466
+ const initMcp = useCallback2(async () => {
12495
13467
  if (!cfg?.mcpServers || mcpInitRef.current) return;
12496
13468
  mcpInitRef.current = true;
12497
13469
  const manager = mcpManagerRef.current;
@@ -12552,7 +13524,7 @@ function App({
12552
13524
  ]);
12553
13525
  }
12554
13526
  }, [cfg]);
12555
- const initLsp = useCallback(async () => {
13527
+ const initLsp = useCallback2(async () => {
12556
13528
  if (!cfg?.lspEnabled || !cfg?.lspServers || lspInitRef.current) {
12557
13529
  if (lspInitRef.current) return;
12558
13530
  if (!cfg?.lspEnabled) {
@@ -12615,7 +13587,7 @@ function App({
12615
13587
  ]);
12616
13588
  }
12617
13589
  }, [cfg]);
12618
- useEffect5(() => {
13590
+ useEffect6(() => {
12619
13591
  if (cfg && !mcpInitRef.current) {
12620
13592
  void initMcp();
12621
13593
  }
@@ -12623,7 +13595,7 @@ function App({
12623
13595
  void initLsp();
12624
13596
  }
12625
13597
  }, [cfg, initMcp, initLsp]);
12626
- const ensureSessionId = useCallback(() => {
13598
+ const ensureSessionId = useCallback2(() => {
12627
13599
  if (sessionIdRef.current) return sessionIdRef.current;
12628
13600
  const firstUser = messagesRef.current.find((m) => m.role === "user");
12629
13601
  let firstText = "session";
@@ -12636,7 +13608,7 @@ function App({
12636
13608
  sessionIdRef.current = makeSessionId(firstText);
12637
13609
  return sessionIdRef.current;
12638
13610
  }, []);
12639
- const saveSessionSafe = useCallback(async () => {
13611
+ const saveSessionSafe = useCallback2(async () => {
12640
13612
  if (!cfg) return;
12641
13613
  ensureSessionId();
12642
13614
  try {
@@ -12653,7 +13625,7 @@ function App({
12653
13625
  } catch {
12654
13626
  }
12655
13627
  }, [cfg, ensureSessionId]);
12656
- const onIterationEnd = useCallback(
13628
+ const onIterationEnd = useCallback2(
12657
13629
  async (messages, signal) => {
12658
13630
  if (signal.aborted) return messages;
12659
13631
  if (!shouldCompact({ messages })) return messages;
@@ -12731,31 +13703,42 @@ function App({
12731
13703
  },
12732
13704
  [cfg]
12733
13705
  );
12734
- useInput6((inputChar, key) => {
13706
+ useInput7((inputChar, key) => {
12735
13707
  if (key.ctrl && inputChar === "c") {
12736
13708
  const hadPerm = permResolveRef.current !== null;
13709
+ const hadLimit = limitResolveRef.current !== null;
12737
13710
  if (hadPerm) {
12738
13711
  permResolveRef.current("deny");
12739
13712
  permResolveRef.current = null;
12740
13713
  setPerm(null);
12741
13714
  }
12742
- if (busy && activeControllerRef.current) {
13715
+ if (hadLimit) {
13716
+ limitResolveRef.current("stop");
13717
+ limitResolveRef.current = null;
13718
+ setLimitModal(null);
13719
+ }
13720
+ if (busyRef.current && activeControllerRef.current) {
12743
13721
  activeControllerRef.current.abort();
12744
13722
  setQueue([]);
12745
13723
  setEvents((e) => [...e, { kind: "info", key: mkKey(), text: "(interrupted)" }]);
12746
- } else if (!hadPerm) {
13724
+ } else if (!hadPerm && !hadLimit) {
12747
13725
  void lspManagerRef.current.stopAll().finally(() => exit());
12748
13726
  }
12749
13727
  return;
12750
13728
  }
12751
13729
  if (key.escape) {
12752
- const modalOpen = perm !== null || showHelpMenu || showLspWizard || showCommandList || commandWizard !== null || commandToDelete !== null || resumeSessions !== null;
12753
- if (!modalOpen && busy && activeControllerRef.current) {
13730
+ const modalOpen = perm !== null || limitModal !== null || showHelpMenu || showLspWizard || showCommandList || commandWizard !== null || commandToDelete !== null || resumeSessions !== null;
13731
+ if (!modalOpen && busyRef.current && activeControllerRef.current) {
12754
13732
  if (permResolveRef.current) {
12755
13733
  permResolveRef.current("deny");
12756
13734
  permResolveRef.current = null;
12757
13735
  setPerm(null);
12758
13736
  }
13737
+ if (limitResolveRef.current) {
13738
+ limitResolveRef.current("stop");
13739
+ limitResolveRef.current = null;
13740
+ setLimitModal(null);
13741
+ }
12759
13742
  activeControllerRef.current.abort();
12760
13743
  setQueue([]);
12761
13744
  setEvents((e) => [...e, { kind: "info", key: mkKey(), text: "(interrupted)" }]);
@@ -12775,7 +13758,7 @@ function App({
12775
13758
  return;
12776
13759
  }
12777
13760
  });
12778
- const flushAssistantUpdates = useCallback(() => {
13761
+ const flushAssistantUpdates = useCallback2(() => {
12779
13762
  flushTimeoutRef.current = null;
12780
13763
  const pending = pendingTextRef.current;
12781
13764
  if (pending.size === 0) return;
@@ -12793,7 +13776,7 @@ function App({
12793
13776
  })
12794
13777
  );
12795
13778
  }, []);
12796
- const updateAssistant = useCallback(
13779
+ const updateAssistant = useCallback2(
12797
13780
  (id, patch) => {
12798
13781
  const result = patch({ text: "", reasoning: "" });
12799
13782
  const assistantResult = result;
@@ -12822,7 +13805,7 @@ function App({
12822
13805
  },
12823
13806
  [flushAssistantUpdates]
12824
13807
  );
12825
- const updateTool = useCallback(
13808
+ const updateTool = useCallback2(
12826
13809
  (id, patch) => {
12827
13810
  setEvents(
12828
13811
  (evts) => evts.map(
@@ -12832,11 +13815,11 @@ function App({
12832
13815
  },
12833
13816
  []
12834
13817
  );
12835
- const updateGatewayMeta = useCallback((meta) => {
13818
+ const updateGatewayMeta = useCallback2((meta) => {
12836
13819
  gatewayMetaRef.current = meta;
12837
13820
  setGatewayMeta(meta);
12838
13821
  }, []);
12839
- const runCompact = useCallback(async () => {
13822
+ const runCompact = useCallback2(async () => {
12840
13823
  if (!cfg) return;
12841
13824
  if (busy) {
12842
13825
  setEvents((e) => [...e, { kind: "info", key: mkKey(), text: "can't compact while model is running" }]);
@@ -12921,40 +13904,23 @@ function App({
12921
13904
  setTurnStartedAt(null);
12922
13905
  activeControllerRef.current = null;
12923
13906
  permResolveRef.current = null;
13907
+ limitResolveRef.current = null;
12924
13908
  pendingToolCallsRef.current.clear();
12925
13909
  }
12926
13910
  }, [cfg, busy, saveSessionSafe]);
12927
- const openResumePicker = useCallback(async () => {
13911
+ const openResumePicker = useCallback2(async () => {
12928
13912
  const sessions = await listSessions(200, process.cwd());
12929
13913
  setResumeSessions(sessions);
12930
13914
  }, []);
12931
- const runInit = useCallback(async () => {
13915
+ const runInit = useCallback2(async () => {
12932
13916
  if (!cfg) return;
12933
13917
  if (busy) {
12934
13918
  setEvents((e) => [...e, { kind: "info", key: mkKey(), text: "can't /init while model is running" }]);
12935
13919
  return;
12936
13920
  }
12937
13921
  const cwd = process.cwd();
12938
- const existingName = ["KIMI.md", "KIMIFLARE.md", "AGENT.md"].find((n) => existsSync2(join19(cwd, n)));
12939
- const isRefresh = existingName !== void 0;
12940
- const promptParts = [
12941
- isRefresh ? `Regenerate ${existingName} at the repository root to refresh project context. If the file already exists, read it first and preserve anything still accurate, updating only what has changed.` : "Generate a KIMI.md at the repository root so future agents have project context.",
12942
- "",
12943
- "First, use the `glob`, `read`, and `grep` tools to understand the project: read `package.json`, the top-level `README.md` if present, the tsconfig / build config, and skim the top-level source directory structure.",
12944
- isRefresh ? `Also read the existing ${existingName} so you know what to keep vs. update.` : null,
12945
- "",
12946
- "Then call the `write` tool to create `KIMI.md` at the repo root with these sections, terse (aim \u2264 100 lines total):",
12947
- "",
12948
- "- **Project** \u2014 one-line description + primary language/runtime.",
12949
- "- **Build / test / run** \u2014 exact shell commands an agent should use.",
12950
- "- **Layout** \u2014 key directories and what lives in each.",
12951
- "- **Conventions** \u2014 naming, import style, file structure, commit style, anything surprising.",
12952
- "- **Do / Don't** \u2014 quirks or rules future agents should know.",
12953
- "",
12954
- "Do not call `tasks_set` for this. Just read what you need, then write the file."
12955
- ];
12956
- const prompt = promptParts.filter((p) => p !== null).join("\n");
12957
- setEvents((e) => [...e, { kind: "user", key: mkKey(), text: isRefresh ? `/init (refreshing ${existingName})` : "/init" }]);
13922
+ const { prompt, targetFilename, isRefresh } = buildInitPrompt(cwd);
13923
+ setEvents((e) => [...e, { kind: "user", key: mkKey(), text: isRefresh ? `/init (refreshing ${targetFilename})` : "/init" }]);
12958
13924
  messagesRef.current.push({ role: "user", content: sanitizeString(prompt) });
12959
13925
  setBusy(true);
12960
13926
  setTurnStartedAt(Date.now());
@@ -12986,13 +13952,15 @@ function App({
12986
13952
  sessionId: ensureSessionId(),
12987
13953
  memoryManager: memoryManagerRef.current,
12988
13954
  codeMode: effectiveCodeMode,
13955
+ cloudMode: cfg.cloudMode,
13956
+ cloudToken: initialCloudToken,
12989
13957
  onIterationEnd,
12990
13958
  onFileChange: (path, content) => {
12991
13959
  if (content) {
12992
13960
  lspManagerRef.current.notifyChange(path, content);
12993
13961
  } else {
12994
13962
  void import("fs/promises").then(
12995
- ({ readFile: readFile16 }) => readFile16(path, "utf8").then((c) => lspManagerRef.current.notifyChange(path, c)).catch(() => {
13963
+ ({ readFile: readFile17 }) => readFile17(path, "utf8").then((c) => lspManagerRef.current.notifyChange(path, c)).catch(() => {
12996
13964
  })
12997
13965
  );
12998
13966
  }
@@ -13086,7 +14054,7 @@ function App({
13086
14054
  })
13087
14055
  }
13088
14056
  });
13089
- if (existsSync2(join19(cwd, "KIMI.md"))) {
14057
+ if (existsSync3(join22(cwd, "KIMI.md"))) {
13090
14058
  if (cacheStableRef.current) {
13091
14059
  messagesRef.current[1] = {
13092
14060
  role: "system",
@@ -13141,10 +14109,11 @@ function App({
13141
14109
  activeAsstIdRef.current = null;
13142
14110
  activeControllerRef.current = null;
13143
14111
  permResolveRef.current = null;
14112
+ limitResolveRef.current = null;
13144
14113
  pendingToolCallsRef.current.clear();
13145
14114
  }
13146
14115
  }, [cfg, busy, updateAssistant, updateTool, updateGatewayMeta]);
13147
- const handleThemePick = useCallback(
14116
+ const handleThemePick = useCallback2(
13148
14117
  (picked) => {
13149
14118
  setShowThemePicker(false);
13150
14119
  setOriginalTheme(null);
@@ -13163,7 +14132,7 @@ function App({
13163
14132
  },
13164
14133
  [cfg, originalTheme]
13165
14134
  );
13166
- const handleResumePick = useCallback(
14135
+ const handleResumePick = useCallback2(
13167
14136
  async (picked) => {
13168
14137
  setResumeSessions(null);
13169
14138
  if (!picked) return;
@@ -13221,7 +14190,7 @@ function App({
13221
14190
  },
13222
14191
  []
13223
14192
  );
13224
- const handleSlash = useCallback(
14193
+ const handleSlash = useCallback2(
13225
14194
  (cmd) => {
13226
14195
  const raw = cmd.trim();
13227
14196
  const [head, ...rest] = raw.split(/\s+/);
@@ -13315,6 +14284,10 @@ function App({
13315
14284
  setEvents((e) => [...e, { kind: "info", key: mkKey(), text: "no config loaded" }]);
13316
14285
  return true;
13317
14286
  }
14287
+ if (cfg.cloudMode) {
14288
+ setEvents((e) => [...e, { kind: "info", key: mkKey(), text: "AI Gateway is managed by Kimiflare Cloud" }]);
14289
+ return true;
14290
+ }
13318
14291
  const sub = rest[0]?.toLowerCase() ?? "";
13319
14292
  const subArg = rest.slice(1).join(" ").trim();
13320
14293
  if (!sub || sub === "status") {
@@ -13703,7 +14676,7 @@ ${lines.join("\n")}` }]);
13703
14676
  if (c === "/hello") {
13704
14677
  const session = crypto.randomUUID();
13705
14678
  const url = `${FEEDBACK_WORKER_URL}/?s=${session}&v=${getAppVersion()}`;
13706
- openBrowser(url);
14679
+ openBrowser2(url);
13707
14680
  setEvents((e) => [
13708
14681
  ...e,
13709
14682
  { kind: "info", key: mkKey(), text: "Opened voice note page in your browser. Record your message there and hit Send when you're done." }
@@ -13828,7 +14801,7 @@ ${lines.join("\n")}` }]);
13828
14801
  setEvents((e) => [
13829
14802
  ...e,
13830
14803
  { kind: "info", key: mkKey(), text: `Starting remote session for ${repo.owner}/${repo.name}...` },
13831
- { kind: "info", key: mkKey(), text: `Budget: ${formatTokens3(budget)} tokens. TTL: ${ttl} min.` }
14804
+ { kind: "info", key: mkKey(), text: `Budget: ${formatTokens4(budget)} tokens. TTL: ${ttl} min.` }
13832
14805
  ]);
13833
14806
  try {
13834
14807
  const data = await startRemoteSession({
@@ -13916,7 +14889,7 @@ ${lines.join("\n")}` }]);
13916
14889
  },
13917
14890
  [cfg, exit, usage, effort, theme, mode, openResumePicker, runCompact, runInit, initMcp, setCfg, setShowRemoteDashboard, setSelectedRemoteSession]
13918
14891
  );
13919
- const handleHelpCommand = useCallback(
14892
+ const handleHelpCommand = useCallback2(
13920
14893
  (command) => {
13921
14894
  setShowHelpMenu(false);
13922
14895
  const executed = handleSlash(command);
@@ -13926,7 +14899,7 @@ ${lines.join("\n")}` }]);
13926
14899
  },
13927
14900
  [handleSlash]
13928
14901
  );
13929
- const handleCommandSave = useCallback(
14902
+ const handleCommandSave = useCallback2(
13930
14903
  async (opts2) => {
13931
14904
  setCommandWizard(null);
13932
14905
  try {
@@ -13948,7 +14921,7 @@ ${lines.join("\n")}` }]);
13948
14921
  },
13949
14922
  [commandWizard, reloadCustomCommands, setEvents]
13950
14923
  );
13951
- const handleCommandDelete = useCallback(
14924
+ const handleCommandDelete = useCallback2(
13952
14925
  async (cmd) => {
13953
14926
  setCommandToDelete(null);
13954
14927
  try {
@@ -13967,7 +14940,7 @@ ${lines.join("\n")}` }]);
13967
14940
  },
13968
14941
  [reloadCustomCommands, setEvents]
13969
14942
  );
13970
- const processMessage = useCallback(
14943
+ const processMessage = useCallback2(
13971
14944
  async (text, displayText) => {
13972
14945
  if (!cfg) return;
13973
14946
  let trimmed = text.trim();
@@ -14166,6 +15139,10 @@ ${lines.join("\n")}` }]);
14166
15139
  }
14167
15140
  permResolveRef.current = resolve2;
14168
15141
  setPerm({ tool: req.tool, args: req.args, resolve: resolve2 });
15142
+ }),
15143
+ onToolLimitReached: () => new Promise((resolve2) => {
15144
+ limitResolveRef.current = resolve2;
15145
+ setLimitModal({ limit: 50, resolve: resolve2 });
14169
15146
  })
14170
15147
  };
14171
15148
  try {
@@ -14185,6 +15162,8 @@ ${lines.join("\n")}` }]);
14185
15162
  memoryManager: memoryManagerRef.current,
14186
15163
  keepLastImageTurns: cfg.imageHistoryTurns ?? 2,
14187
15164
  codeMode: effectiveCodeMode,
15165
+ cloudMode: cfg.cloudMode,
15166
+ cloudToken: initialCloudToken,
14188
15167
  onIterationEnd,
14189
15168
  intentClassification: classification,
14190
15169
  onFileChange: (path, content2) => {
@@ -14192,7 +15171,7 @@ ${lines.join("\n")}` }]);
14192
15171
  lspManagerRef.current.notifyChange(path, content2);
14193
15172
  } else {
14194
15173
  void import("fs/promises").then(
14195
- ({ readFile: readFile16 }) => readFile16(path, "utf8").then((c) => lspManagerRef.current.notifyChange(path, c)).catch(() => {
15174
+ ({ readFile: readFile17 }) => readFile17(path, "utf8").then((c) => lspManagerRef.current.notifyChange(path, c)).catch(() => {
14196
15175
  })
14197
15176
  );
14198
15177
  }
@@ -14253,6 +15232,8 @@ ${lines.join("\n")}` }]);
14253
15232
  text: `auto-compact failed: ${compactErr.message ?? String(compactErr)}`
14254
15233
  }
14255
15234
  ]);
15235
+ } else {
15236
+ throw compactErr;
14256
15237
  }
14257
15238
  }
14258
15239
  }
@@ -14322,19 +15303,20 @@ ${lines.join("\n")}` }]);
14322
15303
  activeAsstIdRef.current = null;
14323
15304
  activeControllerRef.current = null;
14324
15305
  permResolveRef.current = null;
15306
+ limitResolveRef.current = null;
14325
15307
  pendingToolCallsRef.current.clear();
14326
15308
  }
14327
15309
  },
14328
15310
  [cfg, handleSlash, updateAssistant, updateTool, saveSessionSafe, updateGatewayMeta]
14329
15311
  );
14330
- useEffect5(() => {
15312
+ useEffect6(() => {
14331
15313
  if (!busy && queue.length > 0) {
14332
15314
  const next = queue[0];
14333
15315
  setQueue((q) => q.slice(1));
14334
15316
  processMessage(next.full, next.display);
14335
15317
  }
14336
15318
  }, [busy, queue, processMessage]);
14337
- const submit = useCallback(
15319
+ const submit = useCallback2(
14338
15320
  (full, display) => {
14339
15321
  const trimmedFull = full.trim();
14340
15322
  if (!trimmedFull) return;
@@ -14355,7 +15337,7 @@ ${lines.join("\n")}` }]);
14355
15337
  [busy, processMessage]
14356
15338
  );
14357
15339
  submitRef.current = submit;
14358
- useEffect5(() => {
15340
+ useEffect6(() => {
14359
15341
  if (compactSuggestedRef.current) return;
14360
15342
  if (usage && usage.prompt_tokens / CONTEXT_LIMIT >= AUTO_COMPACT_SUGGEST_PCT) {
14361
15343
  compactSuggestedRef.current = true;
@@ -14370,24 +15352,41 @@ ${lines.join("\n")}` }]);
14370
15352
  }
14371
15353
  }, [usage]);
14372
15354
  if (!cfg) {
14373
- return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(
15355
+ return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsx23(
14374
15356
  Onboarding,
14375
15357
  {
14376
- onDone: (newCfg) => {
15358
+ onCancel: () => exit(),
15359
+ onDone: async (newCfg) => {
14377
15360
  setCfg(newCfg);
14378
- setEvents((e) => [
14379
- ...e,
14380
- { kind: "info", key: mkKey(), text: "configuration saved \u2014 welcome to kimiflare!" }
14381
- ]);
15361
+ if (newCfg.cloudMode) {
15362
+ const { loadCloudCredentials: loadCloudCredentials2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
15363
+ const creds = await loadCloudCredentials2();
15364
+ if (creds) {
15365
+ setEvents((e) => [
15366
+ ...e,
15367
+ { kind: "info", key: mkKey(), text: "configuration saved \u2014 welcome to kimiflare! (cloud mode)" }
15368
+ ]);
15369
+ } else {
15370
+ setEvents((e) => [
15371
+ ...e,
15372
+ { kind: "info", key: mkKey(), text: "cloud mode configured \u2014 run `kimiflare auth cloud` to sign in" }
15373
+ ]);
15374
+ }
15375
+ } else {
15376
+ setEvents((e) => [
15377
+ ...e,
15378
+ { kind: "info", key: mkKey(), text: "configuration saved \u2014 welcome to kimiflare!" }
15379
+ ]);
15380
+ }
14382
15381
  }
14383
15382
  }
14384
15383
  ) });
14385
15384
  }
14386
15385
  if (resumeSessions !== null) {
14387
- return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx22(ResumePicker, { sessions: resumeSessions, onPick: handleResumePick }) }) });
15386
+ return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsx23(Box21, { flexDirection: "column", children: /* @__PURE__ */ jsx23(ResumePicker, { sessions: resumeSessions, onPick: handleResumePick }) }) });
14388
15387
  }
14389
15388
  if (showRemoteDashboard) {
14390
- return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: selectedRemoteSession ? /* @__PURE__ */ jsx22(
15389
+ return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsx23(Box21, { flexDirection: "column", children: selectedRemoteSession ? /* @__PURE__ */ jsx23(
14391
15390
  RemoteSessionDetail,
14392
15391
  {
14393
15392
  session: selectedRemoteSession,
@@ -14410,7 +15409,7 @@ ${lines.join("\n")}` }]);
14410
15409
  setShowRemoteDashboard(false);
14411
15410
  }
14412
15411
  }
14413
- ) : /* @__PURE__ */ jsx22(
15412
+ ) : /* @__PURE__ */ jsx23(
14414
15413
  RemoteDashboard,
14415
15414
  {
14416
15415
  onSelect: (session) => setSelectedRemoteSession(session),
@@ -14419,23 +15418,24 @@ ${lines.join("\n")}` }]);
14419
15418
  ) }) });
14420
15419
  }
14421
15420
  if (showHelpMenu) {
14422
- return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx22(
15421
+ return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsx23(Box21, { flexDirection: "column", children: /* @__PURE__ */ jsx23(
14423
15422
  HelpMenu,
14424
15423
  {
14425
15424
  customCommands: customCommandsRef.current.filter((c) => !BUILTIN_COMMAND_NAMES.has(c.name.toLowerCase())).map((c) => ({ name: c.name, description: c.description })),
14426
15425
  costAttributionEnabled: cfg?.costAttribution,
15426
+ cloudMode: cfg?.cloudMode,
14427
15427
  onDone: () => setShowHelpMenu(false),
14428
15428
  onCommand: handleHelpCommand
14429
15429
  }
14430
15430
  ) }) });
14431
15431
  }
14432
15432
  if (showLspWizard) {
14433
- return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx22(
15433
+ return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsx23(Box21, { flexDirection: "column", children: /* @__PURE__ */ jsx23(
14434
15434
  LspWizard,
14435
15435
  {
14436
15436
  servers: cfg?.lspServers ?? {},
14437
15437
  currentScope: lspScope,
14438
- hasProjectDir: existsSync2(join19(process.cwd(), ".kimiflare")),
15438
+ hasProjectDir: existsSync3(join22(process.cwd(), ".kimiflare")),
14439
15439
  onDone: () => setShowLspWizard(false),
14440
15440
  onSave: (servers, enabled, scope) => {
14441
15441
  setCfg((c) => c ? { ...c, lspEnabled: enabled, lspServers: servers } : c);
@@ -14467,7 +15467,7 @@ ${lines.join("\n")}` }]);
14467
15467
  ) }) });
14468
15468
  }
14469
15469
  if (commandWizard) {
14470
- return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx22(
15470
+ return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsx23(Box21, { flexDirection: "column", children: /* @__PURE__ */ jsx23(
14471
15471
  CommandWizard,
14472
15472
  {
14473
15473
  mode: commandWizard.mode,
@@ -14480,7 +15480,7 @@ ${lines.join("\n")}` }]);
14480
15480
  ) }) });
14481
15481
  }
14482
15482
  if (commandPicker) {
14483
- return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx22(
15483
+ return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsx23(Box21, { flexDirection: "column", children: /* @__PURE__ */ jsx23(
14484
15484
  CommandPicker,
14485
15485
  {
14486
15486
  commands: customCommandsRef.current,
@@ -14498,15 +15498,15 @@ ${lines.join("\n")}` }]);
14498
15498
  ) }) });
14499
15499
  }
14500
15500
  if (commandToDelete) {
14501
- return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
14502
- /* @__PURE__ */ jsxs20(Text21, { color: theme.accent, bold: true, children: [
15501
+ return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
15502
+ /* @__PURE__ */ jsxs21(Text22, { color: theme.accent, bold: true, children: [
14503
15503
  "Delete /",
14504
15504
  commandToDelete.name,
14505
15505
  "?"
14506
15506
  ] }),
14507
- /* @__PURE__ */ jsx22(Text21, { color: theme.info.color, children: commandToDelete.filepath }),
14508
- /* @__PURE__ */ jsx22(Box20, { marginTop: 1, children: /* @__PURE__ */ jsx22(
14509
- SelectInput9,
15507
+ /* @__PURE__ */ jsx23(Text22, { color: theme.info.color, children: commandToDelete.filepath }),
15508
+ /* @__PURE__ */ jsx23(Box21, { marginTop: 1, children: /* @__PURE__ */ jsx23(
15509
+ SelectInput11,
14510
15510
  {
14511
15511
  items: [
14512
15512
  { label: "Yes, delete", value: "yes", key: "yes" },
@@ -14524,7 +15524,7 @@ ${lines.join("\n")}` }]);
14524
15524
  ] }) });
14525
15525
  }
14526
15526
  if (showCommandList) {
14527
- return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx22(
15527
+ return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsx23(Box21, { flexDirection: "column", children: /* @__PURE__ */ jsx23(
14528
15528
  CommandList,
14529
15529
  {
14530
15530
  commands: customCommandsRef.current,
@@ -14533,12 +15533,12 @@ ${lines.join("\n")}` }]);
14533
15533
  ) }) });
14534
15534
  }
14535
15535
  if (showThemePicker) {
14536
- return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx22(ThemePicker, { themes: themeList(), onPick: handleThemePick, onPreview: (t) => setTheme(t) }) }) });
15536
+ return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsx23(Box21, { flexDirection: "column", children: /* @__PURE__ */ jsx23(ThemePicker, { themes: themeList(), onPick: handleThemePick, onPreview: (t) => setTheme(t) }) }) });
14537
15537
  }
14538
15538
  const hasConversation = events.some((e) => e.kind === "user" || e.kind === "assistant");
14539
- return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", children: [
14540
- !hasConversation && events.length === 0 ? /* @__PURE__ */ jsx22(Welcome, { accountId: cfg.accountId }) : /* @__PURE__ */ jsx22(ChatView, { events, showReasoning, verbose }),
14541
- perm ? /* @__PURE__ */ jsx22(
15539
+ return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", children: [
15540
+ !hasConversation && events.length === 0 ? /* @__PURE__ */ jsx23(Welcome, { accountId: cfg.accountId }) : /* @__PURE__ */ jsx23(ChatView, { events, showReasoning, verbose }),
15541
+ perm ? /* @__PURE__ */ jsx23(
14542
15542
  PermissionModal,
14543
15543
  {
14544
15544
  tool: perm.tool,
@@ -14549,8 +15549,18 @@ ${lines.join("\n")}` }]);
14549
15549
  setPerm(null);
14550
15550
  }
14551
15551
  }
14552
- ) : /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", marginTop: 1, children: [
14553
- tasks.length > 0 && /* @__PURE__ */ jsx22(
15552
+ ) : limitModal ? /* @__PURE__ */ jsx23(
15553
+ LimitModal,
15554
+ {
15555
+ limit: limitModal.limit,
15556
+ onDecide: (d) => {
15557
+ limitModal.resolve(d);
15558
+ limitResolveRef.current = null;
15559
+ setLimitModal(null);
15560
+ }
15561
+ }
15562
+ ) : /* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", marginTop: 1, children: [
15563
+ tasks.length > 0 && /* @__PURE__ */ jsx23(
14554
15564
  TaskList,
14555
15565
  {
14556
15566
  tasks,
@@ -14558,11 +15568,11 @@ ${lines.join("\n")}` }]);
14558
15568
  tokensDelta: Math.max(0, (usage?.prompt_tokens ?? 0) - tasksStartTokens)
14559
15569
  }
14560
15570
  ),
14561
- queue.length > 0 && /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", marginBottom: 1, children: queue.map((q, i) => /* @__PURE__ */ jsxs20(Text21, { color: theme.info.color, children: [
15571
+ queue.length > 0 && /* @__PURE__ */ jsx23(Box21, { flexDirection: "column", marginBottom: 1, children: queue.map((q, i) => /* @__PURE__ */ jsxs21(Text22, { color: theme.info.color, children: [
14562
15572
  "\u23F3 ",
14563
15573
  q.display
14564
15574
  ] }, `queue_${i}`)) }),
14565
- /* @__PURE__ */ jsx22(
15575
+ /* @__PURE__ */ jsx23(
14566
15576
  StatusBar,
14567
15577
  {
14568
15578
  model: cfg.model,
@@ -14576,10 +15586,12 @@ ${lines.join("\n")}` }]);
14576
15586
  hasUpdate,
14577
15587
  latestVersion,
14578
15588
  gatewayMeta,
14579
- codeMode
15589
+ codeMode,
15590
+ cloudMode: cfg.cloudMode,
15591
+ cloudBudget
14580
15592
  }
14581
15593
  ),
14582
- activePicker?.kind === "file" && /* @__PURE__ */ jsx22(
15594
+ activePicker?.kind === "file" && /* @__PURE__ */ jsx23(
14583
15595
  FilePicker,
14584
15596
  {
14585
15597
  items: filteredFileItems,
@@ -14587,7 +15599,7 @@ ${lines.join("\n")}` }]);
14587
15599
  query: pickerQuery ?? ""
14588
15600
  }
14589
15601
  ),
14590
- activePicker?.kind === "slash" && /* @__PURE__ */ jsx22(
15602
+ activePicker?.kind === "slash" && /* @__PURE__ */ jsx23(
14591
15603
  SlashPicker,
14592
15604
  {
14593
15605
  items: filteredSlashItems,
@@ -14595,9 +15607,9 @@ ${lines.join("\n")}` }]);
14595
15607
  query: pickerQuery ?? ""
14596
15608
  }
14597
15609
  ),
14598
- /* @__PURE__ */ jsxs20(Box20, { marginTop: 1, children: [
14599
- /* @__PURE__ */ jsx22(Text21, { color: "#d699b6", children: "\u203A " }),
14600
- /* @__PURE__ */ jsx22(
15610
+ /* @__PURE__ */ jsxs21(Box21, { marginTop: 1, children: [
15611
+ /* @__PURE__ */ jsx23(Text22, { color: "#d699b6", children: "\u203A " }),
15612
+ /* @__PURE__ */ jsx23(
14601
15613
  CustomTextInput,
14602
15614
  {
14603
15615
  value: input,
@@ -14652,15 +15664,16 @@ ${lines.join("\n")}` }]);
14652
15664
  ] })
14653
15665
  ] }) });
14654
15666
  }
14655
- async function renderApp(cfg, updateResult, lspScope = "global", lspProjectPath = null) {
15667
+ async function renderApp(cfg, updateResult, lspScope = "global", lspProjectPath = null, cloudToken) {
14656
15668
  const instance = render(
14657
- /* @__PURE__ */ jsx22(
15669
+ /* @__PURE__ */ jsx23(
14658
15670
  App,
14659
15671
  {
14660
15672
  initialCfg: cfg,
14661
15673
  initialUpdateResult: updateResult,
14662
15674
  initialLspScope: lspScope,
14663
- initialLspProjectPath: lspProjectPath
15675
+ initialLspProjectPath: lspProjectPath,
15676
+ initialCloudToken: cloudToken
14664
15677
  }
14665
15678
  ),
14666
15679
  {
@@ -14687,6 +15700,7 @@ var init_app = __esm({
14687
15700
  init_chat();
14688
15701
  init_status();
14689
15702
  init_permission();
15703
+ init_limit_modal();
14690
15704
  init_resume_picker();
14691
15705
  init_task_list();
14692
15706
  init_text_input();
@@ -14714,6 +15728,7 @@ var init_app = __esm({
14714
15728
  init_builtins();
14715
15729
  init_save();
14716
15730
  init_command_wizard();
15731
+ init_context_generator();
14717
15732
  init_command_picker();
14718
15733
  init_command_list();
14719
15734
  init_lsp_wizard();
@@ -14851,7 +15866,7 @@ function createRemoteCommand() {
14851
15866
 
14852
15867
  // src/index.tsx
14853
15868
  var program = new Command2();
14854
- program.name("kimiflare").description("Terminal coding agent powered by Kimi-K2.6 on Cloudflare Workers AI.").version(getAppVersion()).option("-p, --print <prompt>", "one-shot mode: send prompt, stream reply to stdout, exit").option("-m, --model <id>", "model id (defaults to @cf/moonshotai/kimi-k2.6)").option("--dangerously-allow-all", "auto-approve every permission prompt (print mode only)").option("--reasoning", "include reasoning in stdout (print mode only)").option("--continue-on-limit", "reset tool-call counter and continue when the 50-call limit is hit (print mode only)").option("--max-input-tokens <n>", "cumulative prompt token budget; exits 42 when exhausted (print mode only)", (v) => parseInt(v, 10));
15869
+ program.name("kimiflare").description("Terminal coding agent powered by Kimi-K2.6 on Cloudflare Workers AI.").version(getAppVersion()).option("-p, --print <prompt>", "one-shot mode: send prompt, stream reply to stdout, exit").option("-m, --model <id>", "model id (defaults to @cf/moonshotai/kimi-k2.6)").option("--cloud", "use Kimiflare Cloud (api.kimiflare.com) instead of direct Workers AI").option("--dangerously-allow-all", "auto-approve every permission prompt (print mode only)").option("--reasoning", "include reasoning in stdout (print mode only)").option("--continue-on-limit", "reset tool-call counter and continue when the 50-call limit is hit (print mode only)").option("--max-input-tokens <n>", "cumulative prompt token budget; exits 42 when exhausted (print mode only)", (v) => parseInt(v, 10));
14855
15870
  program.command("cost").description("Show cost attribution by task type (requires costAttribution enabled)").option("-w, --week", "last 7 days (default)").option("-m, --month", "last 30 days").option("-d, --day", "today only").option("-s, --session <id>", "single session detail").option("-c, --category <name>", "filter by category").option("--json", "machine-readable output").option("--reclassify", "re-run classification on all sessions").option("--local-only", "skip Cloudflare reconciliation").action(async (cmdOpts) => {
14856
15871
  const cfg = await loadConfig();
14857
15872
  const enabled = cfg?.costAttribution ?? false;
@@ -14864,6 +15879,25 @@ program.command("cost").description("Show cost attribution by task type (require
14864
15879
  const { runCostCommand: runCostCommand2 } = await Promise.resolve().then(() => (init_cli(), cli_exports));
14865
15880
  await runCostCommand2({ ...cmdOpts, config: cfg });
14866
15881
  });
15882
+ program.command("usage").description("Show Kimiflare Cloud token usage (requires cloud authentication)").action(async () => {
15883
+ const { loadCloudCredentials: loadCloudCredentials2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
15884
+ const creds = await loadCloudCredentials2();
15885
+ if (!creds) {
15886
+ console.error("Not authenticated with Kimiflare Cloud. Run: kimiflare auth cloud");
15887
+ process.exit(1);
15888
+ }
15889
+ const res = await fetch("https://api.kimiflare.com/v1/usage", {
15890
+ headers: { Authorization: `Bearer ${creds.accessToken}` }
15891
+ });
15892
+ if (!res.ok) {
15893
+ console.error(`Failed to fetch usage: ${res.status} ${res.statusText}`);
15894
+ process.exit(1);
15895
+ }
15896
+ const usage = await res.json();
15897
+ console.log(`Token budget: ${usage.remaining.toLocaleString()} / ${usage.input_token_limit.toLocaleString()} remaining`);
15898
+ console.log(`Used: ${usage.input_tokens_used.toLocaleString()}`);
15899
+ console.log(`Grant expires: ${usage.expires_at}`);
15900
+ });
14867
15901
  program.addCommand(createRemoteCommand());
14868
15902
  program.command("auth").description("Authenticate with external services").addCommand(
14869
15903
  new Command2("github").description("Authenticate with GitHub via OAuth device flow").action(async () => {
@@ -14880,6 +15914,37 @@ Open: ${step.url}`);
14880
15914
  if (step.error) process.exit(1);
14881
15915
  }
14882
15916
  })
15917
+ ).addCommand(
15918
+ new Command2("cloud").description("Authenticate with Kimiflare Cloud").action(async () => {
15919
+ const { authenticateDevice: authenticateDevice2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
15920
+ try {
15921
+ const creds = await authenticateDevice2(({ url, userCode, polling }) => {
15922
+ if (!polling) {
15923
+ console.log(`
15924
+ Kimiflare Cloud Authentication`);
15925
+ console.log(`
15926
+ 1. Open this URL in your browser:`);
15927
+ console.log(` ${url}`);
15928
+ console.log(`
15929
+ 2. Sign in with GitHub
15930
+ `);
15931
+ }
15932
+ });
15933
+ console.log(`Authenticated! Token expires at ${new Date(creds.expiresAt * 1e3).toISOString()}`);
15934
+ const usageRes = await fetch("https://api.kimiflare.com/v1/usage", {
15935
+ headers: { Authorization: `Bearer ${creds.accessToken}` }
15936
+ });
15937
+ if (usageRes.ok) {
15938
+ const usage = await usageRes.json();
15939
+ console.log(`
15940
+ Token budget: ${usage.remaining.toLocaleString()} / ${usage.input_token_limit.toLocaleString()} remaining`);
15941
+ console.log(`Grant expires: ${usage.expires_at}`);
15942
+ }
15943
+ } catch (err) {
15944
+ console.error("Authentication failed:", err instanceof Error ? err.message : String(err));
15945
+ process.exit(1);
15946
+ }
15947
+ })
14883
15948
  );
14884
15949
  program.action(async () => {
14885
15950
  await main();
@@ -14902,10 +15967,25 @@ async function main() {
14902
15967
  lspScope = resolved.scope;
14903
15968
  lspProjectPath = resolved.projectPath;
14904
15969
  }
15970
+ const cloudMode = opts.cloud ?? cfg?.cloudMode ?? false;
15971
+ let cloudToken;
15972
+ if (cloudMode) {
15973
+ const { loadCloudCredentials: loadCloudCredentials2, authenticateDevice: authenticateDevice2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
15974
+ let cloudCreds = await loadCloudCredentials2();
15975
+ if (!cloudCreds) {
15976
+ console.error("kimiflare: cloud mode requires authentication.\nRun: kimiflare auth cloud\n");
15977
+ process.exit(2);
15978
+ }
15979
+ cloudToken = cloudCreds.accessToken;
15980
+ cfg = {
15981
+ ...cfg ?? { accountId: "", apiToken: "", model: DEFAULT_MODEL },
15982
+ cloudMode: true
15983
+ };
15984
+ }
14905
15985
  if (opts.print !== void 0) {
14906
15986
  if (!cfg) {
14907
15987
  console.error(
14908
- 'kimiflare: missing credentials.\nSet CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN, or write them to\n ~/.config/kimiflare/config.json (chmod 600)\n { "accountId": "...", "apiToken": "...", "model": "@cf/moonshotai/kimi-k2.6" }'
15988
+ 'kimiflare: missing credentials.\nSet CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN, or write them to\n ~/.config/kimiflare/config.json (chmod 600)\n { "accountId": "...", "apiToken": "...", "model": "@cf/moonshotai/kimi-k2.6" }\nOr use cloud mode: kimiflare --cloud -p "..."'
14909
15989
  );
14910
15990
  process.exit(2);
14911
15991
  }
@@ -14917,6 +15997,7 @@ async function main() {
14917
15997
  allowAll: !!opts.dangerouslyAllowAll,
14918
15998
  showReasoning: !!opts.reasoning,
14919
15999
  codeMode: cfg.codeMode,
16000
+ cloudToken,
14920
16001
  continueOnLimit: !!opts.continueOnLimit,
14921
16002
  maxInputTokens: opts.maxInputTokens,
14922
16003
  updateResult
@@ -14932,9 +16013,9 @@ async function main() {
14932
16013
  const { renderApp: renderApp2 } = await Promise.resolve().then(() => (init_app(), app_exports));
14933
16014
  if (cfg) {
14934
16015
  const model = opts.model ?? cfg.model ?? DEFAULT_MODEL;
14935
- await renderApp2({ ...cfg, model }, updateResult, lspScope, lspProjectPath);
16016
+ await renderApp2({ ...cfg, model }, updateResult, lspScope, lspProjectPath, cloudToken);
14936
16017
  } else {
14937
- await renderApp2(null, updateResult, lspScope, lspProjectPath);
16018
+ await renderApp2(null, updateResult, lspScope, lspProjectPath, cloudToken);
14938
16019
  }
14939
16020
  }
14940
16021
  function gatewayFromPrintOpts(opts2) {
@@ -14948,6 +16029,10 @@ function gatewayFromPrintOpts(opts2) {
14948
16029
  };
14949
16030
  }
14950
16031
  async function runPrintMode(opts2) {
16032
+ if (opts2.cloudMode) {
16033
+ process.stderr.write(`[cloud mode: api.kimiflare.com]
16034
+ `);
16035
+ }
14951
16036
  if (opts2.updateResult.hasUpdate) {
14952
16037
  process.stderr.write(
14953
16038
  `\x1B[33mkimiflare update available: ${opts2.updateResult.localVersion} \u2192 ${opts2.updateResult.latestVersion}\x1B[0m
@@ -14980,6 +16065,8 @@ async function runPrintMode(opts2) {
14980
16065
  codeMode: opts2.codeMode,
14981
16066
  continueOnLimit: opts2.continueOnLimit,
14982
16067
  maxInputTokens: opts2.maxInputTokens,
16068
+ cloudMode: opts2.cloudMode,
16069
+ cloudToken: opts2.cloudToken,
14983
16070
  coauthor: opts2.coauthor !== false ? { name: opts2.coauthorName || "kimiflare", email: opts2.coauthorEmail || "kimiflare@proton.me" } : void 0,
14984
16071
  callbacks: {
14985
16072
  onReasoningDelta: opts2.showReasoning ? (delta) => {