kimiflare 0.32.0 → 0.34.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
@@ -9,6 +9,15 @@ var __export = (target, all) => {
9
9
  };
10
10
 
11
11
  // src/config.ts
12
+ var config_exports = {};
13
+ __export(config_exports, {
14
+ DEFAULT_MODEL: () => DEFAULT_MODEL,
15
+ DEFAULT_REASONING_EFFORT: () => DEFAULT_REASONING_EFFORT,
16
+ EFFORTS: () => EFFORTS,
17
+ configPath: () => configPath,
18
+ loadConfig: () => loadConfig,
19
+ saveConfig: () => saveConfig
20
+ });
12
21
  import { readFile, mkdir, writeFile, chmod } from "fs/promises";
13
22
  import { homedir } from "os";
14
23
  import { join } from "path";
@@ -933,7 +942,10 @@ async function logTurnDebug(ctx) {
933
942
  toolSavingsPct: toolTotalRaw > 0 ? Math.round((toolTotalRaw - toolTotalReduced) / toolTotalRaw * 100) : 0,
934
943
  cacheDiagnostics,
935
944
  compaction: ctx.compaction,
936
- shadowStrip: ctx.shadowStrip
945
+ shadowStrip: ctx.shadowStrip,
946
+ durationMs: ctx.durationMs,
947
+ intentClassification: ctx.intentClassification,
948
+ codeMode: ctx.codeMode
937
949
  });
938
950
  }
939
951
  var LOG_VERSION;
@@ -945,6 +957,87 @@ var init_cost_debug = __esm({
945
957
  }
946
958
  });
947
959
 
960
+ // src/memory/extractors.ts
961
+ function safeJsonParse(text) {
962
+ try {
963
+ return JSON.parse(text);
964
+ } catch {
965
+ return null;
966
+ }
967
+ }
968
+ var EXTRACTORS;
969
+ var init_extractors = __esm({
970
+ "src/memory/extractors.ts"() {
971
+ "use strict";
972
+ EXTRACTORS = [
973
+ {
974
+ id: "package_json",
975
+ match: (tool, file) => tool === "read" && /package\.json$/.test(file || ""),
976
+ extract: (content, file) => {
977
+ const pkg = safeJsonParse(content);
978
+ if (!pkg) return null;
979
+ const deps = Object.keys(pkg.dependencies || {}).slice(0, 10);
980
+ const devDeps = Object.keys(pkg.devDependencies || {}).slice(0, 5);
981
+ const scripts = Object.keys(pkg.scripts || {}).slice(0, 5);
982
+ return {
983
+ content: `Project dependencies: ${deps.join(", ") || "none"}. Dev dependencies: ${devDeps.join(", ") || "none"}. Scripts: ${scripts.join(", ") || "none"}. Type: ${pkg.type || "commonjs"}.`,
984
+ category: "fact",
985
+ importance: 4,
986
+ topicKey: "project_dependencies",
987
+ relatedFiles: file ? [file] : void 0
988
+ };
989
+ }
990
+ },
991
+ {
992
+ id: "tsconfig",
993
+ match: (tool, file) => tool === "read" && /tsconfig.*\.json$/.test(file || ""),
994
+ extract: (content, file) => {
995
+ const ts = safeJsonParse(content);
996
+ if (!ts) return null;
997
+ const opts2 = ts.compilerOptions || {};
998
+ return {
999
+ content: `TypeScript config: target=${opts2.target || "default"}, module=${opts2.module || "default"}, strict=${opts2.strict || false}, jsx=${opts2.jsx || "none"}.`,
1000
+ category: "fact",
1001
+ importance: 4,
1002
+ topicKey: "project_tsconfig",
1003
+ relatedFiles: file ? [file] : void 0
1004
+ };
1005
+ }
1006
+ },
1007
+ {
1008
+ id: "entry_point",
1009
+ match: (tool, file) => tool === "read" && /src\/(index|main)\.(ts|tsx|js|jsx)$/.test(file || ""),
1010
+ extract: (content, file) => {
1011
+ const exports = content.match(/export\s+(?:default\s+)?(?:function|class|const|interface|type)\s+(\w+)/g);
1012
+ const exportNames = exports ? exports.map((e) => e.split(/\s+/).pop()).filter((n) => !!n).slice(0, 5) : [];
1013
+ return {
1014
+ content: `Entry point ${file} exports: ${exportNames.join(", ") || "default export or side effects"}.`,
1015
+ category: "fact",
1016
+ importance: 3,
1017
+ topicKey: "project_entry_point",
1018
+ relatedFiles: file ? [file] : void 0
1019
+ };
1020
+ }
1021
+ },
1022
+ {
1023
+ id: "edit_event",
1024
+ match: (tool, file) => (tool === "edit" || tool === "write") && !!file,
1025
+ extract: (_content, file) => {
1026
+ if (!file) return null;
1027
+ const safeKey = file.replace(/[^a-zA-Z0-9]/g, "_");
1028
+ return {
1029
+ content: `File modified: ${file}.`,
1030
+ category: "event",
1031
+ importance: 2,
1032
+ topicKey: `event_edit_${safeKey}`,
1033
+ relatedFiles: [file]
1034
+ };
1035
+ }
1036
+ }
1037
+ ];
1038
+ }
1039
+ });
1040
+
948
1041
  // src/agent/strip-reasoning.ts
949
1042
  function stripHistoricalReasoning(messages, opts2 = {}) {
950
1043
  const keepLast = opts2.keepLast ?? DEFAULT_KEEP_LAST;
@@ -1275,6 +1368,7 @@ var init_code_mode = __esm({
1275
1368
 
1276
1369
  // src/agent/loop.ts
1277
1370
  async function runAgentTurn(opts2) {
1371
+ const turnStart = performance.now();
1278
1372
  const max = opts2.maxToolIterations ?? 50;
1279
1373
  const codeMode = opts2.codeMode ?? false;
1280
1374
  let toolDefs;
@@ -1328,7 +1422,28 @@ Use console.log() to return results. Only console.log output will be sent back t
1328
1422
  const webFetchHistory = [];
1329
1423
  const MAX_WEB_FETCH_PER_TURN = 5;
1330
1424
  const WEB_FETCH_DOMAIN_THRESHOLD = 2;
1331
- for (let iter = 0; iter < max; iter++) {
1425
+ let cumulativePromptTokens = 0;
1426
+ let iter = 0;
1427
+ let budgetExhausted = false;
1428
+ while (true) {
1429
+ if (budgetExhausted) {
1430
+ opts2.messages.push({
1431
+ role: "system",
1432
+ content: "You have reached the cumulative input token budget for this session. Please synthesize your findings and provide a final summary of what was accomplished."
1433
+ });
1434
+ }
1435
+ if (iter >= max) {
1436
+ if (opts2.continueOnLimit) {
1437
+ opts2.messages.push({
1438
+ role: "system",
1439
+ 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."
1440
+ });
1441
+ iter = 0;
1442
+ } else {
1443
+ throw new Error(`kimiflare: tool iteration limit reached (${max})`);
1444
+ }
1445
+ }
1446
+ iter++;
1332
1447
  turn++;
1333
1448
  const previousMessages = opts2.messages.slice();
1334
1449
  const toolCalls = [];
@@ -1426,7 +1541,13 @@ Use console.log() to return results. Only console.log output will be sent back t
1426
1541
  }
1427
1542
  }
1428
1543
  if (opts2.signal.aborted) throw new DOMException("aborted", "AbortError");
1429
- if (lastUsage) opts2.callbacks.onUsageFinal?.(lastUsage, gatewayMeta);
1544
+ if (lastUsage) {
1545
+ opts2.callbacks.onUsageFinal?.(lastUsage, gatewayMeta);
1546
+ cumulativePromptTokens += lastUsage.prompt_tokens;
1547
+ if (!budgetExhausted && opts2.maxInputTokens !== void 0 && opts2.maxInputTokens > 0 && cumulativePromptTokens >= opts2.maxInputTokens && toolCalls.length > 0) {
1548
+ budgetExhausted = true;
1549
+ }
1550
+ }
1430
1551
  const assistantMsg = {
1431
1552
  role: "assistant",
1432
1553
  content: content ? sanitizeString(content) : null,
@@ -1455,6 +1576,9 @@ Use console.log() to return results. Only console.log output will be sent back t
1455
1576
  shadowStrip: shadowStripMetrics
1456
1577
  });
1457
1578
  }
1579
+ if (budgetExhausted) {
1580
+ throw new BudgetExhaustedError();
1581
+ }
1458
1582
  return;
1459
1583
  }
1460
1584
  for (const tc of toolCalls) {
@@ -1589,10 +1713,38 @@ ${sandboxResult.output}` : sandboxResult.output;
1589
1713
  name: result.name
1590
1714
  });
1591
1715
  opts2.callbacks.onToolResult?.(result);
1716
+ if (opts2.memoryManager) {
1717
+ let filePath;
1718
+ try {
1719
+ const args = JSON.parse(tc.function.arguments || "{}");
1720
+ filePath = args.path;
1721
+ } catch {
1722
+ }
1723
+ for (const extractor of EXTRACTORS) {
1724
+ if (extractor.match(tc.function.name, filePath)) {
1725
+ const memory = extractor.extract(result.content, filePath);
1726
+ if (memory) {
1727
+ void opts2.memoryManager.remember(
1728
+ memory.content,
1729
+ memory.category,
1730
+ memory.importance,
1731
+ opts2.cwd,
1732
+ opts2.sessionId ?? "unknown",
1733
+ opts2.signal
1734
+ ).catch(() => {
1735
+ });
1736
+ }
1737
+ }
1738
+ }
1739
+ }
1592
1740
  recentToolCalls.push(loopSignature);
1593
1741
  if (recentToolCalls.length > LOOP_WINDOW) recentToolCalls.shift();
1594
1742
  }
1595
1743
  }
1744
+ if (opts2.onIterationEnd) {
1745
+ opts2.messages = await opts2.onIterationEnd(opts2.messages, opts2.signal);
1746
+ if (opts2.signal.aborted) throw new DOMException("aborted", "AbortError");
1747
+ }
1596
1748
  if (opts2.sessionId && lastUsage) {
1597
1749
  void logTurnDebug({
1598
1750
  sessionId: opts2.sessionId,
@@ -1601,11 +1753,16 @@ ${sandboxResult.output}` : sandboxResult.output;
1601
1753
  previousMessages,
1602
1754
  toolResults,
1603
1755
  usage: lastUsage,
1604
- shadowStrip: shadowStripMetrics
1756
+ shadowStrip: shadowStripMetrics,
1757
+ durationMs: Math.round(performance.now() - turnStart),
1758
+ intentClassification: opts2.intentClassification,
1759
+ codeMode: opts2.codeMode
1605
1760
  });
1606
1761
  }
1762
+ if (budgetExhausted) {
1763
+ throw new BudgetExhaustedError();
1764
+ }
1607
1765
  }
1608
- throw new Error(`kimiflare: tool iteration limit reached (${opts2.maxToolIterations ?? 50})`);
1609
1766
  }
1610
1767
  function validateToolArguments(raw) {
1611
1768
  if (!raw || !raw.trim()) return "{}";
@@ -1616,7 +1773,7 @@ function validateToolArguments(raw) {
1616
1773
  return "{}";
1617
1774
  }
1618
1775
  }
1619
- var codeModeApiCache;
1776
+ var BudgetExhaustedError, codeModeApiCache;
1620
1777
  var init_loop = __esm({
1621
1778
  "src/agent/loop.ts"() {
1622
1779
  "use strict";
@@ -1624,8 +1781,15 @@ var init_loop = __esm({
1624
1781
  init_registry();
1625
1782
  init_messages();
1626
1783
  init_cost_debug();
1784
+ init_extractors();
1627
1785
  init_strip_reasoning();
1628
1786
  init_code_mode();
1787
+ BudgetExhaustedError = class extends Error {
1788
+ constructor(message2 = "Cumulative input token budget exhausted") {
1789
+ super(message2);
1790
+ this.name = "BudgetExhaustedError";
1791
+ }
1792
+ };
1629
1793
  codeModeApiCache = /* @__PURE__ */ new Map();
1630
1794
  }
1631
1795
  });
@@ -3387,6 +3551,229 @@ var init_update_check = __esm({
3387
3551
  }
3388
3552
  });
3389
3553
 
3554
+ // src/remote/session-store.ts
3555
+ import { readFile as readFile8, writeFile as writeFile6, mkdir as mkdir6, readdir as readdir2 } from "fs/promises";
3556
+ import { homedir as homedir6 } from "os";
3557
+ import { join as join9 } from "path";
3558
+ function remoteDir() {
3559
+ const xdg = process.env.XDG_DATA_HOME || join9(homedir6(), ".config");
3560
+ return join9(xdg, "kimiflare", "remote");
3561
+ }
3562
+ async function saveRemoteSession(session) {
3563
+ const dir = remoteDir();
3564
+ await mkdir6(dir, { recursive: true });
3565
+ const path = join9(dir, `${session.sessionId}.json`);
3566
+ await writeFile6(path, JSON.stringify(session, null, 2) + "\n", "utf8");
3567
+ }
3568
+ async function loadRemoteSession(sessionId) {
3569
+ try {
3570
+ const path = join9(remoteDir(), `${sessionId}.json`);
3571
+ const raw = await readFile8(path, "utf8");
3572
+ return JSON.parse(raw);
3573
+ } catch {
3574
+ return null;
3575
+ }
3576
+ }
3577
+ async function listRemoteSessions() {
3578
+ const dir = remoteDir();
3579
+ try {
3580
+ const files = await readdir2(dir);
3581
+ const sessions = [];
3582
+ for (const file of files) {
3583
+ if (!file.endsWith(".json")) continue;
3584
+ try {
3585
+ const raw = await readFile8(join9(dir, file), "utf8");
3586
+ sessions.push(JSON.parse(raw));
3587
+ } catch {
3588
+ }
3589
+ }
3590
+ return sessions.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
3591
+ } catch {
3592
+ return [];
3593
+ }
3594
+ }
3595
+ async function getMostRecentRemoteSession() {
3596
+ const sessions = await listRemoteSessions();
3597
+ return sessions[0] ?? null;
3598
+ }
3599
+ var init_session_store = __esm({
3600
+ "src/remote/session-store.ts"() {
3601
+ "use strict";
3602
+ }
3603
+ });
3604
+
3605
+ // src/remote/deploy.ts
3606
+ import { execSync } from "child_process";
3607
+ import { join as join10, dirname as dirname5 } from "path";
3608
+ import { fileURLToPath as fileURLToPath3 } from "url";
3609
+ import { randomBytes } from "crypto";
3610
+ function generateSecret() {
3611
+ return randomBytes(32).toString("hex");
3612
+ }
3613
+ function runCapture(cmd, cwd) {
3614
+ return execSync(cmd, { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }).trim();
3615
+ }
3616
+ async function* deployForTui() {
3617
+ yield { message: "Checking prerequisites..." };
3618
+ try {
3619
+ runCapture("wrangler --version");
3620
+ } catch {
3621
+ yield { message: "wrangler not found. Install: npm install -g wrangler", error: true };
3622
+ yield { message: "Then run: wrangler login", error: true };
3623
+ throw new Error("wrangler not installed");
3624
+ }
3625
+ yield { message: "wrangler OK" };
3626
+ try {
3627
+ runCapture("wrangler whoami");
3628
+ } catch {
3629
+ yield { message: "wrangler not authenticated. Run: wrangler login", error: true };
3630
+ throw new Error("wrangler not authenticated");
3631
+ }
3632
+ yield { message: "wrangler authenticated" };
3633
+ try {
3634
+ runCapture("docker --version");
3635
+ } catch {
3636
+ yield { message: "Docker not found. Install: https://docs.docker.com/get-docker/", error: true };
3637
+ throw new Error("docker not installed");
3638
+ }
3639
+ yield { message: "Docker OK" };
3640
+ yield { message: "Building remote agent bundle..." };
3641
+ try {
3642
+ runCapture("npm run build:remote-agent", join10(REMOTE_DIR, ".."));
3643
+ yield { message: "Agent bundle built" };
3644
+ } catch (err) {
3645
+ yield { message: `Build failed: ${err instanceof Error ? err.message : String(err)}`, error: true };
3646
+ throw err;
3647
+ }
3648
+ yield { message: "Deploying Worker to Cloudflare..." };
3649
+ try {
3650
+ runCapture("wrangler deploy", WORKER_DIR);
3651
+ yield { message: "Worker deployed" };
3652
+ } catch (err) {
3653
+ yield { message: `Deploy failed: ${err instanceof Error ? err.message : String(err)}`, error: true };
3654
+ throw err;
3655
+ }
3656
+ let workerUrl;
3657
+ try {
3658
+ const info = runCapture("wrangler info", WORKER_DIR);
3659
+ const match = info.match(/https:\/\/[^\s]+\.workers\.dev/);
3660
+ if (match) workerUrl = match[0];
3661
+ } catch {
3662
+ }
3663
+ if (!workerUrl) {
3664
+ yield { message: "Could not auto-detect Worker URL", error: true };
3665
+ throw new Error("Worker URL not found");
3666
+ }
3667
+ yield { message: `Worker URL: ${workerUrl}` };
3668
+ const authSecret = generateSecret();
3669
+ const cfg = await loadConfig();
3670
+ const cfToken = process.env.CF_API_TOKEN ?? cfg?.apiToken;
3671
+ if (!cfToken) {
3672
+ yield { message: "CF_API_TOKEN not found. Set CF_API_TOKEN env var or apiToken in config", error: true };
3673
+ throw new Error("CF_API_TOKEN missing");
3674
+ }
3675
+ yield { message: "Setting Worker secrets..." };
3676
+ try {
3677
+ execSync(`wrangler secret put REMOTE_AUTH_SECRET`, {
3678
+ cwd: WORKER_DIR,
3679
+ input: authSecret,
3680
+ stdio: ["pipe", "pipe", "pipe"]
3681
+ });
3682
+ execSync(`wrangler secret put CF_API_TOKEN`, {
3683
+ cwd: WORKER_DIR,
3684
+ input: cfToken,
3685
+ stdio: ["pipe", "pipe", "pipe"]
3686
+ });
3687
+ yield { message: "Secrets set" };
3688
+ } catch (err) {
3689
+ yield { message: `Secret setup failed: ${err instanceof Error ? err.message : String(err)}`, error: true };
3690
+ throw err;
3691
+ }
3692
+ const imageTag = "ghcr.io/sinameraji/kimiflare-remote-agent:latest";
3693
+ yield { message: "Building container image..." };
3694
+ try {
3695
+ runCapture(`docker build -t ${imageTag} .`, REMOTE_DIR);
3696
+ yield { message: "Image built" };
3697
+ } catch (err) {
3698
+ yield { message: `Image build failed: ${err instanceof Error ? err.message : String(err)}`, error: true };
3699
+ throw err;
3700
+ }
3701
+ yield { message: `Pushing ${imageTag}...` };
3702
+ try {
3703
+ runCapture(`docker push ${imageTag}`, REMOTE_DIR);
3704
+ yield { message: "Image pushed" };
3705
+ } catch (err) {
3706
+ yield { message: `Push failed: ${err instanceof Error ? err.message : String(err)}`, error: true };
3707
+ yield { message: "Make sure you're logged into ghcr.io: docker login ghcr.io -u USERNAME -p GITHUB_TOKEN", error: true };
3708
+ throw err;
3709
+ }
3710
+ const nextCfg = {
3711
+ ...cfg ?? { accountId: "", apiToken: "", model: "@cf/moonshotai/kimi-k2.6" },
3712
+ remoteWorkerUrl: workerUrl,
3713
+ remoteAuthSecret: authSecret
3714
+ };
3715
+ await saveConfig(nextCfg);
3716
+ yield { message: "Config saved" };
3717
+ yield { message: "Remote infrastructure ready!", done: true };
3718
+ return { workerUrl, authSecret };
3719
+ }
3720
+ async function runDeploy() {
3721
+ console.log("kimiflare remote deploy\n");
3722
+ try {
3723
+ for await (const step of deployForTui()) {
3724
+ console.log(step.message);
3725
+ if (step.done) break;
3726
+ if (step.error) process.exit(1);
3727
+ }
3728
+ console.log("\nDeploy complete!");
3729
+ } catch (err) {
3730
+ console.error(`Deploy failed: ${err instanceof Error ? err.message : String(err)}`);
3731
+ process.exit(1);
3732
+ }
3733
+ }
3734
+ async function checkDeployStatus() {
3735
+ let wrangler = false;
3736
+ let wranglerAuth = false;
3737
+ let docker = false;
3738
+ let workerUrl;
3739
+ try {
3740
+ execSync("wrangler --version", { stdio: "pipe" });
3741
+ wrangler = true;
3742
+ } catch {
3743
+ }
3744
+ if (wrangler) {
3745
+ try {
3746
+ execSync("wrangler whoami", { stdio: "pipe" });
3747
+ wranglerAuth = true;
3748
+ } catch {
3749
+ }
3750
+ }
3751
+ try {
3752
+ execSync("docker --version", { stdio: "pipe" });
3753
+ docker = true;
3754
+ } catch {
3755
+ }
3756
+ const cfg = await loadConfig();
3757
+ if (cfg?.remoteWorkerUrl) {
3758
+ try {
3759
+ const res = await fetch(`${cfg.remoteWorkerUrl}/health`, { signal: AbortSignal.timeout(5e3) });
3760
+ if (res.ok) workerUrl = cfg.remoteWorkerUrl;
3761
+ } catch {
3762
+ }
3763
+ }
3764
+ return { wrangler, wranglerAuth, docker, workerUrl };
3765
+ }
3766
+ var __dirname, REMOTE_DIR, WORKER_DIR;
3767
+ var init_deploy = __esm({
3768
+ "src/remote/deploy.ts"() {
3769
+ "use strict";
3770
+ init_config();
3771
+ __dirname = dirname5(fileURLToPath3(import.meta.url));
3772
+ REMOTE_DIR = join10(__dirname, "..", "..", "..", "remote");
3773
+ WORKER_DIR = join10(REMOTE_DIR, "worker");
3774
+ }
3775
+ });
3776
+
3390
3777
  // src/cost-attribution/types.ts
3391
3778
  var ALL_CATEGORIES;
3392
3779
  var init_types = __esm({
@@ -3806,12 +4193,12 @@ var init_heuristic = __esm({
3806
4193
  });
3807
4194
 
3808
4195
  // src/cost-attribution/classify-from-session.ts
3809
- import { readFile as readFile8 } from "fs/promises";
3810
- import { join as join9 } from "path";
3811
- import { homedir as homedir6 } from "os";
4196
+ import { readFile as readFile9 } from "fs/promises";
4197
+ import { join as join11 } from "path";
4198
+ import { homedir as homedir7 } from "os";
3812
4199
  function sessionsDir() {
3813
- const xdg = process.env.XDG_DATA_HOME || join9(homedir6(), ".local", "share");
3814
- return join9(xdg, "kimiflare", "sessions");
4200
+ const xdg = process.env.XDG_DATA_HOME || join11(homedir7(), ".local", "share");
4201
+ return join11(xdg, "kimiflare", "sessions");
3815
4202
  }
3816
4203
  function parseToolCalls(calls) {
3817
4204
  return calls.map((c) => {
@@ -3825,7 +4212,7 @@ function parseToolCalls(calls) {
3825
4212
  }
3826
4213
  async function classifyFromSessionFile(sessionId) {
3827
4214
  try {
3828
- const raw = await readFile8(join9(sessionsDir(), `${sessionId}.json`), "utf8");
4215
+ const raw = await readFile9(join11(sessionsDir(), `${sessionId}.json`), "utf8");
3829
4216
  const session = JSON.parse(raw);
3830
4217
  const messages = session.messages ?? [];
3831
4218
  const turns = [];
@@ -3858,15 +4245,15 @@ var cli_exports = {};
3858
4245
  __export(cli_exports, {
3859
4246
  runCostCommand: () => runCostCommand
3860
4247
  });
3861
- import { readFile as readFile9 } from "fs/promises";
3862
- import { join as join10 } from "path";
3863
- import { homedir as homedir7 } from "os";
4248
+ import { readFile as readFile10 } from "fs/promises";
4249
+ import { join as join12 } from "path";
4250
+ import { homedir as homedir8 } from "os";
3864
4251
  function usageDir() {
3865
- const xdg = process.env.XDG_DATA_HOME || join10(homedir7(), ".local", "share");
3866
- return join10(xdg, "kimiflare");
4252
+ const xdg = process.env.XDG_DATA_HOME || join12(homedir8(), ".local", "share");
4253
+ return join12(xdg, "kimiflare");
3867
4254
  }
3868
4255
  function usagePath() {
3869
- return join10(usageDir(), "usage.json");
4256
+ return join12(usageDir(), "usage.json");
3870
4257
  }
3871
4258
  function today() {
3872
4259
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
@@ -3878,7 +4265,7 @@ function daysAgo(n) {
3878
4265
  }
3879
4266
  async function loadLog() {
3880
4267
  try {
3881
- const raw = await readFile9(usagePath(), "utf8");
4268
+ const raw = await readFile10(usagePath(), "utf8");
3882
4269
  return JSON.parse(raw);
3883
4270
  } catch {
3884
4271
  return { version: 1, days: [], sessions: [] };
@@ -3964,6 +4351,94 @@ var init_cli = __esm({
3964
4351
  }
3965
4352
  });
3966
4353
 
4354
+ // src/remote/tui-auth.ts
4355
+ var tui_auth_exports = {};
4356
+ __export(tui_auth_exports, {
4357
+ authGitHubForTui: () => authGitHubForTui
4358
+ });
4359
+ function sleep2(ms) {
4360
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
4361
+ }
4362
+ async function* authGitHubForTui() {
4363
+ yield { message: "Starting GitHub OAuth device flow..." };
4364
+ const deviceRes = await fetch(GITHUB_DEVICE_AUTH_URL, {
4365
+ method: "POST",
4366
+ headers: {
4367
+ Accept: "application/json",
4368
+ "Content-Type": "application/x-www-form-urlencoded"
4369
+ },
4370
+ body: new URLSearchParams({ client_id: CLIENT_ID, scope: "repo" })
4371
+ });
4372
+ if (!deviceRes.ok) {
4373
+ yield { message: `Failed to request device code: ${deviceRes.status}`, error: true };
4374
+ throw new Error("Device code request failed");
4375
+ }
4376
+ const deviceData = await deviceRes.json();
4377
+ yield {
4378
+ message: `Open ${deviceData.verification_uri} and enter code: ${deviceData.user_code}`,
4379
+ url: deviceData.verification_uri,
4380
+ code: deviceData.user_code
4381
+ };
4382
+ const startTime = Date.now();
4383
+ const expiresIn = deviceData.expires_in * 1e3;
4384
+ const interval = deviceData.interval * 1e3;
4385
+ while (Date.now() - startTime < expiresIn) {
4386
+ await sleep2(interval);
4387
+ const tokenRes = await fetch(GITHUB_ACCESS_TOKEN_URL, {
4388
+ method: "POST",
4389
+ headers: {
4390
+ Accept: "application/json",
4391
+ "Content-Type": "application/x-www-form-urlencoded"
4392
+ },
4393
+ body: new URLSearchParams({
4394
+ client_id: CLIENT_ID,
4395
+ device_code: deviceData.device_code,
4396
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code"
4397
+ })
4398
+ });
4399
+ if (!tokenRes.ok) continue;
4400
+ const tokenData = await tokenRes.json();
4401
+ if (tokenData.error === "authorization_pending") {
4402
+ continue;
4403
+ }
4404
+ if (tokenData.error === "slow_down") {
4405
+ await sleep2(interval * 2);
4406
+ continue;
4407
+ }
4408
+ if (tokenData.error) {
4409
+ yield { message: `OAuth error: ${tokenData.error}`, error: true };
4410
+ throw new Error(tokenData.error);
4411
+ }
4412
+ if (tokenData.access_token) {
4413
+ const cfg = await loadConfig() ?? {
4414
+ accountId: "",
4415
+ apiToken: "",
4416
+ model: "@cf/moonshotai/kimi-k2.6"
4417
+ };
4418
+ await saveConfig({
4419
+ ...cfg,
4420
+ githubOAuthToken: tokenData.access_token,
4421
+ githubRefreshToken: tokenData.refresh_token,
4422
+ githubTokenExpiry: tokenData.expires_in ? Date.now() + tokenData.expires_in * 1e3 : void 0
4423
+ });
4424
+ yield { message: "GitHub authentication successful!", done: true };
4425
+ return;
4426
+ }
4427
+ }
4428
+ yield { message: "Device flow expired. Please try again.", error: true };
4429
+ throw new Error("Device flow expired");
4430
+ }
4431
+ var GITHUB_DEVICE_AUTH_URL, GITHUB_ACCESS_TOKEN_URL, CLIENT_ID;
4432
+ var init_tui_auth = __esm({
4433
+ "src/remote/tui-auth.ts"() {
4434
+ "use strict";
4435
+ init_config();
4436
+ GITHUB_DEVICE_AUTH_URL = "https://github.com/login/device/code";
4437
+ GITHUB_ACCESS_TOKEN_URL = "https://github.com/login/oauth/access_token";
4438
+ CLIENT_ID = process.env.KIMIFLARE_GITHUB_CLIENT_ID ?? "Ov23liM7lJX1xE2V1sVK";
4439
+ }
4440
+ });
4441
+
3967
4442
  // src/agent/compact.ts
3968
4443
  function indexOfNthUserFromEnd(messages, n) {
3969
4444
  let seen = 0;
@@ -4785,12 +5260,12 @@ var init_connection = __esm({
4785
5260
  });
4786
5261
 
4787
5262
  // src/lsp/protocol.ts
4788
- import { pathToFileURL, fileURLToPath as fileURLToPath3 } from "url";
5263
+ import { pathToFileURL, fileURLToPath as fileURLToPath4 } from "url";
4789
5264
  function toUri(path) {
4790
5265
  return pathToFileURL(path).href;
4791
5266
  }
4792
5267
  function fromUri(uri) {
4793
- return fileURLToPath3(uri);
5268
+ return fileURLToPath4(uri);
4794
5269
  }
4795
5270
  function symbolKindName(kind) {
4796
5271
  const names = {
@@ -7413,7 +7888,7 @@ var init_help_menu = __esm({
7413
7888
  commands: [
7414
7889
  { command: "/init", description: "scan this repo and write a KIMI.md" },
7415
7890
  { command: "/logout", description: "clear credentials" },
7416
- { command: "filePicker", description: "enable with KIMIFLARE_FILE_PICKER=1 or filePicker: true in config", selectable: false }
7891
+ { command: "filePicker", description: "enabled by default; disable with KIMIFLARE_FILE_PICKER=0 or filePicker: false in config", selectable: false }
7417
7892
  ]
7418
7893
  }
7419
7894
  ];
@@ -7425,96 +7900,446 @@ var init_help_menu = __esm({
7425
7900
  }
7426
7901
  });
7427
7902
 
7428
- // src/sessions.ts
7429
- var sessions_exports = {};
7430
- __export(sessions_exports, {
7431
- listSessions: () => listSessions,
7432
- loadSession: () => loadSession,
7433
- makeSessionId: () => makeSessionId,
7434
- pruneSessions: () => pruneSessions,
7435
- saveSession: () => saveSession
7903
+ // src/remote/worker-client.ts
7904
+ var worker_client_exports = {};
7905
+ __export(worker_client_exports, {
7906
+ cancelRemoteSession: () => cancelRemoteSession,
7907
+ getRemoteStatus: () => getRemoteStatus,
7908
+ startRemoteSession: () => startRemoteSession,
7909
+ streamRemoteProgress: () => streamRemoteProgress
7436
7910
  });
7437
- import { readFile as readFile10, writeFile as writeFile6, mkdir as mkdir6, readdir as readdir2, stat as stat3 } from "fs/promises";
7438
- import { homedir as homedir8 } from "os";
7439
- import { join as join11 } from "path";
7440
- function sessionsDir2() {
7441
- const xdg = process.env.XDG_DATA_HOME || join11(homedir8(), ".local", "share");
7442
- return join11(xdg, "kimiflare", "sessions");
7443
- }
7444
- function sanitize(text) {
7445
- return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
7446
- }
7447
- function makeSessionId(firstPrompt) {
7448
- const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
7449
- const slug = sanitize(firstPrompt) || "session";
7450
- return `${ts}_${slug}`;
7451
- }
7452
- async function saveSession(file) {
7453
- const dir = sessionsDir2();
7454
- await mkdir6(dir, { recursive: true });
7455
- const path = join11(dir, `${file.id}.json`);
7456
- await writeFile6(path, JSON.stringify(file, null, 2), "utf8");
7457
- return path;
7458
- }
7459
- async function pruneSessions() {
7460
- const dir = sessionsDir2();
7461
- const files = await listFilesByMtime(dir, /\.json$/);
7462
- return pruneFiles(files, RETENTION.sessionMaxAgeDays, RETENTION.sessionMaxCount);
7911
+ async function startRemoteSession(opts2) {
7912
+ const workerUrl = opts2.cfg.remoteWorkerUrl;
7913
+ if (!workerUrl) {
7914
+ throw new Error("Remote worker URL not configured. Set remoteWorkerUrl in config.");
7915
+ }
7916
+ const githubToken = opts2.cfg.githubOAuthToken;
7917
+ if (!githubToken) {
7918
+ throw new Error("GitHub token not found. Run `kimiflare auth github` first.");
7919
+ }
7920
+ const res = await fetch(`${workerUrl}/remote/start`, {
7921
+ method: "POST",
7922
+ headers: {
7923
+ "Content-Type": "application/json",
7924
+ Authorization: `Bearer ${opts2.cfg.remoteAuthSecret ?? ""}`
7925
+ },
7926
+ body: JSON.stringify({
7927
+ prompt: opts2.prompt,
7928
+ repo: opts2.repo,
7929
+ githubToken,
7930
+ accountId: opts2.cfg.accountId,
7931
+ apiToken: opts2.cfg.apiToken,
7932
+ model: opts2.cfg.model,
7933
+ reasoningEffort: opts2.cfg.reasoningEffort,
7934
+ ttlMinutes: opts2.ttlMinutes ?? opts2.cfg.remoteTtlMinutes,
7935
+ tokensBudget: opts2.tokensBudget ?? opts2.cfg.remoteMaxInputTokens
7936
+ })
7937
+ });
7938
+ if (!res.ok) {
7939
+ const text = await res.text();
7940
+ throw new Error(`Failed to start remote session: ${res.status} ${text}`);
7941
+ }
7942
+ const data = await res.json();
7943
+ await saveRemoteSession({
7944
+ sessionId: data.sessionId,
7945
+ prompt: opts2.prompt,
7946
+ repo: `${opts2.repo.owner}/${opts2.repo.name}`,
7947
+ workerUrl,
7948
+ status: "running",
7949
+ branch: `kimiflare/remote/${data.sessionId}`,
7950
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
7951
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
7952
+ });
7953
+ return data;
7463
7954
  }
7464
- async function listSessions(limit = 30) {
7465
- const dir = sessionsDir2();
7466
- let entries;
7467
- try {
7468
- entries = await readdir2(dir);
7469
- } catch {
7470
- return [];
7955
+ async function* streamRemoteProgress(workerUrl, sessionId, signal) {
7956
+ const res = await fetch(`${workerUrl}/remote/stream/${sessionId}`, { signal });
7957
+ if (!res.ok) {
7958
+ throw new Error(`Failed to connect to stream: ${res.status}`);
7471
7959
  }
7472
- const summaries = [];
7473
- for (const name of entries) {
7474
- if (!name.endsWith(".json")) continue;
7475
- const path = join11(dir, name);
7960
+ if (!res.body) {
7961
+ throw new Error("No response body");
7962
+ }
7963
+ for await (const line of readSSE(res.body, signal)) {
7476
7964
  try {
7477
- const [s, raw] = await Promise.all([stat3(path), readFile10(path, "utf8")]);
7478
- const parsed = JSON.parse(raw);
7479
- const firstUser = parsed.messages.find((m) => m.role === "user");
7480
- const firstPrompt = typeof firstUser?.content === "string" ? firstUser.content : firstUser?.content ? firstUser.content.find((p) => p.type === "text")?.text ?? "(no prompt)" : "(no prompt)";
7481
- summaries.push({
7482
- id: parsed.id,
7483
- filePath: path,
7484
- cwd: parsed.cwd,
7485
- firstPrompt: firstPrompt.slice(0, 80),
7486
- messageCount: parsed.messages.filter((m) => m.role !== "system").length,
7487
- updatedAt: parsed.updatedAt ?? s.mtime.toISOString()
7488
- });
7965
+ yield JSON.parse(line);
7489
7966
  } catch {
7490
7967
  }
7491
7968
  }
7492
- summaries.sort((a, b) => b.updatedAt < a.updatedAt ? -1 : 1);
7493
- return summaries.slice(0, limit);
7494
7969
  }
7495
- async function loadSession(filePath) {
7496
- const raw = await readFile10(filePath, "utf8");
7497
- return JSON.parse(raw);
7970
+ async function getRemoteStatus(workerUrl, sessionId, authSecret) {
7971
+ const res = await fetch(`${workerUrl}/remote/status/${sessionId}`, {
7972
+ headers: authSecret ? { Authorization: `Bearer ${authSecret}` } : {}
7973
+ });
7974
+ if (!res.ok) {
7975
+ const text = await res.text();
7976
+ throw new Error(`Failed to get status: ${res.status} ${text}`);
7977
+ }
7978
+ return res.json();
7498
7979
  }
7499
- var init_sessions = __esm({
7500
- "src/sessions.ts"() {
7980
+ async function cancelRemoteSession(workerUrl, sessionId, authSecret) {
7981
+ const res = await fetch(`${workerUrl}/remote/cancel/${sessionId}`, {
7982
+ method: "POST",
7983
+ headers: authSecret ? { Authorization: `Bearer ${authSecret}` } : {}
7984
+ });
7985
+ if (!res.ok) {
7986
+ const text = await res.text();
7987
+ throw new Error(`Failed to cancel session: ${res.status} ${text}`);
7988
+ }
7989
+ }
7990
+ var init_worker_client = __esm({
7991
+ "src/remote/worker-client.ts"() {
7501
7992
  "use strict";
7502
- init_storage_limits();
7993
+ init_session_store();
7994
+ init_sse();
7503
7995
  }
7504
7996
  });
7505
7997
 
7506
- // src/util/image.ts
7507
- import { readFile as readFile11 } from "fs/promises";
7508
- import { basename as basename3 } from "path";
7509
- async function encodeImageFile(filePath) {
7510
- const buf = await readFile11(filePath);
7511
- if (buf.byteLength > MAX_IMAGE_BYTES) {
7512
- throw new Error(
7513
- `image too large (${(buf.byteLength / 1024 / 1024).toFixed(1)} MB); max is ${MAX_IMAGE_BYTES / 1024 / 1024} MB`
7514
- );
7998
+ // src/remote/tui-deploy.ts
7999
+ var init_tui_deploy = __esm({
8000
+ "src/remote/tui-deploy.ts"() {
8001
+ "use strict";
8002
+ init_deploy();
7515
8003
  }
7516
- const ext = filePath.slice(filePath.lastIndexOf(".")).toLowerCase();
7517
- const mime = EXT_TO_MIME[ext] ?? "image/jpeg";
8004
+ });
8005
+
8006
+ // src/ui/remote-dashboard.tsx
8007
+ import { useEffect as useEffect4, useState as useState7 } from "react";
8008
+ import { Box as Box12, Text as Text13, useInput as useInput3 } from "ink";
8009
+ import SelectInput4 from "ink-select-input";
8010
+ import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
8011
+ function RemoteDashboard({ onSelect, onCancel }) {
8012
+ const theme = useTheme();
8013
+ const [sessions, setSessions] = useState7([]);
8014
+ const [loading, setLoading] = useState7(true);
8015
+ const [error, setError] = useState7(null);
8016
+ const [refreshing, setRefreshing] = useState7(false);
8017
+ useEffect4(() => {
8018
+ loadSessions();
8019
+ }, []);
8020
+ async function loadSessions() {
8021
+ try {
8022
+ setRefreshing(true);
8023
+ const list = await listRemoteSessions();
8024
+ const updated = await Promise.all(
8025
+ list.map(async (s) => {
8026
+ if (s.status === "running" || s.status === "pending") {
8027
+ try {
8028
+ const status = await getRemoteStatus(s.workerUrl, s.sessionId);
8029
+ return {
8030
+ ...s,
8031
+ status: status.status,
8032
+ prUrl: status.prUrl ?? s.prUrl,
8033
+ tokensUsed: status.tokensUsed ?? s.tokensUsed,
8034
+ tokensBudget: status.tokensBudget ?? s.tokensBudget,
8035
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
8036
+ };
8037
+ } catch {
8038
+ return s;
8039
+ }
8040
+ }
8041
+ return s;
8042
+ })
8043
+ );
8044
+ setSessions(updated.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()));
8045
+ setError(null);
8046
+ } catch (err) {
8047
+ setError(err instanceof Error ? err.message : String(err));
8048
+ } finally {
8049
+ setLoading(false);
8050
+ setRefreshing(false);
8051
+ }
8052
+ }
8053
+ useInput3((input, key) => {
8054
+ if (input === "r" || input === "R") {
8055
+ void loadSessions();
8056
+ }
8057
+ if (key.escape && onCancel) {
8058
+ onCancel();
8059
+ }
8060
+ });
8061
+ const items = sessions.map((s) => ({
8062
+ label: formatSessionLine(s),
8063
+ value: s.sessionId
8064
+ }));
8065
+ if (loading) {
8066
+ return /* @__PURE__ */ jsx14(Box12, { flexDirection: "column", padding: 1, children: /* @__PURE__ */ jsx14(Text13, { color: theme.accent, children: "Loading remote sessions..." }) });
8067
+ }
8068
+ if (error) {
8069
+ return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", padding: 1, children: [
8070
+ /* @__PURE__ */ jsxs12(Text13, { color: theme.error, children: [
8071
+ "Error: ",
8072
+ error
8073
+ ] }),
8074
+ /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "Press R to retry, Esc to close" })
8075
+ ] });
8076
+ }
8077
+ if (sessions.length === 0) {
8078
+ return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", padding: 1, children: [
8079
+ /* @__PURE__ */ jsx14(Text13, { color: theme.accent, children: "No remote sessions yet." }),
8080
+ /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "Type /remote <prompt> to start one." }),
8081
+ /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "Press Esc to close" })
8082
+ ] });
8083
+ }
8084
+ return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", padding: 1, children: [
8085
+ /* @__PURE__ */ jsxs12(Text13, { bold: true, color: theme.accent, children: [
8086
+ "Recent remote tasks ",
8087
+ refreshing ? "(refreshing...)" : ""
8088
+ ] }),
8089
+ /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(
8090
+ SelectInput4,
8091
+ {
8092
+ items,
8093
+ onSelect: (item) => {
8094
+ const session = sessions.find((s) => s.sessionId === item.value);
8095
+ if (session) onSelect?.(session);
8096
+ }
8097
+ }
8098
+ ) }),
8099
+ /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "\u2191\u2193 navigate \u2022 Enter select \u2022 R refresh \u2022 Esc close" }) })
8100
+ ] });
8101
+ }
8102
+ function formatSessionLine(s) {
8103
+ const icon = s.status === "done" ? "\u2705" : s.status === "error" ? "\u274C" : s.status === "cancelled" ? "\u23F9\uFE0F" : s.status === "running" ? "\u23F3" : "\u23F8";
8104
+ const ago = formatAgo(new Date(s.updatedAt));
8105
+ const prompt = s.prompt.slice(0, 30) + (s.prompt.length > 30 ? "\u2026" : "");
8106
+ const outcome = s.prUrl ? `PR ${s.prUrl.split("/").pop()}` : s.status;
8107
+ const cost = s.tokensUsed && s.tokensBudget ? ` (${formatTokens2(s.tokensUsed)}/${formatTokens2(s.tokensBudget)})` : s.tokensUsed ? ` (${formatTokens2(s.tokensUsed)})` : "";
8108
+ return `${icon} ${prompt} \u2192 ${outcome} ${ago}${cost}`;
8109
+ }
8110
+ function formatAgo(date) {
8111
+ const ms = Date.now() - date.getTime();
8112
+ const minutes = Math.floor(ms / 6e4);
8113
+ const hours = Math.floor(minutes / 60);
8114
+ const days = Math.floor(hours / 24);
8115
+ if (days > 0) return `${days}d ago`;
8116
+ if (hours > 0) return `${hours}h ago`;
8117
+ if (minutes > 0) return `${minutes}m ago`;
8118
+ return "just now";
8119
+ }
8120
+ function formatTokens2(n) {
8121
+ if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
8122
+ if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
8123
+ return String(n);
8124
+ }
8125
+ function RemoteSessionDetail({
8126
+ session,
8127
+ onBack,
8128
+ onCancel
8129
+ }) {
8130
+ const theme = useTheme();
8131
+ const [cancelling, setCancelling] = useState7(false);
8132
+ useInput3((input, key) => {
8133
+ if (key.escape) {
8134
+ onBack();
8135
+ }
8136
+ if ((input === "c" || input === "C") && onCancel && (session.status === "running" || session.status === "pending")) {
8137
+ void handleCancel();
8138
+ }
8139
+ });
8140
+ async function handleCancel() {
8141
+ if (!onCancel) return;
8142
+ setCancelling(true);
8143
+ try {
8144
+ await cancelRemoteSession(session.workerUrl, session.sessionId);
8145
+ onCancel(session);
8146
+ } catch {
8147
+ } finally {
8148
+ setCancelling(false);
8149
+ }
8150
+ }
8151
+ const isRunning = session.status === "running" || session.status === "pending";
8152
+ return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", padding: 1, children: [
8153
+ /* @__PURE__ */ jsx14(Text13, { bold: true, color: theme.accent, children: "Remote Session" }),
8154
+ /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "column", children: [
8155
+ /* @__PURE__ */ jsxs12(Text13, { children: [
8156
+ "ID: ",
8157
+ session.sessionId
8158
+ ] }),
8159
+ /* @__PURE__ */ jsxs12(Text13, { children: [
8160
+ "Repo: ",
8161
+ session.repo
8162
+ ] }),
8163
+ /* @__PURE__ */ jsxs12(Text13, { children: [
8164
+ "Status: ",
8165
+ session.status
8166
+ ] }),
8167
+ /* @__PURE__ */ jsxs12(Text13, { children: [
8168
+ "Prompt: ",
8169
+ session.prompt
8170
+ ] }),
8171
+ session.prUrl && /* @__PURE__ */ jsxs12(Text13, { children: [
8172
+ "PR: ",
8173
+ session.prUrl
8174
+ ] }),
8175
+ session.errorMessage && /* @__PURE__ */ jsxs12(Text13, { color: theme.error, children: [
8176
+ "Error: ",
8177
+ session.errorMessage
8178
+ ] }),
8179
+ session.tokensUsed !== void 0 && /* @__PURE__ */ jsxs12(Text13, { children: [
8180
+ "Tokens: ",
8181
+ formatTokens2(session.tokensUsed),
8182
+ session.tokensBudget ? ` / ${formatTokens2(session.tokensBudget)}` : ""
8183
+ ] }),
8184
+ /* @__PURE__ */ jsxs12(Text13, { children: [
8185
+ "Created: ",
8186
+ new Date(session.createdAt).toLocaleString()
8187
+ ] }),
8188
+ session.finishedAt && /* @__PURE__ */ jsxs12(Text13, { children: [
8189
+ "Finished: ",
8190
+ new Date(session.finishedAt).toLocaleString()
8191
+ ] })
8192
+ ] }),
8193
+ /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "row", gap: 2, children: [
8194
+ isRunning && onCancel && /* @__PURE__ */ jsx14(Text13, { color: theme.error, children: cancelling ? "Cancelling..." : "[C] Cancel session" }),
8195
+ /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "Esc back" })
8196
+ ] })
8197
+ ] });
8198
+ }
8199
+ var init_remote_dashboard = __esm({
8200
+ "src/ui/remote-dashboard.tsx"() {
8201
+ "use strict";
8202
+ init_theme_context();
8203
+ init_session_store();
8204
+ init_worker_client();
8205
+ }
8206
+ });
8207
+
8208
+ // src/intent/classify.ts
8209
+ function classifyIntent(prompt) {
8210
+ let intentScore = 0;
8211
+ let matchedIntent = "other";
8212
+ for (const [intent, pattern] of Object.entries(INTENT_PATTERNS)) {
8213
+ const matches = (prompt.match(pattern) || []).length;
8214
+ if (matches > intentScore) {
8215
+ intentScore = matches;
8216
+ matchedIntent = intent;
8217
+ }
8218
+ }
8219
+ const hasFileMentions = (prompt.match(/@\w+|\b[\w/-]+\.(ts|tsx|js|jsx|py|go|rs)\b/g) || []).length;
8220
+ const hasMutatingVerb = /\b(add|create|write|edit|delete|remove|rename|migrate|implement)\b/i.test(prompt);
8221
+ const isQuestion = prompt.trim().endsWith("?") || /\b(what|how|why|is|does|can)\b/i.test(prompt.split(" ")[0] || "");
8222
+ const rawScore = Math.min(
8223
+ 1,
8224
+ intentScore * 0.25 + (hasFileMentions > 2 ? 0.3 : hasFileMentions * 0.1) + (hasMutatingVerb ? 0.25 : 0) + (isQuestion ? 0 : 0.1)
8225
+ );
8226
+ const tier = rawScore < 0.3 ? "light" : rawScore < 0.65 ? "medium" : "heavy";
8227
+ return {
8228
+ intent: matchedIntent,
8229
+ rawScore,
8230
+ tier,
8231
+ confidence: 0.5 + (intentScore > 0 ? 0.3 : 0) + (hasFileMentions > 0 ? 0.1 : 0)
8232
+ };
8233
+ }
8234
+ var INTENT_PATTERNS;
8235
+ var init_classify = __esm({
8236
+ "src/intent/classify.ts"() {
8237
+ "use strict";
8238
+ INTENT_PATTERNS = {
8239
+ qa: /\b(what|how|why|explain|describe|what's|what is)\b/i,
8240
+ diagnose: /\b(broken|failing|error|bug|crash|why.*fail|not working)\b/i,
8241
+ verify: /\b(correct|right|verify|review|check|is this|does this)\b/i,
8242
+ polish: /\b(rename|refactor|extract|move|clean|lint|format)\b/i,
8243
+ small_edit: /\b(add|change|update|fix|remove|delete)\b.+\b(line|here|this|variable|function)\b/i,
8244
+ feature_bounded: /\b(add|implement|create|support)\b.+\b(flag|option|param|arg|field)\b/i,
8245
+ feature_exploratory: /\b(add|implement|migrate|integrate|build)\b.+\b(module|system|auth|oauth|framework|service)\b/i,
8246
+ explore: /\b(how.*work|architecture|structure|where.*used|find.*all|understand)\b/i,
8247
+ meta: /\b(plan|design|strategy|ontology|roadmap|approach)\b/i
8248
+ };
8249
+ }
8250
+ });
8251
+
8252
+ // src/sessions.ts
8253
+ var sessions_exports = {};
8254
+ __export(sessions_exports, {
8255
+ listSessions: () => listSessions,
8256
+ loadSession: () => loadSession,
8257
+ makeSessionId: () => makeSessionId,
8258
+ pruneSessions: () => pruneSessions,
8259
+ saveSession: () => saveSession
8260
+ });
8261
+ import { readFile as readFile11, writeFile as writeFile7, mkdir as mkdir7, readdir as readdir3, stat as stat4 } from "fs/promises";
8262
+ import { homedir as homedir9 } from "os";
8263
+ import { join as join13 } from "path";
8264
+ function sessionsDir2() {
8265
+ const xdg = process.env.XDG_DATA_HOME || join13(homedir9(), ".local", "share");
8266
+ return join13(xdg, "kimiflare", "sessions");
8267
+ }
8268
+ function sanitize(text) {
8269
+ return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
8270
+ }
8271
+ function makeSessionId(firstPrompt) {
8272
+ const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
8273
+ const slug = sanitize(firstPrompt) || "session";
8274
+ return `${ts}_${slug}`;
8275
+ }
8276
+ async function saveSession(file) {
8277
+ const dir = sessionsDir2();
8278
+ await mkdir7(dir, { recursive: true });
8279
+ const path = join13(dir, `${file.id}.json`);
8280
+ await writeFile7(path, JSON.stringify(file, null, 2), "utf8");
8281
+ return path;
8282
+ }
8283
+ async function pruneSessions() {
8284
+ const dir = sessionsDir2();
8285
+ const files = await listFilesByMtime(dir, /\.json$/);
8286
+ return pruneFiles(files, RETENTION.sessionMaxAgeDays, RETENTION.sessionMaxCount);
8287
+ }
8288
+ async function listSessions(limit = 30, cwd) {
8289
+ const dir = sessionsDir2();
8290
+ let entries;
8291
+ try {
8292
+ entries = await readdir3(dir);
8293
+ } catch {
8294
+ return [];
8295
+ }
8296
+ const summaries = [];
8297
+ for (const name of entries) {
8298
+ if (!name.endsWith(".json")) continue;
8299
+ const path = join13(dir, name);
8300
+ try {
8301
+ const [s, raw] = await Promise.all([stat4(path), readFile11(path, "utf8")]);
8302
+ const parsed = JSON.parse(raw);
8303
+ if (cwd && parsed.cwd !== cwd) continue;
8304
+ const firstUser = parsed.messages.find((m) => m.role === "user");
8305
+ const firstPrompt = typeof firstUser?.content === "string" ? firstUser.content : firstUser?.content ? firstUser.content.find((p) => p.type === "text")?.text ?? "(no prompt)" : "(no prompt)";
8306
+ summaries.push({
8307
+ id: parsed.id,
8308
+ filePath: path,
8309
+ cwd: parsed.cwd,
8310
+ firstPrompt: firstPrompt.slice(0, 80),
8311
+ messageCount: parsed.messages.filter((m) => m.role !== "system").length,
8312
+ updatedAt: parsed.updatedAt ?? s.mtime.toISOString()
8313
+ });
8314
+ } catch {
8315
+ }
8316
+ }
8317
+ summaries.sort((a, b) => b.updatedAt < a.updatedAt ? -1 : 1);
8318
+ return summaries.slice(0, limit);
8319
+ }
8320
+ async function loadSession(filePath) {
8321
+ const raw = await readFile11(filePath, "utf8");
8322
+ return JSON.parse(raw);
8323
+ }
8324
+ var init_sessions = __esm({
8325
+ "src/sessions.ts"() {
8326
+ "use strict";
8327
+ init_storage_limits();
8328
+ }
8329
+ });
8330
+
8331
+ // src/util/image.ts
8332
+ import { readFile as readFile12 } from "fs/promises";
8333
+ import { basename as basename3 } from "path";
8334
+ async function encodeImageFile(filePath) {
8335
+ const buf = await readFile12(filePath);
8336
+ if (buf.byteLength > MAX_IMAGE_BYTES) {
8337
+ throw new Error(
8338
+ `image too large (${(buf.byteLength / 1024 / 1024).toFixed(1)} MB); max is ${MAX_IMAGE_BYTES / 1024 / 1024} MB`
8339
+ );
8340
+ }
8341
+ const ext = filePath.slice(filePath.lastIndexOf(".")).toLowerCase();
8342
+ const mime = EXT_TO_MIME[ext] ?? "image/jpeg";
7518
8343
  const b64 = buf.toString("base64");
7519
8344
  return {
7520
8345
  filename: basename3(filePath),
@@ -7543,15 +8368,15 @@ var init_image = __esm({
7543
8368
  });
7544
8369
 
7545
8370
  // src/usage-tracker.ts
7546
- import { readFile as readFile12, writeFile as writeFile7, mkdir as mkdir7 } from "fs/promises";
7547
- import { homedir as homedir9 } from "os";
7548
- import { join as join12 } from "path";
8371
+ import { readFile as readFile13, writeFile as writeFile8, mkdir as mkdir8 } from "fs/promises";
8372
+ import { homedir as homedir10 } from "os";
8373
+ import { join as join14 } from "path";
7549
8374
  function usageDir2() {
7550
- const xdg = process.env.XDG_DATA_HOME || join12(homedir9(), ".local", "share");
7551
- return join12(xdg, "kimiflare");
8375
+ const xdg = process.env.XDG_DATA_HOME || join14(homedir10(), ".local", "share");
8376
+ return join14(xdg, "kimiflare");
7552
8377
  }
7553
8378
  function usagePath2() {
7554
- return join12(usageDir2(), "usage.json");
8379
+ return join14(usageDir2(), "usage.json");
7555
8380
  }
7556
8381
  function today2() {
7557
8382
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
@@ -7562,7 +8387,7 @@ function cutoffDate(daysBack) {
7562
8387
  }
7563
8388
  async function loadLog2() {
7564
8389
  try {
7565
- const raw = await readFile12(usagePath2(), "utf8");
8390
+ const raw = await readFile13(usagePath2(), "utf8");
7566
8391
  const parsed = JSON.parse(raw);
7567
8392
  if (parsed.version === LOG_VERSION2) return parsed;
7568
8393
  } catch {
@@ -7570,8 +8395,8 @@ async function loadLog2() {
7570
8395
  return { version: LOG_VERSION2, days: [], sessions: [] };
7571
8396
  }
7572
8397
  async function saveLog(log) {
7573
- await mkdir7(usageDir2(), { recursive: true });
7574
- await writeFile7(usagePath2(), JSON.stringify(log, null, 2), "utf8");
8398
+ await mkdir8(usageDir2(), { recursive: true });
8399
+ await writeFile8(usagePath2(), JSON.stringify(log, null, 2), "utf8");
7575
8400
  }
7576
8401
  function getOrCreateDay(log, date) {
7577
8402
  let day = log.days.find((d) => d.date === date);
@@ -7777,7 +8602,7 @@ __export(db_exports, {
7777
8602
  updateMemoryEmbedding: () => updateMemoryEmbedding
7778
8603
  });
7779
8604
  import Database from "better-sqlite3";
7780
- import { dirname as dirname5 } from "path";
8605
+ import { dirname as dirname6 } from "path";
7781
8606
  import { mkdirSync, statSync as statSync2 } from "fs";
7782
8607
  function initSchema(db) {
7783
8608
  db.exec(`
@@ -7862,7 +8687,7 @@ function openMemoryDb(dbPath) {
7862
8687
  if (dbInstance) {
7863
8688
  dbInstance.close();
7864
8689
  }
7865
- mkdirSync(dirname5(dbPath), { recursive: true });
8690
+ mkdirSync(dirname6(dbPath), { recursive: true });
7866
8691
  dbInstance = new Database(dbPath);
7867
8692
  dbInstance.pragma("journal_mode = WAL");
7868
8693
  dbInstance.pragma("foreign_keys = ON");
@@ -8156,7 +8981,7 @@ function truncateForEmbedding(text) {
8156
8981
  if (text.length <= MAX_EMBED_CHARS) return text;
8157
8982
  return text.slice(0, MAX_EMBED_CHARS);
8158
8983
  }
8159
- async function sleep2(ms) {
8984
+ async function sleep3(ms) {
8160
8985
  return new Promise((resolve2) => setTimeout(resolve2, ms));
8161
8986
  }
8162
8987
  async function fetchWithRetry(url, init, retries = 3) {
@@ -8167,7 +8992,7 @@ async function fetchWithRetry(url, init, retries = 3) {
8167
8992
  if (res.ok) return res;
8168
8993
  if (res.status === 429 || res.status >= 500) {
8169
8994
  const delay = 1e3 * 2 ** i;
8170
- await sleep2(delay);
8995
+ await sleep3(delay);
8171
8996
  continue;
8172
8997
  }
8173
8998
  const errText = await res.text().catch(() => "unknown error");
@@ -8175,7 +9000,7 @@ async function fetchWithRetry(url, init, retries = 3) {
8175
9000
  } catch (e) {
8176
9001
  lastError = e;
8177
9002
  if (i < retries - 1) {
8178
- await sleep2(1e3 * 2 ** i);
9003
+ await sleep3(1e3 * 2 ** i);
8179
9004
  }
8180
9005
  }
8181
9006
  }
@@ -8789,16 +9614,16 @@ Context: This memory was explicitly provided by the user during a conversation.`
8789
9614
  });
8790
9615
 
8791
9616
  // src/util/state.ts
8792
- import { readFile as readFile13, writeFile as writeFile8, mkdir as mkdir8 } from "fs/promises";
8793
- import { homedir as homedir10 } from "os";
8794
- import { join as join14 } from "path";
9617
+ import { readFile as readFile14, writeFile as writeFile9, mkdir as mkdir9 } from "fs/promises";
9618
+ import { homedir as homedir11 } from "os";
9619
+ import { join as join16 } from "path";
8795
9620
  function statePath() {
8796
- const xdg = process.env.XDG_CONFIG_HOME || join14(homedir10(), ".config");
8797
- return join14(xdg, "kimiflare", "state.json");
9621
+ const xdg = process.env.XDG_CONFIG_HOME || join16(homedir11(), ".config");
9622
+ return join16(xdg, "kimiflare", "state.json");
8798
9623
  }
8799
9624
  async function readState() {
8800
9625
  try {
8801
- const raw = await readFile13(statePath(), "utf8");
9626
+ const raw = await readFile14(statePath(), "utf8");
8802
9627
  return JSON.parse(raw);
8803
9628
  } catch {
8804
9629
  return {};
@@ -8806,8 +9631,8 @@ async function readState() {
8806
9631
  }
8807
9632
  async function writeState(state) {
8808
9633
  const path = statePath();
8809
- await mkdir8(join14(path, ".."), { recursive: true });
8810
- await writeFile8(path, JSON.stringify(state, null, 2) + "\n", "utf8");
9634
+ await mkdir9(join16(path, ".."), { recursive: true });
9635
+ await writeFile9(path, JSON.stringify(state, null, 2) + "\n", "utf8");
8811
9636
  }
8812
9637
  async function markCreatorMessageSeen(version) {
8813
9638
  const state = await readState();
@@ -8880,15 +9705,15 @@ var init_frontmatter = __esm({
8880
9705
 
8881
9706
  // src/commands/loader.ts
8882
9707
  import { open, realpath } from "fs/promises";
8883
- import { homedir as homedir11 } from "os";
8884
- import { join as join15, relative as relative4, sep as sep2 } from "path";
9708
+ import { homedir as homedir12 } from "os";
9709
+ import { join as join17, relative as relative4, sep as sep2 } from "path";
8885
9710
  import fg3 from "fast-glob";
8886
9711
  function projectCommandsDir(cwd = process.cwd()) {
8887
- return join15(cwd, ".kimiflare", "commands");
9712
+ return join17(cwd, ".kimiflare", "commands");
8888
9713
  }
8889
9714
  function globalCommandsDir() {
8890
- const xdg = process.env.XDG_CONFIG_HOME || join15(homedir11(), ".config");
8891
- return join15(xdg, "kimiflare", "commands");
9715
+ const xdg = process.env.XDG_CONFIG_HOME || join17(homedir12(), ".config");
9716
+ return join17(xdg, "kimiflare", "commands");
8892
9717
  }
8893
9718
  async function loadCustomCommands(cwd = process.cwd()) {
8894
9719
  const warnings = [];
@@ -9250,6 +10075,7 @@ var init_builtins = __esm({
9250
10075
  { name: "compact", description: "Summarize old turns to free context", source: "builtin" },
9251
10076
  { name: "clear", description: "Clear current conversation", source: "builtin" },
9252
10077
  { name: "init", description: "Scan repo and write KIMI.md", source: "builtin" },
10078
+ { name: "remote", argHint: "<prompt>", description: "Run a remote session on Cloudflare", source: "builtin" },
9253
10079
  { name: "update", description: "Check for updates", source: "builtin" },
9254
10080
  { name: "hello", description: "Send a voice note to the creator", source: "builtin" },
9255
10081
  { name: "logout", description: "Clear stored credentials", source: "builtin" },
@@ -9263,8 +10089,8 @@ var init_builtins = __esm({
9263
10089
  });
9264
10090
 
9265
10091
  // src/commands/save.ts
9266
- import { mkdir as mkdir9, writeFile as writeFile9, unlink as unlink2 } from "fs/promises";
9267
- import { dirname as dirname6 } from "path";
10092
+ import { mkdir as mkdir10, writeFile as writeFile10, unlink as unlink2 } from "fs/promises";
10093
+ import { dirname as dirname7 } from "path";
9268
10094
  async function saveCustomCommand(opts2) {
9269
10095
  const dir = opts2.source === "project" ? projectCommandsDir(opts2.cwd) : globalCommandsDir();
9270
10096
  const filepath = `${dir}/${opts2.name}.md`;
@@ -9275,8 +10101,8 @@ async function saveCustomCommand(opts2) {
9275
10101
  if (opts2.effort) data.effort = opts2.effort;
9276
10102
  const frontmatter = serializeFrontmatter(data);
9277
10103
  const content = frontmatter + opts2.template;
9278
- await mkdir9(dirname6(filepath), { recursive: true });
9279
- await writeFile9(filepath, content, "utf8");
10104
+ await mkdir10(dirname7(filepath), { recursive: true });
10105
+ await writeFile10(filepath, content, "utf8");
9280
10106
  return { filepath };
9281
10107
  }
9282
10108
  async function deleteCustomCommand(cmd) {
@@ -9291,21 +10117,21 @@ var init_save = __esm({
9291
10117
  });
9292
10118
 
9293
10119
  // src/ui/command-wizard.tsx
9294
- import { useState as useState7 } from "react";
9295
- import { Box as Box12, Text as Text13, useInput as useInput3, useWindowSize as useWindowSize2 } from "ink";
9296
- import SelectInput4 from "ink-select-input";
9297
- import { Fragment as Fragment2, jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
10120
+ import { useState as useState8 } from "react";
10121
+ import { Box as Box13, Text as Text14, useInput as useInput4, useWindowSize as useWindowSize2 } from "ink";
10122
+ import SelectInput5 from "ink-select-input";
10123
+ import { Fragment as Fragment2, jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
9298
10124
  function CommandWizard({ mode, initial, existingNames, builtinNames, onDone, onSave }) {
9299
10125
  const theme = useTheme();
9300
- const [step, setStep] = useState7("name");
9301
- const [name, setName] = useState7(initial?.name ?? "");
9302
- const [description, setDescription] = useState7(initial?.description ?? "");
9303
- const [template, setTemplate] = useState7(initial?.template ?? "");
9304
- const [cmdMode, setCmdMode] = useState7(initial?.mode);
9305
- const [cmdEffort, setCmdEffort] = useState7(initial?.effort);
9306
- const [cmdModel, setCmdModel] = useState7(initial?.model);
9307
- const [source, setSource] = useState7(initial?.source ?? "project");
9308
- const [error, setError] = useState7(null);
10126
+ const [step, setStep] = useState8("name");
10127
+ const [name, setName] = useState8(initial?.name ?? "");
10128
+ const [description, setDescription] = useState8(initial?.description ?? "");
10129
+ const [template, setTemplate] = useState8(initial?.template ?? "");
10130
+ const [cmdMode, setCmdMode] = useState8(initial?.mode);
10131
+ const [cmdEffort, setCmdEffort] = useState8(initial?.effort);
10132
+ const [cmdModel, setCmdModel] = useState8(initial?.model);
10133
+ const [source, setSource] = useState8(initial?.source ?? "project");
10134
+ const [error, setError] = useState8(null);
9309
10135
  const { columns } = useWindowSize2();
9310
10136
  const totalSteps = 5;
9311
10137
  const stepIndex = step === "name" ? 1 : step === "description" ? 2 : step === "template" ? 3 : step === "advanced" || step === "mode" || step === "effort" || step === "model" ? 4 : step === "location" ? 4 : 5;
@@ -9318,7 +10144,7 @@ function CommandWizard({ mode, initial, existingNames, builtinNames, onDone, onS
9318
10144
  if (existingNames.includes(trimmed) && !isEditingSelf(trimmed)) return `/${trimmed} already exists`;
9319
10145
  return null;
9320
10146
  };
9321
- useInput3((_input, key) => {
10147
+ useInput4((_input, key) => {
9322
10148
  if (key.escape) {
9323
10149
  onDone();
9324
10150
  }
@@ -9418,8 +10244,8 @@ ${template}`;
9418
10244
  const renderStep = () => {
9419
10245
  switch (step) {
9420
10246
  case "name":
9421
- return /* @__PURE__ */ jsxs12(Fragment2, { children: [
9422
- /* @__PURE__ */ jsxs12(Text13, { color: theme.accent, bold: true, children: [
10247
+ return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10248
+ /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
9423
10249
  mode === "create" ? "Create" : "Edit",
9424
10250
  " custom command \u2014 Name (",
9425
10251
  stepIndex,
@@ -9427,8 +10253,8 @@ ${template}`;
9427
10253
  totalSteps,
9428
10254
  ")"
9429
10255
  ] }),
9430
- error && /* @__PURE__ */ jsx14(Text13, { color: theme.error, children: error }),
9431
- /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(
10256
+ error && /* @__PURE__ */ jsx15(Text14, { color: theme.error, children: error }),
10257
+ /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
9432
10258
  CustomTextInput,
9433
10259
  {
9434
10260
  value: name,
@@ -9437,11 +10263,11 @@ ${template}`;
9437
10263
  focus: true
9438
10264
  }
9439
10265
  ) }),
9440
- /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, children: "letters, numbers, _ - / only; must start with a letter" })
10266
+ /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "letters, numbers, _ - / only; must start with a letter" })
9441
10267
  ] });
9442
10268
  case "description":
9443
- return /* @__PURE__ */ jsxs12(Fragment2, { children: [
9444
- /* @__PURE__ */ jsxs12(Text13, { color: theme.accent, bold: true, children: [
10269
+ return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10270
+ /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
9445
10271
  mode === "create" ? "Create" : "Edit",
9446
10272
  " custom command \u2014 Description (",
9447
10273
  stepIndex,
@@ -9449,7 +10275,7 @@ ${template}`;
9449
10275
  totalSteps,
9450
10276
  ")"
9451
10277
  ] }),
9452
- /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(
10278
+ /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
9453
10279
  CustomTextInput,
9454
10280
  {
9455
10281
  value: description,
@@ -9458,49 +10284,49 @@ ${template}`;
9458
10284
  focus: true
9459
10285
  }
9460
10286
  ) }),
9461
- /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, children: "Press Enter to skip" })
10287
+ /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Press Enter to skip" })
9462
10288
  ] });
9463
10289
  case "template": {
9464
- const guide = /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", paddingLeft: 1, children: [
9465
- /* @__PURE__ */ jsx14(Text13, { color: theme.accent, bold: true, children: "What is this?" }),
9466
- /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, children: "A prompt template \u2014 instructions to the AI." }),
9467
- /* @__PURE__ */ jsxs12(Text13, { color: theme.info.color, children: [
10290
+ const guide = /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", paddingLeft: 1, children: [
10291
+ /* @__PURE__ */ jsx15(Text14, { color: theme.accent, bold: true, children: "What is this?" }),
10292
+ /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "A prompt template \u2014 instructions to the AI." }),
10293
+ /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
9468
10294
  "When you type /",
9469
10295
  name || "yourcommand",
9470
10296
  " later, this gets sent to the model."
9471
10297
  ] }),
9472
- /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "column", children: [
9473
- /* @__PURE__ */ jsx14(Text13, { color: theme.accent, bold: true, children: "Variables" }),
9474
- /* @__PURE__ */ jsxs12(Text13, { color: theme.info.color, children: [
10298
+ /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "column", children: [
10299
+ /* @__PURE__ */ jsx15(Text14, { color: theme.accent, bold: true, children: "Variables" }),
10300
+ /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
9475
10301
  " ",
9476
10302
  "$1, $2 ... \u2192 arguments you type"
9477
10303
  ] }),
9478
- /* @__PURE__ */ jsxs12(Text13, { color: theme.info.color, children: [
10304
+ /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
9479
10305
  " ",
9480
10306
  "$ARGUMENTS \u2192 everything after the command"
9481
10307
  ] })
9482
10308
  ] }),
9483
- /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "column", children: [
9484
- /* @__PURE__ */ jsx14(Text13, { color: theme.accent, bold: true, children: "Dynamic inlines" }),
9485
- /* @__PURE__ */ jsxs12(Text13, { color: theme.info.color, children: [
10309
+ /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "column", children: [
10310
+ /* @__PURE__ */ jsx15(Text14, { color: theme.accent, bold: true, children: "Dynamic inlines" }),
10311
+ /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
9486
10312
  " ",
9487
10313
  "!`git diff` \u2192 shell output inlined"
9488
10314
  ] }),
9489
- /* @__PURE__ */ jsxs12(Text13, { color: theme.info.color, children: [
10315
+ /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
9490
10316
  " ",
9491
10317
  "@README.md \u2192 file contents inlined"
9492
10318
  ] })
9493
10319
  ] }),
9494
- /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "column", children: [
9495
- /* @__PURE__ */ jsx14(Text13, { color: theme.accent, bold: true, children: "Example" }),
9496
- /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, children: "Review this PR diff:" }),
9497
- /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, children: "!`git diff main...HEAD`" }),
9498
- /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, children: "Focus on: $1" })
10320
+ /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "column", children: [
10321
+ /* @__PURE__ */ jsx15(Text14, { color: theme.accent, bold: true, children: "Example" }),
10322
+ /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Review this PR diff:" }),
10323
+ /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "!`git diff main...HEAD`" }),
10324
+ /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Focus on: $1" })
9499
10325
  ] })
9500
10326
  ] });
9501
- const inputArea = /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", flexGrow: 1, children: [
9502
- error && /* @__PURE__ */ jsx14(Text13, { color: theme.error, children: error }),
9503
- /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(
10327
+ const inputArea = /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", flexGrow: 1, children: [
10328
+ error && /* @__PURE__ */ jsx15(Text14, { color: theme.error, children: error }),
10329
+ /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
9504
10330
  CustomTextInput,
9505
10331
  {
9506
10332
  value: template,
@@ -9510,13 +10336,13 @@ ${template}`;
9510
10336
  enablePaste: true
9511
10337
  }
9512
10338
  ) }),
9513
- columns < 100 && /* @__PURE__ */ jsxs12(Fragment2, { children: [
9514
- /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, children: "Paste multi-line templates with Ctrl+V." }),
9515
- /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, children: "Variables: $1 $2 ... $ARGUMENTS Shell: !`cmd` File: @path" })
10339
+ columns < 100 && /* @__PURE__ */ jsxs13(Fragment2, { children: [
10340
+ /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Paste multi-line templates with Ctrl+V." }),
10341
+ /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Variables: $1 $2 ... $ARGUMENTS Shell: !`cmd` File: @path" })
9516
10342
  ] })
9517
10343
  ] });
9518
- return /* @__PURE__ */ jsxs12(Fragment2, { children: [
9519
- /* @__PURE__ */ jsxs12(Text13, { color: theme.accent, bold: true, children: [
10344
+ return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10345
+ /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
9520
10346
  mode === "create" ? "Create" : "Edit",
9521
10347
  " custom command \u2014 Template (",
9522
10348
  stepIndex,
@@ -9524,10 +10350,10 @@ ${template}`;
9524
10350
  totalSteps,
9525
10351
  ")"
9526
10352
  ] }),
9527
- columns >= 100 ? /* @__PURE__ */ jsxs12(Box12, { flexDirection: "row", marginTop: 1, children: [
9528
- /* @__PURE__ */ jsx14(Box12, { flexDirection: "column", width: "50%", children: inputArea }),
9529
- /* @__PURE__ */ jsx14(Box12, { flexDirection: "column", width: "50%", children: guide })
9530
- ] }) : /* @__PURE__ */ jsx14(Box12, { flexDirection: "column", marginTop: 1, children: inputArea })
10353
+ columns >= 100 ? /* @__PURE__ */ jsxs13(Box13, { flexDirection: "row", marginTop: 1, children: [
10354
+ /* @__PURE__ */ jsx15(Box13, { flexDirection: "column", width: "50%", children: inputArea }),
10355
+ /* @__PURE__ */ jsx15(Box13, { flexDirection: "column", width: "50%", children: guide })
10356
+ ] }) : /* @__PURE__ */ jsx15(Box13, { flexDirection: "column", marginTop: 1, children: inputArea })
9531
10357
  ] });
9532
10358
  }
9533
10359
  case "advanced": {
@@ -9536,8 +10362,8 @@ ${template}`;
9536
10362
  { label: "Skip", value: "skip", key: "skip" },
9537
10363
  { label: "\u2190 Cancel", value: "cancel", key: "cancel" }
9538
10364
  ];
9539
- return /* @__PURE__ */ jsxs12(Fragment2, { children: [
9540
- /* @__PURE__ */ jsxs12(Text13, { color: theme.accent, bold: true, children: [
10365
+ return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10366
+ /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
9541
10367
  mode === "create" ? "Create" : "Edit",
9542
10368
  " custom command \u2014 Options (",
9543
10369
  stepIndex,
@@ -9545,8 +10371,8 @@ ${template}`;
9545
10371
  totalSteps,
9546
10372
  ")"
9547
10373
  ] }),
9548
- /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(
9549
- SelectInput4,
10374
+ /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
10375
+ SelectInput5,
9550
10376
  {
9551
10377
  items,
9552
10378
  onSelect: (item) => {
@@ -9565,17 +10391,17 @@ ${template}`;
9565
10391
  { label: cmdMode === "auto" ? "auto \xB7 current" : "auto", value: "auto", key: "auto" },
9566
10392
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
9567
10393
  ];
9568
- return /* @__PURE__ */ jsxs12(Fragment2, { children: [
9569
- /* @__PURE__ */ jsxs12(Text13, { color: theme.accent, bold: true, children: [
10394
+ return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10395
+ /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
9570
10396
  "Mode override (",
9571
10397
  stepIndex,
9572
10398
  "/",
9573
10399
  totalSteps,
9574
10400
  ")"
9575
10401
  ] }),
9576
- /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, children: "Saved to file but not yet enforced at runtime" }),
9577
- /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(
9578
- SelectInput4,
10402
+ /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Saved to file but not yet enforced at runtime" }),
10403
+ /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
10404
+ SelectInput5,
9579
10405
  {
9580
10406
  items,
9581
10407
  onSelect: (item) => {
@@ -9594,16 +10420,16 @@ ${template}`;
9594
10420
  { label: cmdEffort === "high" ? "high \xB7 current" : "high", value: "high", key: "high" },
9595
10421
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
9596
10422
  ];
9597
- return /* @__PURE__ */ jsxs12(Fragment2, { children: [
9598
- /* @__PURE__ */ jsxs12(Text13, { color: theme.accent, bold: true, children: [
10423
+ return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10424
+ /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
9599
10425
  "Reasoning effort (",
9600
10426
  stepIndex,
9601
10427
  "/",
9602
10428
  totalSteps,
9603
10429
  ")"
9604
10430
  ] }),
9605
- /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(
9606
- SelectInput4,
10431
+ /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
10432
+ SelectInput5,
9607
10433
  {
9608
10434
  items,
9609
10435
  onSelect: (item) => {
@@ -9615,15 +10441,15 @@ ${template}`;
9615
10441
  ] });
9616
10442
  }
9617
10443
  case "model":
9618
- return /* @__PURE__ */ jsxs12(Fragment2, { children: [
9619
- /* @__PURE__ */ jsxs12(Text13, { color: theme.accent, bold: true, children: [
10444
+ return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10445
+ /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
9620
10446
  "Model override (",
9621
10447
  stepIndex,
9622
10448
  "/",
9623
10449
  totalSteps,
9624
10450
  ")"
9625
10451
  ] }),
9626
- /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(
10452
+ /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
9627
10453
  CustomTextInput,
9628
10454
  {
9629
10455
  value: cmdModel ?? "",
@@ -9632,7 +10458,7 @@ ${template}`;
9632
10458
  focus: true
9633
10459
  }
9634
10460
  ) }),
9635
- /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, children: "Press Enter to skip" })
10461
+ /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Press Enter to skip" })
9636
10462
  ] });
9637
10463
  case "location": {
9638
10464
  const items = [
@@ -9640,16 +10466,16 @@ ${template}`;
9640
10466
  { label: source === "global" ? "Global \xB7 current" : "Global", value: "global", key: "global" },
9641
10467
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
9642
10468
  ];
9643
- return /* @__PURE__ */ jsxs12(Fragment2, { children: [
9644
- /* @__PURE__ */ jsxs12(Text13, { color: theme.accent, bold: true, children: [
10469
+ return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10470
+ /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
9645
10471
  "Save location (",
9646
10472
  stepIndex,
9647
10473
  "/",
9648
10474
  totalSteps,
9649
10475
  ")"
9650
10476
  ] }),
9651
- /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(
9652
- SelectInput4,
10477
+ /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
10478
+ SelectInput5,
9653
10479
  {
9654
10480
  items,
9655
10481
  onSelect: (item) => {
@@ -9658,7 +10484,7 @@ ${template}`;
9658
10484
  }
9659
10485
  }
9660
10486
  ) }),
9661
- /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, children: "Project: .kimiflare/commands/ Global: ~/.config/kimiflare/commands/" })
10487
+ /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Project: .kimiflare/commands/ Global: ~/.config/kimiflare/commands/" })
9662
10488
  ] });
9663
10489
  }
9664
10490
  case "confirm": {
@@ -9666,8 +10492,8 @@ ${template}`;
9666
10492
  { label: "Save", value: "save", key: "save" },
9667
10493
  { label: "Cancel", value: "cancel", key: "cancel" }
9668
10494
  ];
9669
- return /* @__PURE__ */ jsxs12(Fragment2, { children: [
9670
- /* @__PURE__ */ jsxs12(Text13, { color: theme.accent, bold: true, children: [
10495
+ return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10496
+ /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
9671
10497
  mode === "create" ? "Create" : "Edit",
9672
10498
  " custom command \u2014 Confirm (",
9673
10499
  stepIndex,
@@ -9675,14 +10501,14 @@ ${template}`;
9675
10501
  totalSteps,
9676
10502
  ")"
9677
10503
  ] }),
9678
- /* @__PURE__ */ jsxs12(Text13, { color: theme.info.color, children: [
10504
+ /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
9679
10505
  source === "project" ? ".kimiflare/commands/" : "~/.config/kimiflare/commands/",
9680
10506
  name,
9681
10507
  ".md"
9682
10508
  ] }),
9683
- /* @__PURE__ */ jsx14(Box12, { marginTop: 1, flexDirection: "column", children: previewContent().split("\n").map((line, i) => /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, children: line || " " }, i)) }),
9684
- /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(
9685
- SelectInput4,
10509
+ /* @__PURE__ */ jsx15(Box13, { marginTop: 1, flexDirection: "column", children: previewContent().split("\n").map((line, i) => /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: line || " " }, i)) }),
10510
+ /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
10511
+ SelectInput5,
9686
10512
  {
9687
10513
  items,
9688
10514
  onSelect: (item) => handleConfirm(item.value)
@@ -9692,7 +10518,7 @@ ${template}`;
9692
10518
  }
9693
10519
  }
9694
10520
  };
9695
- return /* @__PURE__ */ jsx14(Box12, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: renderStep() });
10521
+ return /* @__PURE__ */ jsx15(Box13, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: renderStep() });
9696
10522
  }
9697
10523
  var NAME_RE;
9698
10524
  var init_command_wizard = __esm({
@@ -9705,9 +10531,9 @@ var init_command_wizard = __esm({
9705
10531
  });
9706
10532
 
9707
10533
  // src/ui/command-picker.tsx
9708
- import { Box as Box13, Text as Text14 } from "ink";
9709
- import SelectInput5 from "ink-select-input";
9710
- import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
10534
+ import { Box as Box14, Text as Text15 } from "ink";
10535
+ import SelectInput6 from "ink-select-input";
10536
+ import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
9711
10537
  function CommandPicker({ commands, title, onPick }) {
9712
10538
  const theme = useTheme();
9713
10539
  const items = commands.map((cmd) => ({
@@ -9716,11 +10542,11 @@ function CommandPicker({ commands, title, onPick }) {
9716
10542
  key: cmd.name
9717
10543
  }));
9718
10544
  items.push({ label: "\u2190 Cancel", value: null, key: "__cancel__" });
9719
- return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
9720
- /* @__PURE__ */ jsx15(Text14, { color: theme.accent, bold: true, children: title }),
9721
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select." }),
9722
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
9723
- SelectInput5,
10545
+ return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10546
+ /* @__PURE__ */ jsx16(Text15, { color: theme.accent, bold: true, children: title }),
10547
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select." }),
10548
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
10549
+ SelectInput6,
9724
10550
  {
9725
10551
  items,
9726
10552
  onSelect: (item) => {
@@ -9742,64 +10568,64 @@ var init_command_picker = __esm({
9742
10568
  });
9743
10569
 
9744
10570
  // src/ui/command-list.tsx
9745
- import { Box as Box14, Text as Text15, useInput as useInput4 } from "ink";
9746
- import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
10571
+ import { Box as Box15, Text as Text16, useInput as useInput5 } from "ink";
10572
+ import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
9747
10573
  function CommandList({ commands, onDone }) {
9748
10574
  const theme = useTheme();
9749
- useInput4((_input, key) => {
10575
+ useInput5((_input, key) => {
9750
10576
  if (key.escape) {
9751
10577
  onDone();
9752
10578
  }
9753
10579
  });
9754
- return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
9755
- /* @__PURE__ */ jsx16(Text15, { color: theme.accent, bold: true, children: "Custom commands" }),
9756
- /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, dimColor: false, children: "Esc to close." }),
9757
- /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, flexDirection: "column", children: [
9758
- commands.length === 0 && /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "No custom commands found." }),
9759
- commands.map((cmd) => /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", marginBottom: 1, children: [
9760
- /* @__PURE__ */ jsxs14(Text15, { color: theme.accent, bold: true, children: [
10580
+ return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10581
+ /* @__PURE__ */ jsx17(Text16, { color: theme.accent, bold: true, children: "Custom commands" }),
10582
+ /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, dimColor: false, children: "Esc to close." }),
10583
+ /* @__PURE__ */ jsxs15(Box15, { marginTop: 1, flexDirection: "column", children: [
10584
+ commands.length === 0 && /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, children: "No custom commands found." }),
10585
+ commands.map((cmd) => /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", marginBottom: 1, children: [
10586
+ /* @__PURE__ */ jsxs15(Text16, { color: theme.accent, bold: true, children: [
9761
10587
  "/",
9762
10588
  cmd.name
9763
10589
  ] }),
9764
- /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
10590
+ /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
9765
10591
  " ",
9766
10592
  "source: ",
9767
10593
  cmd.source
9768
10594
  ] }),
9769
- /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
10595
+ /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
9770
10596
  " ",
9771
10597
  "path: ",
9772
10598
  cmd.filepath
9773
10599
  ] }),
9774
- cmd.description && /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
10600
+ cmd.description && /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
9775
10601
  " ",
9776
10602
  "desc: ",
9777
10603
  cmd.description
9778
10604
  ] }),
9779
- cmd.mode && /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
10605
+ cmd.mode && /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
9780
10606
  " ",
9781
10607
  "mode: ",
9782
10608
  cmd.mode
9783
10609
  ] }),
9784
- cmd.effort && /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
10610
+ cmd.effort && /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
9785
10611
  " ",
9786
10612
  "effort: ",
9787
10613
  cmd.effort
9788
10614
  ] }),
9789
- cmd.model && /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
10615
+ cmd.model && /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
9790
10616
  " ",
9791
10617
  "model: ",
9792
10618
  cmd.model
9793
10619
  ] }),
9794
- /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
10620
+ /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
9795
10621
  " ",
9796
10622
  "template:"
9797
10623
  ] }),
9798
- cmd.template.split("\n").slice(0, 5).map((line, i) => /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
10624
+ cmd.template.split("\n").slice(0, 5).map((line, i) => /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
9799
10625
  " ",
9800
10626
  line || " "
9801
10627
  ] }, i)),
9802
- cmd.template.split("\n").length > 5 && /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
10628
+ cmd.template.split("\n").length > 5 && /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
9803
10629
  " ",
9804
10630
  "..."
9805
10631
  ] })
@@ -9815,20 +10641,20 @@ var init_command_list = __esm({
9815
10641
  });
9816
10642
 
9817
10643
  // src/ui/lsp-wizard.tsx
9818
- import { useState as useState8 } from "react";
9819
- import { Box as Box15, Text as Text16 } from "ink";
9820
- import SelectInput6 from "ink-select-input";
10644
+ import { useState as useState9 } from "react";
10645
+ import { Box as Box16, Text as Text17 } from "ink";
10646
+ import SelectInput7 from "ink-select-input";
9821
10647
  import { spawn as spawn3 } from "child_process";
9822
- import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
10648
+ import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
9823
10649
  function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
9824
10650
  const theme = useTheme();
9825
- const [page, setPage] = useState8("main");
9826
- const [selectedPreset, setSelectedPreset] = useState8(null);
9827
- const [customName, setCustomName] = useState8("");
9828
- const [customCommand, setCustomCommand] = useState8("");
9829
- const [installState, setInstallState] = useState8({ status: "idle", output: "" });
9830
- const [pendingServers, setPendingServers] = useState8(null);
9831
- const [pendingEnabled, setPendingEnabled] = useState8(true);
10651
+ const [page, setPage] = useState9("main");
10652
+ const [selectedPreset, setSelectedPreset] = useState9(null);
10653
+ const [customName, setCustomName] = useState9("");
10654
+ const [customCommand, setCustomCommand] = useState9("");
10655
+ const [installState, setInstallState] = useState9({ status: "idle", output: "" });
10656
+ const [pendingServers, setPendingServers] = useState9(null);
10657
+ const [pendingEnabled, setPendingEnabled] = useState9(true);
9832
10658
  const runInstall = (command) => {
9833
10659
  setInstallState({ status: "running", output: "Installing..." });
9834
10660
  const child = spawn3("bash", ["-lc", command], {
@@ -9930,11 +10756,11 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
9930
10756
  { label: "(close)", value: "__close__", key: "__close__" }
9931
10757
  ];
9932
10758
  if (page === "main") {
9933
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
9934
- /* @__PURE__ */ jsx17(Text16, { color: theme.accent, bold: true, children: "LSP Servers" }),
9935
- /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select." }),
9936
- /* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
9937
- SelectInput6,
10759
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10760
+ /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "LSP Servers" }),
10761
+ /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select." }),
10762
+ /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
10763
+ SelectInput7,
9938
10764
  {
9939
10765
  items: mainItems,
9940
10766
  onSelect: (item) => {
@@ -9961,11 +10787,11 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
9961
10787
  }),
9962
10788
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
9963
10789
  ];
9964
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
9965
- /* @__PURE__ */ jsx17(Text16, { color: theme.accent, bold: true, children: "Add LSP Server" }),
9966
- /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, dimColor: false, children: "Select a language server to configure." }),
9967
- /* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
9968
- SelectInput6,
10790
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10791
+ /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Add LSP Server" }),
10792
+ /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Select a language server to configure." }),
10793
+ /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
10794
+ SelectInput7,
9969
10795
  {
9970
10796
  items,
9971
10797
  onSelect: (item) => {
@@ -9992,19 +10818,19 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
9992
10818
  { label: isSuccess ? "Save to config \u2713" : "Save anyway", value: "save", key: "save" },
9993
10819
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
9994
10820
  ];
9995
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
9996
- /* @__PURE__ */ jsxs15(Text16, { color: theme.accent, bold: true, children: [
10821
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10822
+ /* @__PURE__ */ jsxs16(Text17, { color: theme.accent, bold: true, children: [
9997
10823
  "Install ",
9998
10824
  selectedPreset.name
9999
10825
  ] }),
10000
- /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, dimColor: false, children: selectedPreset.installHint }),
10001
- /* @__PURE__ */ jsxs15(Box15, { marginTop: 1, flexDirection: "column", children: [
10002
- /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, dimColor: false, children: "Command:" }),
10003
- /* @__PURE__ */ jsx17(Text16, { color: theme.accent, children: selectedPreset.installCommand || "(none required)" })
10826
+ /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: selectedPreset.installHint }),
10827
+ /* @__PURE__ */ jsxs16(Box16, { marginTop: 1, flexDirection: "column", children: [
10828
+ /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Command:" }),
10829
+ /* @__PURE__ */ jsx18(Text17, { color: theme.accent, children: selectedPreset.installCommand || "(none required)" })
10004
10830
  ] }),
10005
- installState.output && /* @__PURE__ */ jsx17(Box15, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx17(Text16, { color: isSuccess ? theme.accent : theme.error, children: installState.output.slice(-500) }) }),
10006
- /* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
10007
- SelectInput6,
10831
+ installState.output && /* @__PURE__ */ jsx18(Box16, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx18(Text17, { color: isSuccess ? theme.accent : theme.error, children: installState.output.slice(-500) }) }),
10832
+ /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
10833
+ SelectInput7,
10008
10834
  {
10009
10835
  items,
10010
10836
  onSelect: (item) => {
@@ -10021,16 +10847,16 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
10021
10847
  }
10022
10848
  }
10023
10849
  ) }),
10024
- isSuccess && /* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(Text16, { color: theme.accent, children: "Server saved. Run /lsp reload to start it." }) })
10850
+ isSuccess && /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(Text17, { color: theme.accent, children: "Server saved. Run /lsp reload to start it." }) })
10025
10851
  ] });
10026
10852
  }
10027
10853
  if (page === "custom-name") {
10028
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10029
- /* @__PURE__ */ jsx17(Text16, { color: theme.accent, bold: true, children: "Custom LSP Server \u2014 Name" }),
10030
- /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, dimColor: false, children: "Enter a name for this server (e.g., my-server)." }),
10031
- /* @__PURE__ */ jsxs15(Box15, { marginTop: 1, children: [
10032
- /* @__PURE__ */ jsx17(Text16, { color: theme.accent, children: "\u203A " }),
10033
- /* @__PURE__ */ jsx17(
10854
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10855
+ /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Custom LSP Server \u2014 Name" }),
10856
+ /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Enter a name for this server (e.g., my-server)." }),
10857
+ /* @__PURE__ */ jsxs16(Box16, { marginTop: 1, children: [
10858
+ /* @__PURE__ */ jsx18(Text17, { color: theme.accent, children: "\u203A " }),
10859
+ /* @__PURE__ */ jsx18(
10034
10860
  CustomTextInput,
10035
10861
  {
10036
10862
  value: customName,
@@ -10044,8 +10870,8 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
10044
10870
  }
10045
10871
  )
10046
10872
  ] }),
10047
- /* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
10048
- SelectInput6,
10873
+ /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
10874
+ SelectInput7,
10049
10875
  {
10050
10876
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
10051
10877
  onSelect: () => setPage("add")
@@ -10054,12 +10880,12 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
10054
10880
  ] });
10055
10881
  }
10056
10882
  if (page === "custom-command") {
10057
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10058
- /* @__PURE__ */ jsx17(Text16, { color: theme.accent, bold: true, children: "Custom LSP Server \u2014 Command" }),
10059
- /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, dimColor: false, children: "Enter the command to start the server (space-separated)." }),
10060
- /* @__PURE__ */ jsxs15(Box15, { marginTop: 1, children: [
10061
- /* @__PURE__ */ jsx17(Text16, { color: theme.accent, children: "\u203A " }),
10062
- /* @__PURE__ */ jsx17(
10883
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10884
+ /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Custom LSP Server \u2014 Command" }),
10885
+ /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Enter the command to start the server (space-separated)." }),
10886
+ /* @__PURE__ */ jsxs16(Box16, { marginTop: 1, children: [
10887
+ /* @__PURE__ */ jsx18(Text17, { color: theme.accent, children: "\u203A " }),
10888
+ /* @__PURE__ */ jsx18(
10063
10889
  CustomTextInput,
10064
10890
  {
10065
10891
  value: customCommand,
@@ -10073,8 +10899,8 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
10073
10899
  }
10074
10900
  )
10075
10901
  ] }),
10076
- /* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
10077
- SelectInput6,
10902
+ /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
10903
+ SelectInput7,
10078
10904
  {
10079
10905
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
10080
10906
  onSelect: () => setPage("custom-name")
@@ -10097,11 +10923,11 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
10097
10923
  },
10098
10924
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
10099
10925
  ];
10100
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10101
- /* @__PURE__ */ jsx17(Text16, { color: theme.accent, bold: true, children: "Save LSP Config" }),
10102
- /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, dimColor: false, children: "Where should this server configuration be saved?" }),
10103
- /* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
10104
- SelectInput6,
10926
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10927
+ /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Save LSP Config" }),
10928
+ /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Where should this server configuration be saved?" }),
10929
+ /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
10930
+ SelectInput7,
10105
10931
  {
10106
10932
  items,
10107
10933
  onSelect: (item) => {
@@ -10119,11 +10945,11 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
10119
10945
  if (page === "edit") {
10120
10946
  const keys = Object.keys(servers);
10121
10947
  if (keys.length === 0) {
10122
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10123
- /* @__PURE__ */ jsx17(Text16, { color: theme.accent, bold: true, children: "Edit LSP Server" }),
10124
- /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, children: "No servers configured." }),
10125
- /* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
10126
- SelectInput6,
10948
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10949
+ /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Edit LSP Server" }),
10950
+ /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, children: "No servers configured." }),
10951
+ /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
10952
+ SelectInput7,
10127
10953
  {
10128
10954
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
10129
10955
  onSelect: () => setPage("main")
@@ -10143,11 +10969,11 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
10143
10969
  }),
10144
10970
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
10145
10971
  ];
10146
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10147
- /* @__PURE__ */ jsx17(Text16, { color: theme.accent, bold: true, children: "Edit LSP Server" }),
10148
- /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, dimColor: false, children: "Select a server to toggle enabled/disabled." }),
10149
- /* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
10150
- SelectInput6,
10972
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10973
+ /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Edit LSP Server" }),
10974
+ /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Select a server to toggle enabled/disabled." }),
10975
+ /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
10976
+ SelectInput7,
10151
10977
  {
10152
10978
  items,
10153
10979
  onSelect: (item) => {
@@ -10164,11 +10990,11 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
10164
10990
  if (page === "delete") {
10165
10991
  const keys = Object.keys(servers);
10166
10992
  if (keys.length === 0) {
10167
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10168
- /* @__PURE__ */ jsx17(Text16, { color: theme.accent, bold: true, children: "Delete LSP Server" }),
10169
- /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, children: "No servers configured." }),
10170
- /* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
10171
- SelectInput6,
10993
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10994
+ /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Delete LSP Server" }),
10995
+ /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, children: "No servers configured." }),
10996
+ /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
10997
+ SelectInput7,
10172
10998
  {
10173
10999
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
10174
11000
  onSelect: () => setPage("main")
@@ -10184,11 +11010,11 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
10184
11010
  })),
10185
11011
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
10186
11012
  ];
10187
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10188
- /* @__PURE__ */ jsx17(Text16, { color: theme.accent, bold: true, children: "Delete LSP Server" }),
10189
- /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, dimColor: false, children: "Select a server to remove from config." }),
10190
- /* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
10191
- SelectInput6,
11013
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11014
+ /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Delete LSP Server" }),
11015
+ /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Select a server to remove from config." }),
11016
+ /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
11017
+ SelectInput7,
10192
11018
  {
10193
11019
  items,
10194
11020
  onSelect: (item) => {
@@ -10204,15 +11030,15 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
10204
11030
  }
10205
11031
  if (page === "list") {
10206
11032
  const keys = Object.keys(servers);
10207
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10208
- /* @__PURE__ */ jsx17(Text16, { color: theme.accent, bold: true, children: "Configured LSP Servers" }),
10209
- keys.length === 0 ? /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, children: "No servers configured." }) : /* @__PURE__ */ jsx17(Box15, { marginTop: 1, flexDirection: "column", children: keys.map((k) => {
11033
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11034
+ /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Configured LSP Servers" }),
11035
+ 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) => {
10210
11036
  const s = servers[k];
10211
11037
  const status = s.enabled !== false ? "enabled" : "disabled";
10212
- return /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, children: ` ${k.padEnd(16)} ${status} ${s.command.join(" ")}` }, k);
11038
+ return /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, children: ` ${k.padEnd(16)} ${status} ${s.command.join(" ")}` }, k);
10213
11039
  }) }),
10214
- /* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
10215
- SelectInput6,
11040
+ /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
11041
+ SelectInput7,
10216
11042
  {
10217
11043
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
10218
11044
  onSelect: () => setPage("main")
@@ -10338,9 +11164,9 @@ var init_lsp_wizard = __esm({
10338
11164
  });
10339
11165
 
10340
11166
  // src/ui/theme-picker.tsx
10341
- import { Box as Box16, Text as Text17 } from "ink";
10342
- import SelectInput7 from "ink-select-input";
10343
- import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
11167
+ import { Box as Box17, Text as Text18 } from "ink";
11168
+ import SelectInput8 from "ink-select-input";
11169
+ import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
10344
11170
  function PaletteSwatches({ palette }) {
10345
11171
  const colors = [
10346
11172
  palette.primary,
@@ -10348,7 +11174,7 @@ function PaletteSwatches({ palette }) {
10348
11174
  palette.success,
10349
11175
  palette.error
10350
11176
  ];
10351
- return /* @__PURE__ */ jsx18(Box16, { children: colors.map((c, i) => /* @__PURE__ */ jsx18(Text17, { color: c, children: "\u2588" }, i)) });
11177
+ return /* @__PURE__ */ jsx19(Box17, { children: colors.map((c, i) => /* @__PURE__ */ jsx19(Text18, { color: c, children: "\u2588" }, i)) });
10352
11178
  }
10353
11179
  function ThemePicker({ themes, onPick, onPreview }) {
10354
11180
  const current = useTheme();
@@ -10356,10 +11182,10 @@ function ThemePicker({ themes, onPick, onPreview }) {
10356
11182
  ...themes.map((t) => ({ label: t.label, value: t.name })),
10357
11183
  { label: "< Back", value: "__back__" }
10358
11184
  ];
10359
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: current.accent, paddingX: 1, children: [
10360
- /* @__PURE__ */ jsx18(Text17, { color: current.accent, bold: true, children: "Pick a theme" }),
10361
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
10362
- SelectInput7,
11185
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: current.accent, paddingX: 1, children: [
11186
+ /* @__PURE__ */ jsx19(Text18, { color: current.accent, bold: true, children: "Pick a theme" }),
11187
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
11188
+ SelectInput8,
10363
11189
  {
10364
11190
  items,
10365
11191
  onHighlight: (item) => {
@@ -10378,9 +11204,9 @@ function ThemePicker({ themes, onPick, onPreview }) {
10378
11204
  itemComponent: ({ label, isSelected }) => {
10379
11205
  const t = themes.find((x) => x.label === label);
10380
11206
  const color = t?.accent ?? current.accent;
10381
- return /* @__PURE__ */ jsxs16(Box16, { children: [
10382
- /* @__PURE__ */ jsx18(Text17, { color, bold: isSelected, dimColor: !isSelected, children: label }),
10383
- t && /* @__PURE__ */ jsx18(Box16, { marginLeft: 1, children: /* @__PURE__ */ jsx18(PaletteSwatches, { palette: t.palette }) })
11207
+ return /* @__PURE__ */ jsxs17(Box17, { children: [
11208
+ /* @__PURE__ */ jsx19(Text18, { color, bold: isSelected, dimColor: !isSelected, children: label }),
11209
+ t && /* @__PURE__ */ jsx19(Box17, { marginLeft: 1, children: /* @__PURE__ */ jsx19(PaletteSwatches, { palette: t.palette }) })
10384
11210
  ] });
10385
11211
  }
10386
11212
  }
@@ -10524,8 +11350,8 @@ var init_lsp_nudge = __esm({
10524
11350
  });
10525
11351
 
10526
11352
  // src/ui/file-picker.tsx
10527
- import { Box as Box17, Text as Text18 } from "ink";
10528
- import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
11353
+ import { Box as Box18, Text as Text19 } from "ink";
11354
+ import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
10529
11355
  function FilePicker({ items, selectedIndex, query }) {
10530
11356
  const theme = useTheme();
10531
11357
  let startIndex = 0;
@@ -10535,12 +11361,12 @@ function FilePicker({ items, selectedIndex, query }) {
10535
11361
  const visible = items.slice(startIndex, startIndex + VISIBLE_LIMIT);
10536
11362
  const hasMoreAbove = startIndex > 0;
10537
11363
  const hasMoreBelow = items.length > startIndex + VISIBLE_LIMIT;
10538
- return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10539
- /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: query ? `Files matching "${query}"` : "Mention a file" }),
10540
- /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select, Esc to cancel." }),
10541
- /* @__PURE__ */ jsxs17(Box17, { marginTop: 1, flexDirection: "column", children: [
10542
- visible.length === 0 && /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, children: "No matches" }),
10543
- hasMoreAbove && /* @__PURE__ */ jsxs17(Text18, { color: theme.info.color, children: [
11364
+ return /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11365
+ /* @__PURE__ */ jsx20(Text19, { color: theme.accent, bold: true, children: query ? `Files matching "${query}"` : "Mention a file" }),
11366
+ /* @__PURE__ */ jsx20(Text19, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select, Esc to cancel." }),
11367
+ /* @__PURE__ */ jsxs18(Box18, { marginTop: 1, flexDirection: "column", children: [
11368
+ visible.length === 0 && /* @__PURE__ */ jsx20(Text19, { color: theme.info.color, children: "No matches" }),
11369
+ hasMoreAbove && /* @__PURE__ */ jsxs18(Text19, { color: theme.info.color, children: [
10544
11370
  "\u2026 ",
10545
11371
  startIndex,
10546
11372
  " more above"
@@ -10549,12 +11375,12 @@ function FilePicker({ items, selectedIndex, query }) {
10549
11375
  const actualIndex = startIndex + i;
10550
11376
  const isSelected = actualIndex === selectedIndex;
10551
11377
  const label = item.isDirectory ? `${item.name}/` : item.name;
10552
- return /* @__PURE__ */ jsxs17(Text18, { color: isSelected ? theme.accent : void 0, bold: isSelected, children: [
11378
+ return /* @__PURE__ */ jsxs18(Text19, { color: isSelected ? theme.accent : void 0, bold: isSelected, children: [
10553
11379
  isSelected ? "\u203A " : " ",
10554
11380
  label
10555
11381
  ] }, item.name);
10556
11382
  }),
10557
- hasMoreBelow && /* @__PURE__ */ jsxs17(Text18, { color: theme.info.color, children: [
11383
+ hasMoreBelow && /* @__PURE__ */ jsxs18(Text19, { color: theme.info.color, children: [
10558
11384
  "\u2026 ",
10559
11385
  items.length - (startIndex + VISIBLE_LIMIT),
10560
11386
  " more below"
@@ -10572,8 +11398,8 @@ var init_file_picker = __esm({
10572
11398
  });
10573
11399
 
10574
11400
  // src/ui/slash-picker.tsx
10575
- import { Box as Box18, Text as Text19 } from "ink";
10576
- import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
11401
+ import { Box as Box19, Text as Text20 } from "ink";
11402
+ import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
10577
11403
  function sourceBadge(source) {
10578
11404
  if (source === "builtin") return "";
10579
11405
  if (source === "project") return "project";
@@ -10593,12 +11419,12 @@ function SlashPicker({ items, selectedIndex, query }) {
10593
11419
  const hasMoreBelow = items.length > startIndex + VISIBLE_LIMIT2;
10594
11420
  const longestLabel = visible.reduce((m, it) => Math.max(m, commandLabel(it).length), 0);
10595
11421
  const nameColWidth = Math.max(NAME_COL_MIN_WIDTH, longestLabel + NAME_DESC_GAP);
10596
- return /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10597
- /* @__PURE__ */ jsx20(Text19, { color: theme.accent, bold: true, children: query ? `Commands matching "/${query}"` : "Slash commands" }),
10598
- /* @__PURE__ */ jsx20(Text19, { color: theme.info.color, children: "Arrow keys to navigate, Enter to select, Esc to cancel." }),
10599
- /* @__PURE__ */ jsxs18(Box18, { marginTop: 1, flexDirection: "column", children: [
10600
- visible.length === 0 && /* @__PURE__ */ jsx20(Text19, { color: theme.info.color, children: "No matches" }),
10601
- hasMoreAbove && /* @__PURE__ */ jsxs18(Text19, { color: theme.info.color, children: [
11422
+ return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11423
+ /* @__PURE__ */ jsx21(Text20, { color: theme.accent, bold: true, children: query ? `Commands matching "/${query}"` : "Slash commands" }),
11424
+ /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, children: "Arrow keys to navigate, Enter to select, Esc to cancel." }),
11425
+ /* @__PURE__ */ jsxs19(Box19, { marginTop: 1, flexDirection: "column", children: [
11426
+ visible.length === 0 && /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, children: "No matches" }),
11427
+ hasMoreAbove && /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
10602
11428
  "\u2026 ",
10603
11429
  startIndex,
10604
11430
  " more above"
@@ -10608,16 +11434,16 @@ function SlashPicker({ items, selectedIndex, query }) {
10608
11434
  const isSelected = actualIndex === selectedIndex;
10609
11435
  const nameCol = commandLabel(item).padEnd(nameColWidth);
10610
11436
  const badge = sourceBadge(item.source);
10611
- return /* @__PURE__ */ jsxs18(Text19, { color: isSelected ? theme.accent : void 0, bold: isSelected, children: [
11437
+ return /* @__PURE__ */ jsxs19(Text20, { color: isSelected ? theme.accent : void 0, bold: isSelected, children: [
10612
11438
  isSelected ? "\u203A " : " ",
10613
11439
  nameCol,
10614
- /* @__PURE__ */ jsxs18(Text19, { color: theme.info.color, children: [
11440
+ /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
10615
11441
  item.description,
10616
11442
  badge && ` [${badge}]`
10617
11443
  ] })
10618
11444
  ] }, item.name);
10619
11445
  }),
10620
- hasMoreBelow && /* @__PURE__ */ jsxs18(Text19, { color: theme.info.color, children: [
11446
+ hasMoreBelow && /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
10621
11447
  "\u2026 ",
10622
11448
  items.length - (startIndex + VISIBLE_LIMIT2),
10623
11449
  " more below"
@@ -10697,15 +11523,15 @@ var tui_report_exports = {};
10697
11523
  __export(tui_report_exports, {
10698
11524
  getCategoryReportText: () => getCategoryReportText
10699
11525
  });
10700
- import { readFile as readFile14 } from "fs/promises";
10701
- import { join as join16 } from "path";
10702
- import { homedir as homedir12 } from "os";
11526
+ import { readFile as readFile15 } from "fs/promises";
11527
+ import { join as join18 } from "path";
11528
+ import { homedir as homedir13 } from "os";
10703
11529
  function usageDir3() {
10704
- const xdg = process.env.XDG_DATA_HOME || join16(homedir12(), ".local", "share");
10705
- return join16(xdg, "kimiflare");
11530
+ const xdg = process.env.XDG_DATA_HOME || join18(homedir13(), ".local", "share");
11531
+ return join18(xdg, "kimiflare");
10706
11532
  }
10707
11533
  function usagePath3() {
10708
- return join16(usageDir3(), "usage.json");
11534
+ return join18(usageDir3(), "usage.json");
10709
11535
  }
10710
11536
  function today3() {
10711
11537
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
@@ -10717,7 +11543,7 @@ function daysAgo2(n) {
10717
11543
  }
10718
11544
  async function loadLog3() {
10719
11545
  try {
10720
- const raw = await readFile14(usagePath3(), "utf8");
11546
+ const raw = await readFile15(usagePath3(), "utf8");
10721
11547
  return JSON.parse(raw);
10722
11548
  } catch {
10723
11549
  return { version: 1, days: [], sessions: [] };
@@ -10783,17 +11609,18 @@ __export(app_exports, {
10783
11609
  shouldOpenMentionPicker: () => shouldOpenMentionPicker,
10784
11610
  shouldOpenSlashPicker: () => shouldOpenSlashPicker
10785
11611
  });
10786
- import React13, { useState as useState9, useRef as useRef3, useEffect as useEffect4, useCallback } from "react";
10787
- import { Box as Box19, Text as Text20, useApp, useInput as useInput5, render } from "ink";
10788
- import SelectInput8 from "ink-select-input";
11612
+ import React14, { useState as useState10, useRef as useRef3, useEffect as useEffect5, useCallback } from "react";
11613
+ import { Box as Box20, Text as Text21, useApp, useInput as useInput6, render } from "ink";
11614
+ import SelectInput9 from "ink-select-input";
10789
11615
  import { existsSync as existsSync2, statSync as statSync3 } from "fs";
10790
- import { join as join17 } from "path";
11616
+ import { join as join19 } from "path";
10791
11617
  import { unlink as unlink3 } from "fs/promises";
11618
+ import { execSync as execSync2 } from "child_process";
10792
11619
  import { spawn as spawn4 } from "child_process";
10793
11620
  import { platform as platform2 } from "os";
10794
11621
  import fg4 from "fast-glob";
10795
11622
  import { readFileSync as readFileSync3 } from "fs";
10796
- import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
11623
+ import { jsx as jsx22, jsxs as jsxs20 } from "react/jsx-runtime";
10797
11624
  function buildFilePickerIgnoreList(cwd) {
10798
11625
  const hardcoded = [
10799
11626
  // Dependencies
@@ -10864,7 +11691,7 @@ function buildFilePickerIgnoreList(cwd) {
10864
11691
  ];
10865
11692
  const gitignorePatterns = [];
10866
11693
  try {
10867
- const gitignorePath = join17(cwd, ".gitignore");
11694
+ const gitignorePath = join19(cwd, ".gitignore");
10868
11695
  const stats = statSync3(gitignorePath);
10869
11696
  if (stats.size > MAX_GITIGNORE_SIZE) {
10870
11697
  return hardcoded;
@@ -10938,6 +11765,26 @@ function openBrowser(url) {
10938
11765
  const child = spawn4(cmd, [url], { detached: true, stdio: "ignore" });
10939
11766
  child.unref();
10940
11767
  }
11768
+ function detectGitHubRepo(cachedRepo) {
11769
+ if (cachedRepo) {
11770
+ const parts = cachedRepo.split("/");
11771
+ if (parts.length === 2) return { owner: parts[0], name: parts[1] };
11772
+ }
11773
+ try {
11774
+ const remoteUrl = execSync2("git remote get-url origin", { cwd: process.cwd(), encoding: "utf8" }).trim();
11775
+ const httpsMatch = remoteUrl.match(/github\.com\/([^\/]+)\/([^\/]+?)(?:\.git)?$/);
11776
+ if (httpsMatch) return { owner: httpsMatch[1], name: httpsMatch[2] };
11777
+ const sshMatch = remoteUrl.match(/github\.com:([^\/]+)\/([^\/]+?)(?:\.git)?$/);
11778
+ if (sshMatch) return { owner: sshMatch[1], name: sshMatch[2] };
11779
+ } catch {
11780
+ }
11781
+ return null;
11782
+ }
11783
+ function formatTokens3(n) {
11784
+ if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
11785
+ if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
11786
+ return String(n);
11787
+ }
10941
11788
  function capEvents(prev) {
10942
11789
  if (prev.length <= MAX_EVENTS) return prev;
10943
11790
  return prev.slice(prev.length - MAX_EVENTS);
@@ -11000,10 +11847,10 @@ function App({
11000
11847
  initialLspProjectPath
11001
11848
  }) {
11002
11849
  const { exit } = useApp();
11003
- const [cfg, setCfg] = useState9(initialCfg);
11004
- const [lspScope, setLspScope] = useState9(initialLspScope);
11005
- const [lspProjectPath, setLspProjectPath] = useState9(initialLspProjectPath);
11006
- const [events, setRawEvents] = useState9([]);
11850
+ const [cfg, setCfg] = useState10(initialCfg);
11851
+ const [lspScope, setLspScope] = useState10(initialLspScope);
11852
+ const [lspProjectPath, setLspProjectPath] = useState10(initialLspProjectPath);
11853
+ const [events, setRawEvents] = useState10([]);
11007
11854
  const setEvents = useCallback(
11008
11855
  (updater) => {
11009
11856
  setRawEvents((prev) => {
@@ -11013,45 +11860,47 @@ function App({
11013
11860
  },
11014
11861
  []
11015
11862
  );
11016
- const [input, setInput] = useState9("");
11017
- const [busy, setBusy] = useState9(false);
11018
- const [usage, setUsage] = useState9(null);
11019
- const [sessionUsage, setSessionUsage] = useState9(null);
11020
- const [gatewayMeta, setGatewayMeta] = useState9(null);
11021
- const [showReasoning, setShowReasoning] = useState9(false);
11022
- const [perm, setPerm] = useState9(null);
11023
- const [queue, setQueue] = useState9([]);
11024
- const [history, setHistory] = useState9([]);
11025
- const [historyIndex, setHistoryIndex] = useState9(-1);
11026
- const [draftInput, setDraftInput] = useState9("");
11027
- const [mode, setMode] = useState9("edit");
11028
- const [codeMode, setCodeMode] = useState9(initialCfg?.codeMode ?? false);
11029
- const filePickerEnabled = initialCfg?.filePicker ?? false;
11030
- const [effort, setEffort] = useState9(
11863
+ const [input, setInput] = useState10("");
11864
+ const [busy, setBusy] = useState10(false);
11865
+ const [usage, setUsage] = useState10(null);
11866
+ const [sessionUsage, setSessionUsage] = useState10(null);
11867
+ const [gatewayMeta, setGatewayMeta] = useState10(null);
11868
+ const [showReasoning, setShowReasoning] = useState10(false);
11869
+ const [perm, setPerm] = useState10(null);
11870
+ const [queue, setQueue] = useState10([]);
11871
+ const [history, setHistory] = useState10([]);
11872
+ const [historyIndex, setHistoryIndex] = useState10(-1);
11873
+ const [draftInput, setDraftInput] = useState10("");
11874
+ const [mode, setMode] = useState10("edit");
11875
+ const [codeMode, setCodeMode] = useState10(false);
11876
+ const filePickerEnabled = initialCfg?.filePicker ?? true;
11877
+ const [effort, setEffort] = useState10(
11031
11878
  initialCfg?.reasoningEffort ?? DEFAULT_REASONING_EFFORT
11032
11879
  );
11033
- const [resumeSessions, setResumeSessions] = useState9(null);
11034
- const [showHelpMenu, setShowHelpMenu] = useState9(false);
11035
- const [commandWizard, setCommandWizard] = useState9(null);
11036
- const [commandPicker, setCommandPicker] = useState9(null);
11037
- const [commandToDelete, setCommandToDelete] = useState9(null);
11038
- const [showCommandList, setShowCommandList] = useState9(false);
11039
- const [showLspWizard, setShowLspWizard] = useState9(false);
11040
- const [tasks, setTasks] = useState9([]);
11041
- const [tasksStartedAt, setTasksStartedAt] = useState9(null);
11042
- const [tasksStartTokens, setTasksStartTokens] = useState9(0);
11043
- const [turnStartedAt, setTurnStartedAt] = useState9(null);
11044
- const [verbose, setVerbose] = useState9(false);
11045
- const [hasUpdate, setHasUpdate] = useState9(initialUpdateResult?.hasUpdate ?? false);
11046
- const [latestVersion, setLatestVersion] = useState9(initialUpdateResult?.latestVersion ?? null);
11047
- const [theme, setTheme] = useState9(resolveTheme(initialCfg?.theme));
11048
- const [showThemePicker, setShowThemePicker] = useState9(false);
11049
- const [originalTheme, setOriginalTheme] = useState9(null);
11050
- const [cursorOffset, setCursorOffset] = useState9(0);
11051
- const [activePicker, setActivePicker] = useState9(null);
11052
- const [filePickerItems, setFilePickerItems] = useState9([]);
11880
+ const [resumeSessions, setResumeSessions] = useState10(null);
11881
+ const [showHelpMenu, setShowHelpMenu] = useState10(false);
11882
+ const [commandWizard, setCommandWizard] = useState10(null);
11883
+ const [commandPicker, setCommandPicker] = useState10(null);
11884
+ const [commandToDelete, setCommandToDelete] = useState10(null);
11885
+ const [showCommandList, setShowCommandList] = useState10(false);
11886
+ const [showLspWizard, setShowLspWizard] = useState10(false);
11887
+ const [showRemoteDashboard, setShowRemoteDashboard] = useState10(false);
11888
+ const [selectedRemoteSession, setSelectedRemoteSession] = useState10(null);
11889
+ const [tasks, setTasks] = useState10([]);
11890
+ const [tasksStartedAt, setTasksStartedAt] = useState10(null);
11891
+ const [tasksStartTokens, setTasksStartTokens] = useState10(0);
11892
+ const [turnStartedAt, setTurnStartedAt] = useState10(null);
11893
+ const [verbose, setVerbose] = useState10(false);
11894
+ const [hasUpdate, setHasUpdate] = useState10(initialUpdateResult?.hasUpdate ?? false);
11895
+ const [latestVersion, setLatestVersion] = useState10(initialUpdateResult?.latestVersion ?? null);
11896
+ const [theme, setTheme] = useState10(resolveTheme(initialCfg?.theme));
11897
+ const [showThemePicker, setShowThemePicker] = useState10(false);
11898
+ const [originalTheme, setOriginalTheme] = useState10(null);
11899
+ const [cursorOffset, setCursorOffset] = useState10(0);
11900
+ const [activePicker, setActivePicker] = useState10(null);
11901
+ const [filePickerItems, setFilePickerItems] = useState10([]);
11053
11902
  const filePickerLoadedRef = useRef3(false);
11054
- const [customCommandsVersion, setCustomCommandsVersion] = useState9(0);
11903
+ const [customCommandsVersion, setCustomCommandsVersion] = useState10(0);
11055
11904
  const cacheStableRef = useRef3(initialCfg?.cacheStablePrompts !== false);
11056
11905
  const messagesRef = useRef3(
11057
11906
  makePrefixMessages(cacheStableRef.current, cfg?.model ?? DEFAULT_MODEL, "edit", ALL_TOOLS)
@@ -11089,15 +11938,15 @@ function App({
11089
11938
  const pickerCancelRef = useRef3(null);
11090
11939
  const pickerAnchor = activePicker?.anchor ?? null;
11091
11940
  const pickerKind = activePicker?.kind ?? null;
11092
- const pickerQuery = React13.useMemo(() => {
11941
+ const pickerQuery = React14.useMemo(() => {
11093
11942
  if (pickerAnchor === null) return null;
11094
11943
  return input.slice(pickerAnchor + 1, cursorOffset);
11095
11944
  }, [input, cursorOffset, pickerAnchor]);
11096
- const filteredFileItems = React13.useMemo(() => {
11945
+ const filteredFileItems = React14.useMemo(() => {
11097
11946
  if (pickerKind !== "file" || pickerQuery === null) return [];
11098
11947
  return filterPickerItems(filePickerItems, pickerQuery);
11099
11948
  }, [pickerKind, filePickerItems, pickerQuery]);
11100
- const allSlashCommands = React13.useMemo(() => {
11949
+ const allSlashCommands = React14.useMemo(() => {
11101
11950
  const customs = customCommandsRef.current.filter((c) => !BUILTIN_COMMAND_NAMES.has(c.name.toLowerCase())).map((c) => ({
11102
11951
  name: c.name,
11103
11952
  description: c.description ?? "",
@@ -11105,11 +11954,11 @@ function App({
11105
11954
  }));
11106
11955
  return [...BUILTIN_COMMANDS, ...customs];
11107
11956
  }, [customCommandsVersion]);
11108
- const filteredSlashItems = React13.useMemo(() => {
11957
+ const filteredSlashItems = React14.useMemo(() => {
11109
11958
  if (pickerKind !== "slash" || pickerQuery === null) return [];
11110
11959
  return fuzzyFilter(allSlashCommands, pickerQuery, (c) => c.name).slice(0, 50);
11111
11960
  }, [pickerKind, allSlashCommands, pickerQuery]);
11112
- useEffect4(() => {
11961
+ useEffect5(() => {
11113
11962
  if (activePicker !== null) {
11114
11963
  const trigger = activePicker.kind === "file" ? "@" : "/";
11115
11964
  if (cursorOffset < activePicker.anchor) {
@@ -11166,14 +12015,14 @@ function App({
11166
12015
  return;
11167
12016
  }
11168
12017
  }, [input, cursorOffset, activePicker, filePickerEnabled]);
11169
- useEffect4(() => {
12018
+ useEffect5(() => {
11170
12019
  if (activePicker?.kind !== "file") return;
11171
12020
  const max = Math.max(0, filteredFileItems.length - 1);
11172
12021
  if (activePicker.selected > max) {
11173
12022
  setActivePicker({ ...activePicker, selected: max });
11174
12023
  }
11175
12024
  }, [filteredFileItems.length, activePicker]);
11176
- useEffect4(() => {
12025
+ useEffect5(() => {
11177
12026
  if (activePicker?.kind !== "slash") return;
11178
12027
  const max = Math.max(0, filteredSlashItems.length - 1);
11179
12028
  if (activePicker.selected > max) {
@@ -11217,7 +12066,7 @@ function App({
11217
12066
  pickerCancelRef.current = cursorOffset;
11218
12067
  setActivePicker(null);
11219
12068
  }, [cursorOffset]);
11220
- useEffect4(() => {
12069
+ useEffect5(() => {
11221
12070
  const modalActive = showHelpMenu || commandWizard !== null || commandPicker !== null || commandToDelete !== null || showCommandList || showLspWizard || resumeSessions !== null || perm !== null;
11222
12071
  if (modalActive && activePicker !== null) {
11223
12072
  setActivePicker(null);
@@ -11233,7 +12082,7 @@ function App({
11233
12082
  perm,
11234
12083
  activePicker
11235
12084
  ]);
11236
- useEffect4(() => {
12085
+ useEffect5(() => {
11237
12086
  if (!cfg) return;
11238
12087
  void Promise.resolve().then(() => (init_sessions(), sessions_exports)).then(
11239
12088
  ({ pruneSessions: pruneSessions2 }) => pruneSessions2().then((removed) => {
@@ -11259,7 +12108,7 @@ function App({
11259
12108
  }
11260
12109
  });
11261
12110
  if (cfg.memoryEnabled) {
11262
- const dbPath = cfg.memoryDbPath ?? join17(process.cwd(), ".kimiflare", "memory.db");
12111
+ const dbPath = cfg.memoryDbPath ?? join19(process.cwd(), ".kimiflare", "memory.db");
11263
12112
  const manager = new MemoryManager({
11264
12113
  dbPath,
11265
12114
  accountId: cfg.accountId,
@@ -11326,7 +12175,7 @@ function App({
11326
12175
  }
11327
12176
  });
11328
12177
  }, [cfg, setEvents]);
11329
- useEffect4(() => {
12178
+ useEffect5(() => {
11330
12179
  const id = setInterval(() => {
11331
12180
  try {
11332
12181
  performance.clearMarks();
@@ -11351,7 +12200,7 @@ function App({
11351
12200
  ]);
11352
12201
  }
11353
12202
  }, [setEvents]);
11354
- useEffect4(() => {
12203
+ useEffect5(() => {
11355
12204
  if (!cfg || updateCheckedRef.current) return;
11356
12205
  updateCheckedRef.current = true;
11357
12206
  if (initialUpdateResult) {
@@ -11402,7 +12251,7 @@ function App({
11402
12251
  }
11403
12252
  });
11404
12253
  }, [cfg, initialUpdateResult]);
11405
- useEffect4(() => {
12254
+ useEffect5(() => {
11406
12255
  modeRef.current = mode;
11407
12256
  if (cacheStableRef.current) {
11408
12257
  messagesRef.current[1] = {
@@ -11429,10 +12278,10 @@ function App({
11429
12278
  executorRef.current.clearSessionPermissions();
11430
12279
  }
11431
12280
  }, [mode, cfg?.model]);
11432
- useEffect4(() => {
12281
+ useEffect5(() => {
11433
12282
  effortRef.current = effort;
11434
12283
  }, [effort]);
11435
- useEffect4(() => {
12284
+ useEffect5(() => {
11436
12285
  if (!cfg) return;
11437
12286
  const id = setInterval(() => {
11438
12287
  void checkForUpdate().then((result) => {
@@ -11587,7 +12436,7 @@ function App({
11587
12436
  ]);
11588
12437
  }
11589
12438
  }, [cfg]);
11590
- useEffect4(() => {
12439
+ useEffect5(() => {
11591
12440
  if (cfg && !mcpInitRef.current) {
11592
12441
  void initMcp();
11593
12442
  }
@@ -11625,7 +12474,85 @@ function App({
11625
12474
  } catch {
11626
12475
  }
11627
12476
  }, [cfg, ensureSessionId]);
11628
- useInput5((inputChar, key) => {
12477
+ const onIterationEnd = useCallback(
12478
+ async (messages, signal) => {
12479
+ if (signal.aborted) return messages;
12480
+ if (!shouldCompact({ messages })) return messages;
12481
+ if (compiledContextRef.current) {
12482
+ const store = artifactStoreRef.current;
12483
+ const result = compactMessages2({
12484
+ messages,
12485
+ state: sessionStateRef.current,
12486
+ store
12487
+ });
12488
+ if (result.metrics.rawTurnsRemoved > 0) {
12489
+ sessionStateRef.current = result.newState;
12490
+ setEvents((e) => [
12491
+ ...e,
12492
+ {
12493
+ kind: "info",
12494
+ key: mkKey(),
12495
+ text: `auto-compacted: ${result.metrics.estimatedTokensBefore} \u2192 ${result.metrics.estimatedTokensAfter} tokens (${result.metrics.archivedArtifacts} artifacts)`
12496
+ }
12497
+ ]);
12498
+ await saveSessionSafe();
12499
+ }
12500
+ const manager = memoryManagerRef.current;
12501
+ if (manager && !signal.aborted) {
12502
+ try {
12503
+ const cwd = process.cwd();
12504
+ const queryText = sessionStateRef.current.task || cwd;
12505
+ const results = await manager.recall({ text: queryText, repoPath: cwd, limit: 5 });
12506
+ if (results.length > 0 && !signal.aborted) {
12507
+ const text = await manager.synthesizeRecalled(results);
12508
+ const lastSystemIdx = result.newMessages.findLastIndex((m) => m.role === "system");
12509
+ const insertIdx = lastSystemIdx >= 0 ? lastSystemIdx + 1 : result.newMessages.length;
12510
+ result.newMessages.splice(insertIdx, 0, { role: "system", content: text });
12511
+ setEvents((e) => [
12512
+ ...e,
12513
+ {
12514
+ kind: "memory",
12515
+ key: mkKey(),
12516
+ text: `recalled ${results.length} memory${results.length === 1 ? "" : "ies"} after compaction`
12517
+ }
12518
+ ]);
12519
+ await saveSessionSafe();
12520
+ }
12521
+ } catch {
12522
+ }
12523
+ }
12524
+ return result.newMessages;
12525
+ }
12526
+ if (cfg && !signal.aborted) {
12527
+ try {
12528
+ const result = await compactMessages({
12529
+ accountId: cfg.accountId,
12530
+ apiToken: cfg.apiToken,
12531
+ model: cfg.model,
12532
+ messages,
12533
+ signal,
12534
+ gateway: gatewayFromConfig(cfg)
12535
+ });
12536
+ if (result.replacedCount > 0) {
12537
+ setEvents((e) => [
12538
+ ...e,
12539
+ {
12540
+ kind: "info",
12541
+ key: mkKey(),
12542
+ text: `auto-compacted: ${result.replacedCount} messages summarized`
12543
+ }
12544
+ ]);
12545
+ await saveSessionSafe();
12546
+ }
12547
+ return result.newMessages;
12548
+ } catch {
12549
+ }
12550
+ }
12551
+ return messages;
12552
+ },
12553
+ [cfg]
12554
+ );
12555
+ useInput6((inputChar, key) => {
11629
12556
  if (key.ctrl && inputChar === "c") {
11630
12557
  const hadPerm = permResolveRef.current !== null;
11631
12558
  if (hadPerm) {
@@ -11668,10 +12595,6 @@ function App({
11668
12595
  setVerbose((v) => !v);
11669
12596
  return;
11670
12597
  }
11671
- if (key.ctrl && inputChar === "m") {
11672
- setCodeMode((c) => !c);
11673
- return;
11674
- }
11675
12598
  });
11676
12599
  const flushAssistantUpdates = useCallback(() => {
11677
12600
  flushTimeoutRef.current = null;
@@ -11823,7 +12746,7 @@ function App({
11823
12746
  }
11824
12747
  }, [cfg, busy, saveSessionSafe]);
11825
12748
  const openResumePicker = useCallback(async () => {
11826
- const sessions = await listSessions(200);
12749
+ const sessions = await listSessions(200, process.cwd());
11827
12750
  setResumeSessions(sessions);
11828
12751
  }, []);
11829
12752
  const runInit = useCallback(async () => {
@@ -11833,23 +12756,13 @@ function App({
11833
12756
  return;
11834
12757
  }
11835
12758
  const cwd = process.cwd();
11836
- for (const name of ["KIMI.md", "KIMIFLARE.md", "AGENT.md"]) {
11837
- if (existsSync2(join17(cwd, name))) {
11838
- setEvents((e) => [
11839
- ...e,
11840
- {
11841
- kind: "info",
11842
- key: mkKey(),
11843
- text: `${name} already exists at ${join17(cwd, name)} \u2014 delete it first if you want to regenerate`
11844
- }
11845
- ]);
11846
- return;
11847
- }
11848
- }
11849
- const prompt = [
11850
- "Generate a KIMI.md at the repository root so future agents have project context.",
12759
+ const existingName = ["KIMI.md", "KIMIFLARE.md", "AGENT.md"].find((n) => existsSync2(join19(cwd, n)));
12760
+ const isRefresh = existingName !== void 0;
12761
+ const promptParts = [
12762
+ 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.",
11851
12763
  "",
11852
12764
  "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.",
12765
+ isRefresh ? `Also read the existing ${existingName} so you know what to keep vs. update.` : null,
11853
12766
  "",
11854
12767
  "Then call the `write` tool to create `KIMI.md` at the repo root with these sections, terse (aim \u2264 100 lines total):",
11855
12768
  "",
@@ -11860,13 +12773,23 @@ function App({
11860
12773
  "- **Do / Don't** \u2014 quirks or rules future agents should know.",
11861
12774
  "",
11862
12775
  "Do not call `tasks_set` for this. Just read what you need, then write the file."
11863
- ].join("\n");
11864
- setEvents((e) => [...e, { kind: "user", key: mkKey(), text: "/init" }]);
12776
+ ];
12777
+ const prompt = promptParts.filter((p) => p !== null).join("\n");
12778
+ setEvents((e) => [...e, { kind: "user", key: mkKey(), text: isRefresh ? `/init (refreshing ${existingName})` : "/init" }]);
11865
12779
  messagesRef.current.push({ role: "user", content: sanitizeString(prompt) });
11866
12780
  setBusy(true);
11867
12781
  setTurnStartedAt(Date.now());
11868
12782
  const controller = new AbortController();
11869
12783
  activeControllerRef.current = controller;
12784
+ const initClassification = classifyIntent(prompt);
12785
+ const initEffortForTier = {
12786
+ light: "low",
12787
+ medium: "medium",
12788
+ heavy: "high"
12789
+ };
12790
+ const initReasoningEffort = initEffortForTier[initClassification.tier] ?? effortRef.current;
12791
+ const effectiveCodeMode = initClassification.tier === "heavy";
12792
+ setCodeMode(effectiveCodeMode);
11870
12793
  try {
11871
12794
  await runAgentTurn({
11872
12795
  accountId: cfg.accountId,
@@ -11878,17 +12801,21 @@ function App({
11878
12801
  executor: executorRef.current,
11879
12802
  cwd,
11880
12803
  signal: controller.signal,
11881
- reasoningEffort: effortRef.current,
12804
+ reasoningEffort: initReasoningEffort,
12805
+ intentClassification: initClassification,
11882
12806
  coauthor: cfg.coauthor !== false ? { name: cfg.coauthorName || "kimiflare", email: cfg.coauthorEmail || "kimiflare@proton.me" } : void 0,
11883
12807
  sessionId: ensureSessionId(),
11884
12808
  memoryManager: memoryManagerRef.current,
11885
- codeMode,
12809
+ codeMode: effectiveCodeMode,
12810
+ maxInputTokens: effectiveCodeMode ? 2e5 : void 0,
12811
+ continueOnLimit: effectiveCodeMode ? true : void 0,
12812
+ onIterationEnd,
11886
12813
  onFileChange: (path, content) => {
11887
12814
  if (content) {
11888
12815
  lspManagerRef.current.notifyChange(path, content);
11889
12816
  } else {
11890
12817
  void import("fs/promises").then(
11891
- ({ readFile: readFile15 }) => readFile15(path, "utf8").then((c) => lspManagerRef.current.notifyChange(path, c)).catch(() => {
12818
+ ({ readFile: readFile16 }) => readFile16(path, "utf8").then((c) => lspManagerRef.current.notifyChange(path, c)).catch(() => {
11892
12819
  })
11893
12820
  );
11894
12821
  }
@@ -11982,7 +12909,7 @@ function App({
11982
12909
  })
11983
12910
  }
11984
12911
  });
11985
- if (existsSync2(join17(cwd, "KIMI.md"))) {
12912
+ if (existsSync2(join19(cwd, "KIMI.md"))) {
11986
12913
  if (cacheStableRef.current) {
11987
12914
  messagesRef.current[1] = {
11988
12915
  role: "system",
@@ -12029,6 +12956,7 @@ function App({
12029
12956
  ]);
12030
12957
  }
12031
12958
  } finally {
12959
+ setCodeMode(false);
12032
12960
  const asstId = activeAsstIdRef.current;
12033
12961
  if (asstId !== null) updateAssistant(asstId, () => ({ streaming: false }));
12034
12962
  setBusy(false);
@@ -12639,13 +13567,177 @@ ${lines.join("\n")}` }]);
12639
13567
  ]);
12640
13568
  return true;
12641
13569
  }
13570
+ if (c === "/remote") {
13571
+ if (arg === "status" || arg === "cancel") {
13572
+ setEvents((e) => [
13573
+ ...e,
13574
+ { kind: "info", key: mkKey(), text: `Use \`kimiflare remote ${arg}\` from your shell.` }
13575
+ ]);
13576
+ return true;
13577
+ }
13578
+ const prompt = rest.join(" ").trim();
13579
+ if (!prompt) {
13580
+ setShowRemoteDashboard(true);
13581
+ return true;
13582
+ }
13583
+ const repo = detectGitHubRepo(cfg?.githubRepo);
13584
+ if (!repo) {
13585
+ setEvents((e) => [
13586
+ ...e,
13587
+ { kind: "info", key: mkKey(), text: "Could not detect GitHub repo. Run from a repo with a GitHub remote, or set githubRepo in config." }
13588
+ ]);
13589
+ return true;
13590
+ }
13591
+ (async () => {
13592
+ if (!cfg?.remoteWorkerUrl) {
13593
+ setEvents((e) => [
13594
+ ...e,
13595
+ { kind: "info", key: mkKey(), text: "Remote infrastructure not deployed yet. Setting up now (~2 min)..." }
13596
+ ]);
13597
+ try {
13598
+ for await (const step of deployForTui()) {
13599
+ setEvents((e) => [
13600
+ ...e,
13601
+ { kind: step.error ? "error" : "info", key: mkKey(), text: step.message }
13602
+ ]);
13603
+ if (step.done) break;
13604
+ }
13605
+ } catch {
13606
+ setEvents((e) => [
13607
+ ...e,
13608
+ { kind: "error", key: mkKey(), text: "Deploy failed. Fix the issue above and try /remote again." }
13609
+ ]);
13610
+ return;
13611
+ }
13612
+ const { loadConfig: reloadConfig } = await Promise.resolve().then(() => (init_config(), config_exports));
13613
+ const newCfg = await reloadConfig();
13614
+ if (newCfg) setCfg(newCfg);
13615
+ }
13616
+ const currentCfg = cfg ?? await loadConfig();
13617
+ if (!currentCfg?.remoteWorkerUrl) {
13618
+ setEvents((e) => [
13619
+ ...e,
13620
+ { kind: "error", key: mkKey(), text: "Deploy seemed to succeed but config wasn't saved. Try again." }
13621
+ ]);
13622
+ return;
13623
+ }
13624
+ if (!currentCfg.githubOAuthToken) {
13625
+ setEvents((e) => [
13626
+ ...e,
13627
+ { kind: "info", key: mkKey(), text: "GitHub not authenticated. Starting OAuth device flow..." }
13628
+ ]);
13629
+ try {
13630
+ for await (const step of authGitHubForTui()) {
13631
+ setEvents((e) => [
13632
+ ...e,
13633
+ { kind: step.error ? "error" : "info", key: mkKey(), text: step.message }
13634
+ ]);
13635
+ if (step.done) break;
13636
+ }
13637
+ } catch {
13638
+ setEvents((e) => [
13639
+ ...e,
13640
+ { kind: "error", key: mkKey(), text: "GitHub auth failed. Try `kimiflare auth github` from shell." }
13641
+ ]);
13642
+ return;
13643
+ }
13644
+ const { loadConfig: reloadConfig } = await Promise.resolve().then(() => (init_config(), config_exports));
13645
+ const newCfg = await reloadConfig();
13646
+ if (newCfg) setCfg(newCfg);
13647
+ }
13648
+ const finalCfg = await loadConfig() ?? currentCfg;
13649
+ const ttl = finalCfg.remoteTtlMinutes ?? 30;
13650
+ const budget = finalCfg.remoteMaxInputTokens ?? 5e6;
13651
+ setEvents((e) => [
13652
+ ...e,
13653
+ { kind: "info", key: mkKey(), text: `Starting remote session for ${repo.owner}/${repo.name}...` },
13654
+ { kind: "info", key: mkKey(), text: `Budget: ${formatTokens3(budget)} tokens. TTL: ${ttl} min.` }
13655
+ ]);
13656
+ try {
13657
+ const data = await startRemoteSession({
13658
+ prompt,
13659
+ repo,
13660
+ cfg: finalCfg,
13661
+ ttlMinutes: finalCfg.remoteTtlMinutes,
13662
+ tokensBudget: finalCfg.remoteMaxInputTokens
13663
+ });
13664
+ setEvents((e) => [
13665
+ ...e,
13666
+ { kind: "info", key: mkKey(), text: `Session started: ${data.sessionId}` }
13667
+ ]);
13668
+ for await (const ev of streamRemoteProgress(
13669
+ finalCfg.remoteWorkerUrl,
13670
+ data.sessionId,
13671
+ activeControllerRef.current?.signal
13672
+ )) {
13673
+ const event = ev;
13674
+ if (event.type === "text_delta") {
13675
+ setEvents((e) => [
13676
+ ...e,
13677
+ { kind: "info", key: mkKey(), text: String(event.text ?? "") }
13678
+ ]);
13679
+ } else if (event.type === "tool_call") {
13680
+ setEvents((e) => [
13681
+ ...e,
13682
+ { kind: "info", key: mkKey(), text: `\u2192 ${String(event.name ?? "")}` }
13683
+ ]);
13684
+ } else if (event.type === "done") {
13685
+ const prUrl = event.prUrl;
13686
+ const tokensUsed = event.tokensUsed;
13687
+ const tokensBudget = event.tokensBudget;
13688
+ setEvents((e) => [
13689
+ ...e,
13690
+ { kind: "info", key: mkKey(), text: prUrl ? `Done \u2014 PR: ${prUrl}` : "Done" }
13691
+ ]);
13692
+ await saveRemoteSession({
13693
+ sessionId: data.sessionId,
13694
+ prompt,
13695
+ repo: `${repo.owner}/${repo.name}`,
13696
+ workerUrl: finalCfg.remoteWorkerUrl,
13697
+ status: "done",
13698
+ prUrl,
13699
+ tokensUsed,
13700
+ tokensBudget,
13701
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
13702
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
13703
+ });
13704
+ } else if (event.type === "error") {
13705
+ const message2 = String(event.message ?? "");
13706
+ const category = event.category;
13707
+ setEvents((e) => [
13708
+ ...e,
13709
+ { kind: "error", key: mkKey(), text: `Remote error: ${message2}` }
13710
+ ]);
13711
+ await saveRemoteSession({
13712
+ sessionId: data.sessionId,
13713
+ prompt,
13714
+ repo: `${repo.owner}/${repo.name}`,
13715
+ workerUrl: finalCfg.remoteWorkerUrl,
13716
+ status: "error",
13717
+ errorCategory: category ?? "unknown",
13718
+ errorSummary: message2,
13719
+ errorMessage: message2,
13720
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
13721
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
13722
+ });
13723
+ }
13724
+ }
13725
+ } catch (err) {
13726
+ setEvents((e) => [
13727
+ ...e,
13728
+ { kind: "error", key: mkKey(), text: `Failed: ${err instanceof Error ? err.message : String(err)}` }
13729
+ ]);
13730
+ }
13731
+ })();
13732
+ return true;
13733
+ }
12642
13734
  if (c === "/help") {
12643
13735
  setShowHelpMenu(true);
12644
13736
  return true;
12645
13737
  }
12646
13738
  return false;
12647
13739
  },
12648
- [cfg, exit, usage, effort, theme, mode, openResumePicker, runCompact, runInit, initMcp, setCfg]
13740
+ [cfg, exit, usage, effort, theme, mode, openResumePicker, runCompact, runInit, initMcp, setCfg, setShowRemoteDashboard, setSelectedRemoteSession]
12649
13741
  );
12650
13742
  const handleHelpCommand = useCallback(
12651
13743
  (command) => {
@@ -12788,6 +13880,15 @@ ${lines.join("\n")}` }]);
12788
13880
  gatewayMetaRef.current = null;
12789
13881
  setGatewayMeta(null);
12790
13882
  setTurnStartedAt(Date.now());
13883
+ const classification = classifyIntent(trimmed);
13884
+ const effortForTier = {
13885
+ light: "low",
13886
+ medium: "medium",
13887
+ heavy: "high"
13888
+ };
13889
+ const turnReasoningEffort = overrideEffort ?? effortForTier[classification.tier] ?? effortRef.current;
13890
+ const effectiveCodeMode = classification.tier === "heavy";
13891
+ setCodeMode(effectiveCodeMode);
12791
13892
  const controller = new AbortController();
12792
13893
  activeControllerRef.current = controller;
12793
13894
  const sharedCallbacks = {
@@ -12901,18 +14002,22 @@ ${lines.join("\n")}` }]);
12901
14002
  executor: executorRef.current,
12902
14003
  cwd: process.cwd(),
12903
14004
  signal: controller.signal,
12904
- reasoningEffort: overrideEffort ?? effortRef.current,
14005
+ reasoningEffort: turnReasoningEffort,
12905
14006
  coauthor: cfg.coauthor !== false ? { name: cfg.coauthorName || "kimiflare", email: cfg.coauthorEmail || "kimiflare@proton.me" } : void 0,
12906
14007
  sessionId: ensureSessionId(),
12907
14008
  memoryManager: memoryManagerRef.current,
12908
14009
  keepLastImageTurns: cfg.imageHistoryTurns ?? 2,
12909
- codeMode,
14010
+ codeMode: effectiveCodeMode,
14011
+ maxInputTokens: effectiveCodeMode ? 2e5 : void 0,
14012
+ continueOnLimit: effectiveCodeMode ? true : void 0,
14013
+ onIterationEnd,
14014
+ intentClassification: classification,
12910
14015
  onFileChange: (path, content2) => {
12911
14016
  if (content2) {
12912
14017
  lspManagerRef.current.notifyChange(path, content2);
12913
14018
  } else {
12914
14019
  void import("fs/promises").then(
12915
- ({ readFile: readFile15 }) => readFile15(path, "utf8").then((c) => lspManagerRef.current.notifyChange(path, c)).catch(() => {
14020
+ ({ readFile: readFile16 }) => readFile16(path, "utf8").then((c) => lspManagerRef.current.notifyChange(path, c)).catch(() => {
12916
14021
  })
12917
14022
  );
12918
14023
  }
@@ -13034,6 +14139,7 @@ ${lines.join("\n")}` }]);
13034
14139
  }
13035
14140
  }
13036
14141
  } finally {
14142
+ setCodeMode(false);
13037
14143
  const asstId = activeAsstIdRef.current;
13038
14144
  if (asstId !== null) updateAssistant(asstId, () => ({ streaming: false }));
13039
14145
  setBusy(false);
@@ -13046,7 +14152,7 @@ ${lines.join("\n")}` }]);
13046
14152
  },
13047
14153
  [cfg, handleSlash, updateAssistant, updateTool, saveSessionSafe, updateGatewayMeta]
13048
14154
  );
13049
- useEffect4(() => {
14155
+ useEffect5(() => {
13050
14156
  if (!busy && queue.length > 0) {
13051
14157
  const next = queue[0];
13052
14158
  setQueue((q) => q.slice(1));
@@ -13074,7 +14180,7 @@ ${lines.join("\n")}` }]);
13074
14180
  [busy, processMessage]
13075
14181
  );
13076
14182
  submitRef.current = submit;
13077
- useEffect4(() => {
14183
+ useEffect5(() => {
13078
14184
  if (compactSuggestedRef.current) return;
13079
14185
  if (usage && usage.prompt_tokens / CONTEXT_LIMIT >= AUTO_COMPACT_SUGGEST_PCT) {
13080
14186
  compactSuggestedRef.current = true;
@@ -13089,7 +14195,7 @@ ${lines.join("\n")}` }]);
13089
14195
  }
13090
14196
  }, [usage]);
13091
14197
  if (!cfg) {
13092
- return /* @__PURE__ */ jsx21(ThemeProvider, { theme, children: /* @__PURE__ */ jsx21(
14198
+ return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(
13093
14199
  Onboarding,
13094
14200
  {
13095
14201
  onDone: (newCfg) => {
@@ -13103,10 +14209,42 @@ ${lines.join("\n")}` }]);
13103
14209
  ) });
13104
14210
  }
13105
14211
  if (resumeSessions !== null) {
13106
- return /* @__PURE__ */ jsx21(ThemeProvider, { theme, children: /* @__PURE__ */ jsx21(Box19, { flexDirection: "column", children: /* @__PURE__ */ jsx21(ResumePicker, { sessions: resumeSessions, onPick: handleResumePick }) }) });
14212
+ return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx22(ResumePicker, { sessions: resumeSessions, onPick: handleResumePick }) }) });
14213
+ }
14214
+ if (showRemoteDashboard) {
14215
+ return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: selectedRemoteSession ? /* @__PURE__ */ jsx22(
14216
+ RemoteSessionDetail,
14217
+ {
14218
+ session: selectedRemoteSession,
14219
+ onBack: () => setSelectedRemoteSession(null),
14220
+ onCancel: async (session) => {
14221
+ try {
14222
+ const { cancelRemoteSession: cancelRemoteSession2 } = await Promise.resolve().then(() => (init_worker_client(), worker_client_exports));
14223
+ await cancelRemoteSession2(session.workerUrl, session.sessionId);
14224
+ setEvents((e) => [
14225
+ ...e,
14226
+ { kind: "info", key: mkKey(), text: `Cancelled session ${session.sessionId}` }
14227
+ ]);
14228
+ } catch (err) {
14229
+ setEvents((e) => [
14230
+ ...e,
14231
+ { kind: "error", key: mkKey(), text: `Failed to cancel: ${err instanceof Error ? err.message : String(err)}` }
14232
+ ]);
14233
+ }
14234
+ setSelectedRemoteSession(null);
14235
+ setShowRemoteDashboard(false);
14236
+ }
14237
+ }
14238
+ ) : /* @__PURE__ */ jsx22(
14239
+ RemoteDashboard,
14240
+ {
14241
+ onSelect: (session) => setSelectedRemoteSession(session),
14242
+ onCancel: () => setShowRemoteDashboard(false)
14243
+ }
14244
+ ) }) });
13107
14245
  }
13108
14246
  if (showHelpMenu) {
13109
- return /* @__PURE__ */ jsx21(ThemeProvider, { theme, children: /* @__PURE__ */ jsx21(Box19, { flexDirection: "column", children: /* @__PURE__ */ jsx21(
14247
+ return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx22(
13110
14248
  HelpMenu,
13111
14249
  {
13112
14250
  customCommands: customCommandsRef.current.filter((c) => !BUILTIN_COMMAND_NAMES.has(c.name.toLowerCase())).map((c) => ({ name: c.name, description: c.description })),
@@ -13117,12 +14255,12 @@ ${lines.join("\n")}` }]);
13117
14255
  ) }) });
13118
14256
  }
13119
14257
  if (showLspWizard) {
13120
- return /* @__PURE__ */ jsx21(ThemeProvider, { theme, children: /* @__PURE__ */ jsx21(Box19, { flexDirection: "column", children: /* @__PURE__ */ jsx21(
14258
+ return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx22(
13121
14259
  LspWizard,
13122
14260
  {
13123
14261
  servers: cfg?.lspServers ?? {},
13124
14262
  currentScope: lspScope,
13125
- hasProjectDir: existsSync2(join17(process.cwd(), ".kimiflare")),
14263
+ hasProjectDir: existsSync2(join19(process.cwd(), ".kimiflare")),
13126
14264
  onDone: () => setShowLspWizard(false),
13127
14265
  onSave: (servers, enabled, scope) => {
13128
14266
  setCfg((c) => c ? { ...c, lspEnabled: enabled, lspServers: servers } : c);
@@ -13154,7 +14292,7 @@ ${lines.join("\n")}` }]);
13154
14292
  ) }) });
13155
14293
  }
13156
14294
  if (commandWizard) {
13157
- return /* @__PURE__ */ jsx21(ThemeProvider, { theme, children: /* @__PURE__ */ jsx21(Box19, { flexDirection: "column", children: /* @__PURE__ */ jsx21(
14295
+ return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx22(
13158
14296
  CommandWizard,
13159
14297
  {
13160
14298
  mode: commandWizard.mode,
@@ -13167,7 +14305,7 @@ ${lines.join("\n")}` }]);
13167
14305
  ) }) });
13168
14306
  }
13169
14307
  if (commandPicker) {
13170
- return /* @__PURE__ */ jsx21(ThemeProvider, { theme, children: /* @__PURE__ */ jsx21(Box19, { flexDirection: "column", children: /* @__PURE__ */ jsx21(
14308
+ return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx22(
13171
14309
  CommandPicker,
13172
14310
  {
13173
14311
  commands: customCommandsRef.current,
@@ -13185,15 +14323,15 @@ ${lines.join("\n")}` }]);
13185
14323
  ) }) });
13186
14324
  }
13187
14325
  if (commandToDelete) {
13188
- return /* @__PURE__ */ jsx21(ThemeProvider, { theme, children: /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
13189
- /* @__PURE__ */ jsxs19(Text20, { color: theme.accent, bold: true, children: [
14326
+ return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
14327
+ /* @__PURE__ */ jsxs20(Text21, { color: theme.accent, bold: true, children: [
13190
14328
  "Delete /",
13191
14329
  commandToDelete.name,
13192
14330
  "?"
13193
14331
  ] }),
13194
- /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, children: commandToDelete.filepath }),
13195
- /* @__PURE__ */ jsx21(Box19, { marginTop: 1, children: /* @__PURE__ */ jsx21(
13196
- SelectInput8,
14332
+ /* @__PURE__ */ jsx22(Text21, { color: theme.info.color, children: commandToDelete.filepath }),
14333
+ /* @__PURE__ */ jsx22(Box20, { marginTop: 1, children: /* @__PURE__ */ jsx22(
14334
+ SelectInput9,
13197
14335
  {
13198
14336
  items: [
13199
14337
  { label: "Yes, delete", value: "yes", key: "yes" },
@@ -13211,7 +14349,7 @@ ${lines.join("\n")}` }]);
13211
14349
  ] }) });
13212
14350
  }
13213
14351
  if (showCommandList) {
13214
- return /* @__PURE__ */ jsx21(ThemeProvider, { theme, children: /* @__PURE__ */ jsx21(Box19, { flexDirection: "column", children: /* @__PURE__ */ jsx21(
14352
+ return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx22(
13215
14353
  CommandList,
13216
14354
  {
13217
14355
  commands: customCommandsRef.current,
@@ -13220,12 +14358,12 @@ ${lines.join("\n")}` }]);
13220
14358
  ) }) });
13221
14359
  }
13222
14360
  if (showThemePicker) {
13223
- return /* @__PURE__ */ jsx21(ThemeProvider, { theme, children: /* @__PURE__ */ jsx21(Box19, { flexDirection: "column", children: /* @__PURE__ */ jsx21(ThemePicker, { themes: themeList(), onPick: handleThemePick, onPreview: (t) => setTheme(t) }) }) });
14361
+ return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx22(ThemePicker, { themes: themeList(), onPick: handleThemePick, onPreview: (t) => setTheme(t) }) }) });
13224
14362
  }
13225
14363
  const hasConversation = events.some((e) => e.kind === "user" || e.kind === "assistant");
13226
- return /* @__PURE__ */ jsx21(ThemeProvider, { theme, children: /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", children: [
13227
- !hasConversation && events.length === 0 ? /* @__PURE__ */ jsx21(Welcome, { accountId: cfg.accountId }) : /* @__PURE__ */ jsx21(ChatView, { events, showReasoning, verbose }),
13228
- perm ? /* @__PURE__ */ jsx21(
14364
+ return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", children: [
14365
+ !hasConversation && events.length === 0 ? /* @__PURE__ */ jsx22(Welcome, { accountId: cfg.accountId }) : /* @__PURE__ */ jsx22(ChatView, { events, showReasoning, verbose }),
14366
+ perm ? /* @__PURE__ */ jsx22(
13229
14367
  PermissionModal,
13230
14368
  {
13231
14369
  tool: perm.tool,
@@ -13236,8 +14374,8 @@ ${lines.join("\n")}` }]);
13236
14374
  setPerm(null);
13237
14375
  }
13238
14376
  }
13239
- ) : /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", marginTop: 1, children: [
13240
- tasks.length > 0 && /* @__PURE__ */ jsx21(
14377
+ ) : /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", marginTop: 1, children: [
14378
+ tasks.length > 0 && /* @__PURE__ */ jsx22(
13241
14379
  TaskList,
13242
14380
  {
13243
14381
  tasks,
@@ -13245,11 +14383,11 @@ ${lines.join("\n")}` }]);
13245
14383
  tokensDelta: Math.max(0, (usage?.prompt_tokens ?? 0) - tasksStartTokens)
13246
14384
  }
13247
14385
  ),
13248
- queue.length > 0 && /* @__PURE__ */ jsx21(Box19, { flexDirection: "column", marginBottom: 1, children: queue.map((q, i) => /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
14386
+ queue.length > 0 && /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", marginBottom: 1, children: queue.map((q, i) => /* @__PURE__ */ jsxs20(Text21, { color: theme.info.color, children: [
13249
14387
  "\u23F3 ",
13250
14388
  q.display
13251
14389
  ] }, `queue_${i}`)) }),
13252
- /* @__PURE__ */ jsx21(
14390
+ /* @__PURE__ */ jsx22(
13253
14391
  StatusBar,
13254
14392
  {
13255
14393
  model: cfg.model,
@@ -13266,7 +14404,7 @@ ${lines.join("\n")}` }]);
13266
14404
  codeMode
13267
14405
  }
13268
14406
  ),
13269
- activePicker?.kind === "file" && /* @__PURE__ */ jsx21(
14407
+ activePicker?.kind === "file" && /* @__PURE__ */ jsx22(
13270
14408
  FilePicker,
13271
14409
  {
13272
14410
  items: filteredFileItems,
@@ -13274,7 +14412,7 @@ ${lines.join("\n")}` }]);
13274
14412
  query: pickerQuery ?? ""
13275
14413
  }
13276
14414
  ),
13277
- activePicker?.kind === "slash" && /* @__PURE__ */ jsx21(
14415
+ activePicker?.kind === "slash" && /* @__PURE__ */ jsx22(
13278
14416
  SlashPicker,
13279
14417
  {
13280
14418
  items: filteredSlashItems,
@@ -13282,9 +14420,9 @@ ${lines.join("\n")}` }]);
13282
14420
  query: pickerQuery ?? ""
13283
14421
  }
13284
14422
  ),
13285
- /* @__PURE__ */ jsxs19(Box19, { marginTop: 1, children: [
13286
- /* @__PURE__ */ jsx21(Text20, { color: "#d699b6", children: "\u203A " }),
13287
- /* @__PURE__ */ jsx21(
14423
+ /* @__PURE__ */ jsxs20(Box20, { marginTop: 1, children: [
14424
+ /* @__PURE__ */ jsx22(Text21, { color: "#d699b6", children: "\u203A " }),
14425
+ /* @__PURE__ */ jsx22(
13288
14426
  CustomTextInput,
13289
14427
  {
13290
14428
  value: input,
@@ -13341,7 +14479,7 @@ ${lines.join("\n")}` }]);
13341
14479
  }
13342
14480
  async function renderApp(cfg, updateResult, lspScope = "global", lspProjectPath = null) {
13343
14481
  const instance = render(
13344
- /* @__PURE__ */ jsx21(
14482
+ /* @__PURE__ */ jsx22(
13345
14483
  App,
13346
14484
  {
13347
14485
  initialCfg: cfg,
@@ -13382,7 +14520,13 @@ var init_app = __esm({
13382
14520
  init_welcome();
13383
14521
  init_help_menu();
13384
14522
  init_config();
14523
+ init_worker_client();
14524
+ init_session_store();
14525
+ init_tui_deploy();
14526
+ init_tui_auth();
14527
+ init_remote_dashboard();
13385
14528
  init_mode();
14529
+ init_classify();
13386
14530
  init_sessions();
13387
14531
  init_image();
13388
14532
  init_usage_tracker();
@@ -13431,9 +14575,108 @@ init_system_prompt();
13431
14575
  init_executor();
13432
14576
  init_update_check();
13433
14577
  init_version();
14578
+ import { Command as Command2 } from "commander";
14579
+
14580
+ // src/remote/cli.ts
14581
+ init_config();
14582
+ init_session_store();
14583
+ init_deploy();
13434
14584
  import { Command } from "commander";
13435
- var program = new Command();
13436
- 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)");
14585
+ function createRemoteCommand() {
14586
+ const remote = new Command("remote").description("Manage remote sessions");
14587
+ remote.command("deploy").description("Deploy the remote Worker and container image to Cloudflare").action(async () => {
14588
+ await runDeploy();
14589
+ });
14590
+ remote.command("setup").description("Check remote deployment status and prerequisites").action(async () => {
14591
+ const status = await checkDeployStatus();
14592
+ console.log("Remote deployment status:\n");
14593
+ console.log(` wrangler CLI: ${status.wrangler ? "yes" : "no"}`);
14594
+ console.log(` wrangler auth: ${status.wranglerAuth ? "yes" : "no"}`);
14595
+ console.log(` Docker: ${status.docker ? "yes" : "no"}`);
14596
+ console.log(` Worker URL: ${status.workerUrl ?? "not deployed"}`);
14597
+ console.log("\nRun `kimiflare remote deploy` to deploy.");
14598
+ });
14599
+ remote.command("list").description("List remote sessions").action(async () => {
14600
+ const sessions = await listRemoteSessions();
14601
+ if (sessions.length === 0) {
14602
+ console.log("No remote sessions found.");
14603
+ return;
14604
+ }
14605
+ console.log(`Remote sessions (${sessions.length} total):
14606
+ `);
14607
+ for (const s of sessions.slice(0, 20)) {
14608
+ const date = new Date(s.createdAt).toLocaleString();
14609
+ const statusIcon = s.status === "done" ? "\u2705" : s.status === "error" ? "\u274C" : s.status === "running" ? "\u23F3" : "\u23F9\uFE0F";
14610
+ console.log(` ${statusIcon} ${s.sessionId.slice(0, 8)}\u2026 ${s.status.padEnd(10)} ${date} ${s.prompt.slice(0, 50)}`);
14611
+ if (s.prUrl) {
14612
+ console.log(` PR: ${s.prUrl}`);
14613
+ }
14614
+ }
14615
+ });
14616
+ remote.command("status").description("Show remote session status").argument("[session-id]", "Session ID (defaults to most recent)").action(async (sessionId) => {
14617
+ const session = sessionId ? await loadRemoteSession(sessionId) : await getMostRecentRemoteSession();
14618
+ if (!session) {
14619
+ console.log(sessionId ? `Session ${sessionId} not found.` : "No remote sessions found.");
14620
+ return;
14621
+ }
14622
+ const cfg = await loadConfig();
14623
+ const workerUrl = cfg?.remoteWorkerUrl;
14624
+ if (!workerUrl) {
14625
+ console.log("Remote worker not configured.");
14626
+ return;
14627
+ }
14628
+ try {
14629
+ const res = await fetch(`${workerUrl}/remote/status/${session.sessionId}`, {
14630
+ headers: {
14631
+ Authorization: `Bearer ${cfg.remoteAuthSecret ?? ""}`
14632
+ }
14633
+ });
14634
+ if (!res.ok) {
14635
+ console.log(`Failed to fetch status: ${res.status}`);
14636
+ return;
14637
+ }
14638
+ const data = await res.json();
14639
+ console.log(`Session: ${data.sessionId}`);
14640
+ console.log(`Status: ${data.status}`);
14641
+ console.log(`Prompt: ${data.prompt}`);
14642
+ console.log(`Repo: ${data.repo?.owner}/${data.repo?.name}`);
14643
+ console.log(`Branch: ${data.branch}`);
14644
+ console.log(`Turns: ${data.currentTurn} / ${data.maxTurns}`);
14645
+ if (data.prUrl) console.log(`PR: ${data.prUrl}`);
14646
+ if (data.errorMessage) console.log(`Error: ${data.errorMessage}`);
14647
+ } catch (err) {
14648
+ console.log(`Error: ${err instanceof Error ? err.message : String(err)}`);
14649
+ }
14650
+ });
14651
+ remote.command("cancel").description("Cancel a remote session").argument("<session-id>", "Session ID").action(async (sessionId) => {
14652
+ const cfg = await loadConfig();
14653
+ const workerUrl = cfg?.remoteWorkerUrl;
14654
+ if (!workerUrl) {
14655
+ console.log("Remote worker not configured.");
14656
+ return;
14657
+ }
14658
+ try {
14659
+ const res = await fetch(`${workerUrl}/remote/cancel/${sessionId}`, {
14660
+ method: "POST",
14661
+ headers: {
14662
+ Authorization: `Bearer ${cfg.remoteAuthSecret ?? ""}`
14663
+ }
14664
+ });
14665
+ if (!res.ok) {
14666
+ console.log(`Failed to cancel: ${res.status}`);
14667
+ return;
14668
+ }
14669
+ console.log(`Session ${sessionId} cancelled.`);
14670
+ } catch (err) {
14671
+ console.log(`Error: ${err instanceof Error ? err.message : String(err)}`);
14672
+ }
14673
+ });
14674
+ return remote;
14675
+ }
14676
+
14677
+ // src/index.tsx
14678
+ var program = new Command2();
14679
+ 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));
13437
14680
  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) => {
13438
14681
  const cfg = await loadConfig();
13439
14682
  const enabled = cfg?.costAttribution ?? false;
@@ -13446,6 +14689,23 @@ program.command("cost").description("Show cost attribution by task type (require
13446
14689
  const { runCostCommand: runCostCommand2 } = await Promise.resolve().then(() => (init_cli(), cli_exports));
13447
14690
  await runCostCommand2({ ...cmdOpts, config: cfg });
13448
14691
  });
14692
+ program.addCommand(createRemoteCommand());
14693
+ program.command("auth").description("Authenticate with external services").addCommand(
14694
+ new Command2("github").description("Authenticate with GitHub via OAuth device flow").action(async () => {
14695
+ const { authGitHubForTui: authGitHubForTui2 } = await Promise.resolve().then(() => (init_tui_auth(), tui_auth_exports));
14696
+ for await (const step of authGitHubForTui2()) {
14697
+ console.log(step.message);
14698
+ if (step.url && step.code) {
14699
+ console.log(`
14700
+ Open: ${step.url}`);
14701
+ console.log(`Code: ${step.code}
14702
+ `);
14703
+ }
14704
+ if (step.done) break;
14705
+ if (step.error) process.exit(1);
14706
+ }
14707
+ })
14708
+ );
13449
14709
  program.action(async () => {
13450
14710
  await main();
13451
14711
  });
@@ -13482,6 +14742,8 @@ async function main() {
13482
14742
  allowAll: !!opts.dangerouslyAllowAll,
13483
14743
  showReasoning: !!opts.reasoning,
13484
14744
  codeMode: cfg.codeMode,
14745
+ continueOnLimit: !!opts.continueOnLimit,
14746
+ maxInputTokens: opts.maxInputTokens,
13485
14747
  updateResult
13486
14748
  });
13487
14749
  return;
@@ -13529,52 +14791,63 @@ async function runPrintMode(opts2) {
13529
14791
  process.on("SIGINT", () => controller.abort());
13530
14792
  let printedReasoningHeader = false;
13531
14793
  let printedAnswerHeader = false;
13532
- await runAgentTurn({
13533
- accountId: opts2.accountId,
13534
- apiToken: opts2.apiToken,
13535
- model: opts2.model,
13536
- gateway: gatewayFromPrintOpts(opts2),
13537
- messages,
13538
- tools: ALL_TOOLS,
13539
- executor,
13540
- cwd,
13541
- signal: controller.signal,
13542
- codeMode: opts2.codeMode,
13543
- coauthor: opts2.coauthor !== false ? { name: opts2.coauthorName || "kimiflare", email: opts2.coauthorEmail || "kimiflare@proton.me" } : void 0,
13544
- callbacks: {
13545
- onReasoningDelta: opts2.showReasoning ? (delta) => {
13546
- if (!printedReasoningHeader) {
13547
- process.stderr.write("\x1B[2m--- reasoning ---\n");
13548
- printedReasoningHeader = true;
13549
- }
13550
- process.stderr.write(delta);
13551
- } : void 0,
13552
- onTextDelta: (delta) => {
13553
- if (opts2.showReasoning && printedReasoningHeader && !printedAnswerHeader) {
13554
- process.stderr.write("\n--- answer ---\x1B[0m\n");
13555
- printedAnswerHeader = true;
13556
- }
13557
- process.stdout.write(delta);
13558
- },
13559
- onToolCallFinalized: (call) => {
13560
- process.stderr.write(`\x1B[2m[tool ${call.function.name}(${call.function.arguments})]\x1B[0m
14794
+ try {
14795
+ await runAgentTurn({
14796
+ accountId: opts2.accountId,
14797
+ apiToken: opts2.apiToken,
14798
+ model: opts2.model,
14799
+ gateway: gatewayFromPrintOpts(opts2),
14800
+ messages,
14801
+ tools: ALL_TOOLS,
14802
+ executor,
14803
+ cwd,
14804
+ signal: controller.signal,
14805
+ codeMode: opts2.codeMode,
14806
+ continueOnLimit: opts2.continueOnLimit,
14807
+ maxInputTokens: opts2.maxInputTokens,
14808
+ coauthor: opts2.coauthor !== false ? { name: opts2.coauthorName || "kimiflare", email: opts2.coauthorEmail || "kimiflare@proton.me" } : void 0,
14809
+ callbacks: {
14810
+ onReasoningDelta: opts2.showReasoning ? (delta) => {
14811
+ if (!printedReasoningHeader) {
14812
+ process.stderr.write("\x1B[2m--- reasoning ---\n");
14813
+ printedReasoningHeader = true;
14814
+ }
14815
+ process.stderr.write(delta);
14816
+ } : void 0,
14817
+ onTextDelta: (delta) => {
14818
+ if (opts2.showReasoning && printedReasoningHeader && !printedAnswerHeader) {
14819
+ process.stderr.write("\n--- answer ---\x1B[0m\n");
14820
+ printedAnswerHeader = true;
14821
+ }
14822
+ process.stdout.write(delta);
14823
+ },
14824
+ onToolCallFinalized: (call) => {
14825
+ process.stderr.write(`\x1B[2m[tool ${call.function.name}(${call.function.arguments})]\x1B[0m
13561
14826
  `);
13562
- },
13563
- onToolResult: (result) => {
13564
- const snippet = result.content.length > 400 ? result.content.slice(0, 400) + "..." : result.content;
13565
- process.stderr.write(`\x1B[2m[result: ${snippet.replace(/\n/g, " \u23CE ")}]\x1B[0m
14827
+ },
14828
+ onToolResult: (result) => {
14829
+ const snippet = result.content.length > 400 ? result.content.slice(0, 400) + "..." : result.content;
14830
+ process.stderr.write(`\x1B[2m[result: ${snippet.replace(/\n/g, " \u23CE ")}]\x1B[0m
13566
14831
  `);
13567
- },
13568
- askPermission: async ({ tool, args }) => {
13569
- if (opts2.allowAll) return "allow";
13570
- process.stderr.write(
13571
- `\x1B[31m[permission denied: ${tool.name}(${JSON.stringify(args)}) \u2014 pass --dangerously-allow-all to approve in print mode]\x1B[0m
14832
+ },
14833
+ askPermission: async ({ tool, args }) => {
14834
+ if (opts2.allowAll) return "allow";
14835
+ process.stderr.write(
14836
+ `\x1B[31m[permission denied: ${tool.name}(${JSON.stringify(args)}) \u2014 pass --dangerously-allow-all to approve in print mode]\x1B[0m
13572
14837
  `
13573
- );
13574
- return "deny";
14838
+ );
14839
+ return "deny";
14840
+ }
13575
14841
  }
14842
+ });
14843
+ } catch (err) {
14844
+ if (err instanceof BudgetExhaustedError) {
14845
+ process.stderr.write("\n\x1B[33m[Budget exhausted \u2014 exiting with code 42]\x1B[0m\n");
14846
+ process.exitCode = 42;
14847
+ return;
13576
14848
  }
13577
- });
14849
+ throw err;
14850
+ }
13578
14851
  process.stdout.write("\n");
13579
14852
  }
13580
14853
  //# sourceMappingURL=index.js.map