kimiflare 0.35.0 → 0.36.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,5 +1,11 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
4
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
5
+ }) : x)(function(x) {
6
+ if (typeof require !== "undefined") return require.apply(this, arguments);
7
+ throw Error('Dynamic require of "' + x + '" is not supported');
8
+ });
3
9
  var __esm = (fn, res) => function __init() {
4
10
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
5
11
  };
@@ -321,10 +327,8 @@ async function* readSSE(stream, signal) {
321
327
  const decoder = new TextDecoder("utf-8");
322
328
  let buffer = "";
323
329
  const onAbort = () => {
324
- try {
325
- reader.cancel(new DOMException("aborted", "AbortError"));
326
- } catch {
327
- }
330
+ reader.cancel(new DOMException("aborted", "AbortError")).catch(() => {
331
+ });
328
332
  };
329
333
  signal?.addEventListener("abort", onAbort, { once: true });
330
334
  try {
@@ -479,6 +483,9 @@ function isRetryable(err, attempt) {
479
483
  return false;
480
484
  }
481
485
  async function* runKimi(opts2) {
486
+ if (opts2.cloudMode && !opts2.cloudToken) {
487
+ throw new KimiApiError("kimiflare: cloud mode requires a cloud token. Run `kimiflare auth cloud` to authenticate.", void 0, 401);
488
+ }
482
489
  const { url, headers: gatewayHeaders } = buildKimiRequestTarget(opts2);
483
490
  const body = {
484
491
  messages: sanitizeMessagesForApi(opts2.messages),
@@ -1402,6 +1409,11 @@ function stripTypescript(code) {
1402
1409
  return js.trim();
1403
1410
  }
1404
1411
  async function loadTypescript(cwd) {
1412
+ try {
1413
+ const tsPath = await import.meta.resolve("typescript");
1414
+ return await import(tsPath);
1415
+ } catch {
1416
+ }
1405
1417
  let dir = cwd;
1406
1418
  while (dir !== dirname3(dir)) {
1407
1419
  try {
@@ -1669,7 +1681,18 @@ Use console.log() to return results. Only console.log output will be sent back t
1669
1681
  });
1670
1682
  }
1671
1683
  if (iter >= max) {
1672
- if (opts2.continueOnLimit) {
1684
+ if (opts2.callbacks.onToolLimitReached) {
1685
+ const decision = await opts2.callbacks.onToolLimitReached();
1686
+ if (decision === "continue") {
1687
+ opts2.messages.push({
1688
+ role: "system",
1689
+ 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."
1690
+ });
1691
+ iter = 0;
1692
+ } else {
1693
+ return;
1694
+ }
1695
+ } else if (opts2.continueOnLimit) {
1673
1696
  opts2.messages.push({
1674
1697
  role: "system",
1675
1698
  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."
@@ -4614,9 +4637,16 @@ var init_cli = __esm({
4614
4637
  // src/cloud/auth.ts
4615
4638
  var auth_exports = {};
4616
4639
  __export(auth_exports, {
4640
+ CLOUD_API_URL: () => CLOUD_API_URL,
4641
+ POLL_INTERVAL_MS: () => POLL_INTERVAL_MS,
4642
+ POLL_TIMEOUT_MS: () => POLL_TIMEOUT_MS,
4617
4643
  authenticateDevice: () => authenticateDevice,
4618
4644
  clearCloudCredentials: () => clearCloudCredentials,
4645
+ fetchCloudUsage: () => fetchCloudUsage,
4646
+ generateDeviceCodes: () => generateDeviceCodes,
4619
4647
  loadCloudCredentials: () => loadCloudCredentials,
4648
+ pollForToken: () => pollForToken,
4649
+ registerDevice: () => registerDevice,
4620
4650
  saveCloudCredentials: () => saveCloudCredentials
4621
4651
  });
4622
4652
  import { readFile as readFile11, writeFile as writeFile7 } from "fs/promises";
@@ -4634,6 +4664,58 @@ function generateCode() {
4634
4664
  }
4635
4665
  return out;
4636
4666
  }
4667
+ function generateDeviceCodes() {
4668
+ const deviceCode = `device-${generateCode()}-${Date.now()}`;
4669
+ const userCode = `${generateCode()}-${generateCode()}`;
4670
+ const authUrl = `${CLOUD_API_URL}/auth/github?code=${encodeURIComponent(userCode)}`;
4671
+ return { deviceCode, userCode, authUrl };
4672
+ }
4673
+ async function registerDevice(codes) {
4674
+ const registerRes = await fetch(`${CLOUD_API_URL}/auth/device`, {
4675
+ method: "POST",
4676
+ headers: { "Content-Type": "application/json" },
4677
+ body: JSON.stringify({ device_code: codes.deviceCode, user_code: codes.userCode })
4678
+ });
4679
+ if (!registerRes.ok) {
4680
+ const err = await registerRes.json().catch(() => ({}));
4681
+ throw new Error(`Failed to register device: ${err.error || registerRes.statusText}`);
4682
+ }
4683
+ }
4684
+ async function pollForToken(deviceCode) {
4685
+ const pollRes = await fetch(`${CLOUD_API_URL}/auth/poll`, {
4686
+ method: "POST",
4687
+ headers: { "Content-Type": "application/json" },
4688
+ body: JSON.stringify({ device_code: deviceCode })
4689
+ });
4690
+ if (!pollRes.ok) return null;
4691
+ const pollData = await pollRes.json();
4692
+ if (pollData.status === "approved" && pollData.access_token) {
4693
+ const creds = {
4694
+ accessToken: pollData.access_token,
4695
+ expiresAt: Math.floor(Date.now() / 1e3) + 7 * 24 * 60 * 60
4696
+ // 7 days
4697
+ };
4698
+ await saveCloudCredentials(creds);
4699
+ return creds;
4700
+ }
4701
+ return null;
4702
+ }
4703
+ async function fetchCloudUsage(token) {
4704
+ const res = await fetch(`${CLOUD_API_URL}/v1/usage`, {
4705
+ headers: { Authorization: `Bearer ${token}` }
4706
+ });
4707
+ if (!res.ok) return null;
4708
+ const data = await res.json();
4709
+ if (typeof data.remaining !== "number" || typeof data.input_token_limit !== "number" || typeof data.input_tokens_used !== "number" || typeof data.expires_at !== "string") {
4710
+ return null;
4711
+ }
4712
+ return {
4713
+ input_token_limit: data.input_token_limit,
4714
+ input_tokens_used: data.input_tokens_used,
4715
+ remaining: data.remaining,
4716
+ expires_at: data.expires_at
4717
+ };
4718
+ }
4637
4719
  async function loadCloudCredentials() {
4638
4720
  try {
4639
4721
  const raw = await readFile11(cloudCredPath(), "utf8");
@@ -4657,39 +4739,15 @@ async function clearCloudCredentials() {
4657
4739
  }
4658
4740
  }
4659
4741
  async function authenticateDevice(onStatus) {
4660
- const deviceCode = `device-${generateCode()}-${Date.now()}`;
4661
- const userCode = `${generateCode()}-${generateCode()}`;
4662
- const registerRes = await fetch(`${CLOUD_API_URL}/auth/device`, {
4663
- method: "POST",
4664
- headers: { "Content-Type": "application/json" },
4665
- body: JSON.stringify({ device_code: deviceCode, user_code: userCode })
4666
- });
4667
- if (!registerRes.ok) {
4668
- const err = await registerRes.json().catch(() => ({}));
4669
- throw new Error(`Failed to register device: ${err.error || registerRes.statusText}`);
4670
- }
4671
- const authUrl = `${CLOUD_API_URL}/auth/github?code=${encodeURIComponent(userCode)}`;
4672
- onStatus({ url: authUrl, userCode, polling: false });
4742
+ const codes = generateDeviceCodes();
4743
+ await registerDevice(codes);
4744
+ onStatus({ url: codes.authUrl, userCode: codes.userCode, polling: false });
4673
4745
  const startTime = Date.now();
4674
4746
  while (Date.now() - startTime < POLL_TIMEOUT_MS) {
4675
4747
  await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
4676
- onStatus({ url: authUrl, userCode, polling: true });
4677
- const pollRes = await fetch(`${CLOUD_API_URL}/auth/poll`, {
4678
- method: "POST",
4679
- headers: { "Content-Type": "application/json" },
4680
- body: JSON.stringify({ device_code: deviceCode })
4681
- });
4682
- if (!pollRes.ok) continue;
4683
- const pollData = await pollRes.json();
4684
- if (pollData.status === "approved" && pollData.access_token) {
4685
- const creds = {
4686
- accessToken: pollData.access_token,
4687
- expiresAt: Math.floor(Date.now() / 1e3) + 7 * 24 * 60 * 60
4688
- // 7 days
4689
- };
4690
- await saveCloudCredentials(creds);
4691
- return creds;
4692
- }
4748
+ onStatus({ url: codes.authUrl, userCode: codes.userCode, polling: true });
4749
+ const creds = await pollForToken(codes.deviceCode);
4750
+ if (creds) return creds;
4693
4751
  }
4694
4752
  throw new Error("Authentication timed out. Please try again.");
4695
4753
  }
@@ -4699,7 +4757,7 @@ var init_auth = __esm({
4699
4757
  "use strict";
4700
4758
  CLOUD_API_URL = "https://api.kimiflare.com";
4701
4759
  POLL_INTERVAL_MS = 5e3;
4702
- POLL_TIMEOUT_MS = 10 * 60 * 1e3;
4760
+ POLL_TIMEOUT_MS = 15 * 60 * 1e3;
4703
4761
  }
4704
4762
  });
4705
4763
 
@@ -6754,7 +6812,7 @@ import { useEffect, useState } from "react";
6754
6812
  import { Box as Box5, Text as Text5 } from "ink";
6755
6813
  import Spinner3 from "ink-spinner";
6756
6814
  import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
6757
- function StatusBar({ model, usage, sessionUsage, thinking, turnStartedAt, mode, effort, contextLimit, hasUpdate, latestVersion, gatewayMeta, codeMode, cloudMode }) {
6815
+ function StatusBar({ model, usage, sessionUsage, thinking, turnStartedAt, mode, effort, contextLimit, hasUpdate, latestVersion, gatewayMeta, codeMode, cloudMode, cloudBudget }) {
6758
6816
  const theme = useTheme();
6759
6817
  const [now2, setNow] = useState(Date.now());
6760
6818
  const modeColor = mode === "plan" ? theme.modeBadge.plan : mode === "auto" ? theme.modeBadge.auto : theme.modeBadge.edit;
@@ -6787,7 +6845,7 @@ function StatusBar({ model, usage, sessionUsage, thinking, turnStartedAt, mode,
6787
6845
  ] })
6788
6846
  ] }),
6789
6847
  usage && /* @__PURE__ */ jsxs5(Box5, { children: [
6790
- /* @__PURE__ */ jsx6(Text5, { color: theme.info.color, children: buildRightParts(usage, contextLimit, sessionUsage, gatewayMeta).join(" \xB7 ") }),
6848
+ /* @__PURE__ */ jsx6(Text5, { color: theme.info.color, children: buildRightParts(usage, contextLimit, sessionUsage, gatewayMeta, cloudMode, cloudBudget).join(" \xB7 ") }),
6791
6849
  warn ? /* @__PURE__ */ jsxs5(Text5, { color: theme.warn, bold: true, children: [
6792
6850
  " \xB7 ",
6793
6851
  "/compact recommended"
@@ -6801,7 +6859,7 @@ function StatusBar({ model, usage, sessionUsage, thinking, turnStartedAt, mode,
6801
6859
  ] })
6802
6860
  ] });
6803
6861
  }
6804
- function buildRightParts(usage, contextLimit, sessionUsage, gatewayMeta) {
6862
+ function buildRightParts(usage, contextLimit, sessionUsage, gatewayMeta, cloudMode, cloudBudget) {
6805
6863
  const pct = Math.round(usage.prompt_tokens / contextLimit * 100);
6806
6864
  const parts = [];
6807
6865
  if (sessionUsage) {
@@ -6809,19 +6867,35 @@ function buildRightParts(usage, contextLimit, sessionUsage, gatewayMeta) {
6809
6867
  parts.push(`in ${sessionUsage.promptTokens}${cached ? ` (${cached} cached)` : ""}`);
6810
6868
  parts.push(`out ${sessionUsage.completionTokens}`);
6811
6869
  parts.push(`ctx ${pct}%`);
6812
- parts.push(`$${sessionUsage.cost.toFixed(5)}`);
6870
+ if (cloudMode) {
6871
+ parts.push(`\x1B[9m${sessionUsage.cost.toFixed(5)}\x1B[29m`);
6872
+ } else {
6873
+ parts.push(`${sessionUsage.cost.toFixed(5)}`);
6874
+ }
6813
6875
  } else {
6814
6876
  const cached = usage.prompt_tokens_details?.cached_tokens ?? 0;
6815
6877
  const cost = calculateCost(usage.prompt_tokens, usage.completion_tokens, cached);
6816
6878
  parts.push(`in ${usage.prompt_tokens}${cached ? ` (${cached} cached)` : ""}`);
6817
6879
  parts.push(`out ${usage.completion_tokens}`);
6818
6880
  parts.push(`ctx ${pct}%`);
6819
- parts.push(`$${cost.total.toFixed(5)}`);
6881
+ if (cloudMode) {
6882
+ parts.push(`\x1B[9m${cost.total.toFixed(5)}\x1B[29m`);
6883
+ } else {
6884
+ parts.push(`${cost.total.toFixed(5)}`);
6885
+ }
6886
+ }
6887
+ if (cloudMode && cloudBudget) {
6888
+ parts.push(`${formatTokens(cloudBudget.remaining)}/${formatTokens(cloudBudget.limit)} tokens`);
6820
6889
  }
6821
6890
  const gatewayCache = formatGatewayCacheStatus(gatewayMeta);
6822
6891
  if (gatewayCache) parts.push(gatewayCache);
6823
6892
  return parts;
6824
6893
  }
6894
+ function formatTokens(n) {
6895
+ if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
6896
+ if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
6897
+ return String(n);
6898
+ }
6825
6899
  function formatGatewayCacheStatus(gatewayMeta) {
6826
6900
  const status = gatewayMeta?.cacheStatus?.trim();
6827
6901
  return status ? `AI Gateway \xB7 cache ${status.toLowerCase()}` : null;
@@ -6882,11 +6956,48 @@ var init_permission = __esm({
6882
6956
  }
6883
6957
  });
6884
6958
 
6885
- // src/ui/resume-picker.tsx
6886
- import { useState as useState2 } from "react";
6887
- import { Box as Box7, Text as Text7, useWindowSize } from "ink";
6959
+ // src/ui/limit-modal.tsx
6960
+ import { Box as Box7, Text as Text7 } from "ink";
6888
6961
  import SelectInput2 from "ink-select-input";
6889
6962
  import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
6963
+ function LimitModal({ limit, onDecide }) {
6964
+ const theme = useTheme();
6965
+ const items = [
6966
+ { label: "Continue", value: "continue" },
6967
+ { label: "Stop", value: "stop" }
6968
+ ];
6969
+ return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", borderStyle: "round", borderColor: theme.error, paddingX: 1, children: [
6970
+ /* @__PURE__ */ jsxs7(Text7, { color: theme.error, bold: true, children: [
6971
+ "Tool-call limit reached (",
6972
+ limit,
6973
+ ")"
6974
+ ] }),
6975
+ /* @__PURE__ */ jsxs7(Text7, { dimColor: true, children: [
6976
+ "This session has made ",
6977
+ limit,
6978
+ " tool calls. What would you like to do?"
6979
+ ] }),
6980
+ /* @__PURE__ */ jsx8(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx8(
6981
+ SelectInput2,
6982
+ {
6983
+ items,
6984
+ onSelect: (item) => onDecide(item.value)
6985
+ }
6986
+ ) })
6987
+ ] });
6988
+ }
6989
+ var init_limit_modal = __esm({
6990
+ "src/ui/limit-modal.tsx"() {
6991
+ "use strict";
6992
+ init_theme_context();
6993
+ }
6994
+ });
6995
+
6996
+ // src/ui/resume-picker.tsx
6997
+ import { useState as useState2 } from "react";
6998
+ import { Box as Box8, Text as Text8, useWindowSize } from "ink";
6999
+ import SelectInput3 from "ink-select-input";
7000
+ import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
6890
7001
  function ResumePicker({ sessions, onPick }) {
6891
7002
  const theme = useTheme();
6892
7003
  const { rows } = useWindowSize();
@@ -6895,11 +7006,11 @@ function ResumePicker({ sessions, onPick }) {
6895
7006
  const totalPages = Math.max(1, Math.ceil(sessions.length / pageSize));
6896
7007
  const safePage = Math.min(page, totalPages - 1);
6897
7008
  if (sessions.length === 0) {
6898
- return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
6899
- /* @__PURE__ */ jsx8(Text7, { color: theme.accent, bold: true, children: "Resume a session" }),
6900
- /* @__PURE__ */ jsx8(Text7, { color: theme.info.color, children: "No saved sessions yet. Press Enter to dismiss." }),
6901
- /* @__PURE__ */ jsx8(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx8(
6902
- SelectInput2,
7009
+ return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
7010
+ /* @__PURE__ */ jsx9(Text8, { color: theme.accent, bold: true, children: "Resume a session" }),
7011
+ /* @__PURE__ */ jsx9(Text8, { color: theme.info.color, children: "No saved sessions yet. Press Enter to dismiss." }),
7012
+ /* @__PURE__ */ jsx9(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx9(
7013
+ SelectInput3,
6903
7014
  {
6904
7015
  items: [{ label: "(back)", value: "__cancel__" }],
6905
7016
  onSelect: () => onPick(null)
@@ -6921,9 +7032,9 @@ function ResumePicker({ sessions, onPick }) {
6921
7032
  items.push({ label: "\u2192 next page", value: "__next__" });
6922
7033
  }
6923
7034
  items.push({ label: "(cancel)", value: "__cancel__" });
6924
- return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
6925
- /* @__PURE__ */ jsx8(Text7, { color: theme.accent, bold: true, children: "Resume a session" }),
6926
- /* @__PURE__ */ jsxs7(Text7, { color: theme.info.color, children: [
7035
+ return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
7036
+ /* @__PURE__ */ jsx9(Text8, { color: theme.accent, bold: true, children: "Resume a session" }),
7037
+ /* @__PURE__ */ jsxs8(Text8, { color: theme.info.color, children: [
6927
7038
  "Arrow keys to select, Enter to confirm. Page ",
6928
7039
  safePage + 1,
6929
7040
  " of ",
@@ -6932,8 +7043,8 @@ function ResumePicker({ sessions, onPick }) {
6932
7043
  sessions.length,
6933
7044
  " total)"
6934
7045
  ] }),
6935
- /* @__PURE__ */ jsx8(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx8(
6936
- SelectInput2,
7046
+ /* @__PURE__ */ jsx9(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx9(
7047
+ SelectInput3,
6937
7048
  {
6938
7049
  items,
6939
7050
  onSelect: (item) => {
@@ -6973,9 +7084,9 @@ var init_resume_picker = __esm({
6973
7084
 
6974
7085
  // src/ui/task-list.tsx
6975
7086
  import { useEffect as useEffect2, useRef, useState as useState3 } from "react";
6976
- import { Box as Box8, Text as Text8 } from "ink";
7087
+ import { Box as Box9, Text as Text9 } from "ink";
6977
7088
  import Spinner4 from "ink-spinner";
6978
- import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
7089
+ import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
6979
7090
  function TaskList({ tasks, startedAt, tokensDelta }) {
6980
7091
  const theme = useTheme();
6981
7092
  const [now2, setNow] = useState3(Date.now());
@@ -6999,21 +7110,21 @@ function TaskList({ tasks, startedAt, tokensDelta }) {
6999
7110
  const allDone = done === total;
7000
7111
  const header = active ? active.title : allDone ? `${total} tasks done` : `${done}/${total}`;
7001
7112
  const elapsed = startedAt ? formatElapsed2(now2 - startedAt) : null;
7002
- const headerStats = [elapsed, tokensDelta > 0 ? `\u2191 ${formatTokens(tokensDelta)} tokens` : null].filter(Boolean).join(" \xB7 ");
7113
+ const headerStats = [elapsed, tokensDelta > 0 ? `\u2191 ${formatTokens2(tokensDelta)} tokens` : null].filter(Boolean).join(" \xB7 ");
7003
7114
  const visibleTasks = tasks.slice(0, MAX_VISIBLE);
7004
7115
  const hiddenPending = Math.max(0, tasks.length - visibleTasks.length);
7005
- return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", marginBottom: 1, children: [
7006
- /* @__PURE__ */ jsxs8(Box8, { children: [
7007
- /* @__PURE__ */ jsx9(Text8, { color: allDone ? "green" : theme.accent, bold: true, children: header }),
7008
- headerStats && /* @__PURE__ */ jsxs8(Text8, { color: theme.info.color, children: [
7116
+ return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", marginBottom: 1, children: [
7117
+ /* @__PURE__ */ jsxs9(Box9, { children: [
7118
+ /* @__PURE__ */ jsx10(Text9, { color: allDone ? "green" : theme.accent, bold: true, children: header }),
7119
+ headerStats && /* @__PURE__ */ jsxs9(Text9, { color: theme.info.color, children: [
7009
7120
  " ",
7010
7121
  "(",
7011
7122
  headerStats,
7012
7123
  ")"
7013
7124
  ] })
7014
7125
  ] }),
7015
- visibleTasks.map((t) => /* @__PURE__ */ jsx9(TaskRow, { task: t }, t.id)),
7016
- hiddenPending > 0 && /* @__PURE__ */ jsxs8(Text8, { color: theme.info.color, children: [
7126
+ visibleTasks.map((t) => /* @__PURE__ */ jsx10(TaskRow, { task: t }, t.id)),
7127
+ hiddenPending > 0 && /* @__PURE__ */ jsxs9(Text9, { color: theme.info.color, children: [
7017
7128
  " ",
7018
7129
  "\u2026 +",
7019
7130
  hiddenPending,
@@ -7024,21 +7135,21 @@ function TaskList({ tasks, startedAt, tokensDelta }) {
7024
7135
  function TaskRow({ task }) {
7025
7136
  const theme = useTheme();
7026
7137
  if (task.status === "completed") {
7027
- return /* @__PURE__ */ jsxs8(Text8, { color: theme.info.color, children: [
7138
+ return /* @__PURE__ */ jsxs9(Text9, { color: theme.info.color, children: [
7028
7139
  " ",
7029
7140
  "\u2713 ",
7030
- /* @__PURE__ */ jsx9(Text8, { strikethrough: true, children: task.title })
7141
+ /* @__PURE__ */ jsx10(Text9, { strikethrough: true, children: task.title })
7031
7142
  ] });
7032
7143
  }
7033
7144
  if (task.status === "in_progress") {
7034
- return /* @__PURE__ */ jsxs8(Text8, { color: theme.accent, bold: true, children: [
7145
+ return /* @__PURE__ */ jsxs9(Text9, { color: theme.accent, bold: true, children: [
7035
7146
  " ",
7036
- /* @__PURE__ */ jsx9(Spinner4, { type: "dots" }),
7147
+ /* @__PURE__ */ jsx10(Spinner4, { type: "dots" }),
7037
7148
  " ",
7038
7149
  task.title
7039
7150
  ] });
7040
7151
  }
7041
- return /* @__PURE__ */ jsxs8(Text8, { color: theme.info.color, children: [
7152
+ return /* @__PURE__ */ jsxs9(Text9, { color: theme.info.color, children: [
7042
7153
  " ",
7043
7154
  "\u2610 ",
7044
7155
  task.title
@@ -7051,7 +7162,7 @@ function formatElapsed2(ms) {
7051
7162
  if (m === 0) return `${s}s`;
7052
7163
  return `${m}m ${s}s`;
7053
7164
  }
7054
- function formatTokens(n) {
7165
+ function formatTokens2(n) {
7055
7166
  if (n < 1e3) return String(n);
7056
7167
  return `${(n / 1e3).toFixed(1)}k`;
7057
7168
  }
@@ -7586,8 +7697,8 @@ var init_source = __esm({
7586
7697
 
7587
7698
  // src/ui/text-input.tsx
7588
7699
  import { useState as useState4, useEffect as useEffect3, useRef as useRef2 } from "react";
7589
- import { Text as Text9, useInput } from "ink";
7590
- import { jsx as jsx10 } from "react/jsx-runtime";
7700
+ import { Text as Text10, useInput } from "ink";
7701
+ import { jsx as jsx11 } from "react/jsx-runtime";
7591
7702
  function shouldTreatAsPaste(input) {
7592
7703
  if (input.length >= PASTE_CHAR_THRESHOLD) return true;
7593
7704
  const newlines = (input.match(/\n/g) ?? []).length;
@@ -7797,7 +7908,7 @@ function CustomTextInput({
7797
7908
  } else if (cursorOffset === displayValue.length) {
7798
7909
  renderedValue += source_default.inverse(" ");
7799
7910
  }
7800
- return /* @__PURE__ */ jsx10(Text9, { children: renderedValue });
7911
+ return /* @__PURE__ */ jsx11(Text10, { children: renderedValue });
7801
7912
  }
7802
7913
  function findPasteTokenEndingAt(value, pos, pastes) {
7803
7914
  if (pos <= 0 || value[pos - 1] !== "]") return -1;
@@ -7819,11 +7930,28 @@ var init_text_input = __esm({
7819
7930
  });
7820
7931
 
7821
7932
  // src/ui/onboarding.tsx
7822
- import { useState as useState5 } from "react";
7823
- import { Box as Box9, Text as Text10 } from "ink";
7824
- import SelectInput3 from "ink-select-input";
7825
- import { Fragment, jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
7826
- function Onboarding({ onDone }) {
7933
+ import { useState as useState5, useEffect as useEffect4, useCallback } from "react";
7934
+ import { Box as Box10, Text as Text11, useInput as useInput2 } from "ink";
7935
+ import SelectInput4 from "ink-select-input";
7936
+ import Spinner5 from "ink-spinner";
7937
+ import { exec } from "child_process";
7938
+ import { promisify as promisify2 } from "util";
7939
+ import { Fragment, jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
7940
+ function openBrowser(url) {
7941
+ const platform3 = process.platform;
7942
+ const cmd = platform3 === "darwin" ? `open "${url}"` : platform3 === "win32" ? `start "" "${url}"` : `xdg-open "${url}"`;
7943
+ exec(cmd, (err) => {
7944
+ if (err) {
7945
+ }
7946
+ });
7947
+ }
7948
+ function formatRemaining(ms) {
7949
+ const totalSeconds = Math.ceil(ms / 1e3);
7950
+ const mins = Math.floor(totalSeconds / 60);
7951
+ const secs = totalSeconds % 60;
7952
+ return `${mins}:${secs.toString().padStart(2, "0")}`;
7953
+ }
7954
+ function Onboarding({ onDone, onCancel }) {
7827
7955
  const theme = useTheme();
7828
7956
  const [step, setStep] = useState5("mode");
7829
7957
  const [mode, setMode] = useState5("byok");
@@ -7831,15 +7959,109 @@ function Onboarding({ onDone }) {
7831
7959
  const [apiToken, setApiToken] = useState5("");
7832
7960
  const [model, setModel] = useState5(DEFAULT_MODEL);
7833
7961
  const [savedPath, setSavedPath] = useState5(null);
7962
+ const [cloudAuth, setCloudAuth] = useState5(null);
7963
+ const [pollTick, setPollTick] = useState5(0);
7964
+ useEffect4(() => {
7965
+ if (step !== "cloudAuth" || !cloudAuth) return;
7966
+ if (cloudAuth.phase !== "polling") return;
7967
+ let cancelled = false;
7968
+ const tick = setInterval(() => {
7969
+ setPollTick((t) => t + 1);
7970
+ }, 1e3);
7971
+ const poll = async () => {
7972
+ while (!cancelled) {
7973
+ const elapsed = Date.now() - cloudAuth.startTime;
7974
+ if (elapsed >= POLL_TIMEOUT_MS) {
7975
+ if (!cancelled) {
7976
+ setCloudAuth({ phase: "error", message: "Authentication timed out. Please try again." });
7977
+ }
7978
+ return;
7979
+ }
7980
+ try {
7981
+ const creds = await pollForToken(cloudAuth.codes.deviceCode);
7982
+ if (creds && !cancelled) {
7983
+ const usage = await fetchCloudUsage(creds.accessToken);
7984
+ if (usage && !cancelled) {
7985
+ setCloudAuth({
7986
+ phase: "success",
7987
+ creds,
7988
+ usage
7989
+ });
7990
+ } else if (!cancelled) {
7991
+ setCloudAuth({ phase: "error", message: "Authenticated but failed to fetch usage." });
7992
+ }
7993
+ return;
7994
+ }
7995
+ } catch {
7996
+ }
7997
+ await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
7998
+ }
7999
+ };
8000
+ poll();
8001
+ return () => {
8002
+ cancelled = true;
8003
+ clearInterval(tick);
8004
+ };
8005
+ }, [step, cloudAuth]);
8006
+ useInput2(
8007
+ useCallback(
8008
+ (_input, key) => {
8009
+ if (key.escape && onCancel) {
8010
+ onCancel();
8011
+ }
8012
+ },
8013
+ [onCancel]
8014
+ )
8015
+ );
8016
+ const startCloudAuth = useCallback(async () => {
8017
+ try {
8018
+ const codes = generateDeviceCodes();
8019
+ await registerDevice(codes);
8020
+ setCloudAuth({ phase: "ready", codes });
8021
+ setStep("cloudAuth");
8022
+ } catch (err) {
8023
+ setCloudAuth({
8024
+ phase: "error",
8025
+ message: err instanceof Error ? err.message : "Failed to start authentication"
8026
+ });
8027
+ setStep("cloudAuth");
8028
+ }
8029
+ }, []);
7834
8030
  const handleModeSelect = (item) => {
7835
8031
  if (item.value === "cloud") {
7836
8032
  setMode("cloud");
7837
- setStep("cloudDone");
8033
+ void startCloudAuth();
7838
8034
  } else {
7839
8035
  setMode("byok");
7840
8036
  setStep("accountId");
7841
8037
  }
7842
8038
  };
8039
+ const handleOpenBrowser = () => {
8040
+ if (cloudAuth?.phase === "ready") {
8041
+ openBrowser(cloudAuth.codes.authUrl);
8042
+ setCloudAuth({ phase: "polling", codes: cloudAuth.codes, startTime: Date.now() });
8043
+ }
8044
+ };
8045
+ const handleCloudSuccess = async () => {
8046
+ if (cloudAuth?.phase !== "success") return;
8047
+ const cfg = { accountId: "", apiToken: "", model: DEFAULT_MODEL, cloudMode: true };
8048
+ try {
8049
+ const path = await saveConfig(cfg);
8050
+ setSavedPath(path);
8051
+ onDone(cfg);
8052
+ } catch (e) {
8053
+ setSavedPath(`error: ${e.message}`);
8054
+ }
8055
+ };
8056
+ const handleCloudRetry = () => {
8057
+ setCloudAuth(null);
8058
+ void startCloudAuth();
8059
+ };
8060
+ const handleCloudSwitchToByok = () => {
8061
+ setCloudAuth(null);
8062
+ setMode("byok");
8063
+ setStep("accountId");
8064
+ };
7843
8065
  const handleAccountIdSubmit = (value) => {
7844
8066
  const trimmed = value.trim();
7845
8067
  if (!trimmed) return;
@@ -7858,17 +8080,7 @@ function Onboarding({ onDone }) {
7858
8080
  setStep("confirm");
7859
8081
  };
7860
8082
  const handleConfirm = async () => {
7861
- const cfg = mode === "cloud" ? { accountId: "", apiToken: "", model, cloudMode: true } : { accountId, apiToken, model };
7862
- try {
7863
- const path = await saveConfig(cfg);
7864
- setSavedPath(path);
7865
- onDone(cfg);
7866
- } catch (e) {
7867
- setSavedPath(`error: ${e.message}`);
7868
- }
7869
- };
7870
- const handleCloudSave = async () => {
7871
- const cfg = { accountId: "", apiToken: "", model: DEFAULT_MODEL, cloudMode: true };
8083
+ const cfg = { accountId, apiToken, model };
7872
8084
  try {
7873
8085
  const path = await saveConfig(cfg);
7874
8086
  setSavedPath(path);
@@ -7878,27 +8090,27 @@ function Onboarding({ onDone }) {
7878
8090
  }
7879
8091
  };
7880
8092
  const byokSteps = ["accountId", "apiToken", "model", "confirm"];
7881
- const stepIndex = step === "mode" ? 1 : step === "cloudDone" ? 2 : byokSteps.indexOf(step) + 2;
8093
+ const stepIndex = step === "mode" ? 1 : step === "cloudAuth" ? 2 : byokSteps.indexOf(step) + 2;
7882
8094
  const totalSteps = mode === "cloud" ? 2 : byokSteps.length + 1;
7883
- return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", paddingY: 1, children: [
7884
- /* @__PURE__ */ jsxs9(Box9, { marginBottom: 1, children: [
7885
- /* @__PURE__ */ jsx11(Text10, { bold: true, color: theme.palette.primary, children: "kimiflare" }),
7886
- /* @__PURE__ */ jsxs9(Text10, { color: theme.info.color, children: [
8095
+ return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", paddingY: 1, children: [
8096
+ /* @__PURE__ */ jsxs10(Box10, { marginBottom: 1, children: [
8097
+ /* @__PURE__ */ jsx12(Text11, { bold: true, color: theme.palette.primary, children: "kimiflare" }),
8098
+ /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
7887
8099
  " ",
7888
8100
  "Terminal coding agent"
7889
8101
  ] })
7890
8102
  ] }),
7891
- /* @__PURE__ */ jsxs9(Text10, { color: theme.info.color, children: [
8103
+ /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
7892
8104
  "Step ",
7893
8105
  stepIndex,
7894
8106
  " of ",
7895
8107
  totalSteps
7896
8108
  ] }),
7897
- /* @__PURE__ */ jsxs9(Box9, { marginTop: 1, flexDirection: "column", children: [
7898
- step === "mode" && /* @__PURE__ */ jsxs9(Fragment, { children: [
7899
- /* @__PURE__ */ jsx11(Text10, { children: "How do you want to connect?" }),
7900
- /* @__PURE__ */ jsx11(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx11(
7901
- SelectInput3,
8109
+ /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, flexDirection: "column", children: [
8110
+ step === "mode" && /* @__PURE__ */ jsxs10(Fragment, { children: [
8111
+ /* @__PURE__ */ jsx12(Text11, { children: "How do you want to connect?" }),
8112
+ /* @__PURE__ */ jsx12(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx12(
8113
+ SelectInput4,
7902
8114
  {
7903
8115
  items: [
7904
8116
  { label: "Cloud (managed) \u2014 no API key needed", value: "cloud" },
@@ -7908,11 +8120,102 @@ function Onboarding({ onDone }) {
7908
8120
  }
7909
8121
  ) })
7910
8122
  ] }),
7911
- step === "accountId" && /* @__PURE__ */ jsxs9(Fragment, { children: [
7912
- /* @__PURE__ */ jsx11(Text10, { children: "Enter your Cloudflare Account ID" }),
7913
- /* @__PURE__ */ jsxs9(Box9, { marginTop: 1, children: [
7914
- /* @__PURE__ */ jsx11(Text10, { color: theme.palette.primary, children: "\u203A " }),
7915
- /* @__PURE__ */ jsx11(
8123
+ step === "cloudAuth" && cloudAuth?.phase === "ready" && /* @__PURE__ */ jsxs10(Fragment, { children: [
8124
+ /* @__PURE__ */ jsx12(Text11, { children: "Authenticating with Kimiflare Cloud..." }),
8125
+ /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, flexDirection: "column", children: [
8126
+ /* @__PURE__ */ jsx12(Text11, { children: "1. Open this URL in your browser:" }),
8127
+ /* @__PURE__ */ jsx12(Text11, { color: theme.palette.primary, children: cloudAuth.codes.authUrl })
8128
+ ] }),
8129
+ /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
8130
+ /* @__PURE__ */ jsx12(Text11, { children: "2. " }),
8131
+ /* @__PURE__ */ jsx12(Text11, { bold: true, children: "[Press Enter to open browser]" })
8132
+ ] }),
8133
+ /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
8134
+ /* @__PURE__ */ jsx12(Text11, { color: theme.palette.primary, children: "\u203A " }),
8135
+ /* @__PURE__ */ jsx12(
8136
+ CustomTextInput,
8137
+ {
8138
+ value: "",
8139
+ onChange: () => {
8140
+ },
8141
+ onSubmit: handleOpenBrowser
8142
+ }
8143
+ )
8144
+ ] })
8145
+ ] }),
8146
+ step === "cloudAuth" && cloudAuth?.phase === "polling" && /* @__PURE__ */ jsxs10(Fragment, { children: [
8147
+ /* @__PURE__ */ jsxs10(Text11, { children: [
8148
+ /* @__PURE__ */ jsx12(Text11, { color: theme.spinner, children: /* @__PURE__ */ jsx12(Spinner5, { type: "dots" }) }),
8149
+ " ",
8150
+ "Waiting for authentication..."
8151
+ ] }),
8152
+ /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
8153
+ "Expires in ",
8154
+ formatRemaining(POLL_TIMEOUT_MS - (Date.now() - cloudAuth.startTime))
8155
+ ] }),
8156
+ /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
8157
+ "URL: ",
8158
+ cloudAuth.codes.authUrl
8159
+ ] })
8160
+ ] }),
8161
+ step === "cloudAuth" && cloudAuth?.phase === "success" && /* @__PURE__ */ jsxs10(Fragment, { children: [
8162
+ /* @__PURE__ */ jsx12(Text11, { color: theme.palette.success, children: "Authenticated!" }),
8163
+ /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, flexDirection: "column", children: [
8164
+ /* @__PURE__ */ jsxs10(Text11, { children: [
8165
+ "Token budget:",
8166
+ " ",
8167
+ /* @__PURE__ */ jsxs10(Text11, { bold: true, children: [
8168
+ cloudAuth.usage.remaining.toLocaleString(),
8169
+ " /",
8170
+ " ",
8171
+ cloudAuth.usage.input_token_limit.toLocaleString()
8172
+ ] }),
8173
+ " ",
8174
+ "remaining"
8175
+ ] }),
8176
+ /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
8177
+ "Grant expires: ",
8178
+ cloudAuth.usage.expires_at
8179
+ ] })
8180
+ ] }),
8181
+ /* @__PURE__ */ jsx12(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text11, { children: "[Press Enter to continue]" }) }),
8182
+ /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
8183
+ /* @__PURE__ */ jsx12(Text11, { color: theme.palette.primary, children: "\u203A " }),
8184
+ /* @__PURE__ */ jsx12(
8185
+ CustomTextInput,
8186
+ {
8187
+ value: "",
8188
+ onChange: () => {
8189
+ },
8190
+ onSubmit: handleCloudSuccess
8191
+ }
8192
+ )
8193
+ ] })
8194
+ ] }),
8195
+ step === "cloudAuth" && cloudAuth?.phase === "error" && /* @__PURE__ */ jsxs10(Fragment, { children: [
8196
+ /* @__PURE__ */ jsx12(Text11, { color: theme.palette.error, children: "Authentication failed" }),
8197
+ /* @__PURE__ */ jsx12(Text11, { color: theme.info.color, children: cloudAuth.message }),
8198
+ /* @__PURE__ */ jsx12(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx12(
8199
+ SelectInput4,
8200
+ {
8201
+ items: [
8202
+ { label: "Retry", value: "retry" },
8203
+ { label: "Switch to BYOK", value: "byok" },
8204
+ { label: "Cancel", value: "cancel" }
8205
+ ],
8206
+ onSelect: (item) => {
8207
+ if (item.value === "retry") handleCloudRetry();
8208
+ else if (item.value === "byok") handleCloudSwitchToByok();
8209
+ else if (onCancel) onCancel();
8210
+ }
8211
+ }
8212
+ ) })
8213
+ ] }),
8214
+ step === "accountId" && /* @__PURE__ */ jsxs10(Fragment, { children: [
8215
+ /* @__PURE__ */ jsx12(Text11, { children: "Enter your Cloudflare Account ID" }),
8216
+ /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
8217
+ /* @__PURE__ */ jsx12(Text11, { color: theme.palette.primary, children: "\u203A " }),
8218
+ /* @__PURE__ */ jsx12(
7916
8219
  CustomTextInput,
7917
8220
  {
7918
8221
  value: accountId,
@@ -7922,12 +8225,12 @@ function Onboarding({ onDone }) {
7922
8225
  )
7923
8226
  ] })
7924
8227
  ] }),
7925
- step === "apiToken" && /* @__PURE__ */ jsxs9(Fragment, { children: [
7926
- /* @__PURE__ */ jsx11(Text10, { children: "Enter your Cloudflare API Token" }),
7927
- /* @__PURE__ */ jsx11(Text10, { color: theme.info.color, children: "Create one at https://dash.cloudflare.com/profile/api-tokens" }),
7928
- /* @__PURE__ */ jsxs9(Box9, { marginTop: 1, children: [
7929
- /* @__PURE__ */ jsx11(Text10, { color: theme.palette.primary, children: "\u203A " }),
7930
- /* @__PURE__ */ jsx11(
8228
+ step === "apiToken" && /* @__PURE__ */ jsxs10(Fragment, { children: [
8229
+ /* @__PURE__ */ jsx12(Text11, { children: "Enter your Cloudflare API Token" }),
8230
+ /* @__PURE__ */ jsx12(Text11, { color: theme.info.color, children: "Create one at https://dash.cloudflare.com/profile/api-tokens" }),
8231
+ /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
8232
+ /* @__PURE__ */ jsx12(Text11, { color: theme.palette.primary, children: "\u203A " }),
8233
+ /* @__PURE__ */ jsx12(
7931
8234
  CustomTextInput,
7932
8235
  {
7933
8236
  value: apiToken,
@@ -7938,15 +8241,15 @@ function Onboarding({ onDone }) {
7938
8241
  )
7939
8242
  ] })
7940
8243
  ] }),
7941
- step === "model" && /* @__PURE__ */ jsxs9(Fragment, { children: [
7942
- /* @__PURE__ */ jsx11(Text10, { children: "Model ID (press Enter for default)" }),
7943
- /* @__PURE__ */ jsxs9(Text10, { color: theme.info.color, children: [
8244
+ step === "model" && /* @__PURE__ */ jsxs10(Fragment, { children: [
8245
+ /* @__PURE__ */ jsx12(Text11, { children: "Model ID (press Enter for default)" }),
8246
+ /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
7944
8247
  "default: ",
7945
8248
  DEFAULT_MODEL
7946
8249
  ] }),
7947
- /* @__PURE__ */ jsxs9(Box9, { marginTop: 1, children: [
7948
- /* @__PURE__ */ jsx11(Text10, { color: theme.palette.primary, children: "\u203A " }),
7949
- /* @__PURE__ */ jsx11(
8250
+ /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
8251
+ /* @__PURE__ */ jsx12(Text11, { color: theme.palette.primary, children: "\u203A " }),
8252
+ /* @__PURE__ */ jsx12(
7950
8253
  CustomTextInput,
7951
8254
  {
7952
8255
  value: model,
@@ -7956,10 +8259,10 @@ function Onboarding({ onDone }) {
7956
8259
  )
7957
8260
  ] })
7958
8261
  ] }),
7959
- step === "confirm" && /* @__PURE__ */ jsxs9(Fragment, { children: [
7960
- /* @__PURE__ */ jsx11(Text10, { children: "Ready to save configuration" }),
7961
- /* @__PURE__ */ jsxs9(
7962
- Box9,
8262
+ step === "confirm" && /* @__PURE__ */ jsxs10(Fragment, { children: [
8263
+ /* @__PURE__ */ jsx12(Text11, { children: "Ready to save configuration" }),
8264
+ /* @__PURE__ */ jsxs10(
8265
+ Box10,
7963
8266
  {
7964
8267
  flexDirection: "column",
7965
8268
  marginTop: 1,
@@ -7968,25 +8271,25 @@ function Onboarding({ onDone }) {
7968
8271
  borderColor: theme.info.color,
7969
8272
  paddingX: 1,
7970
8273
  children: [
7971
- /* @__PURE__ */ jsxs9(Text10, { color: theme.info.color, children: [
8274
+ /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
7972
8275
  "Account ID: ",
7973
8276
  accountId
7974
8277
  ] }),
7975
- /* @__PURE__ */ jsxs9(Text10, { color: theme.info.color, children: [
8278
+ /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
7976
8279
  "API Token: ",
7977
8280
  "\u2022".repeat(apiToken.length)
7978
8281
  ] }),
7979
- /* @__PURE__ */ jsxs9(Text10, { color: theme.info.color, children: [
8282
+ /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
7980
8283
  "Model: ",
7981
8284
  model
7982
8285
  ] })
7983
8286
  ]
7984
8287
  }
7985
8288
  ),
7986
- /* @__PURE__ */ jsx11(Text10, { children: "Press Enter to confirm, or Ctrl+C to cancel" }),
7987
- /* @__PURE__ */ jsxs9(Box9, { marginTop: 1, children: [
7988
- /* @__PURE__ */ jsx11(Text10, { color: theme.palette.primary, children: "\u203A " }),
7989
- /* @__PURE__ */ jsx11(
8289
+ /* @__PURE__ */ jsx12(Text11, { children: "Press Enter to confirm, or Ctrl+C to cancel" }),
8290
+ /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
8291
+ /* @__PURE__ */ jsx12(Text11, { color: theme.palette.primary, children: "\u203A " }),
8292
+ /* @__PURE__ */ jsx12(
7990
8293
  CustomTextInput,
7991
8294
  {
7992
8295
  value: "",
@@ -7997,68 +8300,54 @@ function Onboarding({ onDone }) {
7997
8300
  )
7998
8301
  ] })
7999
8302
  ] }),
8000
- step === "cloudDone" && /* @__PURE__ */ jsxs9(Fragment, { children: [
8001
- /* @__PURE__ */ jsx11(Text10, { children: "Cloud mode selected" }),
8002
- /* @__PURE__ */ jsx11(Text10, { color: theme.info.color, children: "No API key needed. Run `kimiflare auth cloud` to sign in." }),
8003
- /* @__PURE__ */ jsx11(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text10, { children: "Press Enter to save, or Ctrl+C to cancel" }) }),
8004
- /* @__PURE__ */ jsxs9(Box9, { marginTop: 1, children: [
8005
- /* @__PURE__ */ jsx11(Text10, { color: theme.palette.primary, children: "\u203A " }),
8006
- /* @__PURE__ */ jsx11(
8007
- CustomTextInput,
8008
- {
8009
- value: "",
8010
- onChange: () => {
8011
- },
8012
- onSubmit: handleCloudSave
8013
- }
8014
- )
8015
- ] })
8016
- ] }),
8017
- savedPath && /* @__PURE__ */ jsxs9(Text10, { color: theme.palette.success, children: [
8303
+ savedPath && /* @__PURE__ */ jsxs10(Text11, { color: theme.palette.success, children: [
8018
8304
  "Config saved to ",
8019
8305
  savedPath
8020
8306
  ] })
8021
8307
  ] })
8022
8308
  ] });
8023
8309
  }
8310
+ var execAsync;
8024
8311
  var init_onboarding = __esm({
8025
8312
  "src/ui/onboarding.tsx"() {
8026
8313
  "use strict";
8027
8314
  init_text_input();
8028
8315
  init_config();
8029
8316
  init_theme_context();
8317
+ init_auth();
8318
+ execAsync = promisify2(exec);
8030
8319
  }
8031
8320
  });
8032
8321
 
8033
8322
  // src/ui/welcome.tsx
8034
- import { Box as Box10, Text as Text11 } from "ink";
8035
- import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
8323
+ import { Box as Box11, Text as Text12 } from "ink";
8324
+ import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
8036
8325
  function Welcome({ accountId }) {
8037
8326
  const theme = useTheme();
8038
- return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", marginBottom: 1, children: [
8039
- /* @__PURE__ */ jsxs10(Box10, { marginBottom: 1, children: [
8040
- /* @__PURE__ */ jsx12(Text11, { bold: true, color: theme.accent, children: "kimiflare" }),
8041
- /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
8327
+ return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", marginBottom: 1, children: [
8328
+ /* @__PURE__ */ jsxs11(Box11, { marginBottom: 1, children: [
8329
+ /* @__PURE__ */ jsx13(Text12, { bold: true, color: theme.accent, children: "kimiflare" }),
8330
+ /* @__PURE__ */ jsxs11(Text12, { color: theme.info.color, children: [
8042
8331
  " ",
8043
8332
  "Ready when you are."
8044
8333
  ] })
8045
8334
  ] }),
8046
- accountId && /* @__PURE__ */ jsx12(Box10, { marginBottom: 1, children: /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
8335
+ accountId && /* @__PURE__ */ jsx13(Box11, { marginBottom: 1, children: /* @__PURE__ */ jsxs11(Text12, { color: theme.info.color, children: [
8047
8336
  " ",
8048
8337
  "Check your Cloudflare billing: https://dash.cloudflare.com/",
8049
8338
  accountId,
8050
8339
  "/billing/billable-usage"
8051
8340
  ] }) }),
8052
- /* @__PURE__ */ jsx12(Box10, { flexDirection: "column", children: SUGGESTIONS.map((s, i) => /* @__PURE__ */ jsxs10(Box10, { children: [
8053
- /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
8341
+ /* @__PURE__ */ jsx13(Box11, { flexDirection: "column", children: SUGGESTIONS.map((s, i) => /* @__PURE__ */ jsxs11(Box11, { children: [
8342
+ /* @__PURE__ */ jsxs11(Text12, { color: theme.info.color, children: [
8054
8343
  " ",
8055
8344
  "\u203A",
8056
8345
  " "
8057
8346
  ] }),
8058
- /* @__PURE__ */ jsx12(Text11, { color: theme.user, children: s })
8347
+ /* @__PURE__ */ jsx13(Text12, { color: theme.user, children: s })
8059
8348
  ] }, i)) }),
8060
- /* @__PURE__ */ jsx12(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text11, { color: theme.info.color, children: "Type a message or /help for commands \xB7 ctrl-c to exit \xB7 shift+tab to cycle modes" }) }),
8061
- /* @__PURE__ */ jsx12(Box10, { children: /* @__PURE__ */ jsx12(Text11, { color: theme.info.color, children: "Tip: type /hello to send feedback to the creator" }) })
8349
+ /* @__PURE__ */ jsx13(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx13(Text12, { color: theme.info.color, children: "Type a message or /help for commands \xB7 ctrl-c to exit \xB7 shift+tab to cycle modes" }) }),
8350
+ /* @__PURE__ */ jsx13(Box11, { children: /* @__PURE__ */ jsx13(Text12, { color: theme.info.color, children: "Tip: type /hello to send feedback to the creator" }) })
8062
8351
  ] });
8063
8352
  }
8064
8353
  var SUGGESTIONS;
@@ -8076,14 +8365,14 @@ var init_welcome = __esm({
8076
8365
 
8077
8366
  // src/ui/help-menu.tsx
8078
8367
  import { useState as useState6 } from "react";
8079
- import { Box as Box11, Text as Text12, useInput as useInput2 } from "ink";
8080
- import SelectInput4 from "ink-select-input";
8081
- import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
8368
+ import { Box as Box12, Text as Text13, useInput as useInput3 } from "ink";
8369
+ import SelectInput5 from "ink-select-input";
8370
+ import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
8082
8371
  function HelpMenu({ customCommands, costAttributionEnabled, cloudMode, onDone, onCommand }) {
8083
8372
  const theme = useTheme();
8084
8373
  const [page, setPage] = useState6("main");
8085
8374
  const customs = customCommands ?? [];
8086
- useInput2((_input, key) => {
8375
+ useInput3((_input, key) => {
8087
8376
  if (key.escape) {
8088
8377
  if (page !== "main") {
8089
8378
  setPage("main");
@@ -8107,11 +8396,11 @@ function HelpMenu({ customCommands, costAttributionEnabled, cloudMode, onDone, o
8107
8396
  items2.push({ label: "Run custom commands", value: "custom", key: "custom" });
8108
8397
  }
8109
8398
  items2.push({ label: "(close)", value: "__close__", key: "__close__" });
8110
- return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
8111
- /* @__PURE__ */ jsx13(Text12, { color: theme.accent, bold: true, children: "Help" }),
8112
- /* @__PURE__ */ jsx13(Text12, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select, Esc to close." }),
8113
- /* @__PURE__ */ jsx13(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx13(
8114
- SelectInput4,
8399
+ return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
8400
+ /* @__PURE__ */ jsx14(Text13, { color: theme.accent, bold: true, children: "Help" }),
8401
+ /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select, Esc to close." }),
8402
+ /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(
8403
+ SelectInput5,
8115
8404
  {
8116
8405
  items: items2,
8117
8406
  onSelect: (item) => {
@@ -8123,8 +8412,8 @@ function HelpMenu({ customCommands, costAttributionEnabled, cloudMode, onDone, o
8123
8412
  }
8124
8413
  }
8125
8414
  ) }),
8126
- /* @__PURE__ */ jsx13(Box11, { marginTop: 1, flexDirection: "column", children: SINGLE_COMMANDS.map((cmd) => /* @__PURE__ */ jsx13(Text12, { color: theme.info.color, dimColor: false, children: ` ${cmd.command.padEnd(20)} ${cmd.description}` }, cmd.command)) }),
8127
- /* @__PURE__ */ jsx13(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx13(Text12, { color: theme.info.color, dimColor: false, children: "keys: ctrl-c interrupt/exit \xB7 ctrl-r toggle reasoning \xB7 ctrl-o verbose \xB7 shift+tab cycle mode \xB7 \u2191/\u2193 history" }) })
8415
+ /* @__PURE__ */ jsx14(Box12, { marginTop: 1, flexDirection: "column", children: SINGLE_COMMANDS.map((cmd) => /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, dimColor: false, children: ` ${cmd.command.padEnd(20)} ${cmd.description}` }, cmd.command)) }),
8416
+ /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, dimColor: false, children: "keys: ctrl-c interrupt/exit \xB7 ctrl-r toggle reasoning \xB7 ctrl-o verbose \xB7 shift+tab cycle mode \xB7 \u2191/\u2193 history" }) })
8128
8417
  ] });
8129
8418
  }
8130
8419
  if (page === "custom") {
@@ -8134,11 +8423,11 @@ function HelpMenu({ customCommands, costAttributionEnabled, cloudMode, onDone, o
8134
8423
  key: c.name
8135
8424
  }));
8136
8425
  items2.push({ label: "\u2190 Back", value: "__back__", key: "__back__" });
8137
- return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
8138
- /* @__PURE__ */ jsx13(Text12, { color: theme.accent, bold: true, children: "Custom commands" }),
8139
- /* @__PURE__ */ jsx13(Text12, { color: theme.info.color, dimColor: false, children: customs.length === 0 ? "no custom commands found in .kimiflare/commands/" : "Arrow keys to navigate, Enter to run, Esc to go back." }),
8140
- /* @__PURE__ */ jsx13(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx13(
8141
- SelectInput4,
8426
+ return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
8427
+ /* @__PURE__ */ jsx14(Text13, { color: theme.accent, bold: true, children: "Custom commands" }),
8428
+ /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, dimColor: false, children: customs.length === 0 ? "no custom commands found in .kimiflare/commands/" : "Arrow keys to navigate, Enter to run, Esc to go back." }),
8429
+ /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(
8430
+ SelectInput5,
8142
8431
  {
8143
8432
  items: items2,
8144
8433
  onSelect: (item) => {
@@ -8161,11 +8450,11 @@ function HelpMenu({ customCommands, costAttributionEnabled, cloudMode, onDone, o
8161
8450
  key: cmd.command
8162
8451
  }));
8163
8452
  items.push({ label: "\u2190 Back", value: "__back__", key: "__back__" });
8164
- return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
8165
- /* @__PURE__ */ jsx13(Text12, { color: theme.accent, bold: true, children: category.label }),
8166
- /* @__PURE__ */ jsx13(Text12, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to execute, Esc to go back." }),
8167
- /* @__PURE__ */ jsx13(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx13(
8168
- SelectInput4,
8453
+ return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
8454
+ /* @__PURE__ */ jsx14(Text13, { color: theme.accent, bold: true, children: category.label }),
8455
+ /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to execute, Esc to go back." }),
8456
+ /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(
8457
+ SelectInput5,
8169
8458
  {
8170
8459
  items,
8171
8460
  onSelect: (item) => {
@@ -8177,7 +8466,7 @@ function HelpMenu({ customCommands, costAttributionEnabled, cloudMode, onDone, o
8177
8466
  }
8178
8467
  }
8179
8468
  ) }),
8180
- staticCmds.length > 0 && /* @__PURE__ */ jsx13(Box11, { marginTop: 1, flexDirection: "column", children: staticCmds.map((cmd) => /* @__PURE__ */ jsx13(Text12, { color: theme.info.color, children: ` ${cmd.command.padEnd(28)} ${cmd.description}` }, cmd.command)) })
8469
+ staticCmds.length > 0 && /* @__PURE__ */ jsx14(Box12, { marginTop: 1, flexDirection: "column", children: staticCmds.map((cmd) => /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, children: ` ${cmd.command.padEnd(28)} ${cmd.description}` }, cmd.command)) })
8181
8470
  ] });
8182
8471
  }
8183
8472
  var CATEGORIES, SINGLE_COMMANDS;
@@ -8409,17 +8698,17 @@ var init_tui_deploy = __esm({
8409
8698
  });
8410
8699
 
8411
8700
  // src/ui/remote-dashboard.tsx
8412
- import { useEffect as useEffect4, useState as useState7 } from "react";
8413
- import { Box as Box12, Text as Text13, useInput as useInput3 } from "ink";
8414
- import SelectInput5 from "ink-select-input";
8415
- import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
8701
+ import { useEffect as useEffect5, useState as useState7 } from "react";
8702
+ import { Box as Box13, Text as Text14, useInput as useInput4 } from "ink";
8703
+ import SelectInput6 from "ink-select-input";
8704
+ import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
8416
8705
  function RemoteDashboard({ onSelect, onCancel }) {
8417
8706
  const theme = useTheme();
8418
8707
  const [sessions, setSessions] = useState7([]);
8419
8708
  const [loading, setLoading] = useState7(true);
8420
8709
  const [error, setError] = useState7(null);
8421
8710
  const [refreshing, setRefreshing] = useState7(false);
8422
- useEffect4(() => {
8711
+ useEffect5(() => {
8423
8712
  loadSessions();
8424
8713
  }, []);
8425
8714
  async function loadSessions() {
@@ -8455,7 +8744,7 @@ function RemoteDashboard({ onSelect, onCancel }) {
8455
8744
  setRefreshing(false);
8456
8745
  }
8457
8746
  }
8458
- useInput3((input, key) => {
8747
+ useInput4((input, key) => {
8459
8748
  if (input === "r" || input === "R") {
8460
8749
  void loadSessions();
8461
8750
  }
@@ -8468,31 +8757,31 @@ function RemoteDashboard({ onSelect, onCancel }) {
8468
8757
  value: s.sessionId
8469
8758
  }));
8470
8759
  if (loading) {
8471
- return /* @__PURE__ */ jsx14(Box12, { flexDirection: "column", padding: 1, children: /* @__PURE__ */ jsx14(Text13, { color: theme.accent, children: "Loading remote sessions..." }) });
8760
+ return /* @__PURE__ */ jsx15(Box13, { flexDirection: "column", padding: 1, children: /* @__PURE__ */ jsx15(Text14, { color: theme.accent, children: "Loading remote sessions..." }) });
8472
8761
  }
8473
8762
  if (error) {
8474
- return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", padding: 1, children: [
8475
- /* @__PURE__ */ jsxs12(Text13, { color: theme.error, children: [
8763
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", padding: 1, children: [
8764
+ /* @__PURE__ */ jsxs13(Text14, { color: theme.error, children: [
8476
8765
  "Error: ",
8477
8766
  error
8478
8767
  ] }),
8479
- /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "Press R to retry, Esc to close" })
8768
+ /* @__PURE__ */ jsx15(Text14, { dimColor: true, children: "Press R to retry, Esc to close" })
8480
8769
  ] });
8481
8770
  }
8482
8771
  if (sessions.length === 0) {
8483
- return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", padding: 1, children: [
8484
- /* @__PURE__ */ jsx14(Text13, { color: theme.accent, children: "No remote sessions yet." }),
8485
- /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "Type /remote <prompt> to start one." }),
8486
- /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "Press Esc to close" })
8772
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", padding: 1, children: [
8773
+ /* @__PURE__ */ jsx15(Text14, { color: theme.accent, children: "No remote sessions yet." }),
8774
+ /* @__PURE__ */ jsx15(Text14, { dimColor: true, children: "Type /remote <prompt> to start one." }),
8775
+ /* @__PURE__ */ jsx15(Text14, { dimColor: true, children: "Press Esc to close" })
8487
8776
  ] });
8488
8777
  }
8489
- return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", padding: 1, children: [
8490
- /* @__PURE__ */ jsxs12(Text13, { bold: true, color: theme.accent, children: [
8778
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", padding: 1, children: [
8779
+ /* @__PURE__ */ jsxs13(Text14, { bold: true, color: theme.accent, children: [
8491
8780
  "Recent remote tasks ",
8492
8781
  refreshing ? "(refreshing...)" : ""
8493
8782
  ] }),
8494
- /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(
8495
- SelectInput5,
8783
+ /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
8784
+ SelectInput6,
8496
8785
  {
8497
8786
  items,
8498
8787
  onSelect: (item) => {
@@ -8501,7 +8790,7 @@ function RemoteDashboard({ onSelect, onCancel }) {
8501
8790
  }
8502
8791
  }
8503
8792
  ) }),
8504
- /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "\u2191\u2193 navigate \u2022 Enter select \u2022 R refresh \u2022 Esc close" }) })
8793
+ /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(Text14, { dimColor: true, children: "\u2191\u2193 navigate \u2022 Enter select \u2022 R refresh \u2022 Esc close" }) })
8505
8794
  ] });
8506
8795
  }
8507
8796
  function formatSessionLine(s) {
@@ -8509,7 +8798,7 @@ function formatSessionLine(s) {
8509
8798
  const ago = formatAgo(new Date(s.updatedAt));
8510
8799
  const prompt = s.prompt.slice(0, 30) + (s.prompt.length > 30 ? "\u2026" : "");
8511
8800
  const outcome = s.prUrl ? `PR ${s.prUrl.split("/").pop()}` : s.status;
8512
- const cost = s.tokensUsed && s.tokensBudget ? ` (${formatTokens2(s.tokensUsed)}/${formatTokens2(s.tokensBudget)})` : s.tokensUsed ? ` (${formatTokens2(s.tokensUsed)})` : "";
8801
+ const cost = s.tokensUsed && s.tokensBudget ? ` (${formatTokens3(s.tokensUsed)}/${formatTokens3(s.tokensBudget)})` : s.tokensUsed ? ` (${formatTokens3(s.tokensUsed)})` : "";
8513
8802
  return `${icon} ${prompt} \u2192 ${outcome} ${ago}${cost}`;
8514
8803
  }
8515
8804
  function formatAgo(date) {
@@ -8522,7 +8811,7 @@ function formatAgo(date) {
8522
8811
  if (minutes > 0) return `${minutes}m ago`;
8523
8812
  return "just now";
8524
8813
  }
8525
- function formatTokens2(n) {
8814
+ function formatTokens3(n) {
8526
8815
  if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
8527
8816
  if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
8528
8817
  return String(n);
@@ -8534,7 +8823,7 @@ function RemoteSessionDetail({
8534
8823
  }) {
8535
8824
  const theme = useTheme();
8536
8825
  const [cancelling, setCancelling] = useState7(false);
8537
- useInput3((input, key) => {
8826
+ useInput4((input, key) => {
8538
8827
  if (key.escape) {
8539
8828
  onBack();
8540
8829
  }
@@ -8554,50 +8843,50 @@ function RemoteSessionDetail({
8554
8843
  }
8555
8844
  }
8556
8845
  const isRunning = session.status === "running" || session.status === "pending";
8557
- return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", padding: 1, children: [
8558
- /* @__PURE__ */ jsx14(Text13, { bold: true, color: theme.accent, children: "Remote Session" }),
8559
- /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "column", children: [
8560
- /* @__PURE__ */ jsxs12(Text13, { children: [
8846
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", padding: 1, children: [
8847
+ /* @__PURE__ */ jsx15(Text14, { bold: true, color: theme.accent, children: "Remote Session" }),
8848
+ /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "column", children: [
8849
+ /* @__PURE__ */ jsxs13(Text14, { children: [
8561
8850
  "ID: ",
8562
8851
  session.sessionId
8563
8852
  ] }),
8564
- /* @__PURE__ */ jsxs12(Text13, { children: [
8853
+ /* @__PURE__ */ jsxs13(Text14, { children: [
8565
8854
  "Repo: ",
8566
8855
  session.repo
8567
8856
  ] }),
8568
- /* @__PURE__ */ jsxs12(Text13, { children: [
8857
+ /* @__PURE__ */ jsxs13(Text14, { children: [
8569
8858
  "Status: ",
8570
8859
  session.status
8571
8860
  ] }),
8572
- /* @__PURE__ */ jsxs12(Text13, { children: [
8861
+ /* @__PURE__ */ jsxs13(Text14, { children: [
8573
8862
  "Prompt: ",
8574
8863
  session.prompt
8575
8864
  ] }),
8576
- session.prUrl && /* @__PURE__ */ jsxs12(Text13, { children: [
8865
+ session.prUrl && /* @__PURE__ */ jsxs13(Text14, { children: [
8577
8866
  "PR: ",
8578
8867
  session.prUrl
8579
8868
  ] }),
8580
- session.errorMessage && /* @__PURE__ */ jsxs12(Text13, { color: theme.error, children: [
8869
+ session.errorMessage && /* @__PURE__ */ jsxs13(Text14, { color: theme.error, children: [
8581
8870
  "Error: ",
8582
8871
  session.errorMessage
8583
8872
  ] }),
8584
- session.tokensUsed !== void 0 && /* @__PURE__ */ jsxs12(Text13, { children: [
8873
+ session.tokensUsed !== void 0 && /* @__PURE__ */ jsxs13(Text14, { children: [
8585
8874
  "Tokens: ",
8586
- formatTokens2(session.tokensUsed),
8587
- session.tokensBudget ? ` / ${formatTokens2(session.tokensBudget)}` : ""
8875
+ formatTokens3(session.tokensUsed),
8876
+ session.tokensBudget ? ` / ${formatTokens3(session.tokensBudget)}` : ""
8588
8877
  ] }),
8589
- /* @__PURE__ */ jsxs12(Text13, { children: [
8878
+ /* @__PURE__ */ jsxs13(Text14, { children: [
8590
8879
  "Created: ",
8591
8880
  new Date(session.createdAt).toLocaleString()
8592
8881
  ] }),
8593
- session.finishedAt && /* @__PURE__ */ jsxs12(Text13, { children: [
8882
+ session.finishedAt && /* @__PURE__ */ jsxs13(Text14, { children: [
8594
8883
  "Finished: ",
8595
8884
  new Date(session.finishedAt).toLocaleString()
8596
8885
  ] })
8597
8886
  ] }),
8598
- /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "row", gap: 2, children: [
8599
- isRunning && onCancel && /* @__PURE__ */ jsx14(Text13, { color: theme.error, children: cancelling ? "Cancelling..." : "[C] Cancel session" }),
8600
- /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "Esc back" })
8887
+ /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "row", gap: 2, children: [
8888
+ isRunning && onCancel && /* @__PURE__ */ jsx15(Text14, { color: theme.error, children: cancelling ? "Cancelling..." : "[C] Cancel session" }),
8889
+ /* @__PURE__ */ jsx15(Text14, { dimColor: true, children: "Esc back" })
8601
8890
  ] })
8602
8891
  ] });
8603
8892
  }
@@ -9502,8 +9791,8 @@ function computeExactScore(memory, queryText, cwd) {
9502
9791
  let score = 0;
9503
9792
  const lowerQuery = queryText.toLowerCase();
9504
9793
  for (const file of memory.relatedFiles) {
9505
- const basename4 = file.split("/").pop() ?? file;
9506
- if (lowerQuery.includes(basename4.toLowerCase()) || basename4.toLowerCase().includes(lowerQuery)) {
9794
+ const basename5 = file.split("/").pop() ?? file;
9795
+ if (lowerQuery.includes(basename5.toLowerCase()) || basename5.toLowerCase().includes(lowerQuery)) {
9507
9796
  score += 0.3;
9508
9797
  }
9509
9798
  if (cwd && file.startsWith(cwd)) {
@@ -10281,10 +10570,10 @@ var init_loader = __esm({
10281
10570
  });
10282
10571
 
10283
10572
  // src/commands/renderer.ts
10284
- import { exec } from "child_process";
10573
+ import { exec as exec2 } from "child_process";
10285
10574
  import { open as open2, realpath as realpath2 } from "fs/promises";
10286
10575
  import { isAbsolute as isAbsolute2, relative as relative5, resolve as resolvePathJoin, basename as pathBasename } from "path";
10287
- import { promisify as promisify2 } from "util";
10576
+ import { promisify as promisify3 } from "util";
10288
10577
  function tokenizeArgs(s) {
10289
10578
  return [...s.matchAll(ARG_TOKEN_RE)].map((match) => {
10290
10579
  const token = match[0];
@@ -10351,7 +10640,7 @@ async function replaceShell(prompt, warnings, cmd, shellTimeoutMs) {
10351
10640
  matches.map(async (match) => {
10352
10641
  const command = match[1] ?? "";
10353
10642
  try {
10354
- const { stdout } = await execAsync(command, {
10643
+ const { stdout } = await execAsync2(command, {
10355
10644
  timeout: shellTimeoutMs,
10356
10645
  maxBuffer: 1024 * 1024
10357
10646
  });
@@ -10432,12 +10721,12 @@ async function replaceFiles(prompt, warnings, cmd, cwd, maxFileBytes) {
10432
10721
  function message(error) {
10433
10722
  return error instanceof Error ? error.message : String(error);
10434
10723
  }
10435
- var execAsync, ARG_TOKEN_RE, POSITIONAL_RE, HAS_POSITIONAL, SHELL_RE, FILE_RE, DEFAULT_MAX_FILE_BYTES, DEFAULT_SHELL_TIMEOUT_MS, SECRET_PATTERNS2;
10724
+ var execAsync2, ARG_TOKEN_RE, POSITIONAL_RE, HAS_POSITIONAL, SHELL_RE, FILE_RE, DEFAULT_MAX_FILE_BYTES, DEFAULT_SHELL_TIMEOUT_MS, SECRET_PATTERNS2;
10436
10725
  var init_renderer2 = __esm({
10437
10726
  "src/commands/renderer.ts"() {
10438
10727
  "use strict";
10439
10728
  init_paths();
10440
- execAsync = promisify2(exec);
10729
+ execAsync2 = promisify3(exec2);
10441
10730
  ARG_TOKEN_RE = /(?:"[^"]*"|'[^']*'|[^\s"']+)/g;
10442
10731
  POSITIONAL_RE = /\$(\d+)/g;
10443
10732
  HAS_POSITIONAL = /\$\d+/;
@@ -10535,9 +10824,9 @@ var init_save = __esm({
10535
10824
 
10536
10825
  // src/ui/command-wizard.tsx
10537
10826
  import { useState as useState8 } from "react";
10538
- import { Box as Box13, Text as Text14, useInput as useInput4, useWindowSize as useWindowSize2 } from "ink";
10539
- import SelectInput6 from "ink-select-input";
10540
- import { Fragment as Fragment2, jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
10827
+ import { Box as Box14, Text as Text15, useInput as useInput5, useWindowSize as useWindowSize2 } from "ink";
10828
+ import SelectInput7 from "ink-select-input";
10829
+ import { Fragment as Fragment2, jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
10541
10830
  function CommandWizard({ mode, initial, existingNames, builtinNames, onDone, onSave }) {
10542
10831
  const theme = useTheme();
10543
10832
  const [step, setStep] = useState8("name");
@@ -10561,7 +10850,7 @@ function CommandWizard({ mode, initial, existingNames, builtinNames, onDone, onS
10561
10850
  if (existingNames.includes(trimmed) && !isEditingSelf(trimmed)) return `/${trimmed} already exists`;
10562
10851
  return null;
10563
10852
  };
10564
- useInput4((_input, key) => {
10853
+ useInput5((_input, key) => {
10565
10854
  if (key.escape) {
10566
10855
  onDone();
10567
10856
  }
@@ -10661,8 +10950,8 @@ ${template}`;
10661
10950
  const renderStep = () => {
10662
10951
  switch (step) {
10663
10952
  case "name":
10664
- return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10665
- /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
10953
+ return /* @__PURE__ */ jsxs14(Fragment2, { children: [
10954
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.accent, bold: true, children: [
10666
10955
  mode === "create" ? "Create" : "Edit",
10667
10956
  " custom command \u2014 Name (",
10668
10957
  stepIndex,
@@ -10670,8 +10959,8 @@ ${template}`;
10670
10959
  totalSteps,
10671
10960
  ")"
10672
10961
  ] }),
10673
- error && /* @__PURE__ */ jsx15(Text14, { color: theme.error, children: error }),
10674
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
10962
+ error && /* @__PURE__ */ jsx16(Text15, { color: theme.error, children: error }),
10963
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
10675
10964
  CustomTextInput,
10676
10965
  {
10677
10966
  value: name,
@@ -10680,11 +10969,11 @@ ${template}`;
10680
10969
  focus: true
10681
10970
  }
10682
10971
  ) }),
10683
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "letters, numbers, _ - / only; must start with a letter" })
10972
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "letters, numbers, _ - / only; must start with a letter" })
10684
10973
  ] });
10685
10974
  case "description":
10686
- return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10687
- /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
10975
+ return /* @__PURE__ */ jsxs14(Fragment2, { children: [
10976
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.accent, bold: true, children: [
10688
10977
  mode === "create" ? "Create" : "Edit",
10689
10978
  " custom command \u2014 Description (",
10690
10979
  stepIndex,
@@ -10692,7 +10981,7 @@ ${template}`;
10692
10981
  totalSteps,
10693
10982
  ")"
10694
10983
  ] }),
10695
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
10984
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
10696
10985
  CustomTextInput,
10697
10986
  {
10698
10987
  value: description,
@@ -10701,49 +10990,49 @@ ${template}`;
10701
10990
  focus: true
10702
10991
  }
10703
10992
  ) }),
10704
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Press Enter to skip" })
10993
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "Press Enter to skip" })
10705
10994
  ] });
10706
10995
  case "template": {
10707
- const guide = /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", paddingLeft: 1, children: [
10708
- /* @__PURE__ */ jsx15(Text14, { color: theme.accent, bold: true, children: "What is this?" }),
10709
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "A prompt template \u2014 instructions to the AI." }),
10710
- /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
10996
+ const guide = /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", paddingLeft: 1, children: [
10997
+ /* @__PURE__ */ jsx16(Text15, { color: theme.accent, bold: true, children: "What is this?" }),
10998
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "A prompt template \u2014 instructions to the AI." }),
10999
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
10711
11000
  "When you type /",
10712
11001
  name || "yourcommand",
10713
11002
  " later, this gets sent to the model."
10714
11003
  ] }),
10715
- /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "column", children: [
10716
- /* @__PURE__ */ jsx15(Text14, { color: theme.accent, bold: true, children: "Variables" }),
10717
- /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
11004
+ /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, flexDirection: "column", children: [
11005
+ /* @__PURE__ */ jsx16(Text15, { color: theme.accent, bold: true, children: "Variables" }),
11006
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
10718
11007
  " ",
10719
11008
  "$1, $2 ... \u2192 arguments you type"
10720
11009
  ] }),
10721
- /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
11010
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
10722
11011
  " ",
10723
11012
  "$ARGUMENTS \u2192 everything after the command"
10724
11013
  ] })
10725
11014
  ] }),
10726
- /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "column", children: [
10727
- /* @__PURE__ */ jsx15(Text14, { color: theme.accent, bold: true, children: "Dynamic inlines" }),
10728
- /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
11015
+ /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, flexDirection: "column", children: [
11016
+ /* @__PURE__ */ jsx16(Text15, { color: theme.accent, bold: true, children: "Dynamic inlines" }),
11017
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
10729
11018
  " ",
10730
11019
  "!`git diff` \u2192 shell output inlined"
10731
11020
  ] }),
10732
- /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
11021
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
10733
11022
  " ",
10734
11023
  "@README.md \u2192 file contents inlined"
10735
11024
  ] })
10736
11025
  ] }),
10737
- /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "column", children: [
10738
- /* @__PURE__ */ jsx15(Text14, { color: theme.accent, bold: true, children: "Example" }),
10739
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Review this PR diff:" }),
10740
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "!`git diff main...HEAD`" }),
10741
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Focus on: $1" })
11026
+ /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, flexDirection: "column", children: [
11027
+ /* @__PURE__ */ jsx16(Text15, { color: theme.accent, bold: true, children: "Example" }),
11028
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "Review this PR diff:" }),
11029
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "!`git diff main...HEAD`" }),
11030
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "Focus on: $1" })
10742
11031
  ] })
10743
11032
  ] });
10744
- const inputArea = /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", flexGrow: 1, children: [
10745
- error && /* @__PURE__ */ jsx15(Text14, { color: theme.error, children: error }),
10746
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
11033
+ const inputArea = /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", flexGrow: 1, children: [
11034
+ error && /* @__PURE__ */ jsx16(Text15, { color: theme.error, children: error }),
11035
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
10747
11036
  CustomTextInput,
10748
11037
  {
10749
11038
  value: template,
@@ -10753,13 +11042,13 @@ ${template}`;
10753
11042
  enablePaste: true
10754
11043
  }
10755
11044
  ) }),
10756
- columns < 100 && /* @__PURE__ */ jsxs13(Fragment2, { children: [
10757
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Paste multi-line templates with Ctrl+V." }),
10758
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Variables: $1 $2 ... $ARGUMENTS Shell: !`cmd` File: @path" })
11045
+ columns < 100 && /* @__PURE__ */ jsxs14(Fragment2, { children: [
11046
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "Paste multi-line templates with Ctrl+V." }),
11047
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "Variables: $1 $2 ... $ARGUMENTS Shell: !`cmd` File: @path" })
10759
11048
  ] })
10760
11049
  ] });
10761
- return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10762
- /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
11050
+ return /* @__PURE__ */ jsxs14(Fragment2, { children: [
11051
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.accent, bold: true, children: [
10763
11052
  mode === "create" ? "Create" : "Edit",
10764
11053
  " custom command \u2014 Template (",
10765
11054
  stepIndex,
@@ -10767,10 +11056,10 @@ ${template}`;
10767
11056
  totalSteps,
10768
11057
  ")"
10769
11058
  ] }),
10770
- columns >= 100 ? /* @__PURE__ */ jsxs13(Box13, { flexDirection: "row", marginTop: 1, children: [
10771
- /* @__PURE__ */ jsx15(Box13, { flexDirection: "column", width: "50%", children: inputArea }),
10772
- /* @__PURE__ */ jsx15(Box13, { flexDirection: "column", width: "50%", children: guide })
10773
- ] }) : /* @__PURE__ */ jsx15(Box13, { flexDirection: "column", marginTop: 1, children: inputArea })
11059
+ columns >= 100 ? /* @__PURE__ */ jsxs14(Box14, { flexDirection: "row", marginTop: 1, children: [
11060
+ /* @__PURE__ */ jsx16(Box14, { flexDirection: "column", width: "50%", children: inputArea }),
11061
+ /* @__PURE__ */ jsx16(Box14, { flexDirection: "column", width: "50%", children: guide })
11062
+ ] }) : /* @__PURE__ */ jsx16(Box14, { flexDirection: "column", marginTop: 1, children: inputArea })
10774
11063
  ] });
10775
11064
  }
10776
11065
  case "advanced": {
@@ -10779,8 +11068,8 @@ ${template}`;
10779
11068
  { label: "Skip", value: "skip", key: "skip" },
10780
11069
  { label: "\u2190 Cancel", value: "cancel", key: "cancel" }
10781
11070
  ];
10782
- return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10783
- /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
11071
+ return /* @__PURE__ */ jsxs14(Fragment2, { children: [
11072
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.accent, bold: true, children: [
10784
11073
  mode === "create" ? "Create" : "Edit",
10785
11074
  " custom command \u2014 Options (",
10786
11075
  stepIndex,
@@ -10788,8 +11077,8 @@ ${template}`;
10788
11077
  totalSteps,
10789
11078
  ")"
10790
11079
  ] }),
10791
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
10792
- SelectInput6,
11080
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
11081
+ SelectInput7,
10793
11082
  {
10794
11083
  items,
10795
11084
  onSelect: (item) => {
@@ -10808,17 +11097,17 @@ ${template}`;
10808
11097
  { label: cmdMode === "auto" ? "auto \xB7 current" : "auto", value: "auto", key: "auto" },
10809
11098
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
10810
11099
  ];
10811
- return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10812
- /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
11100
+ return /* @__PURE__ */ jsxs14(Fragment2, { children: [
11101
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.accent, bold: true, children: [
10813
11102
  "Mode override (",
10814
11103
  stepIndex,
10815
11104
  "/",
10816
11105
  totalSteps,
10817
11106
  ")"
10818
11107
  ] }),
10819
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Saved to file but not yet enforced at runtime" }),
10820
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
10821
- SelectInput6,
11108
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "Saved to file but not yet enforced at runtime" }),
11109
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
11110
+ SelectInput7,
10822
11111
  {
10823
11112
  items,
10824
11113
  onSelect: (item) => {
@@ -10837,16 +11126,16 @@ ${template}`;
10837
11126
  { label: cmdEffort === "high" ? "high \xB7 current" : "high", value: "high", key: "high" },
10838
11127
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
10839
11128
  ];
10840
- return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10841
- /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
11129
+ return /* @__PURE__ */ jsxs14(Fragment2, { children: [
11130
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.accent, bold: true, children: [
10842
11131
  "Reasoning effort (",
10843
11132
  stepIndex,
10844
11133
  "/",
10845
11134
  totalSteps,
10846
11135
  ")"
10847
11136
  ] }),
10848
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
10849
- SelectInput6,
11137
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
11138
+ SelectInput7,
10850
11139
  {
10851
11140
  items,
10852
11141
  onSelect: (item) => {
@@ -10858,15 +11147,15 @@ ${template}`;
10858
11147
  ] });
10859
11148
  }
10860
11149
  case "model":
10861
- return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10862
- /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
11150
+ return /* @__PURE__ */ jsxs14(Fragment2, { children: [
11151
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.accent, bold: true, children: [
10863
11152
  "Model override (",
10864
11153
  stepIndex,
10865
11154
  "/",
10866
11155
  totalSteps,
10867
11156
  ")"
10868
11157
  ] }),
10869
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
11158
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
10870
11159
  CustomTextInput,
10871
11160
  {
10872
11161
  value: cmdModel ?? "",
@@ -10875,7 +11164,7 @@ ${template}`;
10875
11164
  focus: true
10876
11165
  }
10877
11166
  ) }),
10878
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Press Enter to skip" })
11167
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "Press Enter to skip" })
10879
11168
  ] });
10880
11169
  case "location": {
10881
11170
  const items = [
@@ -10883,16 +11172,16 @@ ${template}`;
10883
11172
  { label: source === "global" ? "Global \xB7 current" : "Global", value: "global", key: "global" },
10884
11173
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
10885
11174
  ];
10886
- return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10887
- /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
11175
+ return /* @__PURE__ */ jsxs14(Fragment2, { children: [
11176
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.accent, bold: true, children: [
10888
11177
  "Save location (",
10889
11178
  stepIndex,
10890
11179
  "/",
10891
11180
  totalSteps,
10892
11181
  ")"
10893
11182
  ] }),
10894
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
10895
- SelectInput6,
11183
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
11184
+ SelectInput7,
10896
11185
  {
10897
11186
  items,
10898
11187
  onSelect: (item) => {
@@ -10901,7 +11190,7 @@ ${template}`;
10901
11190
  }
10902
11191
  }
10903
11192
  ) }),
10904
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Project: .kimiflare/commands/ Global: ~/.config/kimiflare/commands/" })
11193
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "Project: .kimiflare/commands/ Global: ~/.config/kimiflare/commands/" })
10905
11194
  ] });
10906
11195
  }
10907
11196
  case "confirm": {
@@ -10909,8 +11198,8 @@ ${template}`;
10909
11198
  { label: "Save", value: "save", key: "save" },
10910
11199
  { label: "Cancel", value: "cancel", key: "cancel" }
10911
11200
  ];
10912
- return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10913
- /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
11201
+ return /* @__PURE__ */ jsxs14(Fragment2, { children: [
11202
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.accent, bold: true, children: [
10914
11203
  mode === "create" ? "Create" : "Edit",
10915
11204
  " custom command \u2014 Confirm (",
10916
11205
  stepIndex,
@@ -10918,14 +11207,14 @@ ${template}`;
10918
11207
  totalSteps,
10919
11208
  ")"
10920
11209
  ] }),
10921
- /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
11210
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
10922
11211
  source === "project" ? ".kimiflare/commands/" : "~/.config/kimiflare/commands/",
10923
11212
  name,
10924
11213
  ".md"
10925
11214
  ] }),
10926
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, flexDirection: "column", children: previewContent().split("\n").map((line, i) => /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: line || " " }, i)) }),
10927
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
10928
- SelectInput6,
11215
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, flexDirection: "column", children: previewContent().split("\n").map((line, i) => /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: line || " " }, i)) }),
11216
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
11217
+ SelectInput7,
10929
11218
  {
10930
11219
  items,
10931
11220
  onSelect: (item) => handleConfirm(item.value)
@@ -10935,7 +11224,7 @@ ${template}`;
10935
11224
  }
10936
11225
  }
10937
11226
  };
10938
- return /* @__PURE__ */ jsx15(Box13, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: renderStep() });
11227
+ return /* @__PURE__ */ jsx16(Box14, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: renderStep() });
10939
11228
  }
10940
11229
  var NAME_RE;
10941
11230
  var init_command_wizard = __esm({
@@ -10947,10 +11236,442 @@ var init_command_wizard = __esm({
10947
11236
  }
10948
11237
  });
10949
11238
 
11239
+ // src/init/context-generator.ts
11240
+ import { existsSync as existsSync2, statSync as statSync3 } from "fs";
11241
+ import { join as join20 } from "path";
11242
+ function detectFlavor(cwd) {
11243
+ for (const [flavor, signatures] of Object.entries(FLAVOR_SIGNATURES)) {
11244
+ if (flavor === "generic") continue;
11245
+ for (const sig of signatures) {
11246
+ const path = join20(cwd, sig);
11247
+ if (sig.includes("*")) {
11248
+ try {
11249
+ const parts = sig.split("*");
11250
+ const prefix = parts[0] ?? "";
11251
+ const suffix = parts[1] ?? "";
11252
+ const entries = __require("fs").readdirSync(cwd);
11253
+ if (entries.some((e) => e.startsWith(prefix) && e.endsWith(suffix))) {
11254
+ return flavor;
11255
+ }
11256
+ } catch {
11257
+ }
11258
+ } else if (existsSync2(path)) {
11259
+ return flavor;
11260
+ }
11261
+ }
11262
+ }
11263
+ return "generic";
11264
+ }
11265
+ function findFile(cwd, candidates) {
11266
+ for (const c of candidates) {
11267
+ if (existsSync2(join20(cwd, c))) return c;
11268
+ }
11269
+ return null;
11270
+ }
11271
+ function findSourceRoots(cwd) {
11272
+ const roots = [];
11273
+ for (const r of SOURCE_ROOT_CANDIDATES) {
11274
+ const p = join20(cwd, r);
11275
+ try {
11276
+ const s = statSync3(p);
11277
+ if (s.isDirectory()) roots.push(r);
11278
+ } catch {
11279
+ }
11280
+ }
11281
+ return roots;
11282
+ }
11283
+ function findCiConfig(cwd) {
11284
+ for (const c of CI_PATHS) {
11285
+ if (existsSync2(join20(cwd, c))) {
11286
+ try {
11287
+ const s = statSync3(join20(cwd, c));
11288
+ return s.isDirectory() ? c : c;
11289
+ } catch {
11290
+ }
11291
+ }
11292
+ }
11293
+ return null;
11294
+ }
11295
+ function languageForFlavor(f) {
11296
+ const map = {
11297
+ node: "JavaScript / TypeScript",
11298
+ python: "Python",
11299
+ go: "Go",
11300
+ rust: "Rust",
11301
+ ruby: "Ruby",
11302
+ java: "Java / Kotlin",
11303
+ dotnet: "C# / F#",
11304
+ php: "PHP",
11305
+ elixir: "Elixir",
11306
+ haskell: "Haskell",
11307
+ c: "C",
11308
+ cpp: "C++",
11309
+ zig: "Zig",
11310
+ generic: "Unknown"
11311
+ };
11312
+ return map[f];
11313
+ }
11314
+ function analyzeProject(cwd) {
11315
+ const flavor = detectFlavor(cwd);
11316
+ const packageFiles = {
11317
+ node: ["package.json"],
11318
+ python: ["pyproject.toml", "setup.py", "setup.cfg"],
11319
+ go: ["go.mod"],
11320
+ rust: ["Cargo.toml"],
11321
+ ruby: ["Gemfile"],
11322
+ java: ["pom.xml", "build.gradle", "build.gradle.kts"],
11323
+ dotnet: ["*.csproj"],
11324
+ php: ["composer.json"],
11325
+ elixir: ["mix.exs"],
11326
+ haskell: ["package.yaml", "*.cabal"],
11327
+ c: ["Makefile", "CMakeLists.txt"],
11328
+ cpp: ["Makefile", "CMakeLists.txt"],
11329
+ zig: ["build.zig"],
11330
+ generic: []
11331
+ };
11332
+ const lockFiles = {
11333
+ node: ["package-lock.json", "yarn.lock", "pnpm-lock.yaml", "bun.lockb"],
11334
+ python: ["poetry.lock", "uv.lock", "Pipfile.lock"],
11335
+ go: ["go.sum"],
11336
+ rust: ["Cargo.lock"],
11337
+ ruby: ["Gemfile.lock"],
11338
+ java: [],
11339
+ dotnet: [],
11340
+ php: ["composer.lock"],
11341
+ elixir: ["mix.lock"],
11342
+ haskell: [],
11343
+ c: [],
11344
+ cpp: [],
11345
+ zig: [],
11346
+ generic: []
11347
+ };
11348
+ const buildFiles = {
11349
+ node: ["tsup.config.ts", "vite.config.ts", "webpack.config.js", "rollup.config.js", "esbuild.js", "next.config.js", "nuxt.config.ts", "astro.config.mjs", "svelte.config.js"],
11350
+ python: ["setup.py", "setup.cfg", "pyproject.toml"],
11351
+ go: ["Makefile"],
11352
+ rust: ["Cargo.toml"],
11353
+ ruby: ["Rakefile"],
11354
+ java: ["pom.xml", "build.gradle"],
11355
+ dotnet: ["*.sln"],
11356
+ php: [],
11357
+ elixir: ["mix.exs"],
11358
+ haskell: ["package.yaml", "*.cabal"],
11359
+ c: ["Makefile", "CMakeLists.txt"],
11360
+ cpp: ["Makefile", "CMakeLists.txt"],
11361
+ zig: ["build.zig"],
11362
+ generic: []
11363
+ };
11364
+ const testConfigs = {
11365
+ node: ["vitest.config.ts", "jest.config.js", "playwright.config.ts", "cypress.config.ts", "ava.config.js"],
11366
+ python: ["pytest.ini", "tox.ini", "setup.cfg"],
11367
+ go: [],
11368
+ rust: [],
11369
+ ruby: ["Rakefile", "spec_helper.rb"],
11370
+ java: [],
11371
+ dotnet: [],
11372
+ php: ["phpunit.xml"],
11373
+ elixir: ["test/test_helper.exs"],
11374
+ haskell: [],
11375
+ c: ["Makefile"],
11376
+ cpp: ["Makefile"],
11377
+ zig: [],
11378
+ generic: []
11379
+ };
11380
+ const lintConfigs = {
11381
+ node: [".eslintrc", ".eslintrc.js", ".eslintrc.json", ".prettierrc", "biome.json", "deno.json"],
11382
+ python: [".flake8", "pyproject.toml", "setup.cfg", ".pylintrc", "ruff.toml"],
11383
+ go: [],
11384
+ rust: ["rustfmt.toml", "clippy.toml"],
11385
+ ruby: [".rubocop.yml"],
11386
+ java: [],
11387
+ dotnet: [],
11388
+ php: [],
11389
+ elixir: [".formatter.exs"],
11390
+ haskell: [],
11391
+ c: [".clang-format", ".clang-tidy"],
11392
+ cpp: [".clang-format", ".clang-tidy"],
11393
+ zig: [],
11394
+ generic: []
11395
+ };
11396
+ const typeConfigs = {
11397
+ node: ["tsconfig.json", "jsconfig.json"],
11398
+ python: ["pyproject.toml", "setup.cfg", "mypy.ini"],
11399
+ go: [],
11400
+ rust: [],
11401
+ ruby: [],
11402
+ java: [],
11403
+ dotnet: [],
11404
+ php: [],
11405
+ elixir: [],
11406
+ haskell: [],
11407
+ c: [],
11408
+ cpp: [],
11409
+ zig: [],
11410
+ generic: []
11411
+ };
11412
+ return {
11413
+ flavor,
11414
+ primaryLanguage: languageForFlavor(flavor),
11415
+ packageFile: findFile(cwd, packageFiles[flavor]),
11416
+ lockFile: findFile(cwd, lockFiles[flavor]),
11417
+ buildFile: findFile(cwd, buildFiles[flavor]),
11418
+ testConfig: findFile(cwd, testConfigs[flavor]),
11419
+ lintConfig: findFile(cwd, lintConfigs[flavor]),
11420
+ typeConfig: findFile(cwd, typeConfigs[flavor]),
11421
+ ciConfig: findCiConfig(cwd),
11422
+ readme: findFile(cwd, ["README.md", "README.rst", "README.txt", "Readme.md"]),
11423
+ sourceRoots: findSourceRoots(cwd),
11424
+ hasGit: existsSync2(join20(cwd, ".git"))
11425
+ };
11426
+ }
11427
+ function bashDiscoveryCommands(profile) {
11428
+ const cmds = [];
11429
+ if (profile.hasGit) {
11430
+ cmds.push(
11431
+ "git log --oneline -20",
11432
+ "git branch -a | head -20"
11433
+ );
11434
+ }
11435
+ switch (profile.flavor) {
11436
+ case "node":
11437
+ cmds.push(
11438
+ `cat package.json | jq -r '.scripts | to_entries[] | "\\(.key): \\(.value)"' 2>/dev/null || node -e "const p=require('./package.json'); Object.entries(p.scripts||{}).forEach(([k,v])=>console.log(k+': '+v))"`,
11439
+ "ls -la node_modules/.bin 2>/dev/null | head -30 || true"
11440
+ );
11441
+ break;
11442
+ case "python":
11443
+ cmds.push(
11444
+ `python -c "import tomllib; f=open('pyproject.toml','rb'); d=tomllib.load(f); [print(f'{k}: {v}') for k,v in d.get('project',{}).get('scripts',{}).items()]" 2>/dev/null || true`,
11445
+ "make -p 2>/dev/null | grep -E '^[a-zA-Z_-]+:.*$' | head -20 || true"
11446
+ );
11447
+ break;
11448
+ case "go":
11449
+ cmds.push("go help 2>/dev/null | head -10 || true");
11450
+ break;
11451
+ case "rust":
11452
+ cmds.push("cargo --list 2>/dev/null | head -20 || true");
11453
+ break;
11454
+ case "ruby":
11455
+ cmds.push("bundle exec rake -T 2>/dev/null | head -20 || true");
11456
+ break;
11457
+ case "java":
11458
+ cmds.push("./mvnw help:describe -Dplugin=help 2>/dev/null | head -10 || true");
11459
+ break;
11460
+ }
11461
+ cmds.push("ls -la");
11462
+ return cmds;
11463
+ }
11464
+ function discoveryChecklist(profile) {
11465
+ const lines = [];
11466
+ lines.push("## PHASE 1: Project Identity & Configuration");
11467
+ lines.push("");
11468
+ if (profile.readme) {
11469
+ lines.push(`- [ ] Read \`${profile.readme}\` \u2014 extract project name, description, purpose.`);
11470
+ }
11471
+ if (profile.packageFile) {
11472
+ lines.push(`- [ ] Read \`${profile.packageFile}\` \u2014 extract dependencies, scripts, metadata.`);
11473
+ }
11474
+ if (profile.buildFile) {
11475
+ lines.push(`- [ ] Read \`${profile.buildFile}\` \u2014 understand build system and entry points.`);
11476
+ }
11477
+ if (profile.typeConfig) {
11478
+ lines.push(`- [ ] Read \`${profile.typeConfig}\` \u2014 note strictness, target, module system.`);
11479
+ }
11480
+ if (profile.testConfig) {
11481
+ lines.push(`- [ ] Read \`${profile.testConfig}\` \u2014 understand test runner and conventions.`);
11482
+ }
11483
+ if (profile.lintConfig) {
11484
+ lines.push(`- [ ] Read \`${profile.lintConfig}\` \u2014 note style rules and formatter.`);
11485
+ }
11486
+ if (profile.ciConfig) {
11487
+ lines.push(`- [ ] Inspect CI config in \`${profile.ciConfig}\` \u2014 note checks, matrix, deployment.`);
11488
+ }
11489
+ lines.push("");
11490
+ lines.push("## PHASE 2: Source Structure Discovery");
11491
+ lines.push("");
11492
+ for (const root of profile.sourceRoots) {
11493
+ lines.push(`- [ ] Use \`glob\` to list files in \`${root}/**/*\` (limit to ~50 files).`);
11494
+ lines.push(`- [ ] Read 3-5 representative files from \`${root}\` to understand code patterns.`);
11495
+ }
11496
+ if (profile.sourceRoots.length === 0) {
11497
+ lines.push("- [ ] Use `glob` to find source files (`**/*.{js,ts,py,go,rs,rb,java,cs,php,ex,hs,c,cpp,zig}`) \u2014 list top 50.");
11498
+ lines.push("- [ ] Read 3-5 representative source files to understand code patterns.");
11499
+ }
11500
+ lines.push("- [ ] Use `glob` to find test files and note their location/naming pattern.");
11501
+ lines.push("- [ ] Use `glob` to find config files at root level.");
11502
+ lines.push("");
11503
+ lines.push("## PHASE 3: Convention Extraction");
11504
+ lines.push("");
11505
+ lines.push("- [ ] Use `grep` to find import patterns (e.g., `import .* from` or `require(`).");
11506
+ lines.push("- [ ] Use `grep` to find export patterns (e.g., `export ` or `module.exports`).");
11507
+ lines.push("- [ ] Check for any `.editorconfig`, `.gitignore`, or `CONTRIBUTING.md`.");
11508
+ if (profile.hasGit) {
11509
+ lines.push("- [ ] Run `git log --oneline -20` to understand commit style and recent activity.");
11510
+ lines.push("- [ ] Run `git branch -a | head -20` to understand branching strategy.");
11511
+ }
11512
+ lines.push("");
11513
+ lines.push("## PHASE 4: Build & Development Workflow");
11514
+ lines.push("");
11515
+ const bashCmds = bashDiscoveryCommands(profile);
11516
+ for (const cmd of bashCmds) {
11517
+ lines.push(`- [ ] Run \`bash\` with: \`${cmd}\``);
11518
+ }
11519
+ lines.push("");
11520
+ lines.push("## PHASE 5: Architecture & Patterns (Deep Dive)");
11521
+ lines.push("");
11522
+ lines.push("- [ ] Identify the main entry point(s) of the application.");
11523
+ lines.push("- [ ] Identify the testing framework and how tests are organized.");
11524
+ lines.push("- [ ] Look for any architectural patterns: MVC, hexagonal, actor model, etc.");
11525
+ lines.push("- [ ] Note any code-generation, build-time transforms, or code-mod tools.");
11526
+ lines.push("- [ ] Check for Docker, docker-compose, or deployment configs.");
11527
+ lines.push("- [ ] Note any monorepo patterns (workspaces, turborepo, nx, etc.).");
11528
+ return lines.join("\n");
11529
+ }
11530
+ function sectionTemplate() {
11531
+ return `
11532
+ Generate the context document with these sections. Be concise but comprehensive.
11533
+ Aim for 100\u2013200 lines total. Use markdown tables where they save space.
11534
+
11535
+ ### Required Sections
11536
+
11537
+ 1. **Project** \u2014 One-line description + primary language/runtime + key frameworks.
11538
+
11539
+ 2. **Build / test / run** \u2014 Exact shell commands. Include:
11540
+ - Development server / watch mode
11541
+ - Production build
11542
+ - Test commands (unit, integration, e2e if separate)
11543
+ - Lint / format commands
11544
+ - Type-checking commands
11545
+ - Any setup / install commands
11546
+ Note which commands are slow or require special setup.
11547
+
11548
+ 3. **Layout** \u2014 Table of key directories AND a one-sentence rationale for each.
11549
+ Explain *why* things live where they do, not just *what* is there.
11550
+
11551
+ 4. **Conventions** \u2014 Cover:
11552
+ - Naming conventions (files, variables, types, tests)
11553
+ - Import style and path resolution quirks
11554
+ - File organization patterns
11555
+ - Commit message style (if discernible from git history)
11556
+ - Branching strategy
11557
+ - TypeScript / type system strictness rules
11558
+ - Testing conventions (naming, location, mocks)
11559
+ - Anything surprising or non-obvious
11560
+
11561
+ 5. **Dependencies** \u2014 Rules for adding dependencies:
11562
+ - Package manager commands
11563
+ - Dev vs runtime dependency conventions
11564
+ - Native deps that must stay external (if bundling)
11565
+ - Version pinning policy
11566
+
11567
+ 6. **Do / Don't** \u2014 Numbered list of hard rules:
11568
+ - Security rules (never commit secrets, etc.)
11569
+ - Performance rules (don't bundle X, etc.)
11570
+ - Style rules that aren't caught by linters
11571
+ - Common mistakes to avoid
11572
+ - Anything that would make a maintainer sad
11573
+
11574
+ 7. **Debugging & Troubleshooting** \u2014 Common issues:
11575
+ - How to run in debug mode
11576
+ - Common build failures and fixes
11577
+ - How to reset / clean the project
11578
+ - Where logs live
11579
+
11580
+ 8. **Architecture Notes** (if applicable) \u2014 Brief notes on:
11581
+ - Key abstractions and their responsibilities
11582
+ - Data flow
11583
+ - External integrations
11584
+ - State management approach
11585
+ `.trim();
11586
+ }
11587
+ function buildInitPrompt(cwd) {
11588
+ const existingName = ["KIMI.md", "KIMIFLARE.md", "AGENT.md"].find(
11589
+ (n) => existsSync2(join20(cwd, n))
11590
+ );
11591
+ const isRefresh = existingName !== void 0;
11592
+ const targetFilename = existingName ?? "KIMI.md";
11593
+ const profile = analyzeProject(cwd);
11594
+ const checklist = discoveryChecklist(profile);
11595
+ const sections = sectionTemplate();
11596
+ const promptParts = [
11597
+ isRefresh ? `Regenerate \`${targetFilename}\` at the repository root to refresh project context. The file already exists \u2014 read it first and preserve anything still accurate, updating only what has changed or is missing.` : `Generate a \`${targetFilename}\` at the repository root so future agents have comprehensive project context.`,
11598
+ "",
11599
+ "This is a **structured investigation**. Follow the checklist below systematically. Use the `glob`, `read`, `grep`, and `bash` tools to gather information. Do not skip steps.",
11600
+ "",
11601
+ `**Detected project profile:** ${profile.primaryLanguage} (${profile.flavor})`,
11602
+ profile.packageFile ? `- Package file: ${profile.packageFile}` : null,
11603
+ profile.buildFile ? `- Build file: ${profile.buildFile}` : null,
11604
+ profile.testConfig ? `- Test config: ${profile.testConfig}` : null,
11605
+ profile.typeConfig ? `- Type config: ${profile.typeConfig}` : null,
11606
+ profile.lintConfig ? `- Lint config: ${profile.lintConfig}` : null,
11607
+ profile.ciConfig ? `- CI config: ${profile.ciConfig}` : null,
11608
+ profile.sourceRoots.length > 0 ? `- Source roots: ${profile.sourceRoots.join(", ")}` : null,
11609
+ profile.hasGit ? `- Git repository: yes` : null,
11610
+ "",
11611
+ "---",
11612
+ "",
11613
+ checklist,
11614
+ "",
11615
+ "---",
11616
+ "",
11617
+ sections,
11618
+ "",
11619
+ isRefresh ? `After writing the file, re-read \`${targetFilename}\` and verify it is complete and accurate.` : "After writing the file, re-read it and verify all sections are present and accurate.",
11620
+ "",
11621
+ "Do not call `tasks_set` for this. Just follow the checklist, gather information, then write the file."
11622
+ ];
11623
+ const prompt = promptParts.filter((p) => p !== null).join("\n");
11624
+ return { prompt, targetFilename, isRefresh };
11625
+ }
11626
+ var FLAVOR_SIGNATURES, SOURCE_ROOT_CANDIDATES, CI_PATHS;
11627
+ var init_context_generator = __esm({
11628
+ "src/init/context-generator.ts"() {
11629
+ "use strict";
11630
+ FLAVOR_SIGNATURES = {
11631
+ node: ["package.json", "package-lock.json", "yarn.lock", "pnpm-lock.yaml", "bun.lockb", "node_modules"],
11632
+ python: ["pyproject.toml", "setup.py", "setup.cfg", "requirements.txt", "Pipfile", "poetry.lock", "uv.lock", "tox.ini"],
11633
+ go: ["go.mod", "go.sum"],
11634
+ rust: ["Cargo.toml", "Cargo.lock"],
11635
+ ruby: ["Gemfile", "Gemfile.lock", "*.gemspec"],
11636
+ java: ["pom.xml", "build.gradle", "build.gradle.kts"],
11637
+ dotnet: ["*.csproj", "*.fsproj", "*.sln"],
11638
+ php: ["composer.json", "composer.lock"],
11639
+ elixir: ["mix.exs", "mix.lock"],
11640
+ haskell: ["package.yaml", "*.cabal", "stack.yaml"],
11641
+ c: ["Makefile", "CMakeLists.txt", "configure.ac"],
11642
+ cpp: ["Makefile", "CMakeLists.txt", "configure.ac"],
11643
+ zig: ["build.zig", "build.zig.zon"],
11644
+ generic: []
11645
+ };
11646
+ SOURCE_ROOT_CANDIDATES = [
11647
+ "src",
11648
+ "lib",
11649
+ "app",
11650
+ "source",
11651
+ "Sources",
11652
+ "pkg",
11653
+ "internal",
11654
+ "cmd",
11655
+ "bin",
11656
+ "packages",
11657
+ "projects"
11658
+ ];
11659
+ CI_PATHS = [
11660
+ ".github/workflows",
11661
+ ".gitlab-ci.yml",
11662
+ ".circleci",
11663
+ "azure-pipelines.yml",
11664
+ "Jenkinsfile",
11665
+ ".buildkite",
11666
+ "cloudbuild.yaml"
11667
+ ];
11668
+ }
11669
+ });
11670
+
10950
11671
  // src/ui/command-picker.tsx
10951
- import { Box as Box14, Text as Text15 } from "ink";
10952
- import SelectInput7 from "ink-select-input";
10953
- import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
11672
+ import { Box as Box15, Text as Text16 } from "ink";
11673
+ import SelectInput8 from "ink-select-input";
11674
+ import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
10954
11675
  function CommandPicker({ commands, title, onPick }) {
10955
11676
  const theme = useTheme();
10956
11677
  const items = commands.map((cmd) => ({
@@ -10959,11 +11680,11 @@ function CommandPicker({ commands, title, onPick }) {
10959
11680
  key: cmd.name
10960
11681
  }));
10961
11682
  items.push({ label: "\u2190 Cancel", value: null, key: "__cancel__" });
10962
- return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10963
- /* @__PURE__ */ jsx16(Text15, { color: theme.accent, bold: true, children: title }),
10964
- /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select." }),
10965
- /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
10966
- SelectInput7,
11683
+ return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11684
+ /* @__PURE__ */ jsx17(Text16, { color: theme.accent, bold: true, children: title }),
11685
+ /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select." }),
11686
+ /* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
11687
+ SelectInput8,
10967
11688
  {
10968
11689
  items,
10969
11690
  onSelect: (item) => {
@@ -10985,64 +11706,64 @@ var init_command_picker = __esm({
10985
11706
  });
10986
11707
 
10987
11708
  // src/ui/command-list.tsx
10988
- import { Box as Box15, Text as Text16, useInput as useInput5 } from "ink";
10989
- import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
11709
+ import { Box as Box16, Text as Text17, useInput as useInput6 } from "ink";
11710
+ import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
10990
11711
  function CommandList({ commands, onDone }) {
10991
11712
  const theme = useTheme();
10992
- useInput5((_input, key) => {
11713
+ useInput6((_input, key) => {
10993
11714
  if (key.escape) {
10994
11715
  onDone();
10995
11716
  }
10996
11717
  });
10997
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10998
- /* @__PURE__ */ jsx17(Text16, { color: theme.accent, bold: true, children: "Custom commands" }),
10999
- /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, dimColor: false, children: "Esc to close." }),
11000
- /* @__PURE__ */ jsxs15(Box15, { marginTop: 1, flexDirection: "column", children: [
11001
- commands.length === 0 && /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, children: "No custom commands found." }),
11002
- commands.map((cmd) => /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", marginBottom: 1, children: [
11003
- /* @__PURE__ */ jsxs15(Text16, { color: theme.accent, bold: true, children: [
11718
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11719
+ /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Custom commands" }),
11720
+ /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Esc to close." }),
11721
+ /* @__PURE__ */ jsxs16(Box16, { marginTop: 1, flexDirection: "column", children: [
11722
+ commands.length === 0 && /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, children: "No custom commands found." }),
11723
+ commands.map((cmd) => /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", marginBottom: 1, children: [
11724
+ /* @__PURE__ */ jsxs16(Text17, { color: theme.accent, bold: true, children: [
11004
11725
  "/",
11005
11726
  cmd.name
11006
11727
  ] }),
11007
- /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
11728
+ /* @__PURE__ */ jsxs16(Text17, { color: theme.info.color, children: [
11008
11729
  " ",
11009
11730
  "source: ",
11010
11731
  cmd.source
11011
11732
  ] }),
11012
- /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
11733
+ /* @__PURE__ */ jsxs16(Text17, { color: theme.info.color, children: [
11013
11734
  " ",
11014
11735
  "path: ",
11015
11736
  cmd.filepath
11016
11737
  ] }),
11017
- cmd.description && /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
11738
+ cmd.description && /* @__PURE__ */ jsxs16(Text17, { color: theme.info.color, children: [
11018
11739
  " ",
11019
11740
  "desc: ",
11020
11741
  cmd.description
11021
11742
  ] }),
11022
- cmd.mode && /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
11743
+ cmd.mode && /* @__PURE__ */ jsxs16(Text17, { color: theme.info.color, children: [
11023
11744
  " ",
11024
11745
  "mode: ",
11025
11746
  cmd.mode
11026
11747
  ] }),
11027
- cmd.effort && /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
11748
+ cmd.effort && /* @__PURE__ */ jsxs16(Text17, { color: theme.info.color, children: [
11028
11749
  " ",
11029
11750
  "effort: ",
11030
11751
  cmd.effort
11031
11752
  ] }),
11032
- cmd.model && /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
11753
+ cmd.model && /* @__PURE__ */ jsxs16(Text17, { color: theme.info.color, children: [
11033
11754
  " ",
11034
11755
  "model: ",
11035
11756
  cmd.model
11036
11757
  ] }),
11037
- /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
11758
+ /* @__PURE__ */ jsxs16(Text17, { color: theme.info.color, children: [
11038
11759
  " ",
11039
11760
  "template:"
11040
11761
  ] }),
11041
- cmd.template.split("\n").slice(0, 5).map((line, i) => /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
11762
+ cmd.template.split("\n").slice(0, 5).map((line, i) => /* @__PURE__ */ jsxs16(Text17, { color: theme.info.color, children: [
11042
11763
  " ",
11043
11764
  line || " "
11044
11765
  ] }, i)),
11045
- cmd.template.split("\n").length > 5 && /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
11766
+ cmd.template.split("\n").length > 5 && /* @__PURE__ */ jsxs16(Text17, { color: theme.info.color, children: [
11046
11767
  " ",
11047
11768
  "..."
11048
11769
  ] })
@@ -11059,10 +11780,10 @@ var init_command_list = __esm({
11059
11780
 
11060
11781
  // src/ui/lsp-wizard.tsx
11061
11782
  import { useState as useState9 } from "react";
11062
- import { Box as Box16, Text as Text17 } from "ink";
11063
- import SelectInput8 from "ink-select-input";
11783
+ import { Box as Box17, Text as Text18 } from "ink";
11784
+ import SelectInput9 from "ink-select-input";
11064
11785
  import { spawn as spawn3 } from "child_process";
11065
- import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
11786
+ import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
11066
11787
  function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
11067
11788
  const theme = useTheme();
11068
11789
  const [page, setPage] = useState9("main");
@@ -11173,11 +11894,11 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
11173
11894
  { label: "(close)", value: "__close__", key: "__close__" }
11174
11895
  ];
11175
11896
  if (page === "main") {
11176
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11177
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "LSP Servers" }),
11178
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select." }),
11179
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
11180
- SelectInput8,
11897
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11898
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: "LSP Servers" }),
11899
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select." }),
11900
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
11901
+ SelectInput9,
11181
11902
  {
11182
11903
  items: mainItems,
11183
11904
  onSelect: (item) => {
@@ -11204,11 +11925,11 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
11204
11925
  }),
11205
11926
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
11206
11927
  ];
11207
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11208
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Add LSP Server" }),
11209
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Select a language server to configure." }),
11210
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
11211
- SelectInput8,
11928
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11929
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: "Add LSP Server" }),
11930
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, dimColor: false, children: "Select a language server to configure." }),
11931
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
11932
+ SelectInput9,
11212
11933
  {
11213
11934
  items,
11214
11935
  onSelect: (item) => {
@@ -11235,19 +11956,19 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
11235
11956
  { label: isSuccess ? "Save to config \u2713" : "Save anyway", value: "save", key: "save" },
11236
11957
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
11237
11958
  ];
11238
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11239
- /* @__PURE__ */ jsxs16(Text17, { color: theme.accent, bold: true, children: [
11959
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11960
+ /* @__PURE__ */ jsxs17(Text18, { color: theme.accent, bold: true, children: [
11240
11961
  "Install ",
11241
11962
  selectedPreset.name
11242
11963
  ] }),
11243
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: selectedPreset.installHint }),
11244
- /* @__PURE__ */ jsxs16(Box16, { marginTop: 1, flexDirection: "column", children: [
11245
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Command:" }),
11246
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, children: selectedPreset.installCommand || "(none required)" })
11964
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, dimColor: false, children: selectedPreset.installHint }),
11965
+ /* @__PURE__ */ jsxs17(Box17, { marginTop: 1, flexDirection: "column", children: [
11966
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, dimColor: false, children: "Command:" }),
11967
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, children: selectedPreset.installCommand || "(none required)" })
11247
11968
  ] }),
11248
- installState.output && /* @__PURE__ */ jsx18(Box16, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx18(Text17, { color: isSuccess ? theme.accent : theme.error, children: installState.output.slice(-500) }) }),
11249
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
11250
- SelectInput8,
11969
+ installState.output && /* @__PURE__ */ jsx19(Box17, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx19(Text18, { color: isSuccess ? theme.accent : theme.error, children: installState.output.slice(-500) }) }),
11970
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
11971
+ SelectInput9,
11251
11972
  {
11252
11973
  items,
11253
11974
  onSelect: (item) => {
@@ -11264,16 +11985,16 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
11264
11985
  }
11265
11986
  }
11266
11987
  ) }),
11267
- isSuccess && /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(Text17, { color: theme.accent, children: "Server saved. Run /lsp reload to start it." }) })
11988
+ isSuccess && /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(Text18, { color: theme.accent, children: "Server saved. Run /lsp reload to start it." }) })
11268
11989
  ] });
11269
11990
  }
11270
11991
  if (page === "custom-name") {
11271
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11272
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Custom LSP Server \u2014 Name" }),
11273
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Enter a name for this server (e.g., my-server)." }),
11274
- /* @__PURE__ */ jsxs16(Box16, { marginTop: 1, children: [
11275
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, children: "\u203A " }),
11276
- /* @__PURE__ */ jsx18(
11992
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11993
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: "Custom LSP Server \u2014 Name" }),
11994
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, dimColor: false, children: "Enter a name for this server (e.g., my-server)." }),
11995
+ /* @__PURE__ */ jsxs17(Box17, { marginTop: 1, children: [
11996
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, children: "\u203A " }),
11997
+ /* @__PURE__ */ jsx19(
11277
11998
  CustomTextInput,
11278
11999
  {
11279
12000
  value: customName,
@@ -11287,8 +12008,8 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
11287
12008
  }
11288
12009
  )
11289
12010
  ] }),
11290
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
11291
- SelectInput8,
12011
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
12012
+ SelectInput9,
11292
12013
  {
11293
12014
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
11294
12015
  onSelect: () => setPage("add")
@@ -11297,12 +12018,12 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
11297
12018
  ] });
11298
12019
  }
11299
12020
  if (page === "custom-command") {
11300
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11301
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Custom LSP Server \u2014 Command" }),
11302
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Enter the command to start the server (space-separated)." }),
11303
- /* @__PURE__ */ jsxs16(Box16, { marginTop: 1, children: [
11304
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, children: "\u203A " }),
11305
- /* @__PURE__ */ jsx18(
12021
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
12022
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: "Custom LSP Server \u2014 Command" }),
12023
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, dimColor: false, children: "Enter the command to start the server (space-separated)." }),
12024
+ /* @__PURE__ */ jsxs17(Box17, { marginTop: 1, children: [
12025
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, children: "\u203A " }),
12026
+ /* @__PURE__ */ jsx19(
11306
12027
  CustomTextInput,
11307
12028
  {
11308
12029
  value: customCommand,
@@ -11316,8 +12037,8 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
11316
12037
  }
11317
12038
  )
11318
12039
  ] }),
11319
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
11320
- SelectInput8,
12040
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
12041
+ SelectInput9,
11321
12042
  {
11322
12043
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
11323
12044
  onSelect: () => setPage("custom-name")
@@ -11340,11 +12061,11 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
11340
12061
  },
11341
12062
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
11342
12063
  ];
11343
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11344
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Save LSP Config" }),
11345
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Where should this server configuration be saved?" }),
11346
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
11347
- SelectInput8,
12064
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
12065
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: "Save LSP Config" }),
12066
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, dimColor: false, children: "Where should this server configuration be saved?" }),
12067
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
12068
+ SelectInput9,
11348
12069
  {
11349
12070
  items,
11350
12071
  onSelect: (item) => {
@@ -11362,11 +12083,11 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
11362
12083
  if (page === "edit") {
11363
12084
  const keys = Object.keys(servers);
11364
12085
  if (keys.length === 0) {
11365
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11366
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Edit LSP Server" }),
11367
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, children: "No servers configured." }),
11368
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
11369
- SelectInput8,
12086
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
12087
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: "Edit LSP Server" }),
12088
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, children: "No servers configured." }),
12089
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
12090
+ SelectInput9,
11370
12091
  {
11371
12092
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
11372
12093
  onSelect: () => setPage("main")
@@ -11386,11 +12107,11 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
11386
12107
  }),
11387
12108
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
11388
12109
  ];
11389
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11390
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Edit LSP Server" }),
11391
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Select a server to toggle enabled/disabled." }),
11392
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
11393
- SelectInput8,
12110
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
12111
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: "Edit LSP Server" }),
12112
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, dimColor: false, children: "Select a server to toggle enabled/disabled." }),
12113
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
12114
+ SelectInput9,
11394
12115
  {
11395
12116
  items,
11396
12117
  onSelect: (item) => {
@@ -11407,11 +12128,11 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
11407
12128
  if (page === "delete") {
11408
12129
  const keys = Object.keys(servers);
11409
12130
  if (keys.length === 0) {
11410
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11411
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Delete LSP Server" }),
11412
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, children: "No servers configured." }),
11413
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
11414
- SelectInput8,
12131
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
12132
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: "Delete LSP Server" }),
12133
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, children: "No servers configured." }),
12134
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
12135
+ SelectInput9,
11415
12136
  {
11416
12137
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
11417
12138
  onSelect: () => setPage("main")
@@ -11427,11 +12148,11 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
11427
12148
  })),
11428
12149
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
11429
12150
  ];
11430
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11431
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Delete LSP Server" }),
11432
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Select a server to remove from config." }),
11433
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
11434
- SelectInput8,
12151
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
12152
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: "Delete LSP Server" }),
12153
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, dimColor: false, children: "Select a server to remove from config." }),
12154
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
12155
+ SelectInput9,
11435
12156
  {
11436
12157
  items,
11437
12158
  onSelect: (item) => {
@@ -11447,15 +12168,15 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
11447
12168
  }
11448
12169
  if (page === "list") {
11449
12170
  const keys = Object.keys(servers);
11450
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11451
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Configured LSP Servers" }),
11452
- 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) => {
12171
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
12172
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: "Configured LSP Servers" }),
12173
+ keys.length === 0 ? /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, children: "No servers configured." }) : /* @__PURE__ */ jsx19(Box17, { marginTop: 1, flexDirection: "column", children: keys.map((k) => {
11453
12174
  const s = servers[k];
11454
12175
  const status = s.enabled !== false ? "enabled" : "disabled";
11455
- return /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, children: ` ${k.padEnd(16)} ${status} ${s.command.join(" ")}` }, k);
12176
+ return /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, children: ` ${k.padEnd(16)} ${status} ${s.command.join(" ")}` }, k);
11456
12177
  }) }),
11457
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
11458
- SelectInput8,
12178
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
12179
+ SelectInput9,
11459
12180
  {
11460
12181
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
11461
12182
  onSelect: () => setPage("main")
@@ -11581,9 +12302,9 @@ var init_lsp_wizard = __esm({
11581
12302
  });
11582
12303
 
11583
12304
  // src/ui/theme-picker.tsx
11584
- import { Box as Box17, Text as Text18 } from "ink";
11585
- import SelectInput9 from "ink-select-input";
11586
- import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
12305
+ import { Box as Box18, Text as Text19 } from "ink";
12306
+ import SelectInput10 from "ink-select-input";
12307
+ import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
11587
12308
  function PaletteSwatches({ palette }) {
11588
12309
  const colors = [
11589
12310
  palette.primary,
@@ -11591,7 +12312,7 @@ function PaletteSwatches({ palette }) {
11591
12312
  palette.success,
11592
12313
  palette.error
11593
12314
  ];
11594
- return /* @__PURE__ */ jsx19(Box17, { children: colors.map((c, i) => /* @__PURE__ */ jsx19(Text18, { color: c, children: "\u2588" }, i)) });
12315
+ return /* @__PURE__ */ jsx20(Box18, { children: colors.map((c, i) => /* @__PURE__ */ jsx20(Text19, { color: c, children: "\u2588" }, i)) });
11595
12316
  }
11596
12317
  function ThemePicker({ themes, onPick, onPreview }) {
11597
12318
  const current = useTheme();
@@ -11599,10 +12320,10 @@ function ThemePicker({ themes, onPick, onPreview }) {
11599
12320
  ...themes.map((t) => ({ label: t.label, value: t.name })),
11600
12321
  { label: "< Back", value: "__back__" }
11601
12322
  ];
11602
- return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: current.accent, paddingX: 1, children: [
11603
- /* @__PURE__ */ jsx19(Text18, { color: current.accent, bold: true, children: "Pick a theme" }),
11604
- /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
11605
- SelectInput9,
12323
+ return /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", borderStyle: "round", borderColor: current.accent, paddingX: 1, children: [
12324
+ /* @__PURE__ */ jsx20(Text19, { color: current.accent, bold: true, children: "Pick a theme" }),
12325
+ /* @__PURE__ */ jsx20(Box18, { marginTop: 1, children: /* @__PURE__ */ jsx20(
12326
+ SelectInput10,
11606
12327
  {
11607
12328
  items,
11608
12329
  onHighlight: (item) => {
@@ -11621,9 +12342,9 @@ function ThemePicker({ themes, onPick, onPreview }) {
11621
12342
  itemComponent: ({ label, isSelected }) => {
11622
12343
  const t = themes.find((x) => x.label === label);
11623
12344
  const color = t?.accent ?? current.accent;
11624
- return /* @__PURE__ */ jsxs17(Box17, { children: [
11625
- /* @__PURE__ */ jsx19(Text18, { color, bold: isSelected, dimColor: !isSelected, children: label }),
11626
- t && /* @__PURE__ */ jsx19(Box17, { marginLeft: 1, children: /* @__PURE__ */ jsx19(PaletteSwatches, { palette: t.palette }) })
12345
+ return /* @__PURE__ */ jsxs18(Box18, { children: [
12346
+ /* @__PURE__ */ jsx20(Text19, { color, bold: isSelected, dimColor: !isSelected, children: label }),
12347
+ t && /* @__PURE__ */ jsx20(Box18, { marginLeft: 1, children: /* @__PURE__ */ jsx20(PaletteSwatches, { palette: t.palette }) })
11627
12348
  ] });
11628
12349
  }
11629
12350
  }
@@ -11767,8 +12488,8 @@ var init_lsp_nudge = __esm({
11767
12488
  });
11768
12489
 
11769
12490
  // src/ui/file-picker.tsx
11770
- import { Box as Box18, Text as Text19 } from "ink";
11771
- import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
12491
+ import { Box as Box19, Text as Text20 } from "ink";
12492
+ import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
11772
12493
  function FilePicker({ items, selectedIndex, query }) {
11773
12494
  const theme = useTheme();
11774
12495
  let startIndex = 0;
@@ -11778,12 +12499,12 @@ function FilePicker({ items, selectedIndex, query }) {
11778
12499
  const visible = items.slice(startIndex, startIndex + VISIBLE_LIMIT);
11779
12500
  const hasMoreAbove = startIndex > 0;
11780
12501
  const hasMoreBelow = items.length > startIndex + VISIBLE_LIMIT;
11781
- return /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11782
- /* @__PURE__ */ jsx20(Text19, { color: theme.accent, bold: true, children: query ? `Files matching "${query}"` : "Mention a file" }),
11783
- /* @__PURE__ */ jsx20(Text19, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select, Esc to cancel." }),
11784
- /* @__PURE__ */ jsxs18(Box18, { marginTop: 1, flexDirection: "column", children: [
11785
- visible.length === 0 && /* @__PURE__ */ jsx20(Text19, { color: theme.info.color, children: "No matches" }),
11786
- hasMoreAbove && /* @__PURE__ */ jsxs18(Text19, { color: theme.info.color, children: [
12502
+ return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
12503
+ /* @__PURE__ */ jsx21(Text20, { color: theme.accent, bold: true, children: query ? `Files matching "${query}"` : "Mention a file" }),
12504
+ /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select, Esc to cancel." }),
12505
+ /* @__PURE__ */ jsxs19(Box19, { marginTop: 1, flexDirection: "column", children: [
12506
+ visible.length === 0 && /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, children: "No matches" }),
12507
+ hasMoreAbove && /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
11787
12508
  "\u2026 ",
11788
12509
  startIndex,
11789
12510
  " more above"
@@ -11792,12 +12513,12 @@ function FilePicker({ items, selectedIndex, query }) {
11792
12513
  const actualIndex = startIndex + i;
11793
12514
  const isSelected = actualIndex === selectedIndex;
11794
12515
  const label = item.isDirectory ? `${item.name}/` : item.name;
11795
- return /* @__PURE__ */ jsxs18(Text19, { color: isSelected ? theme.accent : void 0, bold: isSelected, children: [
12516
+ return /* @__PURE__ */ jsxs19(Text20, { color: isSelected ? theme.accent : void 0, bold: isSelected, children: [
11796
12517
  isSelected ? "\u203A " : " ",
11797
12518
  label
11798
12519
  ] }, item.name);
11799
12520
  }),
11800
- hasMoreBelow && /* @__PURE__ */ jsxs18(Text19, { color: theme.info.color, children: [
12521
+ hasMoreBelow && /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
11801
12522
  "\u2026 ",
11802
12523
  items.length - (startIndex + VISIBLE_LIMIT),
11803
12524
  " more below"
@@ -11815,8 +12536,8 @@ var init_file_picker = __esm({
11815
12536
  });
11816
12537
 
11817
12538
  // src/ui/slash-picker.tsx
11818
- import { Box as Box19, Text as Text20 } from "ink";
11819
- import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
12539
+ import { Box as Box20, Text as Text21 } from "ink";
12540
+ import { jsx as jsx22, jsxs as jsxs20 } from "react/jsx-runtime";
11820
12541
  function sourceBadge(source) {
11821
12542
  if (source === "builtin") return "";
11822
12543
  if (source === "project") return "project";
@@ -11836,12 +12557,12 @@ function SlashPicker({ items, selectedIndex, query }) {
11836
12557
  const hasMoreBelow = items.length > startIndex + VISIBLE_LIMIT2;
11837
12558
  const longestLabel = visible.reduce((m, it) => Math.max(m, commandLabel(it).length), 0);
11838
12559
  const nameColWidth = Math.max(NAME_COL_MIN_WIDTH, longestLabel + NAME_DESC_GAP);
11839
- return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11840
- /* @__PURE__ */ jsx21(Text20, { color: theme.accent, bold: true, children: query ? `Commands matching "/${query}"` : "Slash commands" }),
11841
- /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, children: "Arrow keys to navigate, Enter to select, Esc to cancel." }),
11842
- /* @__PURE__ */ jsxs19(Box19, { marginTop: 1, flexDirection: "column", children: [
11843
- visible.length === 0 && /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, children: "No matches" }),
11844
- hasMoreAbove && /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
12560
+ return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
12561
+ /* @__PURE__ */ jsx22(Text21, { color: theme.accent, bold: true, children: query ? `Commands matching "/${query}"` : "Slash commands" }),
12562
+ /* @__PURE__ */ jsx22(Text21, { color: theme.info.color, children: "Arrow keys to navigate, Enter to select, Esc to cancel." }),
12563
+ /* @__PURE__ */ jsxs20(Box20, { marginTop: 1, flexDirection: "column", children: [
12564
+ visible.length === 0 && /* @__PURE__ */ jsx22(Text21, { color: theme.info.color, children: "No matches" }),
12565
+ hasMoreAbove && /* @__PURE__ */ jsxs20(Text21, { color: theme.info.color, children: [
11845
12566
  "\u2026 ",
11846
12567
  startIndex,
11847
12568
  " more above"
@@ -11851,16 +12572,16 @@ function SlashPicker({ items, selectedIndex, query }) {
11851
12572
  const isSelected = actualIndex === selectedIndex;
11852
12573
  const nameCol = commandLabel(item).padEnd(nameColWidth);
11853
12574
  const badge = sourceBadge(item.source);
11854
- return /* @__PURE__ */ jsxs19(Text20, { color: isSelected ? theme.accent : void 0, bold: isSelected, children: [
12575
+ return /* @__PURE__ */ jsxs20(Text21, { color: isSelected ? theme.accent : void 0, bold: isSelected, children: [
11855
12576
  isSelected ? "\u203A " : " ",
11856
12577
  nameCol,
11857
- /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
12578
+ /* @__PURE__ */ jsxs20(Text21, { color: theme.info.color, children: [
11858
12579
  item.description,
11859
12580
  badge && ` [${badge}]`
11860
12581
  ] })
11861
12582
  ] }, item.name);
11862
12583
  }),
11863
- hasMoreBelow && /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
12584
+ hasMoreBelow && /* @__PURE__ */ jsxs20(Text21, { color: theme.info.color, children: [
11864
12585
  "\u2026 ",
11865
12586
  items.length - (startIndex + VISIBLE_LIMIT2),
11866
12587
  " more below"
@@ -11941,14 +12662,14 @@ __export(tui_report_exports, {
11941
12662
  getCategoryReportText: () => getCategoryReportText
11942
12663
  });
11943
12664
  import { readFile as readFile16 } from "fs/promises";
11944
- import { join as join20 } from "path";
12665
+ import { join as join21 } from "path";
11945
12666
  import { homedir as homedir14 } from "os";
11946
12667
  function usageDir3() {
11947
- const xdg = process.env.XDG_DATA_HOME || join20(homedir14(), ".local", "share");
11948
- return join20(xdg, "kimiflare");
12668
+ const xdg = process.env.XDG_DATA_HOME || join21(homedir14(), ".local", "share");
12669
+ return join21(xdg, "kimiflare");
11949
12670
  }
11950
12671
  function usagePath3() {
11951
- return join20(usageDir3(), "usage.json");
12672
+ return join21(usageDir3(), "usage.json");
11952
12673
  }
11953
12674
  function today3() {
11954
12675
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
@@ -12026,18 +12747,18 @@ __export(app_exports, {
12026
12747
  shouldOpenMentionPicker: () => shouldOpenMentionPicker,
12027
12748
  shouldOpenSlashPicker: () => shouldOpenSlashPicker
12028
12749
  });
12029
- import React14, { useState as useState10, useRef as useRef3, useEffect as useEffect5, useCallback } from "react";
12030
- import { Box as Box20, Text as Text21, useApp, useInput as useInput6, render } from "ink";
12031
- import SelectInput10 from "ink-select-input";
12032
- import { existsSync as existsSync2, statSync as statSync3 } from "fs";
12033
- import { join as join21 } from "path";
12750
+ import React14, { useState as useState10, useRef as useRef3, useEffect as useEffect6, useCallback as useCallback2 } from "react";
12751
+ import { Box as Box21, Text as Text22, useApp, useInput as useInput7, render } from "ink";
12752
+ import SelectInput11 from "ink-select-input";
12753
+ import { existsSync as existsSync3, statSync as statSync4 } from "fs";
12754
+ import { join as join22 } from "path";
12034
12755
  import { unlink as unlink3 } from "fs/promises";
12035
12756
  import { execSync as execSync2 } from "child_process";
12036
12757
  import { spawn as spawn4 } from "child_process";
12037
12758
  import { platform as platform2 } from "os";
12038
12759
  import fg4 from "fast-glob";
12039
12760
  import { readFileSync as readFileSync3 } from "fs";
12040
- import { jsx as jsx22, jsxs as jsxs20 } from "react/jsx-runtime";
12761
+ import { jsx as jsx23, jsxs as jsxs21 } from "react/jsx-runtime";
12041
12762
  function buildFilePickerIgnoreList(cwd) {
12042
12763
  const hardcoded = [
12043
12764
  // Dependencies
@@ -12108,8 +12829,8 @@ function buildFilePickerIgnoreList(cwd) {
12108
12829
  ];
12109
12830
  const gitignorePatterns = [];
12110
12831
  try {
12111
- const gitignorePath = join21(cwd, ".gitignore");
12112
- const stats = statSync3(gitignorePath);
12832
+ const gitignorePath = join22(cwd, ".gitignore");
12833
+ const stats = statSync4(gitignorePath);
12113
12834
  if (stats.size > MAX_GITIGNORE_SIZE) {
12114
12835
  return hardcoded;
12115
12836
  }
@@ -12177,7 +12898,7 @@ function gatewayUsageLookupFromConfig(cfg, meta) {
12177
12898
  meta
12178
12899
  };
12179
12900
  }
12180
- function openBrowser(url) {
12901
+ function openBrowser2(url) {
12181
12902
  const cmd = platform2() === "darwin" ? "open" : platform2() === "win32" ? "start" : "xdg-open";
12182
12903
  const child = spawn4(cmd, [url], { detached: true, stdio: "ignore" });
12183
12904
  child.unref();
@@ -12197,7 +12918,7 @@ function detectGitHubRepo(cachedRepo) {
12197
12918
  }
12198
12919
  return null;
12199
12920
  }
12200
- function formatTokens3(n) {
12921
+ function formatTokens4(n) {
12201
12922
  if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
12202
12923
  if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
12203
12924
  return String(n);
@@ -12242,7 +12963,7 @@ function findImagePaths(text) {
12242
12963
  let match;
12243
12964
  while ((match = quotedRegex.exec(text)) !== null) {
12244
12965
  const path = match[1] ?? match[2];
12245
- if (path && isImagePath(path) && existsSync2(path)) {
12966
+ if (path && isImagePath(path) && existsSync3(path)) {
12246
12967
  paths.push(path);
12247
12968
  }
12248
12969
  }
@@ -12251,7 +12972,7 @@ function findImagePaths(text) {
12251
12972
  const processed = remaining.replace(/\\ /g, ESCAPED_SPACE);
12252
12973
  for (const token of processed.split(/\s+/)) {
12253
12974
  const clean = token.replace(new RegExp(ESCAPED_SPACE, "g"), " ").replace(/^["']|["',;:!?]$/g, "").replace(/[.,;:!?]$/, "");
12254
- if (clean && isImagePath(clean) && existsSync2(clean) && !paths.includes(clean)) {
12975
+ if (clean && isImagePath(clean) && existsSync3(clean) && !paths.includes(clean)) {
12255
12976
  paths.push(clean);
12256
12977
  }
12257
12978
  }
@@ -12268,8 +12989,9 @@ function App({
12268
12989
  const [cfg, setCfg] = useState10(initialCfg);
12269
12990
  const [lspScope, setLspScope] = useState10(initialLspScope);
12270
12991
  const [lspProjectPath, setLspProjectPath] = useState10(initialLspProjectPath);
12992
+ const [cloudToken, setCloudToken] = useState10(initialCloudToken);
12271
12993
  const [events, setRawEvents] = useState10([]);
12272
- const setEvents = useCallback(
12994
+ const setEvents = useCallback2(
12273
12995
  (updater) => {
12274
12996
  setRawEvents((prev) => {
12275
12997
  const next = typeof updater === "function" ? updater(prev) : updater;
@@ -12283,8 +13005,10 @@ function App({
12283
13005
  const [usage, setUsage] = useState10(null);
12284
13006
  const [sessionUsage, setSessionUsage] = useState10(null);
12285
13007
  const [gatewayMeta, setGatewayMeta] = useState10(null);
13008
+ const [cloudBudget, setCloudBudget] = useState10(null);
12286
13009
  const [showReasoning, setShowReasoning] = useState10(false);
12287
13010
  const [perm, setPerm] = useState10(null);
13011
+ const [limitModal, setLimitModal] = useState10(null);
12288
13012
  const [queue, setQueue] = useState10([]);
12289
13013
  const [history, setHistory] = useState10([]);
12290
13014
  const [historyIndex, setHistoryIndex] = useState10(-1);
@@ -12314,6 +13038,21 @@ function App({
12314
13038
  const [theme, setTheme] = useState10(resolveTheme(initialCfg?.theme));
12315
13039
  const [showThemePicker, setShowThemePicker] = useState10(false);
12316
13040
  const [originalTheme, setOriginalTheme] = useState10(null);
13041
+ useEffect6(() => {
13042
+ if (!cfg?.cloudMode || !initialCloudToken) return;
13043
+ let cancelled = false;
13044
+ const fetchBudget = async () => {
13045
+ const { fetchCloudUsage: fetchCloudUsage2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
13046
+ const usage2 = await fetchCloudUsage2(initialCloudToken);
13047
+ if (usage2 && !cancelled) {
13048
+ setCloudBudget({ remaining: usage2.remaining, limit: usage2.input_token_limit });
13049
+ }
13050
+ };
13051
+ fetchBudget();
13052
+ return () => {
13053
+ cancelled = true;
13054
+ };
13055
+ }, [cfg?.cloudMode, initialCloudToken]);
12317
13056
  const [cursorOffset, setCursorOffset] = useState10(0);
12318
13057
  const [activePicker, setActivePicker] = useState10(null);
12319
13058
  const [filePickerItems, setFilePickerItems] = useState10([]);
@@ -12327,6 +13066,7 @@ function App({
12327
13066
  const activeAsstIdRef = useRef3(null);
12328
13067
  const activeControllerRef = useRef3(null);
12329
13068
  const permResolveRef = useRef3(null);
13069
+ const limitResolveRef = useRef3(null);
12330
13070
  const pendingToolCallsRef = useRef3(/* @__PURE__ */ new Map());
12331
13071
  const sessionIdRef = useRef3(null);
12332
13072
  const modeRef = useRef3(mode);
@@ -12348,12 +13088,16 @@ function App({
12348
13088
  const lspManagerRef = useRef3(new LspManager());
12349
13089
  const lspToolsRef = useRef3([]);
12350
13090
  const lspInitRef = useRef3(false);
13091
+ const busyRef = useRef3(busy);
12351
13092
  const memoryManagerRef = useRef3(null);
12352
13093
  const sessionStartRecallRef = useRef3(null);
12353
13094
  const pendingTextRef = useRef3(/* @__PURE__ */ new Map());
12354
13095
  const flushTimeoutRef = useRef3(null);
12355
13096
  const customCommandsRef = useRef3([]);
12356
13097
  const pickerCancelRef = useRef3(null);
13098
+ useEffect6(() => {
13099
+ busyRef.current = busy;
13100
+ }, [busy]);
12357
13101
  const pickerAnchor = activePicker?.anchor ?? null;
12358
13102
  const pickerKind = activePicker?.kind ?? null;
12359
13103
  const pickerQuery = React14.useMemo(() => {
@@ -12376,7 +13120,7 @@ function App({
12376
13120
  if (pickerKind !== "slash" || pickerQuery === null) return [];
12377
13121
  return fuzzyFilter(allSlashCommands, pickerQuery, (c) => c.name).slice(0, 50);
12378
13122
  }, [pickerKind, allSlashCommands, pickerQuery]);
12379
- useEffect5(() => {
13123
+ useEffect6(() => {
12380
13124
  if (activePicker !== null) {
12381
13125
  const trigger = activePicker.kind === "file" ? "@" : "/";
12382
13126
  if (cursorOffset < activePicker.anchor) {
@@ -12433,28 +13177,28 @@ function App({
12433
13177
  return;
12434
13178
  }
12435
13179
  }, [input, cursorOffset, activePicker, filePickerEnabled]);
12436
- useEffect5(() => {
13180
+ useEffect6(() => {
12437
13181
  if (activePicker?.kind !== "file") return;
12438
13182
  const max = Math.max(0, filteredFileItems.length - 1);
12439
13183
  if (activePicker.selected > max) {
12440
13184
  setActivePicker({ ...activePicker, selected: max });
12441
13185
  }
12442
13186
  }, [filteredFileItems.length, activePicker]);
12443
- useEffect5(() => {
13187
+ useEffect6(() => {
12444
13188
  if (activePicker?.kind !== "slash") return;
12445
13189
  const max = Math.max(0, filteredSlashItems.length - 1);
12446
13190
  if (activePicker.selected > max) {
12447
13191
  setActivePicker({ ...activePicker, selected: max });
12448
13192
  }
12449
13193
  }, [filteredSlashItems.length, activePicker]);
12450
- const handlePickerUp = useCallback(() => {
13194
+ const handlePickerUp = useCallback2(() => {
12451
13195
  setActivePicker((p) => {
12452
13196
  if (!p) return null;
12453
13197
  const next = Math.max(0, p.selected - 1);
12454
13198
  return next === p.selected ? p : { ...p, selected: next };
12455
13199
  });
12456
13200
  }, []);
12457
- const handlePickerDown = useCallback(() => {
13201
+ const handlePickerDown = useCallback2(() => {
12458
13202
  setActivePicker((p) => {
12459
13203
  if (!p) return null;
12460
13204
  const max = p.kind === "file" ? Math.max(0, filteredFileItems.length - 1) : Math.max(0, filteredSlashItems.length - 1);
@@ -12462,7 +13206,7 @@ function App({
12462
13206
  return next === p.selected ? p : { ...p, selected: next };
12463
13207
  });
12464
13208
  }, [filteredFileItems.length, filteredSlashItems.length]);
12465
- const handlePickerSelect = useCallback(() => {
13209
+ const handlePickerSelect = useCallback2(() => {
12466
13210
  if (!activePicker) return;
12467
13211
  if (activePicker.kind === "file") {
12468
13212
  const item2 = filteredFileItems[activePicker.selected];
@@ -12480,12 +13224,12 @@ function App({
12480
13224
  setActivePicker(null);
12481
13225
  submitRef.current(value);
12482
13226
  }, [activePicker, filteredFileItems, filteredSlashItems, input, cursorOffset]);
12483
- const handlePickerCancel = useCallback(() => {
13227
+ const handlePickerCancel = useCallback2(() => {
12484
13228
  pickerCancelRef.current = cursorOffset;
12485
13229
  setActivePicker(null);
12486
13230
  }, [cursorOffset]);
12487
- useEffect5(() => {
12488
- const modalActive = showHelpMenu || commandWizard !== null || commandPicker !== null || commandToDelete !== null || showCommandList || showLspWizard || resumeSessions !== null || perm !== null;
13231
+ useEffect6(() => {
13232
+ const modalActive = showHelpMenu || commandWizard !== null || commandPicker !== null || commandToDelete !== null || showCommandList || showLspWizard || resumeSessions !== null || perm !== null || limitModal !== null;
12489
13233
  if (modalActive && activePicker !== null) {
12490
13234
  setActivePicker(null);
12491
13235
  }
@@ -12498,9 +13242,10 @@ function App({
12498
13242
  showLspWizard,
12499
13243
  resumeSessions,
12500
13244
  perm,
13245
+ limitModal,
12501
13246
  activePicker
12502
13247
  ]);
12503
- useEffect5(() => {
13248
+ useEffect6(() => {
12504
13249
  if (!cfg) return;
12505
13250
  void Promise.resolve().then(() => (init_sessions(), sessions_exports)).then(
12506
13251
  ({ pruneSessions: pruneSessions2 }) => pruneSessions2().then((removed) => {
@@ -12526,7 +13271,7 @@ function App({
12526
13271
  }
12527
13272
  });
12528
13273
  if (cfg.memoryEnabled) {
12529
- const dbPath = cfg.memoryDbPath ?? join21(process.cwd(), ".kimiflare", "memory.db");
13274
+ const dbPath = cfg.memoryDbPath ?? join22(process.cwd(), ".kimiflare", "memory.db");
12530
13275
  const manager = new MemoryManager({
12531
13276
  dbPath,
12532
13277
  accountId: cfg.accountId,
@@ -12594,7 +13339,7 @@ function App({
12594
13339
  }
12595
13340
  });
12596
13341
  }, [cfg, setEvents]);
12597
- useEffect5(() => {
13342
+ useEffect6(() => {
12598
13343
  const id = setInterval(() => {
12599
13344
  try {
12600
13345
  performance.clearMarks();
@@ -12604,7 +13349,7 @@ function App({
12604
13349
  }, 3e5);
12605
13350
  return () => clearInterval(id);
12606
13351
  }, []);
12607
- const reloadCustomCommands = useCallback(async () => {
13352
+ const reloadCustomCommands = useCallback2(async () => {
12608
13353
  const { commands, warnings } = await loadCustomCommands(process.cwd());
12609
13354
  customCommandsRef.current = commands;
12610
13355
  setCustomCommandsVersion((v) => v + 1);
@@ -12619,7 +13364,7 @@ function App({
12619
13364
  ]);
12620
13365
  }
12621
13366
  }, [setEvents]);
12622
- useEffect5(() => {
13367
+ useEffect6(() => {
12623
13368
  if (!cfg || updateCheckedRef.current) return;
12624
13369
  updateCheckedRef.current = true;
12625
13370
  if (initialUpdateResult) {
@@ -12670,7 +13415,7 @@ function App({
12670
13415
  }
12671
13416
  });
12672
13417
  }, [cfg, initialUpdateResult]);
12673
- useEffect5(() => {
13418
+ useEffect6(() => {
12674
13419
  modeRef.current = mode;
12675
13420
  if (cacheStableRef.current) {
12676
13421
  messagesRef.current[1] = {
@@ -12697,10 +13442,10 @@ function App({
12697
13442
  executorRef.current.clearSessionPermissions();
12698
13443
  }
12699
13444
  }, [mode, cfg?.model]);
12700
- useEffect5(() => {
13445
+ useEffect6(() => {
12701
13446
  effortRef.current = effort;
12702
13447
  }, [effort]);
12703
- useEffect5(() => {
13448
+ useEffect6(() => {
12704
13449
  if (!cfg) return;
12705
13450
  const id = setInterval(() => {
12706
13451
  void checkForUpdate().then((result) => {
@@ -12731,7 +13476,7 @@ function App({
12731
13476
  }, 30 * 60 * 1e3);
12732
13477
  return () => clearInterval(id);
12733
13478
  }, [cfg]);
12734
- const initMcp = useCallback(async () => {
13479
+ const initMcp = useCallback2(async () => {
12735
13480
  if (!cfg?.mcpServers || mcpInitRef.current) return;
12736
13481
  mcpInitRef.current = true;
12737
13482
  const manager = mcpManagerRef.current;
@@ -12792,7 +13537,7 @@ function App({
12792
13537
  ]);
12793
13538
  }
12794
13539
  }, [cfg]);
12795
- const initLsp = useCallback(async () => {
13540
+ const initLsp = useCallback2(async () => {
12796
13541
  if (!cfg?.lspEnabled || !cfg?.lspServers || lspInitRef.current) {
12797
13542
  if (lspInitRef.current) return;
12798
13543
  if (!cfg?.lspEnabled) {
@@ -12855,7 +13600,7 @@ function App({
12855
13600
  ]);
12856
13601
  }
12857
13602
  }, [cfg]);
12858
- useEffect5(() => {
13603
+ useEffect6(() => {
12859
13604
  if (cfg && !mcpInitRef.current) {
12860
13605
  void initMcp();
12861
13606
  }
@@ -12863,7 +13608,7 @@ function App({
12863
13608
  void initLsp();
12864
13609
  }
12865
13610
  }, [cfg, initMcp, initLsp]);
12866
- const ensureSessionId = useCallback(() => {
13611
+ const ensureSessionId = useCallback2(() => {
12867
13612
  if (sessionIdRef.current) return sessionIdRef.current;
12868
13613
  const firstUser = messagesRef.current.find((m) => m.role === "user");
12869
13614
  let firstText = "session";
@@ -12876,7 +13621,7 @@ function App({
12876
13621
  sessionIdRef.current = makeSessionId(firstText);
12877
13622
  return sessionIdRef.current;
12878
13623
  }, []);
12879
- const saveSessionSafe = useCallback(async () => {
13624
+ const saveSessionSafe = useCallback2(async () => {
12880
13625
  if (!cfg) return;
12881
13626
  ensureSessionId();
12882
13627
  try {
@@ -12893,7 +13638,7 @@ function App({
12893
13638
  } catch {
12894
13639
  }
12895
13640
  }, [cfg, ensureSessionId]);
12896
- const onIterationEnd = useCallback(
13641
+ const onIterationEnd = useCallback2(
12897
13642
  async (messages, signal) => {
12898
13643
  if (signal.aborted) return messages;
12899
13644
  if (!shouldCompact({ messages })) return messages;
@@ -12971,31 +13716,42 @@ function App({
12971
13716
  },
12972
13717
  [cfg]
12973
13718
  );
12974
- useInput6((inputChar, key) => {
13719
+ useInput7((inputChar, key) => {
12975
13720
  if (key.ctrl && inputChar === "c") {
12976
13721
  const hadPerm = permResolveRef.current !== null;
13722
+ const hadLimit = limitResolveRef.current !== null;
12977
13723
  if (hadPerm) {
12978
13724
  permResolveRef.current("deny");
12979
13725
  permResolveRef.current = null;
12980
13726
  setPerm(null);
12981
13727
  }
12982
- if (busy && activeControllerRef.current) {
13728
+ if (hadLimit) {
13729
+ limitResolveRef.current("stop");
13730
+ limitResolveRef.current = null;
13731
+ setLimitModal(null);
13732
+ }
13733
+ if (busyRef.current && activeControllerRef.current) {
12983
13734
  activeControllerRef.current.abort();
12984
13735
  setQueue([]);
12985
13736
  setEvents((e) => [...e, { kind: "info", key: mkKey(), text: "(interrupted)" }]);
12986
- } else if (!hadPerm) {
13737
+ } else if (!hadPerm && !hadLimit) {
12987
13738
  void lspManagerRef.current.stopAll().finally(() => exit());
12988
13739
  }
12989
13740
  return;
12990
13741
  }
12991
13742
  if (key.escape) {
12992
- const modalOpen = perm !== null || showHelpMenu || showLspWizard || showCommandList || commandWizard !== null || commandToDelete !== null || resumeSessions !== null;
12993
- if (!modalOpen && busy && activeControllerRef.current) {
13743
+ const modalOpen = perm !== null || limitModal !== null || showHelpMenu || showLspWizard || showCommandList || commandWizard !== null || commandToDelete !== null || resumeSessions !== null;
13744
+ if (!modalOpen && busyRef.current && activeControllerRef.current) {
12994
13745
  if (permResolveRef.current) {
12995
13746
  permResolveRef.current("deny");
12996
13747
  permResolveRef.current = null;
12997
13748
  setPerm(null);
12998
13749
  }
13750
+ if (limitResolveRef.current) {
13751
+ limitResolveRef.current("stop");
13752
+ limitResolveRef.current = null;
13753
+ setLimitModal(null);
13754
+ }
12999
13755
  activeControllerRef.current.abort();
13000
13756
  setQueue([]);
13001
13757
  setEvents((e) => [...e, { kind: "info", key: mkKey(), text: "(interrupted)" }]);
@@ -13015,7 +13771,7 @@ function App({
13015
13771
  return;
13016
13772
  }
13017
13773
  });
13018
- const flushAssistantUpdates = useCallback(() => {
13774
+ const flushAssistantUpdates = useCallback2(() => {
13019
13775
  flushTimeoutRef.current = null;
13020
13776
  const pending = pendingTextRef.current;
13021
13777
  if (pending.size === 0) return;
@@ -13033,7 +13789,7 @@ function App({
13033
13789
  })
13034
13790
  );
13035
13791
  }, []);
13036
- const updateAssistant = useCallback(
13792
+ const updateAssistant = useCallback2(
13037
13793
  (id, patch) => {
13038
13794
  const result = patch({ text: "", reasoning: "" });
13039
13795
  const assistantResult = result;
@@ -13062,7 +13818,7 @@ function App({
13062
13818
  },
13063
13819
  [flushAssistantUpdates]
13064
13820
  );
13065
- const updateTool = useCallback(
13821
+ const updateTool = useCallback2(
13066
13822
  (id, patch) => {
13067
13823
  setEvents(
13068
13824
  (evts) => evts.map(
@@ -13072,11 +13828,11 @@ function App({
13072
13828
  },
13073
13829
  []
13074
13830
  );
13075
- const updateGatewayMeta = useCallback((meta) => {
13831
+ const updateGatewayMeta = useCallback2((meta) => {
13076
13832
  gatewayMetaRef.current = meta;
13077
13833
  setGatewayMeta(meta);
13078
13834
  }, []);
13079
- const runCompact = useCallback(async () => {
13835
+ const runCompact = useCallback2(async () => {
13080
13836
  if (!cfg) return;
13081
13837
  if (busy) {
13082
13838
  setEvents((e) => [...e, { kind: "info", key: mkKey(), text: "can't compact while model is running" }]);
@@ -13161,40 +13917,23 @@ function App({
13161
13917
  setTurnStartedAt(null);
13162
13918
  activeControllerRef.current = null;
13163
13919
  permResolveRef.current = null;
13920
+ limitResolveRef.current = null;
13164
13921
  pendingToolCallsRef.current.clear();
13165
13922
  }
13166
13923
  }, [cfg, busy, saveSessionSafe]);
13167
- const openResumePicker = useCallback(async () => {
13924
+ const openResumePicker = useCallback2(async () => {
13168
13925
  const sessions = await listSessions(200, process.cwd());
13169
13926
  setResumeSessions(sessions);
13170
13927
  }, []);
13171
- const runInit = useCallback(async () => {
13928
+ const runInit = useCallback2(async () => {
13172
13929
  if (!cfg) return;
13173
13930
  if (busy) {
13174
13931
  setEvents((e) => [...e, { kind: "info", key: mkKey(), text: "can't /init while model is running" }]);
13175
13932
  return;
13176
13933
  }
13177
13934
  const cwd = process.cwd();
13178
- const existingName = ["KIMI.md", "KIMIFLARE.md", "AGENT.md"].find((n) => existsSync2(join21(cwd, n)));
13179
- const isRefresh = existingName !== void 0;
13180
- const promptParts = [
13181
- 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.",
13182
- "",
13183
- "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.",
13184
- isRefresh ? `Also read the existing ${existingName} so you know what to keep vs. update.` : null,
13185
- "",
13186
- "Then call the `write` tool to create `KIMI.md` at the repo root with these sections, terse (aim \u2264 100 lines total):",
13187
- "",
13188
- "- **Project** \u2014 one-line description + primary language/runtime.",
13189
- "- **Build / test / run** \u2014 exact shell commands an agent should use.",
13190
- "- **Layout** \u2014 key directories and what lives in each.",
13191
- "- **Conventions** \u2014 naming, import style, file structure, commit style, anything surprising.",
13192
- "- **Do / Don't** \u2014 quirks or rules future agents should know.",
13193
- "",
13194
- "Do not call `tasks_set` for this. Just read what you need, then write the file."
13195
- ];
13196
- const prompt = promptParts.filter((p) => p !== null).join("\n");
13197
- setEvents((e) => [...e, { kind: "user", key: mkKey(), text: isRefresh ? `/init (refreshing ${existingName})` : "/init" }]);
13935
+ const { prompt, targetFilename, isRefresh } = buildInitPrompt(cwd);
13936
+ setEvents((e) => [...e, { kind: "user", key: mkKey(), text: isRefresh ? `/init (refreshing ${targetFilename})` : "/init" }]);
13198
13937
  messagesRef.current.push({ role: "user", content: sanitizeString(prompt) });
13199
13938
  setBusy(true);
13200
13939
  setTurnStartedAt(Date.now());
@@ -13227,7 +13966,7 @@ function App({
13227
13966
  memoryManager: memoryManagerRef.current,
13228
13967
  codeMode: effectiveCodeMode,
13229
13968
  cloudMode: cfg.cloudMode,
13230
- cloudToken: initialCloudToken,
13969
+ cloudToken: cloudToken ?? initialCloudToken,
13231
13970
  onIterationEnd,
13232
13971
  onFileChange: (path, content) => {
13233
13972
  if (content) {
@@ -13328,7 +14067,7 @@ function App({
13328
14067
  })
13329
14068
  }
13330
14069
  });
13331
- if (existsSync2(join21(cwd, "KIMI.md"))) {
14070
+ if (existsSync3(join22(cwd, "KIMI.md"))) {
13332
14071
  if (cacheStableRef.current) {
13333
14072
  messagesRef.current[1] = {
13334
14073
  role: "system",
@@ -13383,10 +14122,11 @@ function App({
13383
14122
  activeAsstIdRef.current = null;
13384
14123
  activeControllerRef.current = null;
13385
14124
  permResolveRef.current = null;
14125
+ limitResolveRef.current = null;
13386
14126
  pendingToolCallsRef.current.clear();
13387
14127
  }
13388
14128
  }, [cfg, busy, updateAssistant, updateTool, updateGatewayMeta]);
13389
- const handleThemePick = useCallback(
14129
+ const handleThemePick = useCallback2(
13390
14130
  (picked) => {
13391
14131
  setShowThemePicker(false);
13392
14132
  setOriginalTheme(null);
@@ -13405,7 +14145,7 @@ function App({
13405
14145
  },
13406
14146
  [cfg, originalTheme]
13407
14147
  );
13408
- const handleResumePick = useCallback(
14148
+ const handleResumePick = useCallback2(
13409
14149
  async (picked) => {
13410
14150
  setResumeSessions(null);
13411
14151
  if (!picked) return;
@@ -13463,7 +14203,7 @@ function App({
13463
14203
  },
13464
14204
  []
13465
14205
  );
13466
- const handleSlash = useCallback(
14206
+ const handleSlash = useCallback2(
13467
14207
  (cmd) => {
13468
14208
  const raw = cmd.trim();
13469
14209
  const [head, ...rest] = raw.split(/\s+/);
@@ -13949,7 +14689,7 @@ ${lines.join("\n")}` }]);
13949
14689
  if (c === "/hello") {
13950
14690
  const session = crypto.randomUUID();
13951
14691
  const url = `${FEEDBACK_WORKER_URL}/?s=${session}&v=${getAppVersion()}`;
13952
- openBrowser(url);
14692
+ openBrowser2(url);
13953
14693
  setEvents((e) => [
13954
14694
  ...e,
13955
14695
  { kind: "info", key: mkKey(), text: "Opened voice note page in your browser. Record your message there and hit Send when you're done." }
@@ -14074,7 +14814,7 @@ ${lines.join("\n")}` }]);
14074
14814
  setEvents((e) => [
14075
14815
  ...e,
14076
14816
  { kind: "info", key: mkKey(), text: `Starting remote session for ${repo.owner}/${repo.name}...` },
14077
- { kind: "info", key: mkKey(), text: `Budget: ${formatTokens3(budget)} tokens. TTL: ${ttl} min.` }
14817
+ { kind: "info", key: mkKey(), text: `Budget: ${formatTokens4(budget)} tokens. TTL: ${ttl} min.` }
14078
14818
  ]);
14079
14819
  try {
14080
14820
  const data = await startRemoteSession({
@@ -14162,7 +14902,7 @@ ${lines.join("\n")}` }]);
14162
14902
  },
14163
14903
  [cfg, exit, usage, effort, theme, mode, openResumePicker, runCompact, runInit, initMcp, setCfg, setShowRemoteDashboard, setSelectedRemoteSession]
14164
14904
  );
14165
- const handleHelpCommand = useCallback(
14905
+ const handleHelpCommand = useCallback2(
14166
14906
  (command) => {
14167
14907
  setShowHelpMenu(false);
14168
14908
  const executed = handleSlash(command);
@@ -14172,7 +14912,7 @@ ${lines.join("\n")}` }]);
14172
14912
  },
14173
14913
  [handleSlash]
14174
14914
  );
14175
- const handleCommandSave = useCallback(
14915
+ const handleCommandSave = useCallback2(
14176
14916
  async (opts2) => {
14177
14917
  setCommandWizard(null);
14178
14918
  try {
@@ -14194,7 +14934,7 @@ ${lines.join("\n")}` }]);
14194
14934
  },
14195
14935
  [commandWizard, reloadCustomCommands, setEvents]
14196
14936
  );
14197
- const handleCommandDelete = useCallback(
14937
+ const handleCommandDelete = useCallback2(
14198
14938
  async (cmd) => {
14199
14939
  setCommandToDelete(null);
14200
14940
  try {
@@ -14213,7 +14953,7 @@ ${lines.join("\n")}` }]);
14213
14953
  },
14214
14954
  [reloadCustomCommands, setEvents]
14215
14955
  );
14216
- const processMessage = useCallback(
14956
+ const processMessage = useCallback2(
14217
14957
  async (text, displayText) => {
14218
14958
  if (!cfg) return;
14219
14959
  let trimmed = text.trim();
@@ -14412,6 +15152,10 @@ ${lines.join("\n")}` }]);
14412
15152
  }
14413
15153
  permResolveRef.current = resolve2;
14414
15154
  setPerm({ tool: req.tool, args: req.args, resolve: resolve2 });
15155
+ }),
15156
+ onToolLimitReached: () => new Promise((resolve2) => {
15157
+ limitResolveRef.current = resolve2;
15158
+ setLimitModal({ limit: 50, resolve: resolve2 });
14415
15159
  })
14416
15160
  };
14417
15161
  try {
@@ -14432,7 +15176,7 @@ ${lines.join("\n")}` }]);
14432
15176
  keepLastImageTurns: cfg.imageHistoryTurns ?? 2,
14433
15177
  codeMode: effectiveCodeMode,
14434
15178
  cloudMode: cfg.cloudMode,
14435
- cloudToken: initialCloudToken,
15179
+ cloudToken: cloudToken ?? initialCloudToken,
14436
15180
  onIterationEnd,
14437
15181
  intentClassification: classification,
14438
15182
  onFileChange: (path, content2) => {
@@ -14501,6 +15245,8 @@ ${lines.join("\n")}` }]);
14501
15245
  text: `auto-compact failed: ${compactErr.message ?? String(compactErr)}`
14502
15246
  }
14503
15247
  ]);
15248
+ } else {
15249
+ throw compactErr;
14504
15250
  }
14505
15251
  }
14506
15252
  }
@@ -14570,19 +15316,20 @@ ${lines.join("\n")}` }]);
14570
15316
  activeAsstIdRef.current = null;
14571
15317
  activeControllerRef.current = null;
14572
15318
  permResolveRef.current = null;
15319
+ limitResolveRef.current = null;
14573
15320
  pendingToolCallsRef.current.clear();
14574
15321
  }
14575
15322
  },
14576
15323
  [cfg, handleSlash, updateAssistant, updateTool, saveSessionSafe, updateGatewayMeta]
14577
15324
  );
14578
- useEffect5(() => {
15325
+ useEffect6(() => {
14579
15326
  if (!busy && queue.length > 0) {
14580
15327
  const next = queue[0];
14581
15328
  setQueue((q) => q.slice(1));
14582
15329
  processMessage(next.full, next.display);
14583
15330
  }
14584
15331
  }, [busy, queue, processMessage]);
14585
- const submit = useCallback(
15332
+ const submit = useCallback2(
14586
15333
  (full, display) => {
14587
15334
  const trimmedFull = full.trim();
14588
15335
  if (!trimmedFull) return;
@@ -14603,7 +15350,7 @@ ${lines.join("\n")}` }]);
14603
15350
  [busy, processMessage]
14604
15351
  );
14605
15352
  submitRef.current = submit;
14606
- useEffect5(() => {
15353
+ useEffect6(() => {
14607
15354
  if (compactSuggestedRef.current) return;
14608
15355
  if (usage && usage.prompt_tokens / CONTEXT_LIMIT >= AUTO_COMPACT_SUGGEST_PCT) {
14609
15356
  compactSuggestedRef.current = true;
@@ -14618,15 +15365,17 @@ ${lines.join("\n")}` }]);
14618
15365
  }
14619
15366
  }, [usage]);
14620
15367
  if (!cfg) {
14621
- return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(
15368
+ return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsx23(
14622
15369
  Onboarding,
14623
15370
  {
15371
+ onCancel: () => exit(),
14624
15372
  onDone: async (newCfg) => {
14625
15373
  setCfg(newCfg);
14626
15374
  if (newCfg.cloudMode) {
14627
15375
  const { loadCloudCredentials: loadCloudCredentials2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
14628
15376
  const creds = await loadCloudCredentials2();
14629
15377
  if (creds) {
15378
+ setCloudToken(creds.accessToken);
14630
15379
  setEvents((e) => [
14631
15380
  ...e,
14632
15381
  { kind: "info", key: mkKey(), text: "configuration saved \u2014 welcome to kimiflare! (cloud mode)" }
@@ -14648,10 +15397,10 @@ ${lines.join("\n")}` }]);
14648
15397
  ) });
14649
15398
  }
14650
15399
  if (resumeSessions !== null) {
14651
- return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx22(ResumePicker, { sessions: resumeSessions, onPick: handleResumePick }) }) });
15400
+ return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsx23(Box21, { flexDirection: "column", children: /* @__PURE__ */ jsx23(ResumePicker, { sessions: resumeSessions, onPick: handleResumePick }) }) });
14652
15401
  }
14653
15402
  if (showRemoteDashboard) {
14654
- return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: selectedRemoteSession ? /* @__PURE__ */ jsx22(
15403
+ return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsx23(Box21, { flexDirection: "column", children: selectedRemoteSession ? /* @__PURE__ */ jsx23(
14655
15404
  RemoteSessionDetail,
14656
15405
  {
14657
15406
  session: selectedRemoteSession,
@@ -14674,7 +15423,7 @@ ${lines.join("\n")}` }]);
14674
15423
  setShowRemoteDashboard(false);
14675
15424
  }
14676
15425
  }
14677
- ) : /* @__PURE__ */ jsx22(
15426
+ ) : /* @__PURE__ */ jsx23(
14678
15427
  RemoteDashboard,
14679
15428
  {
14680
15429
  onSelect: (session) => setSelectedRemoteSession(session),
@@ -14683,7 +15432,7 @@ ${lines.join("\n")}` }]);
14683
15432
  ) }) });
14684
15433
  }
14685
15434
  if (showHelpMenu) {
14686
- return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx22(
15435
+ return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsx23(Box21, { flexDirection: "column", children: /* @__PURE__ */ jsx23(
14687
15436
  HelpMenu,
14688
15437
  {
14689
15438
  customCommands: customCommandsRef.current.filter((c) => !BUILTIN_COMMAND_NAMES.has(c.name.toLowerCase())).map((c) => ({ name: c.name, description: c.description })),
@@ -14695,12 +15444,12 @@ ${lines.join("\n")}` }]);
14695
15444
  ) }) });
14696
15445
  }
14697
15446
  if (showLspWizard) {
14698
- return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx22(
15447
+ return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsx23(Box21, { flexDirection: "column", children: /* @__PURE__ */ jsx23(
14699
15448
  LspWizard,
14700
15449
  {
14701
15450
  servers: cfg?.lspServers ?? {},
14702
15451
  currentScope: lspScope,
14703
- hasProjectDir: existsSync2(join21(process.cwd(), ".kimiflare")),
15452
+ hasProjectDir: existsSync3(join22(process.cwd(), ".kimiflare")),
14704
15453
  onDone: () => setShowLspWizard(false),
14705
15454
  onSave: (servers, enabled, scope) => {
14706
15455
  setCfg((c) => c ? { ...c, lspEnabled: enabled, lspServers: servers } : c);
@@ -14732,7 +15481,7 @@ ${lines.join("\n")}` }]);
14732
15481
  ) }) });
14733
15482
  }
14734
15483
  if (commandWizard) {
14735
- return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx22(
15484
+ return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsx23(Box21, { flexDirection: "column", children: /* @__PURE__ */ jsx23(
14736
15485
  CommandWizard,
14737
15486
  {
14738
15487
  mode: commandWizard.mode,
@@ -14745,7 +15494,7 @@ ${lines.join("\n")}` }]);
14745
15494
  ) }) });
14746
15495
  }
14747
15496
  if (commandPicker) {
14748
- return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx22(
15497
+ return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsx23(Box21, { flexDirection: "column", children: /* @__PURE__ */ jsx23(
14749
15498
  CommandPicker,
14750
15499
  {
14751
15500
  commands: customCommandsRef.current,
@@ -14763,15 +15512,15 @@ ${lines.join("\n")}` }]);
14763
15512
  ) }) });
14764
15513
  }
14765
15514
  if (commandToDelete) {
14766
- return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
14767
- /* @__PURE__ */ jsxs20(Text21, { color: theme.accent, bold: true, children: [
15515
+ return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
15516
+ /* @__PURE__ */ jsxs21(Text22, { color: theme.accent, bold: true, children: [
14768
15517
  "Delete /",
14769
15518
  commandToDelete.name,
14770
15519
  "?"
14771
15520
  ] }),
14772
- /* @__PURE__ */ jsx22(Text21, { color: theme.info.color, children: commandToDelete.filepath }),
14773
- /* @__PURE__ */ jsx22(Box20, { marginTop: 1, children: /* @__PURE__ */ jsx22(
14774
- SelectInput10,
15521
+ /* @__PURE__ */ jsx23(Text22, { color: theme.info.color, children: commandToDelete.filepath }),
15522
+ /* @__PURE__ */ jsx23(Box21, { marginTop: 1, children: /* @__PURE__ */ jsx23(
15523
+ SelectInput11,
14775
15524
  {
14776
15525
  items: [
14777
15526
  { label: "Yes, delete", value: "yes", key: "yes" },
@@ -14789,7 +15538,7 @@ ${lines.join("\n")}` }]);
14789
15538
  ] }) });
14790
15539
  }
14791
15540
  if (showCommandList) {
14792
- return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx22(
15541
+ return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsx23(Box21, { flexDirection: "column", children: /* @__PURE__ */ jsx23(
14793
15542
  CommandList,
14794
15543
  {
14795
15544
  commands: customCommandsRef.current,
@@ -14798,12 +15547,12 @@ ${lines.join("\n")}` }]);
14798
15547
  ) }) });
14799
15548
  }
14800
15549
  if (showThemePicker) {
14801
- return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx22(ThemePicker, { themes: themeList(), onPick: handleThemePick, onPreview: (t) => setTheme(t) }) }) });
15550
+ return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsx23(Box21, { flexDirection: "column", children: /* @__PURE__ */ jsx23(ThemePicker, { themes: themeList(), onPick: handleThemePick, onPreview: (t) => setTheme(t) }) }) });
14802
15551
  }
14803
15552
  const hasConversation = events.some((e) => e.kind === "user" || e.kind === "assistant");
14804
- return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", children: [
14805
- !hasConversation && events.length === 0 ? /* @__PURE__ */ jsx22(Welcome, { accountId: cfg.accountId }) : /* @__PURE__ */ jsx22(ChatView, { events, showReasoning, verbose }),
14806
- perm ? /* @__PURE__ */ jsx22(
15553
+ return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", children: [
15554
+ !hasConversation && events.length === 0 ? /* @__PURE__ */ jsx23(Welcome, { accountId: cfg.accountId }) : /* @__PURE__ */ jsx23(ChatView, { events, showReasoning, verbose }),
15555
+ perm ? /* @__PURE__ */ jsx23(
14807
15556
  PermissionModal,
14808
15557
  {
14809
15558
  tool: perm.tool,
@@ -14814,8 +15563,18 @@ ${lines.join("\n")}` }]);
14814
15563
  setPerm(null);
14815
15564
  }
14816
15565
  }
14817
- ) : /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", marginTop: 1, children: [
14818
- tasks.length > 0 && /* @__PURE__ */ jsx22(
15566
+ ) : limitModal ? /* @__PURE__ */ jsx23(
15567
+ LimitModal,
15568
+ {
15569
+ limit: limitModal.limit,
15570
+ onDecide: (d) => {
15571
+ limitModal.resolve(d);
15572
+ limitResolveRef.current = null;
15573
+ setLimitModal(null);
15574
+ }
15575
+ }
15576
+ ) : /* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", marginTop: 1, children: [
15577
+ tasks.length > 0 && /* @__PURE__ */ jsx23(
14819
15578
  TaskList,
14820
15579
  {
14821
15580
  tasks,
@@ -14823,11 +15582,11 @@ ${lines.join("\n")}` }]);
14823
15582
  tokensDelta: Math.max(0, (usage?.prompt_tokens ?? 0) - tasksStartTokens)
14824
15583
  }
14825
15584
  ),
14826
- queue.length > 0 && /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", marginBottom: 1, children: queue.map((q, i) => /* @__PURE__ */ jsxs20(Text21, { color: theme.info.color, children: [
15585
+ queue.length > 0 && /* @__PURE__ */ jsx23(Box21, { flexDirection: "column", marginBottom: 1, children: queue.map((q, i) => /* @__PURE__ */ jsxs21(Text22, { color: theme.info.color, children: [
14827
15586
  "\u23F3 ",
14828
15587
  q.display
14829
15588
  ] }, `queue_${i}`)) }),
14830
- /* @__PURE__ */ jsx22(
15589
+ /* @__PURE__ */ jsx23(
14831
15590
  StatusBar,
14832
15591
  {
14833
15592
  model: cfg.model,
@@ -14842,10 +15601,11 @@ ${lines.join("\n")}` }]);
14842
15601
  latestVersion,
14843
15602
  gatewayMeta,
14844
15603
  codeMode,
14845
- cloudMode: cfg.cloudMode
15604
+ cloudMode: cfg.cloudMode,
15605
+ cloudBudget
14846
15606
  }
14847
15607
  ),
14848
- activePicker?.kind === "file" && /* @__PURE__ */ jsx22(
15608
+ activePicker?.kind === "file" && /* @__PURE__ */ jsx23(
14849
15609
  FilePicker,
14850
15610
  {
14851
15611
  items: filteredFileItems,
@@ -14853,7 +15613,7 @@ ${lines.join("\n")}` }]);
14853
15613
  query: pickerQuery ?? ""
14854
15614
  }
14855
15615
  ),
14856
- activePicker?.kind === "slash" && /* @__PURE__ */ jsx22(
15616
+ activePicker?.kind === "slash" && /* @__PURE__ */ jsx23(
14857
15617
  SlashPicker,
14858
15618
  {
14859
15619
  items: filteredSlashItems,
@@ -14861,9 +15621,9 @@ ${lines.join("\n")}` }]);
14861
15621
  query: pickerQuery ?? ""
14862
15622
  }
14863
15623
  ),
14864
- /* @__PURE__ */ jsxs20(Box20, { marginTop: 1, children: [
14865
- /* @__PURE__ */ jsx22(Text21, { color: "#d699b6", children: "\u203A " }),
14866
- /* @__PURE__ */ jsx22(
15624
+ /* @__PURE__ */ jsxs21(Box21, { marginTop: 1, children: [
15625
+ /* @__PURE__ */ jsx23(Text22, { color: "#d699b6", children: "\u203A " }),
15626
+ /* @__PURE__ */ jsx23(
14867
15627
  CustomTextInput,
14868
15628
  {
14869
15629
  value: input,
@@ -14920,7 +15680,7 @@ ${lines.join("\n")}` }]);
14920
15680
  }
14921
15681
  async function renderApp(cfg, updateResult, lspScope = "global", lspProjectPath = null, cloudToken) {
14922
15682
  const instance = render(
14923
- /* @__PURE__ */ jsx22(
15683
+ /* @__PURE__ */ jsx23(
14924
15684
  App,
14925
15685
  {
14926
15686
  initialCfg: cfg,
@@ -14954,6 +15714,7 @@ var init_app = __esm({
14954
15714
  init_chat();
14955
15715
  init_status();
14956
15716
  init_permission();
15717
+ init_limit_modal();
14957
15718
  init_resume_picker();
14958
15719
  init_task_list();
14959
15720
  init_text_input();
@@ -14981,6 +15742,7 @@ var init_app = __esm({
14981
15742
  init_builtins();
14982
15743
  init_save();
14983
15744
  init_command_wizard();
15745
+ init_context_generator();
14984
15746
  init_command_picker();
14985
15747
  init_command_list();
14986
15748
  init_lsp_wizard();
@@ -15138,14 +15900,12 @@ program.command("usage").description("Show Kimiflare Cloud token usage (requires
15138
15900
  console.error("Not authenticated with Kimiflare Cloud. Run: kimiflare auth cloud");
15139
15901
  process.exit(1);
15140
15902
  }
15141
- const res = await fetch("https://api.kimiflare.com/v1/usage", {
15142
- headers: { Authorization: `Bearer ${creds.accessToken}` }
15143
- });
15144
- if (!res.ok) {
15145
- console.error(`Failed to fetch usage: ${res.status} ${res.statusText}`);
15903
+ const { fetchCloudUsage: fetchCloudUsage2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
15904
+ const usage = await fetchCloudUsage2(creds.accessToken);
15905
+ if (!usage) {
15906
+ console.error("Failed to fetch usage: invalid response from server");
15146
15907
  process.exit(1);
15147
15908
  }
15148
- const usage = await res.json();
15149
15909
  console.log(`Token budget: ${usage.remaining.toLocaleString()} / ${usage.input_token_limit.toLocaleString()} remaining`);
15150
15910
  console.log(`Used: ${usage.input_tokens_used.toLocaleString()}`);
15151
15911
  console.log(`Grant expires: ${usage.expires_at}`);
@@ -15183,11 +15943,9 @@ Kimiflare Cloud Authentication`);
15183
15943
  }
15184
15944
  });
15185
15945
  console.log(`Authenticated! Token expires at ${new Date(creds.expiresAt * 1e3).toISOString()}`);
15186
- const usageRes = await fetch("https://api.kimiflare.com/v1/usage", {
15187
- headers: { Authorization: `Bearer ${creds.accessToken}` }
15188
- });
15189
- if (usageRes.ok) {
15190
- const usage = await usageRes.json();
15946
+ const { fetchCloudUsage: fetchCloudUsage2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
15947
+ const usage = await fetchCloudUsage2(creds.accessToken);
15948
+ if (usage) {
15191
15949
  console.log(`
15192
15950
  Token budget: ${usage.remaining.toLocaleString()} / ${usage.input_token_limit.toLocaleString()} remaining`);
15193
15951
  console.log(`Grant expires: ${usage.expires_at}`);