kimiflare 0.56.0 → 0.58.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -140,7 +140,7 @@ async function loadConfig() {
140
140
  cacheStablePrompts,
141
141
  compiledContext,
142
142
  imageHistoryTurns: Number.isNaN(imageHistoryTurns) ? void 0 : imageHistoryTurns,
143
- memoryEnabled: envMemoryEnabled ?? true,
143
+ memoryEnabled: envMemoryEnabled ?? false,
144
144
  memoryDbPath: envMemoryDbPath,
145
145
  memoryMaxAgeDays: envMemoryMaxAgeDays,
146
146
  memoryMaxEntries: envMemoryMaxEntries,
@@ -169,7 +169,7 @@ async function loadConfig() {
169
169
  cacheStablePrompts,
170
170
  compiledContext,
171
171
  imageHistoryTurns: Number.isNaN(imageHistoryTurns) ? void 0 : imageHistoryTurns,
172
- memoryEnabled: envMemoryEnabled ?? true,
172
+ memoryEnabled: envMemoryEnabled ?? false,
173
173
  memoryDbPath: envMemoryDbPath,
174
174
  memoryMaxAgeDays: envMemoryMaxAgeDays,
175
175
  memoryMaxEntries: envMemoryMaxEntries,
@@ -199,7 +199,7 @@ async function loadConfig() {
199
199
  cacheStablePrompts: parsed.cacheStablePrompts ?? cacheStablePrompts,
200
200
  compiledContext: parsed.compiledContext ?? compiledContext,
201
201
  imageHistoryTurns: Number.isNaN(imageHistoryTurns) ? parsed.imageHistoryTurns : imageHistoryTurns,
202
- memoryEnabled: envMemoryEnabled ?? parsed.memoryEnabled ?? true,
202
+ memoryEnabled: envMemoryEnabled ?? parsed.memoryEnabled ?? false,
203
203
  memoryDbPath: envMemoryDbPath ?? parsed.memoryDbPath,
204
204
  memoryMaxAgeDays: envMemoryMaxAgeDays ?? parsed.memoryMaxAgeDays,
205
205
  memoryMaxEntries: envMemoryMaxEntries ?? parsed.memoryMaxEntries,
@@ -230,7 +230,7 @@ async function loadConfig() {
230
230
  cacheStablePrompts: parsed.cacheStablePrompts ?? cacheStablePrompts,
231
231
  compiledContext: parsed.compiledContext ?? compiledContext,
232
232
  imageHistoryTurns: Number.isNaN(imageHistoryTurns) ? parsed.imageHistoryTurns : imageHistoryTurns,
233
- memoryEnabled: envMemoryEnabled ?? parsed.memoryEnabled ?? true,
233
+ memoryEnabled: envMemoryEnabled ?? parsed.memoryEnabled ?? false,
234
234
  memoryDbPath: envMemoryDbPath ?? parsed.memoryDbPath,
235
235
  memoryMaxAgeDays: envMemoryMaxAgeDays ?? parsed.memoryMaxAgeDays,
236
236
  memoryMaxEntries: envMemoryMaxEntries ?? parsed.memoryMaxEntries,
@@ -462,6 +462,17 @@ var init_sse = __esm({
462
462
  });
463
463
 
464
464
  // src/util/errors.ts
465
+ function isKillSwitchError(err) {
466
+ return err instanceof KillSwitchError;
467
+ }
468
+ async function detectKillSwitch(res) {
469
+ if (res.status === 503) {
470
+ const data = await res.json().catch(() => ({}));
471
+ if (data.error === "SERVICE_ENDED") {
472
+ throw new KillSwitchError(typeof data.ended_at === "string" ? data.ended_at : void 0);
473
+ }
474
+ }
475
+ }
465
476
  function isCloudQuotaExhaustedError(err) {
466
477
  return err instanceof KimiApiError && err.httpStatus === 429 && /token quota exhausted/i.test(err.message);
467
478
  }
@@ -499,7 +510,7 @@ Get a new token: https://dash.cloudflare.com/profile/api-tokens`;
499
510
  }
500
511
  return message2.replace(/\{[\s\S]*?\}/g, "(see logs for details)");
501
512
  }
502
- var KimiApiError;
513
+ var KimiApiError, KillSwitchError;
503
514
  var init_errors = __esm({
504
515
  "src/util/errors.ts"() {
505
516
  "use strict";
@@ -513,6 +524,14 @@ var init_errors = __esm({
513
524
  code;
514
525
  httpStatus;
515
526
  };
527
+ KillSwitchError = class extends Error {
528
+ endedAt;
529
+ constructor(endedAt) {
530
+ super("SERVICE_ENDED");
531
+ this.name = "KillSwitchError";
532
+ this.endedAt = endedAt;
533
+ }
534
+ };
516
535
  }
517
536
  });
518
537
 
@@ -649,7 +668,9 @@ async function* runKimi(opts2) {
649
668
  body: stableStringify(body, jsonReplacer),
650
669
  signal: opts2.signal
651
670
  });
671
+ await detectKillSwitch(res);
652
672
  } catch (fetchErr) {
673
+ if (fetchErr instanceof KillSwitchError) throw fetchErr;
653
674
  const msg = fetchErr instanceof Error ? fetchErr.message : String(fetchErr);
654
675
  logger.warn("runKimi:fetch_error", { requestId, attempt, error: msg });
655
676
  if (attempt < MAX_ATTEMPTS - 1) {
@@ -2954,6 +2975,20 @@ ${sandboxResult.output}` : sandboxResult.output;
2954
2975
  throw new BudgetExhaustedError();
2955
2976
  }
2956
2977
  if (loopExhausted) {
2978
+ if (opts2.callbacks.onLoopDetected) {
2979
+ const decision = await opts2.callbacks.onLoopDetected();
2980
+ if (decision === "continue") {
2981
+ opts2.messages.push({
2982
+ role: "system",
2983
+ content: "You were stuck calling the same tools with identical arguments. The guardrail has been reset so you can continue. Try a different approach."
2984
+ });
2985
+ loopExhausted = false;
2986
+ recentToolCalls.length = 0;
2987
+ continue;
2988
+ } else {
2989
+ return;
2990
+ }
2991
+ }
2957
2992
  throw new AgentLoopError();
2958
2993
  }
2959
2994
  }
@@ -3285,7 +3320,11 @@ ${toolsBlock}`;
3285
3320
  Project context from ${ctx.name} (${ctx.lineCount} lines, treat as authoritative):
3286
3321
  ${ctx.content.trim()}` : "";
3287
3322
  const modeBlock = opts2.mode ? systemPromptForMode(opts2.mode) : "";
3288
- const skillsBlock = opts2.selectedSkills && opts2.selectedSkills.length > 0 ? `
3323
+ const skillsBlock = opts2.skillContext ? `
3324
+
3325
+ ## Relevant Skills
3326
+
3327
+ ${opts2.skillContext}` : opts2.selectedSkills && opts2.selectedSkills.length > 0 ? `
3289
3328
 
3290
3329
  Active skills for this turn:
3291
3330
  ${opts2.selectedSkills.map((s) => `--- ${s.name} ---
@@ -6218,6 +6257,7 @@ async function registerDevice(codes) {
6218
6257
  headers: { "Content-Type": "application/json" },
6219
6258
  body: JSON.stringify({ device_code: codes.deviceCode, user_code: codes.userCode, device_id: codes.deviceId })
6220
6259
  });
6260
+ await detectKillSwitch(registerRes);
6221
6261
  if (!registerRes.ok) {
6222
6262
  const err = await registerRes.json().catch(() => ({}));
6223
6263
  throw new Error(`Failed to register device: ${err.error || registerRes.statusText}`);
@@ -6229,6 +6269,7 @@ async function pollForToken(deviceCode, deviceId) {
6229
6269
  headers: { "Content-Type": "application/json" },
6230
6270
  body: JSON.stringify({ device_code: deviceCode })
6231
6271
  });
6272
+ await detectKillSwitch(pollRes);
6232
6273
  if (!pollRes.ok) return null;
6233
6274
  const pollData = await pollRes.json();
6234
6275
  if (pollData.status === "approved" && pollData.access_token) {
@@ -6246,7 +6287,13 @@ async function pollForToken(deviceCode, deviceId) {
6246
6287
  async function fetchCloudUsage(token, deviceId) {
6247
6288
  const headers = { Authorization: `Bearer ${token}` };
6248
6289
  if (deviceId) headers["X-Device-ID"] = deviceId;
6249
- const res = await fetch(`${CLOUD_API_URL}/v1/usage`, { headers });
6290
+ let res;
6291
+ try {
6292
+ res = await fetch(`${CLOUD_API_URL}/v1/usage`, { headers });
6293
+ } catch {
6294
+ return null;
6295
+ }
6296
+ await detectKillSwitch(res);
6250
6297
  if (!res.ok) return null;
6251
6298
  const data = await res.json();
6252
6299
  if (typeof data.remaining !== "number" || typeof data.input_token_limit !== "number" || typeof data.input_tokens_used !== "number" || typeof data.expires_at !== "string") {
@@ -6311,6 +6358,7 @@ var CLOUD_API_URL, POLL_INTERVAL_MS, POLL_TIMEOUT_MS;
6311
6358
  var init_auth = __esm({
6312
6359
  "src/cloud/auth.ts"() {
6313
6360
  "use strict";
6361
+ init_errors();
6314
6362
  CLOUD_API_URL = "https://api.kimiflare.com";
6315
6363
  POLL_INTERVAL_MS = 5e3;
6316
6364
  POLL_TIMEOUT_MS = 15 * 60 * 1e3;
@@ -6841,6 +6889,7 @@ async function fetchWithRetry(url, init, retries = 3) {
6841
6889
  for (let i = 0; i < retries; i++) {
6842
6890
  try {
6843
6891
  const res = await fetch(url, init);
6892
+ await detectKillSwitch(res);
6844
6893
  if (res.ok) return res;
6845
6894
  if (res.status === 429 || res.status >= 500) {
6846
6895
  const delay = 1e3 * 2 ** i;
@@ -6860,21 +6909,28 @@ async function fetchWithRetry(url, init, retries = 3) {
6860
6909
  }
6861
6910
  async function fetchEmbeddings(opts2) {
6862
6911
  const model = opts2.model ?? DEFAULT_MODEL2;
6863
- const url = opts2.gateway ? `https://gateway.ai.cloudflare.com/v1/${opts2.accountId}/${opts2.gateway.id}/workers-ai/${model}` : `https://api.cloudflare.com/client/v4/accounts/${opts2.accountId}/ai/run/${model}`;
6912
+ let url;
6864
6913
  const headers = {
6865
- Authorization: `Bearer ${opts2.apiToken}`,
6866
6914
  "Content-Type": "application/json",
6867
6915
  "User-Agent": getUserAgent()
6868
6916
  };
6869
- if (opts2.gateway?.metadata) {
6870
- for (const [k, v] of Object.entries(opts2.gateway.metadata)) {
6871
- headers[`cf-aig-metadata-${k}`] = String(v);
6917
+ if (opts2.cloudMode) {
6918
+ url = "https://api.kimiflare.com/v1/embeddings";
6919
+ if (opts2.cloudToken) headers.Authorization = `Bearer ${opts2.cloudToken}`;
6920
+ if (opts2.cloudDeviceId) headers["X-Device-ID"] = opts2.cloudDeviceId;
6921
+ } else {
6922
+ url = opts2.gateway ? `https://gateway.ai.cloudflare.com/v1/${opts2.accountId}/${opts2.gateway.id}/workers-ai/${model}` : `https://api.cloudflare.com/client/v4/accounts/${opts2.accountId}/ai/run/${model}`;
6923
+ headers.Authorization = `Bearer ${opts2.apiToken}`;
6924
+ if (opts2.gateway?.metadata) {
6925
+ for (const [k, v] of Object.entries(opts2.gateway.metadata)) {
6926
+ headers[`cf-aig-metadata-${k}`] = String(v);
6927
+ }
6872
6928
  }
6873
6929
  }
6874
6930
  const results = [];
6875
6931
  for (const text of opts2.texts) {
6876
6932
  const truncated = truncateForEmbedding(text);
6877
- const body = JSON.stringify({ text: [truncated] });
6933
+ const body = opts2.cloudMode ? JSON.stringify({ model, texts: [truncated] }) : JSON.stringify({ text: [truncated] });
6878
6934
  const res = await fetchWithRetry(url, { method: "POST", headers, body });
6879
6935
  const json = await res.json();
6880
6936
  let vectors = [];
@@ -6932,6 +6988,7 @@ var init_embeddings = __esm({
6932
6988
  "src/memory/embeddings.ts"() {
6933
6989
  "use strict";
6934
6990
  init_version();
6991
+ init_errors();
6935
6992
  DEFAULT_MODEL2 = "@cf/baai/bge-base-en-v1.5";
6936
6993
  MAX_EMBED_CHARS = 2e3;
6937
6994
  }
@@ -6949,8 +7006,8 @@ function computeExactScore(memory, queryText, cwd) {
6949
7006
  let score = 0;
6950
7007
  const lowerQuery = queryText.toLowerCase();
6951
7008
  for (const file of memory.relatedFiles) {
6952
- const basename5 = file.split("/").pop() ?? file;
6953
- if (lowerQuery.includes(basename5.toLowerCase()) || basename5.toLowerCase().includes(lowerQuery)) {
7009
+ const basename6 = file.split("/").pop() ?? file;
7010
+ if (lowerQuery.includes(basename6.toLowerCase()) || basename6.toLowerCase().includes(lowerQuery)) {
6954
7011
  score += 0.3;
6955
7012
  }
6956
7013
  if (cwd && file.startsWith(cwd)) {
@@ -8873,7 +8930,7 @@ async function createAgentSession(opts2) {
8873
8930
  const tools = opts2.tools ?? ALL_TOOLS;
8874
8931
  const executor = new ToolExecutor(tools);
8875
8932
  let memoryManager = null;
8876
- const memoryEnabled = opts2.memoryEnabled ?? config.memoryEnabled ?? true;
8933
+ const memoryEnabled = opts2.memoryEnabled ?? config.memoryEnabled ?? false;
8877
8934
  if (memoryEnabled) {
8878
8935
  const dbPath = config.memoryDbPath ?? join19(homedir12(), ".local", "share", "kimiflare", "memory.db");
8879
8936
  memoryManager = new MemoryManager({
@@ -9062,8 +9119,8 @@ var init_session = __esm({
9062
9119
  const parts = [{ type: "text", text }];
9063
9120
  for (const img of options.images) {
9064
9121
  if ("path" in img) {
9065
- const { readFile: readFile20 } = await import("fs/promises");
9066
- const data = await readFile20(img.path, "base64");
9122
+ const { readFile: readFile21 } = await import("fs/promises");
9123
+ const data = await readFile21(img.path, "base64");
9067
9124
  const mimeType = img.path.endsWith(".png") ? "image/png" : img.path.endsWith(".jpg") || img.path.endsWith(".jpeg") ? "image/jpeg" : "image/webp";
9068
9125
  parts.push({ type: "image_url", image_url: { url: `data:${mimeType};base64,${data}` } });
9069
9126
  } else {
@@ -9307,7 +9364,7 @@ var init_session = __esm({
9307
9364
  this.lspManager?.notifyChange(path, content);
9308
9365
  } else {
9309
9366
  void import("fs/promises").then(
9310
- ({ readFile: readFile20 }) => readFile20(path, "utf8").then((c) => this.lspManager?.notifyChange(path, c)).catch(() => {
9367
+ ({ readFile: readFile21 }) => readFile21(path, "utf8").then((c) => this.lspManager?.notifyChange(path, c)).catch(() => {
9311
9368
  })
9312
9369
  ).catch(() => {
9313
9370
  });
@@ -9862,6 +9919,7 @@ async function sendReport(payload, token) {
9862
9919
  headers,
9863
9920
  body: JSON.stringify(payload)
9864
9921
  });
9922
+ await detectKillSwitch(res);
9865
9923
  if (res.ok) {
9866
9924
  return { ok: true, message: "Report sent. Thanks for helping improve KimiFlare!" };
9867
9925
  }
@@ -9877,6 +9935,7 @@ var init_report2 = __esm({
9877
9935
  "src/cloud/report.ts"() {
9878
9936
  "use strict";
9879
9937
  init_version();
9938
+ init_errors();
9880
9939
  REPORT_URL = "https://api.kimiflare.com/v1/report";
9881
9940
  }
9882
9941
  });
@@ -10700,11 +10759,45 @@ var init_api_error_message = __esm({
10700
10759
  }
10701
10760
  });
10702
10761
 
10762
+ // src/ui/service-ended-message.tsx
10763
+ import { Box as Box6, Text as Text6 } from "ink";
10764
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
10765
+ function ServiceEndedMessage({ endedAt }) {
10766
+ const theme = useTheme();
10767
+ return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", marginY: 1, children: [
10768
+ /* @__PURE__ */ jsx7(Text6, { bold: true, color: theme.accent, children: "KimiFlare Cloud has reached its maximum budget across all users." }),
10769
+ /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", marginTop: 1, children: [
10770
+ /* @__PURE__ */ jsxs6(Text6, { color: theme.info.color, children: [
10771
+ "The free credits period has ended",
10772
+ endedAt ? ` at ${new Date(endedAt).toLocaleString()}` : "",
10773
+ "."
10774
+ ] }),
10775
+ /* @__PURE__ */ jsx7(Text6, { color: theme.info.color, children: "Thank you for using KimiFlare!" })
10776
+ ] }),
10777
+ /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", marginTop: 1, children: [
10778
+ /* @__PURE__ */ jsx7(Text6, { bold: true, children: "To continue using KimiFlare, switch to Bring Your Own Key mode:" }),
10779
+ /* @__PURE__ */ jsxs6(Box6, { paddingLeft: 2, flexDirection: "column", children: [
10780
+ /* @__PURE__ */ jsx7(Text6, { color: theme.info.color, children: "\u2192 Set API token: kimiflare config set-key <your-key>" }),
10781
+ /* @__PURE__ */ jsx7(Text6, { color: theme.info.color, children: "\u2192 Set account ID: kimiflare config set-account <your-account-id>" }),
10782
+ /* @__PURE__ */ jsx7(Text6, { color: theme.info.color, children: "\u2192 Get a token: https://dash.cloudflare.com/profile/api-tokens" }),
10783
+ /* @__PURE__ */ jsx7(Text6, { color: theme.info.color, children: '\u2192 Or re-run kimiflare and select "BYOK \u2014 bring your own Cloudflare key"' })
10784
+ ] })
10785
+ ] }),
10786
+ /* @__PURE__ */ jsx7(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx7(Text6, { color: theme.muted?.color ?? theme.info.color, dimColor: theme.muted?.dim ?? true, children: "You can no longer send messages or authenticate via KimiFlare Cloud." }) })
10787
+ ] });
10788
+ }
10789
+ var init_service_ended_message = __esm({
10790
+ "src/ui/service-ended-message.tsx"() {
10791
+ "use strict";
10792
+ init_theme_context();
10793
+ }
10794
+ });
10795
+
10703
10796
  // src/ui/chat.tsx
10704
10797
  import React4 from "react";
10705
- import { Box as Box6, Text as Text6 } from "ink";
10798
+ import { Box as Box7, Text as Text7 } from "ink";
10706
10799
  import Spinner2 from "ink-spinner";
10707
- import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
10800
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
10708
10801
  function toolSignature(name, args) {
10709
10802
  return `${name}:${args}`;
10710
10803
  }
@@ -10718,6 +10811,7 @@ var init_chat = __esm({
10718
10811
  init_narrator();
10719
10812
  init_cloud_quota_message();
10720
10813
  init_api_error_message();
10814
+ init_service_ended_message();
10721
10815
  ChatView = React4.memo(function ChatView2({ events, showReasoning, verbose, intentTier }) {
10722
10816
  const theme = useTheme();
10723
10817
  const toolCounts = /* @__PURE__ */ new Map();
@@ -10731,12 +10825,12 @@ var init_chat = __esm({
10731
10825
  for (const [sig, count] of toolCounts) {
10732
10826
  if (count >= 3) repeatedSigs.add(sig);
10733
10827
  }
10734
- return /* @__PURE__ */ jsx7(Box6, { flexDirection: "column", children: events.map((e, i) => {
10828
+ return /* @__PURE__ */ jsx8(Box7, { flexDirection: "column", children: events.map((e, i) => {
10735
10829
  const prev = events[i - 1];
10736
10830
  const showSeparator = !!(e.kind === "user" && prev && (prev.kind === "assistant" || prev.kind === "tool"));
10737
- return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
10738
- showSeparator && /* @__PURE__ */ jsx7(Box6, { marginY: 1, children: /* @__PURE__ */ jsx7(Text6, { color: theme.info.color, children: "\u2500".repeat(40) }) }),
10739
- /* @__PURE__ */ jsx7(EventView, { evt: e, showReasoning, verbose, repeatedSigs, intentTier })
10831
+ return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
10832
+ showSeparator && /* @__PURE__ */ jsx8(Box7, { marginY: 1, children: /* @__PURE__ */ jsx8(Text7, { color: theme.info.color, children: "\u2500".repeat(40) }) }),
10833
+ /* @__PURE__ */ jsx8(EventView, { evt: e, showReasoning, verbose, repeatedSigs, intentTier })
10740
10834
  ] }, e.key);
10741
10835
  }) });
10742
10836
  });
@@ -10751,61 +10845,61 @@ var init_chat = __esm({
10751
10845
  if (evt.kind === "user") {
10752
10846
  if (evt.queued) {
10753
10847
  const mutedColor = theme.muted?.color ?? theme.info.color;
10754
- return /* @__PURE__ */ jsx7(Box6, { flexDirection: "column", children: /* @__PURE__ */ jsxs6(Box6, { children: [
10755
- /* @__PURE__ */ jsxs6(Text6, { italic: true, color: mutedColor, children: [
10848
+ return /* @__PURE__ */ jsx8(Box7, { flexDirection: "column", children: /* @__PURE__ */ jsxs7(Box7, { children: [
10849
+ /* @__PURE__ */ jsxs7(Text7, { italic: true, color: mutedColor, children: [
10756
10850
  "\xB7\xB7\xB7",
10757
10851
  " "
10758
10852
  ] }),
10759
- /* @__PURE__ */ jsx7(Text6, { italic: true, color: mutedColor, children: evt.text }),
10760
- /* @__PURE__ */ jsxs6(Text6, { italic: true, color: mutedColor, children: [
10853
+ /* @__PURE__ */ jsx8(Text7, { italic: true, color: mutedColor, children: evt.text }),
10854
+ /* @__PURE__ */ jsxs7(Text7, { italic: true, color: mutedColor, children: [
10761
10855
  " ",
10762
10856
  "(queued)"
10763
10857
  ] })
10764
10858
  ] }) });
10765
10859
  }
10766
- return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
10767
- /* @__PURE__ */ jsxs6(Box6, { children: [
10768
- /* @__PURE__ */ jsxs6(Text6, { bold: true, color: theme.user, children: [
10860
+ return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
10861
+ /* @__PURE__ */ jsxs7(Box7, { children: [
10862
+ /* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.user, children: [
10769
10863
  "\u203A",
10770
10864
  " "
10771
10865
  ] }),
10772
- /* @__PURE__ */ jsx7(Text6, { bold: true, children: evt.text })
10866
+ /* @__PURE__ */ jsx8(Text7, { bold: true, children: evt.text })
10773
10867
  ] }),
10774
- evt.images && evt.images.length > 0 && /* @__PURE__ */ jsx7(Box6, { paddingLeft: 2, children: /* @__PURE__ */ jsxs6(Text6, { color: theme.info.color, children: [
10868
+ evt.images && evt.images.length > 0 && /* @__PURE__ */ jsx8(Box7, { paddingLeft: 2, children: /* @__PURE__ */ jsxs7(Text7, { color: theme.info.color, children: [
10775
10869
  "\u{1F5BC}\uFE0F ",
10776
10870
  evt.images.join(", ")
10777
10871
  ] }) })
10778
10872
  ] });
10779
10873
  }
10780
10874
  if (evt.kind === "assistant") {
10781
- return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", paddingLeft: 2, children: [
10782
- showReasoning && evt.reasoning ? /* @__PURE__ */ jsx7(Box6, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs6(Text6, { color: theme.reasoning.color, children: [
10875
+ return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", paddingLeft: 2, children: [
10876
+ showReasoning && evt.reasoning ? /* @__PURE__ */ jsx8(Box7, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs7(Text7, { color: theme.reasoning.color, children: [
10783
10877
  "thinking\u2026",
10784
10878
  " ",
10785
10879
  evt.reasoning.length > 400 ? evt.reasoning.slice(0, 400) + "\u2026" : evt.reasoning
10786
10880
  ] }) }) : null,
10787
- evt.text ? /* @__PURE__ */ jsx7(MD, { text: evt.text }) : null,
10788
- evt.streaming && /* @__PURE__ */ jsx7(Text6, { color: theme.spinner, children: /* @__PURE__ */ jsx7(Spinner2, { type: "dots" }) })
10881
+ evt.text ? /* @__PURE__ */ jsx8(MD, { text: evt.text }) : null,
10882
+ evt.streaming && /* @__PURE__ */ jsx8(Text7, { color: theme.spinner, children: /* @__PURE__ */ jsx8(Spinner2, { type: "dots" }) })
10789
10883
  ] });
10790
10884
  }
10791
10885
  if (evt.kind === "tool") {
10792
10886
  const isRepeated = repeatedSigs?.has(toolSignature(evt.name, evt.args)) ?? false;
10793
- return /* @__PURE__ */ jsx7(ToolView, { evt, verbose, isRepeated, intentTier });
10887
+ return /* @__PURE__ */ jsx8(ToolView, { evt, verbose, isRepeated, intentTier });
10794
10888
  }
10795
10889
  if (evt.kind === "info") {
10796
- return /* @__PURE__ */ jsxs6(Text6, { color: theme.info.color, children: [
10890
+ return /* @__PURE__ */ jsxs7(Text7, { color: theme.info.color, children: [
10797
10891
  "\xB7 ",
10798
10892
  humanizeInfo(evt.text, intentTier)
10799
10893
  ] });
10800
10894
  }
10801
10895
  if (evt.kind === "memory") {
10802
- return /* @__PURE__ */ jsxs6(Text6, { color: theme.info.color, children: [
10896
+ return /* @__PURE__ */ jsxs7(Text7, { color: theme.info.color, children: [
10803
10897
  "\u25C8 ",
10804
10898
  humanizeMemory(evt.text, intentTier)
10805
10899
  ] });
10806
10900
  }
10807
10901
  if (evt.kind === "cloud_quota_exhausted") {
10808
- return /* @__PURE__ */ jsx7(
10902
+ return /* @__PURE__ */ jsx8(
10809
10903
  CloudQuotaMessage,
10810
10904
  {
10811
10905
  used: evt.used,
@@ -10824,10 +10918,10 @@ var init_chat = __esm({
10824
10918
  }
10825
10919
  const metaText = humanizeMeta(metaParts, intentTier ?? evt.intentTier);
10826
10920
  if (!metaText) return null;
10827
- return /* @__PURE__ */ jsx7(Text6, { color: theme.info.color, dimColor: true, children: metaText });
10921
+ return /* @__PURE__ */ jsx8(Text7, { color: theme.info.color, dimColor: true, children: metaText });
10828
10922
  }
10829
10923
  if (evt.kind === "api_error") {
10830
- return /* @__PURE__ */ jsx7(
10924
+ return /* @__PURE__ */ jsx8(
10831
10925
  ApiErrorMessage,
10832
10926
  {
10833
10927
  httpStatus: evt.httpStatus,
@@ -10836,7 +10930,10 @@ var init_chat = __esm({
10836
10930
  }
10837
10931
  );
10838
10932
  }
10839
- return /* @__PURE__ */ jsxs6(Text6, { color: theme.error, children: [
10933
+ if (evt.kind === "service_ended") {
10934
+ return /* @__PURE__ */ jsx8(ServiceEndedMessage, { endedAt: evt.endedAt });
10935
+ }
10936
+ return /* @__PURE__ */ jsxs7(Text7, { color: theme.error, children: [
10840
10937
  "! ",
10841
10938
  evt.text
10842
10939
  ] });
@@ -10846,9 +10943,9 @@ var init_chat = __esm({
10846
10943
 
10847
10944
  // src/ui/status.tsx
10848
10945
  import { useEffect as useEffect2, useState as useState2 } from "react";
10849
- import { Box as Box7, Text as Text7 } from "ink";
10946
+ import { Box as Box8, Text as Text8 } from "ink";
10850
10947
  import Spinner3 from "ink-spinner";
10851
- import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
10948
+ import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
10852
10949
  function StatusBar({ usage, sessionUsage, thinking, turnStartedAt, mode, contextLimit, gatewayMeta, codeMode, cloudMode, cloudBudget, skillsActive, memoryRecalled, phase, currentTool, lastActivityAt, kimiMdStale, gitBranch, intentTier }) {
10853
10950
  const theme = useTheme();
10854
10951
  const [now2, setNow] = useState2(Date.now());
@@ -10876,32 +10973,32 @@ function StatusBar({ usage, sessionUsage, thinking, turnStartedAt, mode, context
10876
10973
  const idleLabel = idleMs > 3e4 ? ` (idle ${formatElapsed2(Math.floor(idleMs / 1e3))})` : "";
10877
10974
  const thinkingText = metaParts.length > 0 ? `${phaseLabel}${elapsed ? ` \xB7 ${elapsed}` : ""}${idleLabel} \xB7 ${metaParts.join(" \xB7 ")}` : `${phaseLabel}${elapsed ? ` \xB7 ${elapsed}` : ""}${idleLabel}`;
10878
10975
  const readyText = idleParts.length > 0 ? `${idleParts.join(" \xB7 ")} \xB7 ready` : "ready";
10879
- return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
10880
- /* @__PURE__ */ jsxs7(Box7, { children: [
10881
- /* @__PURE__ */ jsxs7(Text7, { color: modeColor, bold: true, children: [
10976
+ return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
10977
+ /* @__PURE__ */ jsxs8(Box8, { children: [
10978
+ /* @__PURE__ */ jsxs8(Text8, { color: modeColor, bold: true, children: [
10882
10979
  "[",
10883
10980
  mode,
10884
10981
  "]"
10885
10982
  ] }),
10886
- /* @__PURE__ */ jsx8(Text7, { children: " " }),
10887
- thinking ? /* @__PURE__ */ jsxs7(Text7, { color: theme.spinner, children: [
10888
- /* @__PURE__ */ jsx8(Spinner3, { type: "dots2" }),
10983
+ /* @__PURE__ */ jsx9(Text8, { children: " " }),
10984
+ thinking ? /* @__PURE__ */ jsxs8(Text8, { color: theme.spinner, children: [
10985
+ /* @__PURE__ */ jsx9(Spinner3, { type: "dots2" }),
10889
10986
  " ",
10890
10987
  thinkingText
10891
- ] }) : /* @__PURE__ */ jsx8(Text7, { color: theme.info.color, children: readyText })
10988
+ ] }) : /* @__PURE__ */ jsx9(Text8, { color: theme.info.color, children: readyText })
10892
10989
  ] }),
10893
- usage && /* @__PURE__ */ jsxs7(Box7, { children: [
10894
- /* @__PURE__ */ jsx8(Text7, { color: theme.info.color, children: buildRightParts(usage, contextLimit, sessionUsage, gatewayMeta, cloudMode, cloudBudget).join(" \xB7 ") }),
10895
- warn ? /* @__PURE__ */ jsxs7(Text7, { color: theme.warn, bold: true, children: [
10990
+ usage && /* @__PURE__ */ jsxs8(Box8, { children: [
10991
+ /* @__PURE__ */ jsx9(Text8, { color: theme.info.color, children: buildRightParts(usage, contextLimit, sessionUsage, gatewayMeta, cloudMode, cloudBudget).join(" \xB7 ") }),
10992
+ warn ? /* @__PURE__ */ jsxs8(Text8, { color: theme.warn, bold: true, children: [
10896
10993
  " \xB7 ",
10897
10994
  "/compact recommended"
10898
10995
  ] }) : null,
10899
- kimiMdStale ? /* @__PURE__ */ jsxs7(Text7, { color: theme.warn, bold: true, children: [
10996
+ kimiMdStale ? /* @__PURE__ */ jsxs8(Text8, { color: theme.warn, bold: true, children: [
10900
10997
  " \xB7 ",
10901
10998
  "\u26A0 KIMI.md stale \xB7 run /init"
10902
10999
  ] }) : null
10903
11000
  ] }),
10904
- !thinking && /* @__PURE__ */ jsx8(Box7, { children: /* @__PURE__ */ jsx8(Text7, { color: theme.muted?.color ?? theme.info.color, dimColor: theme.muted?.dim, children: "tip: shift+tab cycles mode" }) })
11001
+ !thinking && /* @__PURE__ */ jsx9(Box8, { children: /* @__PURE__ */ jsx9(Text8, { color: theme.muted?.color ?? theme.info.color, dimColor: theme.muted?.dim, children: "tip: shift+tab cycles mode" }) })
10905
11002
  ] });
10906
11003
  }
10907
11004
  function buildRightParts(usage, contextLimit, sessionUsage, gatewayMeta, cloudMode, cloudBudget) {
@@ -11482,8 +11579,8 @@ var init_source = __esm({
11482
11579
 
11483
11580
  // src/ui/text-input.tsx
11484
11581
  import { useState as useState3, useEffect as useEffect3, useRef } from "react";
11485
- import { Text as Text8, useInput } from "ink";
11486
- import { jsx as jsx9 } from "react/jsx-runtime";
11582
+ import { Text as Text9, useInput } from "ink";
11583
+ import { jsx as jsx10 } from "react/jsx-runtime";
11487
11584
  function shouldTreatAsPaste(input) {
11488
11585
  if (input.length >= PASTE_CHAR_THRESHOLD) return true;
11489
11586
  const newlines = (input.match(/\n/g) ?? []).length;
@@ -11704,7 +11801,7 @@ function CustomTextInput({
11704
11801
  } else if (cursorOffset === displayValue.length) {
11705
11802
  renderedValue += source_default.inverse(" ");
11706
11803
  }
11707
- return /* @__PURE__ */ jsx9(Text8, { children: renderedValue });
11804
+ return /* @__PURE__ */ jsx10(Text9, { children: renderedValue });
11708
11805
  }
11709
11806
  function findPasteTokenEndingAt(value, pos, pastes) {
11710
11807
  if (pos <= 0 || value[pos - 1] !== "\u2998") return -1;
@@ -11727,9 +11824,9 @@ var init_text_input = __esm({
11727
11824
 
11728
11825
  // src/ui/permission.tsx
11729
11826
  import { useState as useState4, useCallback } from "react";
11730
- import { Box as Box8, Text as Text9, useInput as useInput2 } from "ink";
11827
+ import { Box as Box9, Text as Text10, useInput as useInput2 } from "ink";
11731
11828
  import { platform as platform3 } from "os";
11732
- import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
11829
+ import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
11733
11830
  function formatSelection(label, shortcut) {
11734
11831
  return `${label} [${MOD_KEY}+${shortcut}]`;
11735
11832
  }
@@ -11817,10 +11914,10 @@ function PermissionModal({ tool, args, onDecide, onFeedback }) {
11817
11914
  { isActive: !feedbackActive }
11818
11915
  );
11819
11916
  if (showHelp) {
11820
- return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", borderStyle: "round", borderColor: theme.permission, paddingX: 1, children: [
11821
- /* @__PURE__ */ jsx10(Text9, { color: theme.permission, bold: true, children: "Permission modal \u2014 keyboard shortcuts" }),
11822
- /* @__PURE__ */ jsx10(Text9, { color: theme.info.color, children: "\u2191 / \u2193 or j / k \u2014 navigate options" }),
11823
- /* @__PURE__ */ jsxs8(Text9, { color: theme.info.color, children: [
11917
+ return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", borderStyle: "round", borderColor: theme.permission, paddingX: 1, children: [
11918
+ /* @__PURE__ */ jsx11(Text10, { color: theme.permission, bold: true, children: "Permission modal \u2014 keyboard shortcuts" }),
11919
+ /* @__PURE__ */ jsx11(Text10, { color: theme.info.color, children: "\u2191 / \u2193 or j / k \u2014 navigate options" }),
11920
+ /* @__PURE__ */ jsxs9(Text10, { color: theme.info.color, children: [
11824
11921
  MOD_KEY,
11825
11922
  "+1 / ",
11826
11923
  MOD_KEY,
@@ -11828,31 +11925,31 @@ function PermissionModal({ tool, args, onDecide, onFeedback }) {
11828
11925
  MOD_KEY,
11829
11926
  "+3 \u2014 select option directly"
11830
11927
  ] }),
11831
- /* @__PURE__ */ jsx10(Text9, { color: theme.info.color, children: "Enter \u2014 confirm selection" }),
11832
- /* @__PURE__ */ jsx10(Text9, { color: theme.info.color, children: "Esc \u2014 deny and close" }),
11833
- /* @__PURE__ */ jsx10(Text9, { color: theme.info.color, children: "? \u2014 toggle this help" }),
11834
- /* @__PURE__ */ jsx10(Text9, { color: theme.info.color, children: "When feedback input is open:" }),
11835
- /* @__PURE__ */ jsx10(Text9, { color: theme.info.color, children: " Enter \u2014 submit feedback and deny" }),
11836
- /* @__PURE__ */ jsx10(Text9, { color: theme.info.color, children: " Esc \u2014 deny without feedback" }),
11837
- /* @__PURE__ */ jsx10(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx10(Text9, { color: theme.accent, children: "Press any key to close" }) })
11928
+ /* @__PURE__ */ jsx11(Text10, { color: theme.info.color, children: "Enter \u2014 confirm selection" }),
11929
+ /* @__PURE__ */ jsx11(Text10, { color: theme.info.color, children: "Esc \u2014 deny and close" }),
11930
+ /* @__PURE__ */ jsx11(Text10, { color: theme.info.color, children: "? \u2014 toggle this help" }),
11931
+ /* @__PURE__ */ jsx11(Text10, { color: theme.info.color, children: "When feedback input is open:" }),
11932
+ /* @__PURE__ */ jsx11(Text10, { color: theme.info.color, children: " Enter \u2014 submit feedback and deny" }),
11933
+ /* @__PURE__ */ jsx11(Text10, { color: theme.info.color, children: " Esc \u2014 deny without feedback" }),
11934
+ /* @__PURE__ */ jsx11(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text10, { color: theme.accent, children: "Press any key to close" }) })
11838
11935
  ] });
11839
11936
  }
11840
- return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", borderStyle: "round", borderColor: theme.permission, paddingX: 1, children: [
11841
- /* @__PURE__ */ jsx10(Text9, { color: theme.permission, bold: true, children: "Permission requested" }),
11842
- /* @__PURE__ */ jsxs8(Text9, { children: [
11937
+ return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", borderStyle: "round", borderColor: theme.permission, paddingX: 1, children: [
11938
+ /* @__PURE__ */ jsx11(Text10, { color: theme.permission, bold: true, children: "Permission requested" }),
11939
+ /* @__PURE__ */ jsxs9(Text10, { children: [
11843
11940
  "tool: ",
11844
- /* @__PURE__ */ jsx10(Text9, { color: theme.tool, children: tool.name })
11941
+ /* @__PURE__ */ jsx11(Text10, { color: theme.tool, children: tool.name })
11845
11942
  ] }),
11846
- render2?.title ? /* @__PURE__ */ jsxs8(Text9, { children: [
11943
+ render2?.title ? /* @__PURE__ */ jsxs9(Text10, { children: [
11847
11944
  "action: ",
11848
11945
  render2.title
11849
11946
  ] }) : null,
11850
- render2?.diff ? /* @__PURE__ */ jsx10(Box8, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx10(DiffView, { ...render2.diff }) }) : /* @__PURE__ */ jsxs8(Text9, { color: theme.info.color, children: [
11947
+ render2?.diff ? /* @__PURE__ */ jsx11(Box9, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx11(DiffView, { ...render2.diff }) }) : /* @__PURE__ */ jsxs9(Text10, { color: theme.info.color, children: [
11851
11948
  "args: ",
11852
11949
  JSON.stringify(args)
11853
11950
  ] }),
11854
- /* @__PURE__ */ jsx10(Box8, { marginTop: 1, flexDirection: "column", children: OPTIONS.map((opt, i) => /* @__PURE__ */ jsxs8(
11855
- Text9,
11951
+ /* @__PURE__ */ jsx11(Box9, { marginTop: 1, flexDirection: "column", children: OPTIONS.map((opt, i) => /* @__PURE__ */ jsxs9(
11952
+ Text10,
11856
11953
  {
11857
11954
  color: i === selectedIndex ? theme.accent : void 0,
11858
11955
  bold: i === selectedIndex,
@@ -11863,10 +11960,10 @@ function PermissionModal({ tool, args, onDecide, onFeedback }) {
11863
11960
  },
11864
11961
  opt.value
11865
11962
  )) }),
11866
- feedbackActive && /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexDirection: "column", children: [
11867
- /* @__PURE__ */ jsx10(Text9, { color: theme.palette.error, children: "Tell me what to do instead" }),
11868
- /* @__PURE__ */ jsx10(Text9, { color: theme.info.color, dimColor: true, children: "Press Esc to deny without feedback" }),
11869
- /* @__PURE__ */ jsx10(
11963
+ feedbackActive && /* @__PURE__ */ jsxs9(Box9, { marginTop: 1, flexDirection: "column", children: [
11964
+ /* @__PURE__ */ jsx11(Text10, { color: theme.palette.error, children: "Tell me what to do instead" }),
11965
+ /* @__PURE__ */ jsx11(Text10, { color: theme.info.color, dimColor: true, children: "Press Esc to deny without feedback" }),
11966
+ /* @__PURE__ */ jsx11(
11870
11967
  CustomTextInput,
11871
11968
  {
11872
11969
  value: feedbackValue,
@@ -11896,27 +11993,19 @@ var init_permission = __esm({
11896
11993
  });
11897
11994
 
11898
11995
  // src/ui/limit-modal.tsx
11899
- import { Box as Box9, Text as Text10 } from "ink";
11996
+ import { Box as Box10, Text as Text11 } from "ink";
11900
11997
  import SelectInput from "ink-select-input";
11901
- import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
11902
- function LimitModal({ limit, onDecide }) {
11998
+ import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
11999
+ function LimitModal({ limit, onDecide, title, description }) {
11903
12000
  const theme = useTheme();
11904
12001
  const items = [
11905
12002
  { label: "Continue", value: "continue" },
11906
12003
  { label: "Stop", value: "stop" }
11907
12004
  ];
11908
- return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", borderStyle: "round", borderColor: theme.error, paddingX: 1, children: [
11909
- /* @__PURE__ */ jsxs9(Text10, { color: theme.error, bold: true, children: [
11910
- "Tool-call limit reached (",
11911
- limit,
11912
- ")"
11913
- ] }),
11914
- /* @__PURE__ */ jsxs9(Text10, { dimColor: true, children: [
11915
- "This session has made ",
11916
- limit,
11917
- " tool calls. What would you like to do?"
11918
- ] }),
11919
- /* @__PURE__ */ jsx11(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx11(
12005
+ return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", borderStyle: "round", borderColor: theme.error, paddingX: 1, children: [
12006
+ /* @__PURE__ */ jsx12(Text11, { color: theme.error, bold: true, children: title ?? `Tool-call limit reached (${limit})` }),
12007
+ /* @__PURE__ */ jsx12(Text11, { dimColor: true, children: description ?? `This session has made ${limit} tool calls. What would you like to do?` }),
12008
+ /* @__PURE__ */ jsx12(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx12(
11920
12009
  SelectInput,
11921
12010
  {
11922
12011
  items,
@@ -12003,9 +12092,9 @@ var init_fuzzy = __esm({
12003
12092
 
12004
12093
  // src/ui/resume-picker.tsx
12005
12094
  import { useState as useState5 } from "react";
12006
- import { Box as Box10, Text as Text11, useInput as useInput3 } from "ink";
12095
+ import { Box as Box11, Text as Text12, useInput as useInput3 } from "ink";
12007
12096
  import SelectInput2 from "ink-select-input";
12008
- import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
12097
+ import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
12009
12098
  function ResumePicker({ sessions, onPick }) {
12010
12099
  const theme = useTheme();
12011
12100
  const [page, setPage] = useState5(0);
@@ -12046,10 +12135,10 @@ function ResumePicker({ sessions, onPick }) {
12046
12135
  }
12047
12136
  });
12048
12137
  if (sessions.length === 0) {
12049
- return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
12050
- /* @__PURE__ */ jsx12(Text11, { color: theme.accent, bold: true, children: "Resume a session" }),
12051
- /* @__PURE__ */ jsx12(Text11, { color: theme.info.color, children: "No saved sessions yet. Press Enter to dismiss." }),
12052
- /* @__PURE__ */ jsx12(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx12(
12138
+ return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
12139
+ /* @__PURE__ */ jsx13(Text12, { color: theme.accent, bold: true, children: "Resume a session" }),
12140
+ /* @__PURE__ */ jsx13(Text12, { color: theme.info.color, children: "No saved sessions yet. Press Enter to dismiss." }),
12141
+ /* @__PURE__ */ jsx13(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx13(
12053
12142
  SelectInput2,
12054
12143
  {
12055
12144
  items: [{ label: "(back)", value: "__cancel__" }],
@@ -12062,9 +12151,9 @@ function ResumePicker({ sessions, onPick }) {
12062
12151
  label: `${formatDate(s.updatedAt)} \xB7 ${s.messageCount} msgs \xB7 ${s.title ?? s.firstPrompt}`,
12063
12152
  value: s.id
12064
12153
  }));
12065
- return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
12066
- /* @__PURE__ */ jsx12(Text11, { color: theme.accent, bold: true, children: "Resume a session" }),
12067
- /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
12154
+ return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
12155
+ /* @__PURE__ */ jsx13(Text12, { color: theme.accent, bold: true, children: "Resume a session" }),
12156
+ /* @__PURE__ */ jsxs11(Text12, { color: theme.info.color, children: [
12068
12157
  query ? `Search: ${query}\u258C` : "Type to search\u2026",
12069
12158
  " \xB7 Page ",
12070
12159
  safePage + 1,
@@ -12074,7 +12163,7 @@ function ResumePicker({ sessions, onPick }) {
12074
12163
  filtered.length,
12075
12164
  " total)"
12076
12165
  ] }),
12077
- /* @__PURE__ */ jsx12(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx12(
12166
+ /* @__PURE__ */ jsx13(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx13(
12078
12167
  SelectInput2,
12079
12168
  {
12080
12169
  items,
@@ -12089,7 +12178,7 @@ function ResumePicker({ sessions, onPick }) {
12089
12178
  }
12090
12179
  }
12091
12180
  ) }),
12092
- /* @__PURE__ */ jsx12(Box10, { marginTop: 1, children: /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
12181
+ /* @__PURE__ */ jsx13(Box11, { marginTop: 1, children: /* @__PURE__ */ jsxs11(Text12, { color: theme.info.color, children: [
12093
12182
  safePage > 0 ? "\u2190 prev " : "",
12094
12183
  safePage < totalPages - 1 ? "\u2192 next " : "",
12095
12184
  "q: cancel"
@@ -12121,9 +12210,9 @@ var init_resume_picker = __esm({
12121
12210
 
12122
12211
  // src/ui/checkpoint-picker.tsx
12123
12212
  import { useState as useState6 } from "react";
12124
- import { Box as Box11, Text as Text12, useInput as useInput4 } from "ink";
12213
+ import { Box as Box12, Text as Text13, useInput as useInput4 } from "ink";
12125
12214
  import SelectInput3 from "ink-select-input";
12126
- import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
12215
+ import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
12127
12216
  function CheckpointPicker({ session, checkpoints, onPick }) {
12128
12217
  const theme = useTheme();
12129
12218
  const [selectedIndex, setSelectedIndex] = useState6(0);
@@ -12143,16 +12232,16 @@ function CheckpointPicker({ session, checkpoints, onPick }) {
12143
12232
  value: cp.id
12144
12233
  }))
12145
12234
  ];
12146
- return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
12147
- /* @__PURE__ */ jsx13(Text12, { color: theme.accent, bold: true, children: session.firstPrompt.slice(0, 50) }),
12148
- /* @__PURE__ */ jsxs11(Text12, { color: theme.info.color, children: [
12235
+ return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
12236
+ /* @__PURE__ */ jsx14(Text13, { color: theme.accent, bold: true, children: session.firstPrompt.slice(0, 50) }),
12237
+ /* @__PURE__ */ jsxs12(Text13, { color: theme.info.color, children: [
12149
12238
  session.messageCount,
12150
12239
  " turns \xB7 ",
12151
12240
  checkpoints.length,
12152
12241
  " checkpoint",
12153
12242
  checkpoints.length === 1 ? "" : "s"
12154
12243
  ] }),
12155
- /* @__PURE__ */ jsx13(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx13(
12244
+ /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(
12156
12245
  SelectInput3,
12157
12246
  {
12158
12247
  items,
@@ -12170,7 +12259,7 @@ function CheckpointPicker({ session, checkpoints, onPick }) {
12170
12259
  }
12171
12260
  }
12172
12261
  ) }),
12173
- /* @__PURE__ */ jsx13(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx13(Text12, { color: theme.info.color, children: "q: cancel / go back" }) })
12262
+ /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, children: "q: cancel / go back" }) })
12174
12263
  ] });
12175
12264
  }
12176
12265
  function formatDate2(iso) {
@@ -12195,9 +12284,9 @@ var init_checkpoint_picker = __esm({
12195
12284
 
12196
12285
  // src/ui/task-list.tsx
12197
12286
  import { useEffect as useEffect4, useRef as useRef2, useState as useState7 } from "react";
12198
- import { Box as Box12, Text as Text13 } from "ink";
12287
+ import { Box as Box13, Text as Text14 } from "ink";
12199
12288
  import Spinner4 from "ink-spinner";
12200
- import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
12289
+ import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
12201
12290
  function TaskList({ tasks, startedAt, tokensDelta }) {
12202
12291
  const theme = useTheme();
12203
12292
  const [now2, setNow] = useState7(Date.now());
@@ -12235,18 +12324,18 @@ function TaskList({ tasks, startedAt, tokensDelta }) {
12235
12324
  const headerStats = [elapsed, tokensDelta > 0 ? `\u2191 ${formatTokens3(tokensDelta)} tokens` : null].filter(Boolean).join(" \xB7 ");
12236
12325
  const visibleTasks = tasks.slice(0, MAX_VISIBLE);
12237
12326
  const hiddenPending = Math.max(0, tasks.length - visibleTasks.length);
12238
- return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", marginBottom: 1, children: [
12239
- /* @__PURE__ */ jsxs12(Box12, { children: [
12240
- /* @__PURE__ */ jsx14(Text13, { color: celebrating ? theme.palette.success : allDone ? "green" : theme.accent, bold: true, children: celebrating ? `\u2728 ${header}` : header }),
12241
- headerStats && /* @__PURE__ */ jsxs12(Text13, { color: theme.info.color, children: [
12327
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", marginBottom: 1, children: [
12328
+ /* @__PURE__ */ jsxs13(Box13, { children: [
12329
+ /* @__PURE__ */ jsx15(Text14, { color: celebrating ? theme.palette.success : allDone ? "green" : theme.accent, bold: true, children: celebrating ? `\u2728 ${header}` : header }),
12330
+ headerStats && /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
12242
12331
  " ",
12243
12332
  "(",
12244
12333
  headerStats,
12245
12334
  ")"
12246
12335
  ] })
12247
12336
  ] }),
12248
- visibleTasks.map((t) => /* @__PURE__ */ jsx14(TaskRow, { task: t }, t.id)),
12249
- hiddenPending > 0 && /* @__PURE__ */ jsxs12(Text13, { color: theme.info.color, children: [
12337
+ visibleTasks.map((t) => /* @__PURE__ */ jsx15(TaskRow, { task: t }, t.id)),
12338
+ hiddenPending > 0 && /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
12250
12339
  " ",
12251
12340
  "\u2026 +",
12252
12341
  hiddenPending,
@@ -12257,21 +12346,21 @@ function TaskList({ tasks, startedAt, tokensDelta }) {
12257
12346
  function TaskRow({ task }) {
12258
12347
  const theme = useTheme();
12259
12348
  if (task.status === "completed") {
12260
- return /* @__PURE__ */ jsxs12(Text13, { color: theme.info.color, children: [
12349
+ return /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
12261
12350
  " ",
12262
12351
  "\u2713 ",
12263
- /* @__PURE__ */ jsx14(Text13, { strikethrough: true, children: task.title })
12352
+ /* @__PURE__ */ jsx15(Text14, { strikethrough: true, children: task.title })
12264
12353
  ] });
12265
12354
  }
12266
12355
  if (task.status === "in_progress") {
12267
- return /* @__PURE__ */ jsxs12(Text13, { color: theme.accent, bold: true, children: [
12356
+ return /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
12268
12357
  " ",
12269
- /* @__PURE__ */ jsx14(Spinner4, { type: "line" }),
12358
+ /* @__PURE__ */ jsx15(Spinner4, { type: "line" }),
12270
12359
  " ",
12271
12360
  task.title
12272
12361
  ] });
12273
12362
  }
12274
- return /* @__PURE__ */ jsxs12(Text13, { color: theme.info.color, children: [
12363
+ return /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
12275
12364
  " ",
12276
12365
  "\u2610 ",
12277
12366
  task.title
@@ -12299,12 +12388,12 @@ var init_task_list = __esm({
12299
12388
 
12300
12389
  // src/ui/onboarding.tsx
12301
12390
  import { useState as useState8, useEffect as useEffect5, useCallback as useCallback2 } from "react";
12302
- import { Box as Box13, Text as Text14, useInput as useInput5 } from "ink";
12391
+ import { Box as Box14, Text as Text15, useInput as useInput5 } from "ink";
12303
12392
  import SelectInput4 from "ink-select-input";
12304
12393
  import Spinner5 from "ink-spinner";
12305
12394
  import { exec } from "child_process";
12306
12395
  import { promisify as promisify2 } from "util";
12307
- import { Fragment, jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
12396
+ import { Fragment, jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
12308
12397
  function openBrowser(url) {
12309
12398
  const platform5 = process.platform;
12310
12399
  const cmd = platform5 === "darwin" ? `open "${url}"` : platform5 === "win32" ? `start "" "${url}"` : `xdg-open "${url}"`;
@@ -12360,7 +12449,16 @@ function Onboarding({ onDone, onCancel }) {
12360
12449
  }
12361
12450
  return;
12362
12451
  }
12363
- } catch {
12452
+ } catch (err) {
12453
+ if (isKillSwitchError(err)) {
12454
+ if (!cancelled) {
12455
+ setCloudAuth({
12456
+ phase: "error",
12457
+ message: "KimiFlare Cloud has reached its maximum budget across all users. The free credits period has ended. Switch to BYOK mode to continue using KimiFlare."
12458
+ });
12459
+ }
12460
+ return;
12461
+ }
12364
12462
  }
12365
12463
  await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
12366
12464
  }
@@ -12460,24 +12558,24 @@ function Onboarding({ onDone, onCancel }) {
12460
12558
  const byokSteps = ["accountId", "apiToken", "model", "confirm"];
12461
12559
  const stepIndex = step === "mode" ? 1 : step === "cloudAuth" ? 2 : byokSteps.indexOf(step) + 2;
12462
12560
  const totalSteps = mode === "cloud" ? 2 : byokSteps.length + 1;
12463
- return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", paddingY: 1, children: [
12464
- /* @__PURE__ */ jsxs13(Box13, { marginBottom: 1, children: [
12465
- /* @__PURE__ */ jsx15(Text14, { bold: true, color: theme.palette.primary, children: "kimiflare" }),
12466
- /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
12561
+ return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", paddingY: 1, children: [
12562
+ /* @__PURE__ */ jsxs14(Box14, { marginBottom: 1, children: [
12563
+ /* @__PURE__ */ jsx16(Text15, { bold: true, color: theme.palette.primary, children: "kimiflare" }),
12564
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
12467
12565
  " ",
12468
12566
  "Terminal coding agent"
12469
12567
  ] })
12470
12568
  ] }),
12471
- /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
12569
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
12472
12570
  "Step ",
12473
12571
  stepIndex,
12474
12572
  " of ",
12475
12573
  totalSteps
12476
12574
  ] }),
12477
- /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "column", children: [
12478
- step === "mode" && /* @__PURE__ */ jsxs13(Fragment, { children: [
12479
- /* @__PURE__ */ jsx15(Text14, { children: "How do you want to connect?" }),
12480
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
12575
+ /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, flexDirection: "column", children: [
12576
+ step === "mode" && /* @__PURE__ */ jsxs14(Fragment, { children: [
12577
+ /* @__PURE__ */ jsx16(Text15, { children: "How do you want to connect?" }),
12578
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
12481
12579
  SelectInput4,
12482
12580
  {
12483
12581
  items: [
@@ -12488,19 +12586,19 @@ function Onboarding({ onDone, onCancel }) {
12488
12586
  }
12489
12587
  ) })
12490
12588
  ] }),
12491
- step === "cloudAuth" && cloudAuth?.phase === "ready" && /* @__PURE__ */ jsxs13(Fragment, { children: [
12492
- /* @__PURE__ */ jsx15(Text14, { children: "Authenticating with Kimiflare Cloud..." }),
12493
- /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "column", children: [
12494
- /* @__PURE__ */ jsx15(Text14, { children: "1. Open this URL in your browser:" }),
12495
- /* @__PURE__ */ jsx15(Text14, { color: theme.palette.primary, children: cloudAuth.codes.authUrl })
12589
+ step === "cloudAuth" && cloudAuth?.phase === "ready" && /* @__PURE__ */ jsxs14(Fragment, { children: [
12590
+ /* @__PURE__ */ jsx16(Text15, { children: "Authenticating with Kimiflare Cloud..." }),
12591
+ /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, flexDirection: "column", children: [
12592
+ /* @__PURE__ */ jsx16(Text15, { children: "1. Open this URL in your browser:" }),
12593
+ /* @__PURE__ */ jsx16(Text15, { color: theme.palette.primary, children: cloudAuth.codes.authUrl })
12496
12594
  ] }),
12497
- /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, children: [
12498
- /* @__PURE__ */ jsx15(Text14, { children: "2. " }),
12499
- /* @__PURE__ */ jsx15(Text14, { bold: true, children: "[Press Enter to open browser]" })
12595
+ /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, children: [
12596
+ /* @__PURE__ */ jsx16(Text15, { children: "2. " }),
12597
+ /* @__PURE__ */ jsx16(Text15, { bold: true, children: "[Press Enter to open browser]" })
12500
12598
  ] }),
12501
- /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, children: [
12502
- /* @__PURE__ */ jsx15(Text14, { color: theme.palette.primary, children: "\u203A " }),
12503
- /* @__PURE__ */ jsx15(
12599
+ /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, children: [
12600
+ /* @__PURE__ */ jsx16(Text15, { color: theme.palette.primary, children: "\u203A " }),
12601
+ /* @__PURE__ */ jsx16(
12504
12602
  CustomTextInput,
12505
12603
  {
12506
12604
  value: "",
@@ -12511,28 +12609,28 @@ function Onboarding({ onDone, onCancel }) {
12511
12609
  )
12512
12610
  ] })
12513
12611
  ] }),
12514
- step === "cloudAuth" && cloudAuth?.phase === "polling" && /* @__PURE__ */ jsxs13(Fragment, { children: [
12515
- /* @__PURE__ */ jsxs13(Text14, { children: [
12516
- /* @__PURE__ */ jsx15(Text14, { color: theme.spinner, children: /* @__PURE__ */ jsx15(Spinner5, { type: "dots" }) }),
12612
+ step === "cloudAuth" && cloudAuth?.phase === "polling" && /* @__PURE__ */ jsxs14(Fragment, { children: [
12613
+ /* @__PURE__ */ jsxs14(Text15, { children: [
12614
+ /* @__PURE__ */ jsx16(Text15, { color: theme.spinner, children: /* @__PURE__ */ jsx16(Spinner5, { type: "dots" }) }),
12517
12615
  " ",
12518
12616
  "Waiting for authentication..."
12519
12617
  ] }),
12520
- /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
12618
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
12521
12619
  "Expires in ",
12522
12620
  formatRemaining(POLL_TIMEOUT_MS - (Date.now() - cloudAuth.startTime))
12523
12621
  ] }),
12524
- /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
12622
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
12525
12623
  "URL: ",
12526
12624
  cloudAuth.codes.authUrl
12527
12625
  ] })
12528
12626
  ] }),
12529
- step === "cloudAuth" && cloudAuth?.phase === "success" && /* @__PURE__ */ jsxs13(Fragment, { children: [
12530
- /* @__PURE__ */ jsx15(Text14, { color: theme.palette.success, children: "Authenticated!" }),
12531
- /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "column", children: [
12532
- /* @__PURE__ */ jsxs13(Text14, { children: [
12627
+ step === "cloudAuth" && cloudAuth?.phase === "success" && /* @__PURE__ */ jsxs14(Fragment, { children: [
12628
+ /* @__PURE__ */ jsx16(Text15, { color: theme.palette.success, children: "Authenticated!" }),
12629
+ /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, flexDirection: "column", children: [
12630
+ /* @__PURE__ */ jsxs14(Text15, { children: [
12533
12631
  "Token budget:",
12534
12632
  " ",
12535
- /* @__PURE__ */ jsxs13(Text14, { bold: true, children: [
12633
+ /* @__PURE__ */ jsxs14(Text15, { bold: true, children: [
12536
12634
  cloudAuth.usage.remaining.toLocaleString(),
12537
12635
  " /",
12538
12636
  " ",
@@ -12541,15 +12639,16 @@ function Onboarding({ onDone, onCancel }) {
12541
12639
  " ",
12542
12640
  "remaining"
12543
12641
  ] }),
12544
- /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
12642
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
12545
12643
  "Grant expires: ",
12546
12644
  cloudAuth.usage.expires_at
12547
- ] })
12645
+ ] }),
12646
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "Or when the global pool of free tokens runs out." })
12548
12647
  ] }),
12549
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(Text14, { children: "[Press Enter to continue]" }) }),
12550
- /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, children: [
12551
- /* @__PURE__ */ jsx15(Text14, { color: theme.palette.primary, children: "\u203A " }),
12552
- /* @__PURE__ */ jsx15(
12648
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(Text15, { children: "[Press Enter to continue]" }) }),
12649
+ /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, children: [
12650
+ /* @__PURE__ */ jsx16(Text15, { color: theme.palette.primary, children: "\u203A " }),
12651
+ /* @__PURE__ */ jsx16(
12553
12652
  CustomTextInput,
12554
12653
  {
12555
12654
  value: "",
@@ -12560,10 +12659,10 @@ function Onboarding({ onDone, onCancel }) {
12560
12659
  )
12561
12660
  ] })
12562
12661
  ] }),
12563
- step === "cloudAuth" && cloudAuth?.phase === "error" && /* @__PURE__ */ jsxs13(Fragment, { children: [
12564
- /* @__PURE__ */ jsx15(Text14, { color: theme.palette.error, children: "Authentication failed" }),
12565
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: cloudAuth.message }),
12566
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
12662
+ step === "cloudAuth" && cloudAuth?.phase === "error" && /* @__PURE__ */ jsxs14(Fragment, { children: [
12663
+ /* @__PURE__ */ jsx16(Text15, { color: theme.palette.error, children: "Authentication failed" }),
12664
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: cloudAuth.message }),
12665
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
12567
12666
  SelectInput4,
12568
12667
  {
12569
12668
  items: [
@@ -12579,11 +12678,11 @@ function Onboarding({ onDone, onCancel }) {
12579
12678
  }
12580
12679
  ) })
12581
12680
  ] }),
12582
- step === "accountId" && /* @__PURE__ */ jsxs13(Fragment, { children: [
12583
- /* @__PURE__ */ jsx15(Text14, { children: "Enter your Cloudflare Account ID" }),
12584
- /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, children: [
12585
- /* @__PURE__ */ jsx15(Text14, { color: theme.palette.primary, children: "\u203A " }),
12586
- /* @__PURE__ */ jsx15(
12681
+ step === "accountId" && /* @__PURE__ */ jsxs14(Fragment, { children: [
12682
+ /* @__PURE__ */ jsx16(Text15, { children: "Enter your Cloudflare Account ID" }),
12683
+ /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, children: [
12684
+ /* @__PURE__ */ jsx16(Text15, { color: theme.palette.primary, children: "\u203A " }),
12685
+ /* @__PURE__ */ jsx16(
12587
12686
  CustomTextInput,
12588
12687
  {
12589
12688
  value: accountId,
@@ -12593,12 +12692,12 @@ function Onboarding({ onDone, onCancel }) {
12593
12692
  )
12594
12693
  ] })
12595
12694
  ] }),
12596
- step === "apiToken" && /* @__PURE__ */ jsxs13(Fragment, { children: [
12597
- /* @__PURE__ */ jsx15(Text14, { children: "Enter your Cloudflare API Token" }),
12598
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Create one at https://dash.cloudflare.com/profile/api-tokens" }),
12599
- /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, children: [
12600
- /* @__PURE__ */ jsx15(Text14, { color: theme.palette.primary, children: "\u203A " }),
12601
- /* @__PURE__ */ jsx15(
12695
+ step === "apiToken" && /* @__PURE__ */ jsxs14(Fragment, { children: [
12696
+ /* @__PURE__ */ jsx16(Text15, { children: "Enter your Cloudflare API Token" }),
12697
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "Create one at https://dash.cloudflare.com/profile/api-tokens" }),
12698
+ /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, children: [
12699
+ /* @__PURE__ */ jsx16(Text15, { color: theme.palette.primary, children: "\u203A " }),
12700
+ /* @__PURE__ */ jsx16(
12602
12701
  CustomTextInput,
12603
12702
  {
12604
12703
  value: apiToken,
@@ -12609,15 +12708,15 @@ function Onboarding({ onDone, onCancel }) {
12609
12708
  )
12610
12709
  ] })
12611
12710
  ] }),
12612
- step === "model" && /* @__PURE__ */ jsxs13(Fragment, { children: [
12613
- /* @__PURE__ */ jsx15(Text14, { children: "Model ID (press Enter for default)" }),
12614
- /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
12711
+ step === "model" && /* @__PURE__ */ jsxs14(Fragment, { children: [
12712
+ /* @__PURE__ */ jsx16(Text15, { children: "Model ID (press Enter for default)" }),
12713
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
12615
12714
  "default: ",
12616
12715
  DEFAULT_MODEL
12617
12716
  ] }),
12618
- /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, children: [
12619
- /* @__PURE__ */ jsx15(Text14, { color: theme.palette.primary, children: "\u203A " }),
12620
- /* @__PURE__ */ jsx15(
12717
+ /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, children: [
12718
+ /* @__PURE__ */ jsx16(Text15, { color: theme.palette.primary, children: "\u203A " }),
12719
+ /* @__PURE__ */ jsx16(
12621
12720
  CustomTextInput,
12622
12721
  {
12623
12722
  value: model,
@@ -12627,10 +12726,10 @@ function Onboarding({ onDone, onCancel }) {
12627
12726
  )
12628
12727
  ] })
12629
12728
  ] }),
12630
- step === "confirm" && /* @__PURE__ */ jsxs13(Fragment, { children: [
12631
- /* @__PURE__ */ jsx15(Text14, { children: "Ready to save configuration" }),
12632
- /* @__PURE__ */ jsxs13(
12633
- Box13,
12729
+ step === "confirm" && /* @__PURE__ */ jsxs14(Fragment, { children: [
12730
+ /* @__PURE__ */ jsx16(Text15, { children: "Ready to save configuration" }),
12731
+ /* @__PURE__ */ jsxs14(
12732
+ Box14,
12634
12733
  {
12635
12734
  flexDirection: "column",
12636
12735
  marginTop: 1,
@@ -12639,25 +12738,25 @@ function Onboarding({ onDone, onCancel }) {
12639
12738
  borderColor: theme.info.color,
12640
12739
  paddingX: 1,
12641
12740
  children: [
12642
- /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
12741
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
12643
12742
  "Account ID: ",
12644
12743
  accountId
12645
12744
  ] }),
12646
- /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
12745
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
12647
12746
  "API Token: ",
12648
12747
  "\u2022".repeat(apiToken.length)
12649
12748
  ] }),
12650
- /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
12749
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
12651
12750
  "Model: ",
12652
12751
  model
12653
12752
  ] })
12654
12753
  ]
12655
12754
  }
12656
12755
  ),
12657
- /* @__PURE__ */ jsx15(Text14, { children: "Press Enter to confirm, or Ctrl+C to cancel" }),
12658
- /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, children: [
12659
- /* @__PURE__ */ jsx15(Text14, { color: theme.palette.primary, children: "\u203A " }),
12660
- /* @__PURE__ */ jsx15(
12756
+ /* @__PURE__ */ jsx16(Text15, { children: "Press Enter to confirm, or Ctrl+C to cancel" }),
12757
+ /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, children: [
12758
+ /* @__PURE__ */ jsx16(Text15, { color: theme.palette.primary, children: "\u203A " }),
12759
+ /* @__PURE__ */ jsx16(
12661
12760
  CustomTextInput,
12662
12761
  {
12663
12762
  value: "",
@@ -12668,7 +12767,7 @@ function Onboarding({ onDone, onCancel }) {
12668
12767
  )
12669
12768
  ] })
12670
12769
  ] }),
12671
- savedPath && /* @__PURE__ */ jsxs13(Text14, { color: theme.palette.success, children: [
12770
+ savedPath && /* @__PURE__ */ jsxs14(Text15, { color: theme.palette.success, children: [
12672
12771
  "Config saved to ",
12673
12772
  savedPath
12674
12773
  ] })
@@ -12683,6 +12782,7 @@ var init_onboarding = __esm({
12683
12782
  init_config();
12684
12783
  init_theme_context();
12685
12784
  init_auth();
12785
+ init_errors();
12686
12786
  execAsync = promisify2(exec);
12687
12787
  }
12688
12788
  });
@@ -12726,8 +12826,8 @@ var init_greetings = __esm({
12726
12826
  });
12727
12827
 
12728
12828
  // src/ui/welcome.tsx
12729
- import { Box as Box14, Text as Text15 } from "ink";
12730
- import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
12829
+ import { Box as Box15, Text as Text16 } from "ink";
12830
+ import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
12731
12831
  function Welcome() {
12732
12832
  const theme = useTheme();
12733
12833
  const now2 = /* @__PURE__ */ new Date();
@@ -12735,9 +12835,9 @@ function Welcome() {
12735
12835
  hour: now2.getHours(),
12736
12836
  day: now2.getDay()
12737
12837
  });
12738
- return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", marginBottom: 1, children: [
12739
- /* @__PURE__ */ jsx16(Box14, { marginBottom: 1, children: /* @__PURE__ */ jsx16(Text15, { bold: true, color: theme.accent, children: headline }) }),
12740
- /* @__PURE__ */ jsx16(Box14, { flexDirection: "column", children: /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, dimColor: true, children: "Type / for commands" }) })
12838
+ return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", marginBottom: 1, children: [
12839
+ /* @__PURE__ */ jsx17(Box15, { marginBottom: 1, children: /* @__PURE__ */ jsx17(Text16, { bold: true, color: theme.accent, children: headline }) }),
12840
+ /* @__PURE__ */ jsx17(Box15, { flexDirection: "column", children: /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, dimColor: true, children: "Type / for commands" }) })
12741
12841
  ] });
12742
12842
  }
12743
12843
  var init_welcome = __esm({
@@ -12845,9 +12945,9 @@ var init_worker_client = __esm({
12845
12945
 
12846
12946
  // src/ui/remote-dashboard.tsx
12847
12947
  import { useEffect as useEffect6, useState as useState9 } from "react";
12848
- import { Box as Box15, Text as Text16, useInput as useInput6 } from "ink";
12948
+ import { Box as Box16, Text as Text17, useInput as useInput6 } from "ink";
12849
12949
  import SelectInput5 from "ink-select-input";
12850
- import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
12950
+ import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
12851
12951
  function RemoteDashboard({ onSelect, onCancel }) {
12852
12952
  const theme = useTheme();
12853
12953
  const [sessions, setSessions] = useState9([]);
@@ -12903,30 +13003,30 @@ function RemoteDashboard({ onSelect, onCancel }) {
12903
13003
  value: s.sessionId
12904
13004
  }));
12905
13005
  if (loading) {
12906
- return /* @__PURE__ */ jsx17(Box15, { flexDirection: "column", padding: 1, children: /* @__PURE__ */ jsx17(Text16, { color: theme.accent, children: "Loading remote sessions..." }) });
13006
+ return /* @__PURE__ */ jsx18(Box16, { flexDirection: "column", padding: 1, children: /* @__PURE__ */ jsx18(Text17, { color: theme.accent, children: "Loading remote sessions..." }) });
12907
13007
  }
12908
13008
  if (error) {
12909
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", padding: 1, children: [
12910
- /* @__PURE__ */ jsxs15(Text16, { color: theme.error, children: [
13009
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", padding: 1, children: [
13010
+ /* @__PURE__ */ jsxs16(Text17, { color: theme.error, children: [
12911
13011
  "Error: ",
12912
13012
  error
12913
13013
  ] }),
12914
- /* @__PURE__ */ jsx17(Text16, { dimColor: true, children: "Press R to retry, Esc to close" })
13014
+ /* @__PURE__ */ jsx18(Text17, { dimColor: true, children: "Press R to retry, Esc to close" })
12915
13015
  ] });
12916
13016
  }
12917
13017
  if (sessions.length === 0) {
12918
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", padding: 1, children: [
12919
- /* @__PURE__ */ jsx17(Text16, { color: theme.accent, children: "No remote sessions yet." }),
12920
- /* @__PURE__ */ jsx17(Text16, { dimColor: true, children: "Type /remote <prompt> to start one." }),
12921
- /* @__PURE__ */ jsx17(Text16, { dimColor: true, children: "Press Esc to close" })
13018
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", padding: 1, children: [
13019
+ /* @__PURE__ */ jsx18(Text17, { color: theme.accent, children: "No remote sessions yet." }),
13020
+ /* @__PURE__ */ jsx18(Text17, { dimColor: true, children: "Type /remote <prompt> to start one." }),
13021
+ /* @__PURE__ */ jsx18(Text17, { dimColor: true, children: "Press Esc to close" })
12922
13022
  ] });
12923
13023
  }
12924
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", padding: 1, children: [
12925
- /* @__PURE__ */ jsxs15(Text16, { bold: true, color: theme.accent, children: [
13024
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", padding: 1, children: [
13025
+ /* @__PURE__ */ jsxs16(Text17, { bold: true, color: theme.accent, children: [
12926
13026
  "Recent remote tasks ",
12927
13027
  refreshing ? "(refreshing...)" : ""
12928
13028
  ] }),
12929
- /* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
13029
+ /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
12930
13030
  SelectInput5,
12931
13031
  {
12932
13032
  items,
@@ -12936,7 +13036,7 @@ function RemoteDashboard({ onSelect, onCancel }) {
12936
13036
  }
12937
13037
  }
12938
13038
  ) }),
12939
- /* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(Text16, { dimColor: true, children: "\u2191\u2193 navigate \u2022 Enter select \u2022 R refresh \u2022 Esc close" }) })
13039
+ /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(Text17, { dimColor: true, children: "\u2191\u2193 navigate \u2022 Enter select \u2022 R refresh \u2022 Esc close" }) })
12940
13040
  ] });
12941
13041
  }
12942
13042
  function formatSessionLine(s) {
@@ -12989,50 +13089,50 @@ function RemoteSessionDetail({
12989
13089
  }
12990
13090
  }
12991
13091
  const isRunning = session.status === "running" || session.status === "pending";
12992
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", padding: 1, children: [
12993
- /* @__PURE__ */ jsx17(Text16, { bold: true, color: theme.accent, children: "Remote Session" }),
12994
- /* @__PURE__ */ jsxs15(Box15, { marginTop: 1, flexDirection: "column", children: [
12995
- /* @__PURE__ */ jsxs15(Text16, { children: [
13092
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", padding: 1, children: [
13093
+ /* @__PURE__ */ jsx18(Text17, { bold: true, color: theme.accent, children: "Remote Session" }),
13094
+ /* @__PURE__ */ jsxs16(Box16, { marginTop: 1, flexDirection: "column", children: [
13095
+ /* @__PURE__ */ jsxs16(Text17, { children: [
12996
13096
  "ID: ",
12997
13097
  session.sessionId
12998
13098
  ] }),
12999
- /* @__PURE__ */ jsxs15(Text16, { children: [
13099
+ /* @__PURE__ */ jsxs16(Text17, { children: [
13000
13100
  "Repo: ",
13001
13101
  session.repo
13002
13102
  ] }),
13003
- /* @__PURE__ */ jsxs15(Text16, { children: [
13103
+ /* @__PURE__ */ jsxs16(Text17, { children: [
13004
13104
  "Status: ",
13005
13105
  session.status
13006
13106
  ] }),
13007
- /* @__PURE__ */ jsxs15(Text16, { children: [
13107
+ /* @__PURE__ */ jsxs16(Text17, { children: [
13008
13108
  "Prompt: ",
13009
13109
  session.prompt
13010
13110
  ] }),
13011
- session.prUrl && /* @__PURE__ */ jsxs15(Text16, { children: [
13111
+ session.prUrl && /* @__PURE__ */ jsxs16(Text17, { children: [
13012
13112
  "PR: ",
13013
13113
  session.prUrl
13014
13114
  ] }),
13015
- session.errorMessage && /* @__PURE__ */ jsxs15(Text16, { color: theme.error, children: [
13115
+ session.errorMessage && /* @__PURE__ */ jsxs16(Text17, { color: theme.error, children: [
13016
13116
  "Error: ",
13017
13117
  session.errorMessage
13018
13118
  ] }),
13019
- session.tokensUsed !== void 0 && /* @__PURE__ */ jsxs15(Text16, { children: [
13119
+ session.tokensUsed !== void 0 && /* @__PURE__ */ jsxs16(Text17, { children: [
13020
13120
  "Tokens: ",
13021
13121
  formatTokens4(session.tokensUsed),
13022
13122
  session.tokensBudget ? ` / ${formatTokens4(session.tokensBudget)}` : ""
13023
13123
  ] }),
13024
- /* @__PURE__ */ jsxs15(Text16, { children: [
13124
+ /* @__PURE__ */ jsxs16(Text17, { children: [
13025
13125
  "Created: ",
13026
13126
  new Date(session.createdAt).toLocaleString()
13027
13127
  ] }),
13028
- session.finishedAt && /* @__PURE__ */ jsxs15(Text16, { children: [
13128
+ session.finishedAt && /* @__PURE__ */ jsxs16(Text17, { children: [
13029
13129
  "Finished: ",
13030
13130
  new Date(session.finishedAt).toLocaleString()
13031
13131
  ] })
13032
13132
  ] }),
13033
- /* @__PURE__ */ jsxs15(Box15, { marginTop: 1, flexDirection: "row", gap: 2, children: [
13034
- isRunning && onCancel && /* @__PURE__ */ jsx17(Text16, { color: theme.error, children: cancelling ? "Cancelling..." : "[C] Cancel session" }),
13035
- /* @__PURE__ */ jsx17(Text16, { dimColor: true, children: "Esc back" })
13133
+ /* @__PURE__ */ jsxs16(Box16, { marginTop: 1, flexDirection: "row", gap: 2, children: [
13134
+ isRunning && onCancel && /* @__PURE__ */ jsx18(Text17, { color: theme.error, children: cancelling ? "Cancelling..." : "[C] Cancel session" }),
13135
+ /* @__PURE__ */ jsx18(Text17, { dimColor: true, children: "Esc back" })
13036
13136
  ] })
13037
13137
  ] });
13038
13138
  }
@@ -13154,70 +13254,176 @@ var init_loader = __esm({
13154
13254
  }
13155
13255
  });
13156
13256
 
13157
- // src/skills/router.ts
13158
- import { minimatch } from "minimatch";
13159
- function matchSkill(skill, prompt, cwd) {
13160
- if (!skill.enabled) return false;
13161
- if (skill.match.length === 0) return true;
13162
- for (const pattern of skill.match) {
13163
- if (pattern.includes("/") || pattern.includes("*")) {
13164
- if (minimatch(cwd, pattern) || minimatch(cwd, `**/${pattern}`)) {
13165
- return true;
13166
- }
13167
- }
13168
- if (prompt.toLowerCase().includes(pattern.toLowerCase())) {
13169
- return true;
13170
- }
13257
+ // src/skills/db.ts
13258
+ function initSkillsSchema(db) {
13259
+ db.exec(`
13260
+ CREATE TABLE IF NOT EXISTS skill_index (
13261
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
13262
+ name TEXT NOT NULL,
13263
+ description TEXT,
13264
+ file_path TEXT NOT NULL,
13265
+ content_hash TEXT NOT NULL,
13266
+ parser_version INTEGER NOT NULL DEFAULT 1,
13267
+ updated_at INTEGER NOT NULL
13268
+ );
13269
+
13270
+ CREATE TABLE IF NOT EXISTS skill_sections (
13271
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
13272
+ skill_id INTEGER NOT NULL,
13273
+ heading TEXT NOT NULL,
13274
+ body TEXT NOT NULL,
13275
+ embedding BLOB NOT NULL,
13276
+ FOREIGN KEY (skill_id) REFERENCES skill_index(id) ON DELETE CASCADE
13277
+ );
13278
+
13279
+ CREATE INDEX IF NOT EXISTS idx_skill_path ON skill_index(file_path);
13280
+ `);
13281
+ }
13282
+ function getSkillByPath(db, filePath) {
13283
+ const row = db.prepare("SELECT id, content_hash, parser_version FROM skill_index WHERE file_path = ?").get(filePath);
13284
+ if (!row) return null;
13285
+ return { id: row.id, contentHash: row.content_hash, parserVersion: row.parser_version };
13286
+ }
13287
+ function upsertSkill(db, skill) {
13288
+ const existing = getSkillByPath(db, skill.filePath);
13289
+ const now2 = Date.now();
13290
+ if (existing) {
13291
+ db.prepare(
13292
+ `UPDATE skill_index
13293
+ SET name = ?, description = ?, content_hash = ?, parser_version = ?, updated_at = ?
13294
+ WHERE id = ?`
13295
+ ).run(skill.name, skill.description, skill.contentHash, skill.parserVersion, now2, existing.id);
13296
+ db.prepare("DELETE FROM skill_sections WHERE skill_id = ?").run(existing.id);
13297
+ return existing.id;
13171
13298
  }
13172
- return false;
13299
+ const result = db.prepare(
13300
+ `INSERT INTO skill_index (name, description, file_path, content_hash, parser_version, updated_at)
13301
+ VALUES (?, ?, ?, ?, ?, ?)`
13302
+ ).run(skill.name, skill.description, skill.filePath, skill.contentHash, skill.parserVersion, now2);
13303
+ return Number(result.lastInsertRowid);
13173
13304
  }
13174
- function findConflicts(skill, memorySnippets) {
13175
- const conflicts = [];
13176
- for (const mem of memorySnippets) {
13177
- const memLower = mem.toLowerCase();
13178
- const skillLower = skill.name.toLowerCase();
13179
- if (memLower.includes(skillLower) || skillLower.includes(memLower)) {
13180
- conflicts.push({
13181
- skillName: skill.name,
13182
- memoryContent: mem.slice(0, 200),
13183
- memoryId: ""
13184
- // populated by caller if available
13185
- });
13186
- }
13305
+ function insertSections(db, skillId, sections, embeddings) {
13306
+ const insert = db.prepare(
13307
+ `INSERT INTO skill_sections (skill_id, heading, body, embedding)
13308
+ VALUES (?, ?, ?, ?)`
13309
+ );
13310
+ for (let i = 0; i < sections.length; i++) {
13311
+ const section = sections[i];
13312
+ const embedding = embeddings[i];
13313
+ insert.run(skillId, section.heading, section.body, Buffer.from(embedding.buffer));
13187
13314
  }
13188
- return conflicts;
13189
- }
13190
- function selectSkills(skills, options) {
13191
- const tierBudget = TIER_BUDGETS[options.tier];
13192
- const effectiveBudget = Math.min(tierBudget, options.maxSkillTokens);
13193
- const matched = skills.filter((s) => matchSkill(s, options.prompt, options.cwd));
13194
- const selected = [];
13195
- const dropped = [];
13196
- const allConflicts = [];
13197
- let runningTotal = 0;
13198
- for (const skill of matched) {
13199
- const conflicts = findConflicts(skill, options.memorySnippets);
13200
- allConflicts.push(...conflicts);
13201
- if (runningTotal + skill.estimatedTokens <= effectiveBudget) {
13202
- selected.push(skill);
13203
- runningTotal += skill.estimatedTokens;
13204
- } else {
13205
- dropped.push(skill);
13206
- }
13315
+ }
13316
+ function deleteOrphanedSkills(db, existingPaths) {
13317
+ if (existingPaths.length === 0) {
13318
+ const result2 = db.prepare("DELETE FROM skill_index").run();
13319
+ return Number(result2.changes);
13207
13320
  }
13208
- const budgetUsed = effectiveBudget > 0 ? Math.round(runningTotal / effectiveBudget * 100) : 0;
13321
+ const placeholders = existingPaths.map(() => "?").join(",");
13322
+ const result = db.prepare(`DELETE FROM skill_index WHERE file_path NOT IN (${placeholders})`).run(...existingPaths);
13323
+ return Number(result.changes);
13324
+ }
13325
+ function listAllSectionRows(db) {
13326
+ return db.prepare(
13327
+ `SELECT s.id, s.heading, s.body, s.embedding, i.name, i.description, i.file_path
13328
+ FROM skill_sections s
13329
+ JOIN skill_index i ON s.skill_id = i.id`
13330
+ ).all();
13331
+ }
13332
+ function rowToSectionResult(row) {
13209
13333
  return {
13210
- selectedSkills: selected,
13211
- droppedSkills: dropped,
13212
- totalSkillTokens: runningTotal,
13213
- budgetUsed,
13214
- memoryConflicts: allConflicts
13334
+ id: row.id,
13335
+ heading: row.heading,
13336
+ body: row.body,
13337
+ name: row.name,
13338
+ description: row.description,
13339
+ filePath: row.file_path
13215
13340
  };
13216
13341
  }
13217
- var TIER_BUDGETS;
13218
- var init_router = __esm({
13219
- "src/skills/router.ts"() {
13342
+ var init_db2 = __esm({
13343
+ "src/skills/db.ts"() {
13344
+ "use strict";
13345
+ }
13346
+ });
13347
+
13348
+ // src/skills/search.ts
13349
+ async function searchSections(query, db, opts2) {
13350
+ const embeddings = await fetchEmbeddings({
13351
+ accountId: opts2.accountId,
13352
+ apiToken: opts2.apiToken,
13353
+ model: opts2.model,
13354
+ texts: [query],
13355
+ gateway: opts2.gateway,
13356
+ cloudMode: opts2.cloudMode,
13357
+ cloudToken: opts2.cloudToken,
13358
+ cloudDeviceId: opts2.cloudDeviceId
13359
+ });
13360
+ const queryEmbedding = embeddings[0];
13361
+ if (!queryEmbedding) {
13362
+ throw new Error("Failed to embed query: no embedding returned");
13363
+ }
13364
+ const rows = listAllSectionRows(db);
13365
+ const scored = [];
13366
+ for (const row of rows) {
13367
+ const sectionEmbedding = new Float32Array(row.embedding);
13368
+ const similarity = cosineSimilarity(queryEmbedding, sectionEmbedding);
13369
+ scored.push({
13370
+ ...rowToSectionResult(row),
13371
+ similarity
13372
+ });
13373
+ }
13374
+ scored.sort((a, b) => b.similarity - a.similarity);
13375
+ return scored;
13376
+ }
13377
+ var init_search = __esm({
13378
+ "src/skills/search.ts"() {
13379
+ "use strict";
13380
+ init_embeddings();
13381
+ init_db2();
13382
+ }
13383
+ });
13384
+
13385
+ // src/skills/format.ts
13386
+ function estimateTokens(text) {
13387
+ return Math.ceil(text.length / 4);
13388
+ }
13389
+ function formatSection(section) {
13390
+ return `### ${section.name} \u2014 ${section.heading}
13391
+ ${section.body}
13392
+
13393
+ `;
13394
+ }
13395
+ function packSections(sections, budget) {
13396
+ let context = "";
13397
+ let used = 0;
13398
+ let count = 0;
13399
+ for (const section of sections) {
13400
+ if (section.similarity < MIN_SIMILARITY) break;
13401
+ const text = formatSection(section);
13402
+ const tokens = estimateTokens(text);
13403
+ if (used + tokens > budget) break;
13404
+ context += text;
13405
+ used += tokens;
13406
+ count++;
13407
+ }
13408
+ return { context, tokens: used, count };
13409
+ }
13410
+ function buildSkillContext(sections, tier, maxSkillTokens) {
13411
+ const tierBudget = TIER_BUDGETS[tier];
13412
+ const effectiveBudget = Math.min(tierBudget, maxSkillTokens ?? tierBudget);
13413
+ const packed = packSections(sections, effectiveBudget);
13414
+ const budgetUsed = effectiveBudget > 0 ? Math.round(packed.tokens / effectiveBudget * 100) : 0;
13415
+ return {
13416
+ skillContext: packed.context,
13417
+ sectionCount: packed.count,
13418
+ totalTokens: packed.tokens,
13419
+ budgetUsed
13420
+ };
13421
+ }
13422
+ var MIN_SIMILARITY, TIER_BUDGETS;
13423
+ var init_format = __esm({
13424
+ "src/skills/format.ts"() {
13220
13425
  "use strict";
13426
+ MIN_SIMILARITY = 0.3;
13221
13427
  TIER_BUDGETS = {
13222
13428
  light: 2e3,
13223
13429
  medium: 8e3,
@@ -13226,27 +13432,281 @@ var init_router = __esm({
13226
13432
  }
13227
13433
  });
13228
13434
 
13229
- // src/skills/index.ts
13230
- async function routeSkills(skillDir, opts2) {
13231
- const skills = await loadSkillsFromDir(skillDir);
13232
- return selectSkills(skills, opts2);
13435
+ // src/skills/router.ts
13436
+ async function selectSkills(opts2, deps) {
13437
+ const sections = await searchSections(opts2.prompt, deps.db, {
13438
+ accountId: deps.accountId,
13439
+ apiToken: deps.apiToken,
13440
+ model: deps.embeddingModel,
13441
+ gateway: deps.gateway,
13442
+ cloudMode: deps.cloudMode,
13443
+ cloudToken: deps.cloudToken,
13444
+ cloudDeviceId: deps.cloudDeviceId
13445
+ });
13446
+ return buildSkillContext(sections, opts2.tier, opts2.maxSkillTokens);
13233
13447
  }
13448
+ var init_router = __esm({
13449
+ "src/skills/router.ts"() {
13450
+ "use strict";
13451
+ init_search();
13452
+ init_format();
13453
+ }
13454
+ });
13455
+
13456
+ // src/skills/discovery.ts
13457
+ import { readdir as readdir5, stat as stat6, readFile as readFile15 } from "fs/promises";
13458
+ import { join as join21, extname as extname2 } from "path";
13459
+ async function dirExists(path) {
13460
+ try {
13461
+ const s = await stat6(path);
13462
+ return s.isDirectory();
13463
+ } catch {
13464
+ return false;
13465
+ }
13466
+ }
13467
+ async function fileExists(path) {
13468
+ try {
13469
+ const s = await stat6(path);
13470
+ return s.isFile();
13471
+ } catch {
13472
+ return false;
13473
+ }
13474
+ }
13475
+ async function scanSkillDir(dirPath, source) {
13476
+ if (!await dirExists(dirPath)) return [];
13477
+ const entries = await readdir5(dirPath, { withFileTypes: true });
13478
+ const files = [];
13479
+ for (const entry of entries) {
13480
+ if (!entry.isFile()) continue;
13481
+ if (!SKILL_EXTENSIONS.has(extname2(entry.name))) continue;
13482
+ files.push({ filePath: join21(dirPath, entry.name), source });
13483
+ }
13484
+ return files;
13485
+ }
13486
+ async function discoverSkills(cwd) {
13487
+ const agentsSkills = await scanSkillDir(join21(cwd, ".agents", "skills"), "agents");
13488
+ const agentsMd = await fileExists(join21(cwd, "AGENTS.md")) ? [{ filePath: join21(cwd, "AGENTS.md"), source: "agents-md" }] : [];
13489
+ const githubSkills = await scanSkillDir(join21(cwd, ".github", "skills"), "github");
13490
+ const kimiflareSkills = await scanSkillDir(join21(cwd, ".kimiflare", "skills"), "kimiflare");
13491
+ const ordered = [...agentsSkills, ...agentsMd, ...githubSkills, ...kimiflareSkills];
13492
+ return ordered;
13493
+ }
13494
+ async function readSkillFile(filePath) {
13495
+ const bytes = await readFile15(filePath);
13496
+ return { bytes, text: bytes.toString("utf-8") };
13497
+ }
13498
+ var SKILL_EXTENSIONS;
13499
+ var init_discovery = __esm({
13500
+ "src/skills/discovery.ts"() {
13501
+ "use strict";
13502
+ SKILL_EXTENSIONS = /* @__PURE__ */ new Set([".md"]);
13503
+ }
13504
+ });
13505
+
13506
+ // src/skills/parser.ts
13507
+ import matter2 from "gray-matter";
13508
+ import { createHash as createHash2 } from "crypto";
13509
+ function sha256(input) {
13510
+ return createHash2("sha256").update(input).digest("hex");
13511
+ }
13512
+ function computeContentHash(rawText, parserVersion) {
13513
+ return sha256(`${rawText}
13514
+ <!-- parser_version: ${parserVersion} -->`);
13515
+ }
13516
+ function extractDescription(body, heading) {
13517
+ const lines = body.split("\n").map((l) => l.trim()).filter((l) => l.length > 0);
13518
+ if (lines.length === 0) return heading;
13519
+ const first = lines[0];
13520
+ if (first.startsWith("```") || first.startsWith("-") || first.startsWith("*") || first.startsWith("#") || first.match(/^\d+\./) || first.length < 20) {
13521
+ return heading;
13522
+ }
13523
+ const sentenceMatch = first.match(/^(.+?[.!?])(?:\s|$)/);
13524
+ if (sentenceMatch) {
13525
+ return sentenceMatch[1];
13526
+ }
13527
+ return first.length <= 120 ? first : heading;
13528
+ }
13529
+ function splitIntoSections(markdown) {
13530
+ const lines = markdown.split("\n");
13531
+ const sections = [];
13532
+ let currentHeading = "";
13533
+ let currentBody = [];
13534
+ for (const line of lines) {
13535
+ const h2Match = line.match(/^##\s+(.*)$/);
13536
+ if (h2Match) {
13537
+ const body = currentBody.join("\n").trim();
13538
+ if (body.length > 0 || currentHeading) {
13539
+ sections.push({
13540
+ heading: currentHeading,
13541
+ body
13542
+ });
13543
+ }
13544
+ currentHeading = h2Match[1].trim();
13545
+ currentBody = [];
13546
+ } else {
13547
+ currentBody.push(line);
13548
+ }
13549
+ }
13550
+ const finalBody = currentBody.join("\n").trim();
13551
+ if (finalBody.length > 0 || currentHeading) {
13552
+ sections.push({
13553
+ heading: currentHeading,
13554
+ body: finalBody
13555
+ });
13556
+ }
13557
+ return sections;
13558
+ }
13559
+ function parseSkillFile(filePath, rawText) {
13560
+ const parsed = matter2(rawText);
13561
+ const name = typeof parsed.data.name === "string" ? parsed.data.name : "";
13562
+ const description = typeof parsed.data.description === "string" ? parsed.data.description : "";
13563
+ if (!name) {
13564
+ throw new Error(`Skill file missing required 'name' field: ${filePath}`);
13565
+ }
13566
+ const sections = splitIntoSections(parsed.content);
13567
+ if (sections.length === 0) {
13568
+ sections.push({ heading: name, body: parsed.content.trim() });
13569
+ }
13570
+ const firstSection = sections[0];
13571
+ if (firstSection && firstSection.heading === "") {
13572
+ firstSection.heading = name;
13573
+ }
13574
+ return {
13575
+ name,
13576
+ description,
13577
+ filePath,
13578
+ contentHash: computeContentHash(rawText, PARSER_VERSION),
13579
+ parserVersion: PARSER_VERSION,
13580
+ sections
13581
+ };
13582
+ }
13583
+ function parseAgentsMd(filePath, rawText) {
13584
+ const sections = splitIntoSections(rawText);
13585
+ const skills = [];
13586
+ for (const section of sections) {
13587
+ if (!section.heading) continue;
13588
+ const description = extractDescription(section.body, section.heading);
13589
+ skills.push({
13590
+ name: section.heading,
13591
+ description,
13592
+ filePath,
13593
+ contentHash: computeContentHash(rawText, PARSER_VERSION),
13594
+ parserVersion: PARSER_VERSION,
13595
+ sections: [{ heading: section.heading, body: section.body }]
13596
+ });
13597
+ }
13598
+ return skills;
13599
+ }
13600
+ var PARSER_VERSION;
13601
+ var init_parser = __esm({
13602
+ "src/skills/parser.ts"() {
13603
+ "use strict";
13604
+ PARSER_VERSION = 1;
13605
+ }
13606
+ });
13607
+
13608
+ // src/skills/indexer.ts
13609
+ function buildEmbeddingInput(skill, section) {
13610
+ return `${skill.name}: ${skill.description}
13611
+
13612
+ ${section.heading}
13613
+ ${section.body}`;
13614
+ }
13615
+ async function indexSkills(opts2) {
13616
+ initSkillsSchema(opts2.db);
13617
+ const discovered = await discoverSkills(opts2.cwd);
13618
+ const errors = [];
13619
+ const parsedSkills = [];
13620
+ for (const file of discovered) {
13621
+ try {
13622
+ const { text } = await readSkillFile(file.filePath);
13623
+ if (file.source === "agents-md") {
13624
+ const skills = parseAgentsMd(file.filePath, text);
13625
+ parsedSkills.push(...skills);
13626
+ } else {
13627
+ const skill = parseSkillFile(file.filePath, text);
13628
+ parsedSkills.push(skill);
13629
+ }
13630
+ } catch (err) {
13631
+ errors.push(`Failed to parse ${file.filePath}: ${err instanceof Error ? err.message : String(err)}`);
13632
+ }
13633
+ }
13634
+ const seenNames = /* @__PURE__ */ new Set();
13635
+ const deduped = [];
13636
+ for (const skill of parsedSkills) {
13637
+ if (seenNames.has(skill.name)) continue;
13638
+ seenNames.add(skill.name);
13639
+ deduped.push(skill);
13640
+ }
13641
+ let indexed = 0;
13642
+ let skipped = 0;
13643
+ for (const skill of deduped) {
13644
+ const existing = getSkillByPath(opts2.db, skill.filePath);
13645
+ if (existing && existing.contentHash === skill.contentHash && existing.parserVersion === skill.parserVersion) {
13646
+ skipped++;
13647
+ continue;
13648
+ }
13649
+ const skillId = upsertSkill(opts2.db, skill);
13650
+ if (skill.sections.length > 0) {
13651
+ const inputs = skill.sections.map((section) => buildEmbeddingInput(skill, section));
13652
+ try {
13653
+ const embeddings = await fetchEmbeddings({
13654
+ accountId: opts2.accountId,
13655
+ apiToken: opts2.apiToken,
13656
+ model: opts2.embeddingModel,
13657
+ texts: inputs,
13658
+ gateway: opts2.gateway,
13659
+ cloudMode: opts2.cloudMode,
13660
+ cloudToken: opts2.cloudToken,
13661
+ cloudDeviceId: opts2.cloudDeviceId
13662
+ });
13663
+ insertSections(opts2.db, skillId, skill.sections, embeddings);
13664
+ } catch (err) {
13665
+ errors.push(
13666
+ `Failed to embed sections for ${skill.filePath}: ${err instanceof Error ? err.message : String(err)}`
13667
+ );
13668
+ continue;
13669
+ }
13670
+ }
13671
+ indexed++;
13672
+ }
13673
+ const existingPaths = deduped.map((s) => s.filePath);
13674
+ const removed = deleteOrphanedSkills(opts2.db, existingPaths);
13675
+ return { indexed, skipped, removed, errors };
13676
+ }
13677
+ var init_indexer = __esm({
13678
+ "src/skills/indexer.ts"() {
13679
+ "use strict";
13680
+ init_embeddings();
13681
+ init_discovery();
13682
+ init_parser();
13683
+ init_db2();
13684
+ }
13685
+ });
13686
+
13687
+ // src/skills/index.ts
13234
13688
  var init_skills = __esm({
13235
13689
  "src/skills/index.ts"() {
13236
13690
  "use strict";
13237
13691
  init_loader();
13238
13692
  init_router();
13693
+ init_indexer();
13694
+ init_search();
13695
+ init_format();
13696
+ init_discovery();
13697
+ init_parser();
13698
+ init_db2();
13239
13699
  }
13240
13700
  });
13241
13701
 
13242
13702
  // src/skills/manager.ts
13243
- import { mkdir as mkdir11, writeFile as writeFile11, unlink as unlink2, readFile as readFile15 } from "fs/promises";
13244
- import { join as join21 } from "path";
13245
- import matter2 from "gray-matter";
13703
+ import { mkdir as mkdir11, writeFile as writeFile11, unlink as unlink2, readFile as readFile16 } from "fs/promises";
13704
+ import { join as join22 } from "path";
13705
+ import matter3 from "gray-matter";
13246
13706
  function getSkillDirs(cwd) {
13247
13707
  return {
13248
- projectDir: join21(cwd, ".kimiflare", "skills"),
13249
- globalDir: join21(process.env.HOME ?? "", ".config", "kimiflare", "skills")
13708
+ projectDir: join22(cwd, ".kimiflare", "skills"),
13709
+ globalDir: join22(process.env.HOME ?? "", ".config", "kimiflare", "skills")
13250
13710
  };
13251
13711
  }
13252
13712
  async function listAllSkills(cwd) {
@@ -13260,7 +13720,7 @@ async function listAllSkills(cwd) {
13260
13720
  async function createSkill(opts2) {
13261
13721
  const dirs = getSkillDirs(opts2.cwd);
13262
13722
  const dir = opts2.scope === "project" ? dirs.projectDir : dirs.globalDir;
13263
- const filepath = join21(dir, `${opts2.name}.md`);
13723
+ const filepath = join22(dir, `${opts2.name}.md`);
13264
13724
  const frontmatter = {
13265
13725
  name: opts2.name,
13266
13726
  enabled: true,
@@ -13296,8 +13756,8 @@ async function setSkillEnabled(name, enabled, cwd) {
13296
13756
  const all = await listAllSkills(cwd);
13297
13757
  const skill = all.project.find((s) => s.name === name) ?? all.global.find((s) => s.name === name);
13298
13758
  if (!skill) throw new Error(`skill "${name}" not found`);
13299
- const raw = await readFile15(skill.filePath, "utf-8");
13300
- const parsed = matter2(raw);
13759
+ const raw = await readFile16(skill.filePath, "utf-8");
13760
+ const parsed = matter3(raw);
13301
13761
  parsed.data.enabled = enabled;
13302
13762
  const yaml = Object.entries(parsed.data).map(([k, v]) => {
13303
13763
  if (Array.isArray(v)) return `${k}:
@@ -13324,10 +13784,10 @@ var init_manager4 = __esm({
13324
13784
  });
13325
13785
 
13326
13786
  // src/util/image.ts
13327
- import { readFile as readFile16 } from "fs/promises";
13328
- import { basename as basename3 } from "path";
13787
+ import { readFile as readFile17 } from "fs/promises";
13788
+ import { basename as basename4 } from "path";
13329
13789
  async function encodeImageFile(filePath) {
13330
- const buf = await readFile16(filePath);
13790
+ const buf = await readFile17(filePath);
13331
13791
  if (buf.byteLength > MAX_IMAGE_BYTES) {
13332
13792
  throw new Error(
13333
13793
  `image too large (${(buf.byteLength / 1024 / 1024).toFixed(1)} MB); max is ${MAX_IMAGE_BYTES / 1024 / 1024} MB`
@@ -13337,7 +13797,7 @@ async function encodeImageFile(filePath) {
13337
13797
  const mime = EXT_TO_MIME[ext] ?? "image/jpeg";
13338
13798
  const b64 = buf.toString("base64");
13339
13799
  return {
13340
- filename: basename3(filePath),
13800
+ filename: basename4(filePath),
13341
13801
  mime,
13342
13802
  dataUrl: `data:${mime};base64,${b64}`
13343
13803
  };
@@ -13363,16 +13823,16 @@ var init_image = __esm({
13363
13823
  });
13364
13824
 
13365
13825
  // src/util/state.ts
13366
- import { readFile as readFile17, writeFile as writeFile12, mkdir as mkdir12 } from "fs/promises";
13826
+ import { readFile as readFile18, writeFile as writeFile12, mkdir as mkdir12 } from "fs/promises";
13367
13827
  import { homedir as homedir13 } from "os";
13368
- import { join as join22 } from "path";
13828
+ import { join as join23 } from "path";
13369
13829
  function statePath() {
13370
- const xdg = process.env.XDG_CONFIG_HOME || join22(homedir13(), ".config");
13371
- return join22(xdg, "kimiflare", "state.json");
13830
+ const xdg = process.env.XDG_CONFIG_HOME || join23(homedir13(), ".config");
13831
+ return join23(xdg, "kimiflare", "state.json");
13372
13832
  }
13373
13833
  async function readState() {
13374
13834
  try {
13375
- const raw = await readFile17(statePath(), "utf8");
13835
+ const raw = await readFile18(statePath(), "utf8");
13376
13836
  return JSON.parse(raw);
13377
13837
  } catch {
13378
13838
  return {};
@@ -13380,7 +13840,7 @@ async function readState() {
13380
13840
  }
13381
13841
  async function writeState(state) {
13382
13842
  const path = statePath();
13383
- await mkdir12(join22(path, ".."), { recursive: true });
13843
+ await mkdir12(join23(path, ".."), { recursive: true });
13384
13844
  await writeFile12(path, JSON.stringify(state, null, 2) + "\n", "utf8");
13385
13845
  }
13386
13846
  async function markCreatorMessageSeen(version) {
@@ -13455,14 +13915,14 @@ var init_frontmatter = __esm({
13455
13915
  // src/commands/loader.ts
13456
13916
  import { open, realpath } from "fs/promises";
13457
13917
  import { homedir as homedir14 } from "os";
13458
- import { join as join23, relative as relative4, sep as sep2 } from "path";
13918
+ import { join as join24, relative as relative4, sep as sep2 } from "path";
13459
13919
  import fg3 from "fast-glob";
13460
13920
  function projectCommandsDir(cwd = process.cwd()) {
13461
- return join23(cwd, ".kimiflare", "commands");
13921
+ return join24(cwd, ".kimiflare", "commands");
13462
13922
  }
13463
13923
  function globalCommandsDir() {
13464
- const xdg = process.env.XDG_CONFIG_HOME || join23(homedir14(), ".config");
13465
- return join23(xdg, "kimiflare", "commands");
13924
+ const xdg = process.env.XDG_CONFIG_HOME || join24(homedir14(), ".config");
13925
+ return join24(xdg, "kimiflare", "commands");
13466
13926
  }
13467
13927
  async function loadCustomCommands(cwd = process.cwd()) {
13468
13928
  const warnings = [];
@@ -13869,9 +14329,9 @@ var init_save = __esm({
13869
14329
 
13870
14330
  // src/ui/command-wizard.tsx
13871
14331
  import { useState as useState10 } from "react";
13872
- import { Box as Box16, Text as Text17, useInput as useInput7, useWindowSize } from "ink";
14332
+ import { Box as Box17, Text as Text18, useInput as useInput7, useWindowSize } from "ink";
13873
14333
  import SelectInput6 from "ink-select-input";
13874
- import { Fragment as Fragment2, jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
14334
+ import { Fragment as Fragment2, jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
13875
14335
  function CommandWizard({ mode, initial, existingNames, builtinNames, onDone, onSave }) {
13876
14336
  const theme = useTheme();
13877
14337
  const [step, setStep] = useState10("name");
@@ -13995,8 +14455,8 @@ ${template}`;
13995
14455
  const renderStep = () => {
13996
14456
  switch (step) {
13997
14457
  case "name":
13998
- return /* @__PURE__ */ jsxs16(Fragment2, { children: [
13999
- /* @__PURE__ */ jsxs16(Text17, { color: theme.accent, bold: true, children: [
14458
+ return /* @__PURE__ */ jsxs17(Fragment2, { children: [
14459
+ /* @__PURE__ */ jsxs17(Text18, { color: theme.accent, bold: true, children: [
14000
14460
  mode === "create" ? "Create" : "Edit",
14001
14461
  " custom command \u2014 Name (",
14002
14462
  stepIndex,
@@ -14004,8 +14464,8 @@ ${template}`;
14004
14464
  totalSteps,
14005
14465
  ")"
14006
14466
  ] }),
14007
- error && /* @__PURE__ */ jsx18(Text17, { color: theme.error, children: error }),
14008
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
14467
+ error && /* @__PURE__ */ jsx19(Text18, { color: theme.error, children: error }),
14468
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
14009
14469
  CustomTextInput,
14010
14470
  {
14011
14471
  value: name,
@@ -14014,11 +14474,11 @@ ${template}`;
14014
14474
  focus: true
14015
14475
  }
14016
14476
  ) }),
14017
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, children: "letters, numbers, _ - / only; must start with a letter" })
14477
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, children: "letters, numbers, _ - / only; must start with a letter" })
14018
14478
  ] });
14019
14479
  case "description":
14020
- return /* @__PURE__ */ jsxs16(Fragment2, { children: [
14021
- /* @__PURE__ */ jsxs16(Text17, { color: theme.accent, bold: true, children: [
14480
+ return /* @__PURE__ */ jsxs17(Fragment2, { children: [
14481
+ /* @__PURE__ */ jsxs17(Text18, { color: theme.accent, bold: true, children: [
14022
14482
  mode === "create" ? "Create" : "Edit",
14023
14483
  " custom command \u2014 Description (",
14024
14484
  stepIndex,
@@ -14026,7 +14486,7 @@ ${template}`;
14026
14486
  totalSteps,
14027
14487
  ")"
14028
14488
  ] }),
14029
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
14489
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
14030
14490
  CustomTextInput,
14031
14491
  {
14032
14492
  value: description,
@@ -14035,49 +14495,49 @@ ${template}`;
14035
14495
  focus: true
14036
14496
  }
14037
14497
  ) }),
14038
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, children: "Press Enter to skip" })
14498
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, children: "Press Enter to skip" })
14039
14499
  ] });
14040
14500
  case "template": {
14041
- const guide = /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", paddingLeft: 1, children: [
14042
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "What is this?" }),
14043
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, children: "A prompt template \u2014 instructions to the AI." }),
14044
- /* @__PURE__ */ jsxs16(Text17, { color: theme.info.color, children: [
14501
+ const guide = /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", paddingLeft: 1, children: [
14502
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: "What is this?" }),
14503
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, children: "A prompt template \u2014 instructions to the AI." }),
14504
+ /* @__PURE__ */ jsxs17(Text18, { color: theme.info.color, children: [
14045
14505
  "When you type /",
14046
14506
  name || "yourcommand",
14047
14507
  " later, this gets sent to the model."
14048
14508
  ] }),
14049
- /* @__PURE__ */ jsxs16(Box16, { marginTop: 1, flexDirection: "column", children: [
14050
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Variables" }),
14051
- /* @__PURE__ */ jsxs16(Text17, { color: theme.info.color, children: [
14509
+ /* @__PURE__ */ jsxs17(Box17, { marginTop: 1, flexDirection: "column", children: [
14510
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: "Variables" }),
14511
+ /* @__PURE__ */ jsxs17(Text18, { color: theme.info.color, children: [
14052
14512
  " ",
14053
14513
  "$1, $2 ... \u2192 arguments you type"
14054
14514
  ] }),
14055
- /* @__PURE__ */ jsxs16(Text17, { color: theme.info.color, children: [
14515
+ /* @__PURE__ */ jsxs17(Text18, { color: theme.info.color, children: [
14056
14516
  " ",
14057
14517
  "$ARGUMENTS \u2192 everything after the command"
14058
14518
  ] })
14059
14519
  ] }),
14060
- /* @__PURE__ */ jsxs16(Box16, { marginTop: 1, flexDirection: "column", children: [
14061
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Dynamic inlines" }),
14062
- /* @__PURE__ */ jsxs16(Text17, { color: theme.info.color, children: [
14520
+ /* @__PURE__ */ jsxs17(Box17, { marginTop: 1, flexDirection: "column", children: [
14521
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: "Dynamic inlines" }),
14522
+ /* @__PURE__ */ jsxs17(Text18, { color: theme.info.color, children: [
14063
14523
  " ",
14064
14524
  "!`git diff` \u2192 shell output inlined"
14065
14525
  ] }),
14066
- /* @__PURE__ */ jsxs16(Text17, { color: theme.info.color, children: [
14526
+ /* @__PURE__ */ jsxs17(Text18, { color: theme.info.color, children: [
14067
14527
  " ",
14068
14528
  "@README.md \u2192 file contents inlined"
14069
14529
  ] })
14070
14530
  ] }),
14071
- /* @__PURE__ */ jsxs16(Box16, { marginTop: 1, flexDirection: "column", children: [
14072
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Example" }),
14073
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, children: "Review this PR diff:" }),
14074
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, children: "!`git diff main...HEAD`" }),
14075
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, children: "Focus on: $1" })
14531
+ /* @__PURE__ */ jsxs17(Box17, { marginTop: 1, flexDirection: "column", children: [
14532
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: "Example" }),
14533
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, children: "Review this PR diff:" }),
14534
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, children: "!`git diff main...HEAD`" }),
14535
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, children: "Focus on: $1" })
14076
14536
  ] })
14077
14537
  ] });
14078
- const inputArea = /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", flexGrow: 1, children: [
14079
- error && /* @__PURE__ */ jsx18(Text17, { color: theme.error, children: error }),
14080
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
14538
+ const inputArea = /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", flexGrow: 1, children: [
14539
+ error && /* @__PURE__ */ jsx19(Text18, { color: theme.error, children: error }),
14540
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
14081
14541
  CustomTextInput,
14082
14542
  {
14083
14543
  value: template,
@@ -14087,13 +14547,13 @@ ${template}`;
14087
14547
  enablePaste: true
14088
14548
  }
14089
14549
  ) }),
14090
- columns < 100 && /* @__PURE__ */ jsxs16(Fragment2, { children: [
14091
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, children: "Paste multi-line templates with Ctrl+V." }),
14092
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, children: "Variables: $1 $2 ... $ARGUMENTS Shell: !`cmd` File: @path" })
14550
+ columns < 100 && /* @__PURE__ */ jsxs17(Fragment2, { children: [
14551
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, children: "Paste multi-line templates with Ctrl+V." }),
14552
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, children: "Variables: $1 $2 ... $ARGUMENTS Shell: !`cmd` File: @path" })
14093
14553
  ] })
14094
14554
  ] });
14095
- return /* @__PURE__ */ jsxs16(Fragment2, { children: [
14096
- /* @__PURE__ */ jsxs16(Text17, { color: theme.accent, bold: true, children: [
14555
+ return /* @__PURE__ */ jsxs17(Fragment2, { children: [
14556
+ /* @__PURE__ */ jsxs17(Text18, { color: theme.accent, bold: true, children: [
14097
14557
  mode === "create" ? "Create" : "Edit",
14098
14558
  " custom command \u2014 Template (",
14099
14559
  stepIndex,
@@ -14101,10 +14561,10 @@ ${template}`;
14101
14561
  totalSteps,
14102
14562
  ")"
14103
14563
  ] }),
14104
- columns >= 100 ? /* @__PURE__ */ jsxs16(Box16, { flexDirection: "row", marginTop: 1, children: [
14105
- /* @__PURE__ */ jsx18(Box16, { flexDirection: "column", width: "50%", children: inputArea }),
14106
- /* @__PURE__ */ jsx18(Box16, { flexDirection: "column", width: "50%", children: guide })
14107
- ] }) : /* @__PURE__ */ jsx18(Box16, { flexDirection: "column", marginTop: 1, children: inputArea })
14564
+ columns >= 100 ? /* @__PURE__ */ jsxs17(Box17, { flexDirection: "row", marginTop: 1, children: [
14565
+ /* @__PURE__ */ jsx19(Box17, { flexDirection: "column", width: "50%", children: inputArea }),
14566
+ /* @__PURE__ */ jsx19(Box17, { flexDirection: "column", width: "50%", children: guide })
14567
+ ] }) : /* @__PURE__ */ jsx19(Box17, { flexDirection: "column", marginTop: 1, children: inputArea })
14108
14568
  ] });
14109
14569
  }
14110
14570
  case "advanced": {
@@ -14113,8 +14573,8 @@ ${template}`;
14113
14573
  { label: "Skip", value: "skip", key: "skip" },
14114
14574
  { label: "\u2190 Cancel", value: "cancel", key: "cancel" }
14115
14575
  ];
14116
- return /* @__PURE__ */ jsxs16(Fragment2, { children: [
14117
- /* @__PURE__ */ jsxs16(Text17, { color: theme.accent, bold: true, children: [
14576
+ return /* @__PURE__ */ jsxs17(Fragment2, { children: [
14577
+ /* @__PURE__ */ jsxs17(Text18, { color: theme.accent, bold: true, children: [
14118
14578
  mode === "create" ? "Create" : "Edit",
14119
14579
  " custom command \u2014 Options (",
14120
14580
  stepIndex,
@@ -14122,7 +14582,7 @@ ${template}`;
14122
14582
  totalSteps,
14123
14583
  ")"
14124
14584
  ] }),
14125
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
14585
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
14126
14586
  SelectInput6,
14127
14587
  {
14128
14588
  items,
@@ -14142,16 +14602,16 @@ ${template}`;
14142
14602
  { label: cmdMode === "auto" ? "auto \xB7 current" : "auto", value: "auto", key: "auto" },
14143
14603
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
14144
14604
  ];
14145
- return /* @__PURE__ */ jsxs16(Fragment2, { children: [
14146
- /* @__PURE__ */ jsxs16(Text17, { color: theme.accent, bold: true, children: [
14605
+ return /* @__PURE__ */ jsxs17(Fragment2, { children: [
14606
+ /* @__PURE__ */ jsxs17(Text18, { color: theme.accent, bold: true, children: [
14147
14607
  "Mode override (",
14148
14608
  stepIndex,
14149
14609
  "/",
14150
14610
  totalSteps,
14151
14611
  ")"
14152
14612
  ] }),
14153
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, children: "Saved to file but not yet enforced at runtime" }),
14154
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
14613
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, children: "Saved to file but not yet enforced at runtime" }),
14614
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
14155
14615
  SelectInput6,
14156
14616
  {
14157
14617
  items,
@@ -14171,15 +14631,15 @@ ${template}`;
14171
14631
  { label: cmdEffort === "high" ? "high \xB7 current" : "high", value: "high", key: "high" },
14172
14632
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
14173
14633
  ];
14174
- return /* @__PURE__ */ jsxs16(Fragment2, { children: [
14175
- /* @__PURE__ */ jsxs16(Text17, { color: theme.accent, bold: true, children: [
14634
+ return /* @__PURE__ */ jsxs17(Fragment2, { children: [
14635
+ /* @__PURE__ */ jsxs17(Text18, { color: theme.accent, bold: true, children: [
14176
14636
  "Reasoning effort (",
14177
14637
  stepIndex,
14178
14638
  "/",
14179
14639
  totalSteps,
14180
14640
  ")"
14181
14641
  ] }),
14182
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
14642
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
14183
14643
  SelectInput6,
14184
14644
  {
14185
14645
  items,
@@ -14192,15 +14652,15 @@ ${template}`;
14192
14652
  ] });
14193
14653
  }
14194
14654
  case "model":
14195
- return /* @__PURE__ */ jsxs16(Fragment2, { children: [
14196
- /* @__PURE__ */ jsxs16(Text17, { color: theme.accent, bold: true, children: [
14655
+ return /* @__PURE__ */ jsxs17(Fragment2, { children: [
14656
+ /* @__PURE__ */ jsxs17(Text18, { color: theme.accent, bold: true, children: [
14197
14657
  "Model override (",
14198
14658
  stepIndex,
14199
14659
  "/",
14200
14660
  totalSteps,
14201
14661
  ")"
14202
14662
  ] }),
14203
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
14663
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
14204
14664
  CustomTextInput,
14205
14665
  {
14206
14666
  value: cmdModel ?? "",
@@ -14209,7 +14669,7 @@ ${template}`;
14209
14669
  focus: true
14210
14670
  }
14211
14671
  ) }),
14212
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, children: "Press Enter to skip" })
14672
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, children: "Press Enter to skip" })
14213
14673
  ] });
14214
14674
  case "location": {
14215
14675
  const items = [
@@ -14217,15 +14677,15 @@ ${template}`;
14217
14677
  { label: source === "global" ? "Global \xB7 current" : "Global", value: "global", key: "global" },
14218
14678
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
14219
14679
  ];
14220
- return /* @__PURE__ */ jsxs16(Fragment2, { children: [
14221
- /* @__PURE__ */ jsxs16(Text17, { color: theme.accent, bold: true, children: [
14680
+ return /* @__PURE__ */ jsxs17(Fragment2, { children: [
14681
+ /* @__PURE__ */ jsxs17(Text18, { color: theme.accent, bold: true, children: [
14222
14682
  "Save location (",
14223
14683
  stepIndex,
14224
14684
  "/",
14225
14685
  totalSteps,
14226
14686
  ")"
14227
14687
  ] }),
14228
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
14688
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
14229
14689
  SelectInput6,
14230
14690
  {
14231
14691
  items,
@@ -14235,7 +14695,7 @@ ${template}`;
14235
14695
  }
14236
14696
  }
14237
14697
  ) }),
14238
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, children: "Project: .kimiflare/commands/ Global: ~/.config/kimiflare/commands/" })
14698
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, children: "Project: .kimiflare/commands/ Global: ~/.config/kimiflare/commands/" })
14239
14699
  ] });
14240
14700
  }
14241
14701
  case "confirm": {
@@ -14243,8 +14703,8 @@ ${template}`;
14243
14703
  { label: "Save", value: "save", key: "save" },
14244
14704
  { label: "Cancel", value: "cancel", key: "cancel" }
14245
14705
  ];
14246
- return /* @__PURE__ */ jsxs16(Fragment2, { children: [
14247
- /* @__PURE__ */ jsxs16(Text17, { color: theme.accent, bold: true, children: [
14706
+ return /* @__PURE__ */ jsxs17(Fragment2, { children: [
14707
+ /* @__PURE__ */ jsxs17(Text18, { color: theme.accent, bold: true, children: [
14248
14708
  mode === "create" ? "Create" : "Edit",
14249
14709
  " custom command \u2014 Confirm (",
14250
14710
  stepIndex,
@@ -14252,13 +14712,13 @@ ${template}`;
14252
14712
  totalSteps,
14253
14713
  ")"
14254
14714
  ] }),
14255
- /* @__PURE__ */ jsxs16(Text17, { color: theme.info.color, children: [
14715
+ /* @__PURE__ */ jsxs17(Text18, { color: theme.info.color, children: [
14256
14716
  source === "project" ? ".kimiflare/commands/" : "~/.config/kimiflare/commands/",
14257
14717
  name,
14258
14718
  ".md"
14259
14719
  ] }),
14260
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, flexDirection: "column", children: previewContent().split("\n").map((line, i) => /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, children: line || " " }, i)) }),
14261
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
14720
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, flexDirection: "column", children: previewContent().split("\n").map((line, i) => /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, children: line || " " }, i)) }),
14721
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
14262
14722
  SelectInput6,
14263
14723
  {
14264
14724
  items,
@@ -14269,7 +14729,7 @@ ${template}`;
14269
14729
  }
14270
14730
  }
14271
14731
  };
14272
- return /* @__PURE__ */ jsx18(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: renderStep() });
14732
+ return /* @__PURE__ */ jsx19(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: renderStep() });
14273
14733
  }
14274
14734
  var NAME_RE;
14275
14735
  var init_command_wizard = __esm({
@@ -14283,12 +14743,12 @@ var init_command_wizard = __esm({
14283
14743
 
14284
14744
  // src/init/context-generator.ts
14285
14745
  import { existsSync as existsSync3, statSync as statSync3 } from "fs";
14286
- import { join as join24 } from "path";
14746
+ import { join as join25 } from "path";
14287
14747
  function detectFlavor(cwd) {
14288
14748
  for (const [flavor, signatures] of Object.entries(FLAVOR_SIGNATURES)) {
14289
14749
  if (flavor === "generic") continue;
14290
14750
  for (const sig of signatures) {
14291
- const path = join24(cwd, sig);
14751
+ const path = join25(cwd, sig);
14292
14752
  if (sig.includes("*")) {
14293
14753
  try {
14294
14754
  const parts = sig.split("*");
@@ -14309,14 +14769,14 @@ function detectFlavor(cwd) {
14309
14769
  }
14310
14770
  function findFile(cwd, candidates) {
14311
14771
  for (const c of candidates) {
14312
- if (existsSync3(join24(cwd, c))) return c;
14772
+ if (existsSync3(join25(cwd, c))) return c;
14313
14773
  }
14314
14774
  return null;
14315
14775
  }
14316
14776
  function findSourceRoots(cwd) {
14317
14777
  const roots = [];
14318
14778
  for (const r of SOURCE_ROOT_CANDIDATES) {
14319
- const p = join24(cwd, r);
14779
+ const p = join25(cwd, r);
14320
14780
  try {
14321
14781
  const s = statSync3(p);
14322
14782
  if (s.isDirectory()) roots.push(r);
@@ -14327,9 +14787,9 @@ function findSourceRoots(cwd) {
14327
14787
  }
14328
14788
  function findCiConfig(cwd) {
14329
14789
  for (const c of CI_PATHS) {
14330
- if (existsSync3(join24(cwd, c))) {
14790
+ if (existsSync3(join25(cwd, c))) {
14331
14791
  try {
14332
- const s = statSync3(join24(cwd, c));
14792
+ const s = statSync3(join25(cwd, c));
14333
14793
  return s.isDirectory() ? c : c;
14334
14794
  } catch {
14335
14795
  }
@@ -14466,7 +14926,7 @@ function analyzeProject(cwd) {
14466
14926
  ciConfig: findCiConfig(cwd),
14467
14927
  readme: findFile(cwd, ["README.md", "README.rst", "README.txt", "Readme.md"]),
14468
14928
  sourceRoots: findSourceRoots(cwd),
14469
- hasGit: existsSync3(join24(cwd, ".git"))
14929
+ hasGit: existsSync3(join25(cwd, ".git"))
14470
14930
  };
14471
14931
  }
14472
14932
  function bashDiscoveryCommands(profile) {
@@ -14631,7 +15091,7 @@ Aim for 100\u2013200 lines total. Use markdown tables where they save space.
14631
15091
  }
14632
15092
  function buildInitPrompt(cwd) {
14633
15093
  const existingName = ["KIMI.md", "KIMIFLARE.md", "AGENT.md"].find(
14634
- (n) => existsSync3(join24(cwd, n))
15094
+ (n) => existsSync3(join25(cwd, n))
14635
15095
  );
14636
15096
  const isRefresh = existingName !== void 0;
14637
15097
  const targetFilename = existingName ?? "KIMI.md";
@@ -14714,9 +15174,9 @@ var init_context_generator = __esm({
14714
15174
  });
14715
15175
 
14716
15176
  // src/ui/command-picker.tsx
14717
- import { Box as Box17, Text as Text18 } from "ink";
15177
+ import { Box as Box18, Text as Text19 } from "ink";
14718
15178
  import SelectInput7 from "ink-select-input";
14719
- import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
15179
+ import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
14720
15180
  function CommandPicker({ commands, title, onPick }) {
14721
15181
  const theme = useTheme();
14722
15182
  const items = commands.map((cmd) => ({
@@ -14725,10 +15185,10 @@ function CommandPicker({ commands, title, onPick }) {
14725
15185
  key: cmd.name
14726
15186
  }));
14727
15187
  items.push({ label: "\u2190 Cancel", value: null, key: "__cancel__" });
14728
- return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
14729
- /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: title }),
14730
- /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select." }),
14731
- /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
15188
+ return /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
15189
+ /* @__PURE__ */ jsx20(Text19, { color: theme.accent, bold: true, children: title }),
15190
+ /* @__PURE__ */ jsx20(Text19, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select." }),
15191
+ /* @__PURE__ */ jsx20(Box18, { marginTop: 1, children: /* @__PURE__ */ jsx20(
14732
15192
  SelectInput7,
14733
15193
  {
14734
15194
  items,
@@ -14751,8 +15211,8 @@ var init_command_picker = __esm({
14751
15211
  });
14752
15212
 
14753
15213
  // src/ui/command-list.tsx
14754
- import { Box as Box18, Text as Text19, useInput as useInput8 } from "ink";
14755
- import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
15214
+ import { Box as Box19, Text as Text20, useInput as useInput8 } from "ink";
15215
+ import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
14756
15216
  function CommandList({ commands, onDone }) {
14757
15217
  const theme = useTheme();
14758
15218
  useInput8((_input, key) => {
@@ -14760,55 +15220,55 @@ function CommandList({ commands, onDone }) {
14760
15220
  onDone();
14761
15221
  }
14762
15222
  });
14763
- return /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
14764
- /* @__PURE__ */ jsx20(Text19, { color: theme.accent, bold: true, children: "Custom commands" }),
14765
- /* @__PURE__ */ jsx20(Text19, { color: theme.info.color, dimColor: false, children: "Esc to close." }),
14766
- /* @__PURE__ */ jsxs18(Box18, { marginTop: 1, flexDirection: "column", children: [
14767
- commands.length === 0 && /* @__PURE__ */ jsx20(Text19, { color: theme.info.color, children: "No custom commands found." }),
14768
- commands.map((cmd) => /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", marginBottom: 1, children: [
14769
- /* @__PURE__ */ jsxs18(Text19, { color: theme.accent, bold: true, children: [
15223
+ return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
15224
+ /* @__PURE__ */ jsx21(Text20, { color: theme.accent, bold: true, children: "Custom commands" }),
15225
+ /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, dimColor: false, children: "Esc to close." }),
15226
+ /* @__PURE__ */ jsxs19(Box19, { marginTop: 1, flexDirection: "column", children: [
15227
+ commands.length === 0 && /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, children: "No custom commands found." }),
15228
+ commands.map((cmd) => /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", marginBottom: 1, children: [
15229
+ /* @__PURE__ */ jsxs19(Text20, { color: theme.accent, bold: true, children: [
14770
15230
  "/",
14771
15231
  cmd.name
14772
15232
  ] }),
14773
- /* @__PURE__ */ jsxs18(Text19, { color: theme.info.color, children: [
15233
+ /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
14774
15234
  " ",
14775
15235
  "source: ",
14776
15236
  cmd.source
14777
15237
  ] }),
14778
- /* @__PURE__ */ jsxs18(Text19, { color: theme.info.color, children: [
15238
+ /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
14779
15239
  " ",
14780
15240
  "path: ",
14781
15241
  cmd.filepath
14782
15242
  ] }),
14783
- cmd.description && /* @__PURE__ */ jsxs18(Text19, { color: theme.info.color, children: [
15243
+ cmd.description && /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
14784
15244
  " ",
14785
15245
  "desc: ",
14786
15246
  cmd.description
14787
15247
  ] }),
14788
- cmd.mode && /* @__PURE__ */ jsxs18(Text19, { color: theme.info.color, children: [
15248
+ cmd.mode && /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
14789
15249
  " ",
14790
15250
  "mode: ",
14791
15251
  cmd.mode
14792
15252
  ] }),
14793
- cmd.effort && /* @__PURE__ */ jsxs18(Text19, { color: theme.info.color, children: [
15253
+ cmd.effort && /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
14794
15254
  " ",
14795
15255
  "effort: ",
14796
15256
  cmd.effort
14797
15257
  ] }),
14798
- cmd.model && /* @__PURE__ */ jsxs18(Text19, { color: theme.info.color, children: [
15258
+ cmd.model && /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
14799
15259
  " ",
14800
15260
  "model: ",
14801
15261
  cmd.model
14802
15262
  ] }),
14803
- /* @__PURE__ */ jsxs18(Text19, { color: theme.info.color, children: [
15263
+ /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
14804
15264
  " ",
14805
15265
  "template:"
14806
15266
  ] }),
14807
- cmd.template.split("\n").slice(0, 5).map((line, i) => /* @__PURE__ */ jsxs18(Text19, { color: theme.info.color, children: [
15267
+ cmd.template.split("\n").slice(0, 5).map((line, i) => /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
14808
15268
  " ",
14809
15269
  line || " "
14810
15270
  ] }, i)),
14811
- cmd.template.split("\n").length > 5 && /* @__PURE__ */ jsxs18(Text19, { color: theme.info.color, children: [
15271
+ cmd.template.split("\n").length > 5 && /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
14812
15272
  " ",
14813
15273
  "..."
14814
15274
  ] })
@@ -14825,10 +15285,10 @@ var init_command_list = __esm({
14825
15285
 
14826
15286
  // src/ui/lsp-wizard.tsx
14827
15287
  import { useState as useState11 } from "react";
14828
- import { Box as Box19, Text as Text20 } from "ink";
15288
+ import { Box as Box20, Text as Text21 } from "ink";
14829
15289
  import SelectInput8 from "ink-select-input";
14830
15290
  import { spawn as spawn3 } from "child_process";
14831
- import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
15291
+ import { jsx as jsx22, jsxs as jsxs20 } from "react/jsx-runtime";
14832
15292
  function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
14833
15293
  const theme = useTheme();
14834
15294
  const [page, setPage] = useState11("main");
@@ -14940,10 +15400,10 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
14940
15400
  { label: "(close)", value: "__close__", key: "__close__" }
14941
15401
  ];
14942
15402
  if (page === "main") {
14943
- return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
14944
- /* @__PURE__ */ jsx21(Text20, { color: theme.accent, bold: true, children: "LSP Servers" }),
14945
- /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select." }),
14946
- /* @__PURE__ */ jsx21(Box19, { marginTop: 1, children: /* @__PURE__ */ jsx21(
15403
+ return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
15404
+ /* @__PURE__ */ jsx22(Text21, { color: theme.accent, bold: true, children: "LSP Servers" }),
15405
+ /* @__PURE__ */ jsx22(Text21, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select." }),
15406
+ /* @__PURE__ */ jsx22(Box20, { marginTop: 1, children: /* @__PURE__ */ jsx22(
14947
15407
  SelectInput8,
14948
15408
  {
14949
15409
  items: mainItems,
@@ -14971,10 +15431,10 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
14971
15431
  }),
14972
15432
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
14973
15433
  ];
14974
- return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
14975
- /* @__PURE__ */ jsx21(Text20, { color: theme.accent, bold: true, children: "Add LSP Server" }),
14976
- /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, dimColor: false, children: "Select a language server to configure." }),
14977
- /* @__PURE__ */ jsx21(Box19, { marginTop: 1, children: /* @__PURE__ */ jsx21(
15434
+ return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
15435
+ /* @__PURE__ */ jsx22(Text21, { color: theme.accent, bold: true, children: "Add LSP Server" }),
15436
+ /* @__PURE__ */ jsx22(Text21, { color: theme.info.color, dimColor: false, children: "Select a language server to configure." }),
15437
+ /* @__PURE__ */ jsx22(Box20, { marginTop: 1, children: /* @__PURE__ */ jsx22(
14978
15438
  SelectInput8,
14979
15439
  {
14980
15440
  items,
@@ -15002,18 +15462,18 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
15002
15462
  { label: isSuccess ? "Save to config \u2713" : "Save anyway", value: "save", key: "save" },
15003
15463
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
15004
15464
  ];
15005
- return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
15006
- /* @__PURE__ */ jsxs19(Text20, { color: theme.accent, bold: true, children: [
15465
+ return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
15466
+ /* @__PURE__ */ jsxs20(Text21, { color: theme.accent, bold: true, children: [
15007
15467
  "Install ",
15008
15468
  selectedPreset.name
15009
15469
  ] }),
15010
- /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, dimColor: false, children: selectedPreset.installHint }),
15011
- /* @__PURE__ */ jsxs19(Box19, { marginTop: 1, flexDirection: "column", children: [
15012
- /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, dimColor: false, children: "Command:" }),
15013
- /* @__PURE__ */ jsx21(Text20, { color: theme.accent, children: selectedPreset.installCommand || "(none required)" })
15470
+ /* @__PURE__ */ jsx22(Text21, { color: theme.info.color, dimColor: false, children: selectedPreset.installHint }),
15471
+ /* @__PURE__ */ jsxs20(Box20, { marginTop: 1, flexDirection: "column", children: [
15472
+ /* @__PURE__ */ jsx22(Text21, { color: theme.info.color, dimColor: false, children: "Command:" }),
15473
+ /* @__PURE__ */ jsx22(Text21, { color: theme.accent, children: selectedPreset.installCommand || "(none required)" })
15014
15474
  ] }),
15015
- installState.output && /* @__PURE__ */ jsx21(Box19, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx21(Text20, { color: isSuccess ? theme.accent : theme.error, children: installState.output.slice(-500) }) }),
15016
- /* @__PURE__ */ jsx21(Box19, { marginTop: 1, children: /* @__PURE__ */ jsx21(
15475
+ installState.output && /* @__PURE__ */ jsx22(Box20, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx22(Text21, { color: isSuccess ? theme.accent : theme.error, children: installState.output.slice(-500) }) }),
15476
+ /* @__PURE__ */ jsx22(Box20, { marginTop: 1, children: /* @__PURE__ */ jsx22(
15017
15477
  SelectInput8,
15018
15478
  {
15019
15479
  items,
@@ -15031,16 +15491,16 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
15031
15491
  }
15032
15492
  }
15033
15493
  ) }),
15034
- isSuccess && /* @__PURE__ */ jsx21(Box19, { marginTop: 1, children: /* @__PURE__ */ jsx21(Text20, { color: theme.accent, children: "Server saved. Run /lsp reload to start it." }) })
15494
+ isSuccess && /* @__PURE__ */ jsx22(Box20, { marginTop: 1, children: /* @__PURE__ */ jsx22(Text21, { color: theme.accent, children: "Server saved. Run /lsp reload to start it." }) })
15035
15495
  ] });
15036
15496
  }
15037
15497
  if (page === "custom-name") {
15038
- return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
15039
- /* @__PURE__ */ jsx21(Text20, { color: theme.accent, bold: true, children: "Custom LSP Server \u2014 Name" }),
15040
- /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, dimColor: false, children: "Enter a name for this server (e.g., my-server)." }),
15041
- /* @__PURE__ */ jsxs19(Box19, { marginTop: 1, children: [
15042
- /* @__PURE__ */ jsx21(Text20, { color: theme.accent, children: "\u203A " }),
15043
- /* @__PURE__ */ jsx21(
15498
+ return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
15499
+ /* @__PURE__ */ jsx22(Text21, { color: theme.accent, bold: true, children: "Custom LSP Server \u2014 Name" }),
15500
+ /* @__PURE__ */ jsx22(Text21, { color: theme.info.color, dimColor: false, children: "Enter a name for this server (e.g., my-server)." }),
15501
+ /* @__PURE__ */ jsxs20(Box20, { marginTop: 1, children: [
15502
+ /* @__PURE__ */ jsx22(Text21, { color: theme.accent, children: "\u203A " }),
15503
+ /* @__PURE__ */ jsx22(
15044
15504
  CustomTextInput,
15045
15505
  {
15046
15506
  value: customName,
@@ -15054,7 +15514,7 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
15054
15514
  }
15055
15515
  )
15056
15516
  ] }),
15057
- /* @__PURE__ */ jsx21(Box19, { marginTop: 1, children: /* @__PURE__ */ jsx21(
15517
+ /* @__PURE__ */ jsx22(Box20, { marginTop: 1, children: /* @__PURE__ */ jsx22(
15058
15518
  SelectInput8,
15059
15519
  {
15060
15520
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
@@ -15064,12 +15524,12 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
15064
15524
  ] });
15065
15525
  }
15066
15526
  if (page === "custom-command") {
15067
- return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
15068
- /* @__PURE__ */ jsx21(Text20, { color: theme.accent, bold: true, children: "Custom LSP Server \u2014 Command" }),
15069
- /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, dimColor: false, children: "Enter the command to start the server (space-separated)." }),
15070
- /* @__PURE__ */ jsxs19(Box19, { marginTop: 1, children: [
15071
- /* @__PURE__ */ jsx21(Text20, { color: theme.accent, children: "\u203A " }),
15072
- /* @__PURE__ */ jsx21(
15527
+ return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
15528
+ /* @__PURE__ */ jsx22(Text21, { color: theme.accent, bold: true, children: "Custom LSP Server \u2014 Command" }),
15529
+ /* @__PURE__ */ jsx22(Text21, { color: theme.info.color, dimColor: false, children: "Enter the command to start the server (space-separated)." }),
15530
+ /* @__PURE__ */ jsxs20(Box20, { marginTop: 1, children: [
15531
+ /* @__PURE__ */ jsx22(Text21, { color: theme.accent, children: "\u203A " }),
15532
+ /* @__PURE__ */ jsx22(
15073
15533
  CustomTextInput,
15074
15534
  {
15075
15535
  value: customCommand,
@@ -15083,7 +15543,7 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
15083
15543
  }
15084
15544
  )
15085
15545
  ] }),
15086
- /* @__PURE__ */ jsx21(Box19, { marginTop: 1, children: /* @__PURE__ */ jsx21(
15546
+ /* @__PURE__ */ jsx22(Box20, { marginTop: 1, children: /* @__PURE__ */ jsx22(
15087
15547
  SelectInput8,
15088
15548
  {
15089
15549
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
@@ -15107,10 +15567,10 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
15107
15567
  },
15108
15568
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
15109
15569
  ];
15110
- return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
15111
- /* @__PURE__ */ jsx21(Text20, { color: theme.accent, bold: true, children: "Save LSP Config" }),
15112
- /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, dimColor: false, children: "Where should this server configuration be saved?" }),
15113
- /* @__PURE__ */ jsx21(Box19, { marginTop: 1, children: /* @__PURE__ */ jsx21(
15570
+ return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
15571
+ /* @__PURE__ */ jsx22(Text21, { color: theme.accent, bold: true, children: "Save LSP Config" }),
15572
+ /* @__PURE__ */ jsx22(Text21, { color: theme.info.color, dimColor: false, children: "Where should this server configuration be saved?" }),
15573
+ /* @__PURE__ */ jsx22(Box20, { marginTop: 1, children: /* @__PURE__ */ jsx22(
15114
15574
  SelectInput8,
15115
15575
  {
15116
15576
  items,
@@ -15129,10 +15589,10 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
15129
15589
  if (page === "edit") {
15130
15590
  const keys = Object.keys(servers);
15131
15591
  if (keys.length === 0) {
15132
- return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
15133
- /* @__PURE__ */ jsx21(Text20, { color: theme.accent, bold: true, children: "Edit LSP Server" }),
15134
- /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, children: "No servers configured." }),
15135
- /* @__PURE__ */ jsx21(Box19, { marginTop: 1, children: /* @__PURE__ */ jsx21(
15592
+ return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
15593
+ /* @__PURE__ */ jsx22(Text21, { color: theme.accent, bold: true, children: "Edit LSP Server" }),
15594
+ /* @__PURE__ */ jsx22(Text21, { color: theme.info.color, children: "No servers configured." }),
15595
+ /* @__PURE__ */ jsx22(Box20, { marginTop: 1, children: /* @__PURE__ */ jsx22(
15136
15596
  SelectInput8,
15137
15597
  {
15138
15598
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
@@ -15153,10 +15613,10 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
15153
15613
  }),
15154
15614
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
15155
15615
  ];
15156
- return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
15157
- /* @__PURE__ */ jsx21(Text20, { color: theme.accent, bold: true, children: "Edit LSP Server" }),
15158
- /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, dimColor: false, children: "Select a server to toggle enabled/disabled." }),
15159
- /* @__PURE__ */ jsx21(Box19, { marginTop: 1, children: /* @__PURE__ */ jsx21(
15616
+ return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
15617
+ /* @__PURE__ */ jsx22(Text21, { color: theme.accent, bold: true, children: "Edit LSP Server" }),
15618
+ /* @__PURE__ */ jsx22(Text21, { color: theme.info.color, dimColor: false, children: "Select a server to toggle enabled/disabled." }),
15619
+ /* @__PURE__ */ jsx22(Box20, { marginTop: 1, children: /* @__PURE__ */ jsx22(
15160
15620
  SelectInput8,
15161
15621
  {
15162
15622
  items,
@@ -15174,10 +15634,10 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
15174
15634
  if (page === "delete") {
15175
15635
  const keys = Object.keys(servers);
15176
15636
  if (keys.length === 0) {
15177
- return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
15178
- /* @__PURE__ */ jsx21(Text20, { color: theme.accent, bold: true, children: "Delete LSP Server" }),
15179
- /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, children: "No servers configured." }),
15180
- /* @__PURE__ */ jsx21(Box19, { marginTop: 1, children: /* @__PURE__ */ jsx21(
15637
+ return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
15638
+ /* @__PURE__ */ jsx22(Text21, { color: theme.accent, bold: true, children: "Delete LSP Server" }),
15639
+ /* @__PURE__ */ jsx22(Text21, { color: theme.info.color, children: "No servers configured." }),
15640
+ /* @__PURE__ */ jsx22(Box20, { marginTop: 1, children: /* @__PURE__ */ jsx22(
15181
15641
  SelectInput8,
15182
15642
  {
15183
15643
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
@@ -15194,10 +15654,10 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
15194
15654
  })),
15195
15655
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
15196
15656
  ];
15197
- return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
15198
- /* @__PURE__ */ jsx21(Text20, { color: theme.accent, bold: true, children: "Delete LSP Server" }),
15199
- /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, dimColor: false, children: "Select a server to remove from config." }),
15200
- /* @__PURE__ */ jsx21(Box19, { marginTop: 1, children: /* @__PURE__ */ jsx21(
15657
+ return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
15658
+ /* @__PURE__ */ jsx22(Text21, { color: theme.accent, bold: true, children: "Delete LSP Server" }),
15659
+ /* @__PURE__ */ jsx22(Text21, { color: theme.info.color, dimColor: false, children: "Select a server to remove from config." }),
15660
+ /* @__PURE__ */ jsx22(Box20, { marginTop: 1, children: /* @__PURE__ */ jsx22(
15201
15661
  SelectInput8,
15202
15662
  {
15203
15663
  items,
@@ -15214,14 +15674,14 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
15214
15674
  }
15215
15675
  if (page === "list") {
15216
15676
  const keys = Object.keys(servers);
15217
- return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
15218
- /* @__PURE__ */ jsx21(Text20, { color: theme.accent, bold: true, children: "Configured LSP Servers" }),
15219
- keys.length === 0 ? /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, children: "No servers configured." }) : /* @__PURE__ */ jsx21(Box19, { marginTop: 1, flexDirection: "column", children: keys.map((k) => {
15677
+ return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
15678
+ /* @__PURE__ */ jsx22(Text21, { color: theme.accent, bold: true, children: "Configured LSP Servers" }),
15679
+ keys.length === 0 ? /* @__PURE__ */ jsx22(Text21, { color: theme.info.color, children: "No servers configured." }) : /* @__PURE__ */ jsx22(Box20, { marginTop: 1, flexDirection: "column", children: keys.map((k) => {
15220
15680
  const s = servers[k];
15221
15681
  const status = s.enabled !== false ? "enabled" : "disabled";
15222
- return /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, children: ` ${k.padEnd(16)} ${status} ${s.command.join(" ")}` }, k);
15682
+ return /* @__PURE__ */ jsx22(Text21, { color: theme.info.color, children: ` ${k.padEnd(16)} ${status} ${s.command.join(" ")}` }, k);
15223
15683
  }) }),
15224
- /* @__PURE__ */ jsx21(Box19, { marginTop: 1, children: /* @__PURE__ */ jsx21(
15684
+ /* @__PURE__ */ jsx22(Box20, { marginTop: 1, children: /* @__PURE__ */ jsx22(
15225
15685
  SelectInput8,
15226
15686
  {
15227
15687
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
@@ -15349,9 +15809,9 @@ var init_lsp_wizard = __esm({
15349
15809
  });
15350
15810
 
15351
15811
  // src/ui/theme-picker.tsx
15352
- import { Box as Box20, Text as Text21 } from "ink";
15812
+ import { Box as Box21, Text as Text22 } from "ink";
15353
15813
  import SelectInput9 from "ink-select-input";
15354
- import { jsx as jsx22, jsxs as jsxs20 } from "react/jsx-runtime";
15814
+ import { jsx as jsx23, jsxs as jsxs21 } from "react/jsx-runtime";
15355
15815
  function PaletteSwatches({ palette }) {
15356
15816
  const colors = [
15357
15817
  palette.primary,
@@ -15359,7 +15819,7 @@ function PaletteSwatches({ palette }) {
15359
15819
  palette.success,
15360
15820
  palette.error
15361
15821
  ];
15362
- return /* @__PURE__ */ jsx22(Box20, { children: colors.map((c, i) => /* @__PURE__ */ jsx22(Text21, { color: c, children: "\u2588" }, i)) });
15822
+ return /* @__PURE__ */ jsx23(Box21, { children: colors.map((c, i) => /* @__PURE__ */ jsx23(Text22, { color: c, children: "\u2588" }, i)) });
15363
15823
  }
15364
15824
  function ThemePicker({ themes, onPick }) {
15365
15825
  const current = useTheme();
@@ -15367,9 +15827,9 @@ function ThemePicker({ themes, onPick }) {
15367
15827
  ...themes.map((t) => ({ label: t.label, value: t.name })),
15368
15828
  { label: "< Back", value: "__back__" }
15369
15829
  ];
15370
- return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", borderStyle: "round", borderColor: current.accent, paddingX: 1, children: [
15371
- /* @__PURE__ */ jsx22(Text21, { color: current.accent, bold: true, children: "Pick a theme (restart to apply)" }),
15372
- /* @__PURE__ */ jsx22(Box20, { marginTop: 1, children: /* @__PURE__ */ jsx22(
15830
+ return /* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", borderStyle: "round", borderColor: current.accent, paddingX: 1, children: [
15831
+ /* @__PURE__ */ jsx23(Text22, { color: current.accent, bold: true, children: "Pick a theme (restart to apply)" }),
15832
+ /* @__PURE__ */ jsx23(Box21, { marginTop: 1, children: /* @__PURE__ */ jsx23(
15373
15833
  SelectInput9,
15374
15834
  {
15375
15835
  items,
@@ -15384,9 +15844,9 @@ function ThemePicker({ themes, onPick }) {
15384
15844
  itemComponent: ({ label, isSelected }) => {
15385
15845
  const t = themes.find((x) => x.label === label);
15386
15846
  const color = t?.accent ?? current.accent;
15387
- return /* @__PURE__ */ jsxs20(Box20, { children: [
15388
- /* @__PURE__ */ jsx22(Text21, { color, bold: isSelected, dimColor: !isSelected, children: label }),
15389
- t && /* @__PURE__ */ jsx22(Box20, { marginLeft: 1, children: /* @__PURE__ */ jsx22(PaletteSwatches, { palette: t.palette }) })
15847
+ return /* @__PURE__ */ jsxs21(Box21, { children: [
15848
+ /* @__PURE__ */ jsx23(Text22, { color, bold: isSelected, dimColor: !isSelected, children: label }),
15849
+ t && /* @__PURE__ */ jsx23(Box21, { marginLeft: 1, children: /* @__PURE__ */ jsx23(PaletteSwatches, { palette: t.palette }) })
15390
15850
  ] });
15391
15851
  }
15392
15852
  }
@@ -16273,11 +16733,11 @@ var init_wcag = __esm({
16273
16733
  });
16274
16734
 
16275
16735
  // src/ui/theme-loader.ts
16276
- import { readFile as readFile18, readdir as readdir5 } from "fs/promises";
16277
- import { join as join25 } from "path";
16736
+ import { readFile as readFile19, readdir as readdir6 } from "fs/promises";
16737
+ import { join as join26 } from "path";
16278
16738
  import { homedir as homedir15 } from "os";
16279
16739
  function projectThemesDir(cwd = process.cwd()) {
16280
- return join25(cwd, ".kimiflare", "themes");
16740
+ return join26(cwd, ".kimiflare", "themes");
16281
16741
  }
16282
16742
  function isHexColor(c) {
16283
16743
  return /^#[0-9a-fA-F]{6}$/.test(c);
@@ -16361,15 +16821,15 @@ async function loadThemesFromDir(dir, source) {
16361
16821
  const errors = [];
16362
16822
  let files;
16363
16823
  try {
16364
- files = await readdir5(dir);
16824
+ files = await readdir6(dir);
16365
16825
  } catch {
16366
16826
  return { themes, errors };
16367
16827
  }
16368
16828
  for (const file of files.filter((f) => f.endsWith(".json"))) {
16369
- const path = join25(dir, file);
16829
+ const path = join26(dir, file);
16370
16830
  let raw;
16371
16831
  try {
16372
- raw = await readFile18(path, "utf-8");
16832
+ raw = await readFile19(path, "utf-8");
16373
16833
  } catch (e) {
16374
16834
  errors.push(`${path}: ${e instanceof Error ? e.message : String(e)}`);
16375
16835
  continue;
@@ -16515,8 +16975,8 @@ var init_theme_loader = __esm({
16515
16975
  "use strict";
16516
16976
  init_wcag();
16517
16977
  init_theme();
16518
- USER_THEMES_DIR = join25(
16519
- process.env.XDG_CONFIG_HOME || join25(homedir15(), ".config"),
16978
+ USER_THEMES_DIR = join26(
16979
+ process.env.XDG_CONFIG_HOME || join26(homedir15(), ".config"),
16520
16980
  "kimiflare",
16521
16981
  "themes"
16522
16982
  );
@@ -16573,8 +17033,8 @@ var init_lsp_nudge = __esm({
16573
17033
  });
16574
17034
 
16575
17035
  // src/ui/file-picker.tsx
16576
- import { Box as Box21, Text as Text22 } from "ink";
16577
- import { jsx as jsx23, jsxs as jsxs21 } from "react/jsx-runtime";
17036
+ import { Box as Box22, Text as Text23 } from "ink";
17037
+ import { jsx as jsx24, jsxs as jsxs22 } from "react/jsx-runtime";
16578
17038
  function FilePicker({ items, selectedIndex, query, recentFiles }) {
16579
17039
  const theme = useTheme();
16580
17040
  let startIndex = 0;
@@ -16586,12 +17046,12 @@ function FilePicker({ items, selectedIndex, query, recentFiles }) {
16586
17046
  const hasMoreBelow = items.length > startIndex + VISIBLE_LIMIT;
16587
17047
  const recentInVisible = visible.filter((item) => recentFiles?.has(item.name)).length;
16588
17048
  const hasRecentSection = recentInVisible > 0;
16589
- return /* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
16590
- /* @__PURE__ */ jsx23(Text22, { color: theme.accent, bold: true, children: query ? `Files matching "${query}"` : "Mention a file" }),
16591
- /* @__PURE__ */ jsx23(Text22, { color: theme.info.color, dimColor: true, children: "\u2191\u2193 navigate \xB7 Enter pick \xB7 Esc cancel" }),
16592
- /* @__PURE__ */ jsxs21(Box21, { marginTop: 1, flexDirection: "column", children: [
16593
- visible.length === 0 && /* @__PURE__ */ jsx23(Text22, { color: theme.info.color, children: "No matches" }),
16594
- hasMoreAbove && /* @__PURE__ */ jsxs21(Text22, { color: theme.info.color, dimColor: true, children: [
17049
+ return /* @__PURE__ */ jsxs22(Box22, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
17050
+ /* @__PURE__ */ jsx24(Text23, { color: theme.accent, bold: true, children: query ? `Files matching "${query}"` : "Mention a file" }),
17051
+ /* @__PURE__ */ jsx24(Text23, { color: theme.info.color, dimColor: true, children: "\u2191\u2193 navigate \xB7 Enter pick \xB7 Esc cancel" }),
17052
+ /* @__PURE__ */ jsxs22(Box22, { marginTop: 1, flexDirection: "column", children: [
17053
+ visible.length === 0 && /* @__PURE__ */ jsx24(Text23, { color: theme.info.color, children: "No matches" }),
17054
+ hasMoreAbove && /* @__PURE__ */ jsxs22(Text23, { color: theme.info.color, dimColor: true, children: [
16595
17055
  "\u2026 ",
16596
17056
  startIndex,
16597
17057
  " more above"
@@ -16603,28 +17063,28 @@ function FilePicker({ items, selectedIndex, query, recentFiles }) {
16603
17063
  const label = item.isDirectory ? `${item.name}/` : item.name;
16604
17064
  const isFirstRecent = isRecent && (i === 0 || !recentFiles?.has(visible[i - 1]?.name ?? ""));
16605
17065
  const isFirstNonRecentAfterRecent = !isRecent && (i > 0 && recentFiles?.has(visible[i - 1]?.name ?? ""));
16606
- return /* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", children: [
16607
- hasRecentSection && isFirstRecent && /* @__PURE__ */ jsxs21(Text22, { color: theme.palette.success, bold: true, children: [
17066
+ return /* @__PURE__ */ jsxs22(Box22, { flexDirection: "column", children: [
17067
+ hasRecentSection && isFirstRecent && /* @__PURE__ */ jsxs22(Text23, { color: theme.palette.success, bold: true, children: [
16608
17068
  " ",
16609
17069
  "Recent"
16610
17070
  ] }),
16611
- hasRecentSection && isFirstNonRecentAfterRecent && /* @__PURE__ */ jsxs21(Text22, { color: theme.info.color, dimColor: true, children: [
17071
+ hasRecentSection && isFirstNonRecentAfterRecent && /* @__PURE__ */ jsxs22(Text23, { color: theme.info.color, dimColor: true, children: [
16612
17072
  " ",
16613
17073
  "All files"
16614
17074
  ] }),
16615
- /* @__PURE__ */ jsxs21(Text22, { color: isSelected ? theme.accent : isRecent ? theme.palette.success : void 0, bold: isSelected || isRecent, children: [
17075
+ /* @__PURE__ */ jsxs22(Text23, { color: isSelected ? theme.accent : isRecent ? theme.palette.success : void 0, bold: isSelected || isRecent, children: [
16616
17076
  isSelected ? "\u203A " : isRecent ? "\u2192 " : " ",
16617
17077
  isRecent ? "\u21BB " : "",
16618
17078
  label
16619
17079
  ] })
16620
17080
  ] }, item.name);
16621
17081
  }),
16622
- hasMoreBelow && /* @__PURE__ */ jsxs21(Text22, { color: theme.info.color, dimColor: true, children: [
17082
+ hasMoreBelow && /* @__PURE__ */ jsxs22(Text23, { color: theme.info.color, dimColor: true, children: [
16623
17083
  "\u2026 ",
16624
17084
  items.length - (startIndex + VISIBLE_LIMIT),
16625
17085
  " more below"
16626
17086
  ] }),
16627
- hasRecentSection && /* @__PURE__ */ jsx23(Box21, { marginTop: 1, children: /* @__PURE__ */ jsx23(Text22, { color: theme.info.color, dimColor: true, children: "\u21BB = recently used" }) })
17087
+ hasRecentSection && /* @__PURE__ */ jsx24(Box22, { marginTop: 1, children: /* @__PURE__ */ jsx24(Text23, { color: theme.info.color, dimColor: true, children: "\u21BB = recently used" }) })
16628
17088
  ] })
16629
17089
  ] });
16630
17090
  }
@@ -16638,8 +17098,8 @@ var init_file_picker = __esm({
16638
17098
  });
16639
17099
 
16640
17100
  // src/ui/slash-picker.tsx
16641
- import { Box as Box22, Text as Text23 } from "ink";
16642
- import { jsx as jsx24, jsxs as jsxs22 } from "react/jsx-runtime";
17101
+ import { Box as Box23, Text as Text24 } from "ink";
17102
+ import { jsx as jsx25, jsxs as jsxs23 } from "react/jsx-runtime";
16643
17103
  function sourceBadge(source) {
16644
17104
  if (source === "builtin") return "";
16645
17105
  if (source === "project") return "project";
@@ -16659,12 +17119,12 @@ function SlashPicker({ items, selectedIndex, query }) {
16659
17119
  const hasMoreBelow = items.length > startIndex + VISIBLE_LIMIT2;
16660
17120
  const longestLabel = visible.reduce((m, it) => Math.max(m, commandLabel(it).length), 0);
16661
17121
  const nameColWidth = Math.max(NAME_COL_MIN_WIDTH, longestLabel + NAME_DESC_GAP);
16662
- return /* @__PURE__ */ jsxs22(Box22, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
16663
- /* @__PURE__ */ jsx24(Text23, { color: theme.accent, bold: true, children: query ? `Commands matching "/${query}"` : "Slash commands" }),
16664
- /* @__PURE__ */ jsx24(Text23, { color: theme.info.color, children: "Arrow keys to navigate, Enter to select, Esc to cancel." }),
16665
- /* @__PURE__ */ jsxs22(Box22, { marginTop: 1, flexDirection: "column", children: [
16666
- visible.length === 0 && /* @__PURE__ */ jsx24(Text23, { color: theme.info.color, children: "No matches" }),
16667
- hasMoreAbove && /* @__PURE__ */ jsxs22(Text23, { color: theme.info.color, children: [
17122
+ return /* @__PURE__ */ jsxs23(Box23, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
17123
+ /* @__PURE__ */ jsx25(Text24, { color: theme.accent, bold: true, children: query ? `Commands matching "/${query}"` : "Slash commands" }),
17124
+ /* @__PURE__ */ jsx25(Text24, { color: theme.info.color, children: "Arrow keys to navigate, Enter to select, Esc to cancel." }),
17125
+ /* @__PURE__ */ jsxs23(Box23, { marginTop: 1, flexDirection: "column", children: [
17126
+ visible.length === 0 && /* @__PURE__ */ jsx25(Text24, { color: theme.info.color, children: "No matches" }),
17127
+ hasMoreAbove && /* @__PURE__ */ jsxs23(Text24, { color: theme.info.color, children: [
16668
17128
  "\u2026 ",
16669
17129
  startIndex,
16670
17130
  " more above"
@@ -16674,16 +17134,16 @@ function SlashPicker({ items, selectedIndex, query }) {
16674
17134
  const isSelected = actualIndex === selectedIndex;
16675
17135
  const nameCol = commandLabel(item).padEnd(nameColWidth);
16676
17136
  const badge = sourceBadge(item.source);
16677
- return /* @__PURE__ */ jsxs22(Text23, { color: isSelected ? theme.accent : void 0, bold: isSelected, children: [
17137
+ return /* @__PURE__ */ jsxs23(Text24, { color: isSelected ? theme.accent : void 0, bold: isSelected, children: [
16678
17138
  isSelected ? "\u203A " : " ",
16679
17139
  nameCol,
16680
- /* @__PURE__ */ jsxs22(Text23, { color: theme.info.color, children: [
17140
+ /* @__PURE__ */ jsxs23(Text24, { color: theme.info.color, children: [
16681
17141
  item.description,
16682
17142
  badge && ` [${badge}]`
16683
17143
  ] })
16684
17144
  ] }, item.name);
16685
17145
  }),
16686
- hasMoreBelow && /* @__PURE__ */ jsxs22(Text23, { color: theme.info.color, children: [
17146
+ hasMoreBelow && /* @__PURE__ */ jsxs23(Text24, { color: theme.info.color, children: [
16687
17147
  "\u2026 ",
16688
17148
  items.length - (startIndex + VISIBLE_LIMIT2),
16689
17149
  " more below"
@@ -16707,15 +17167,15 @@ var tui_report_exports = {};
16707
17167
  __export(tui_report_exports, {
16708
17168
  getCategoryReportText: () => getCategoryReportText
16709
17169
  });
16710
- import { readFile as readFile19 } from "fs/promises";
16711
- import { join as join26 } from "path";
17170
+ import { readFile as readFile20 } from "fs/promises";
17171
+ import { join as join27 } from "path";
16712
17172
  import { homedir as homedir16 } from "os";
16713
17173
  function usageDir3() {
16714
- const xdg = process.env.XDG_DATA_HOME || join26(homedir16(), ".local", "share");
16715
- return join26(xdg, "kimiflare");
17174
+ const xdg = process.env.XDG_DATA_HOME || join27(homedir16(), ".local", "share");
17175
+ return join27(xdg, "kimiflare");
16716
17176
  }
16717
17177
  function usagePath3() {
16718
- return join26(usageDir3(), "usage.json");
17178
+ return join27(usageDir3(), "usage.json");
16719
17179
  }
16720
17180
  function today3() {
16721
17181
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
@@ -16727,7 +17187,7 @@ function daysAgo2(n) {
16727
17187
  }
16728
17188
  async function loadLog3() {
16729
17189
  try {
16730
- const raw = await readFile19(usagePath3(), "utf8");
17190
+ const raw = await readFile20(usagePath3(), "utf8");
16731
17191
  return JSON.parse(raw);
16732
17192
  } catch {
16733
17193
  return { version: 1, days: [], sessions: [] };
@@ -16794,17 +17254,17 @@ __export(app_exports, {
16794
17254
  shouldOpenSlashPicker: () => shouldOpenSlashPicker
16795
17255
  });
16796
17256
  import React15, { useState as useState12, useRef as useRef3, useEffect as useEffect7, useCallback as useCallback3 } from "react";
16797
- import { Box as Box23, Text as Text24, useApp, useInput as useInput9, render } from "ink";
17257
+ import { Box as Box24, Text as Text25, useApp, useInput as useInput9, render } from "ink";
16798
17258
  import SelectInput10 from "ink-select-input";
16799
17259
  import { existsSync as existsSync4, statSync as statSync4 } from "fs";
16800
- import { join as join27 } from "path";
17260
+ import { join as join28 } from "path";
16801
17261
  import { unlink as unlink4 } from "fs/promises";
16802
17262
  import { execSync as execSync2 } from "child_process";
16803
17263
  import { spawn as spawn4 } from "child_process";
16804
17264
  import { platform as platform4 } from "os";
16805
17265
  import fg4 from "fast-glob";
16806
17266
  import { readFileSync as readFileSync3 } from "fs";
16807
- import { jsx as jsx25, jsxs as jsxs23 } from "react/jsx-runtime";
17267
+ import { jsx as jsx26, jsxs as jsxs24 } from "react/jsx-runtime";
16808
17268
  function buildFilePickerIgnoreList(cwd) {
16809
17269
  const hardcoded = [
16810
17270
  // Dependencies
@@ -16875,7 +17335,7 @@ function buildFilePickerIgnoreList(cwd) {
16875
17335
  ];
16876
17336
  const gitignorePatterns = [];
16877
17337
  try {
16878
- const gitignorePath = join27(cwd, ".gitignore");
17338
+ const gitignorePath = join28(cwd, ".gitignore");
16879
17339
  const stats = statSync4(gitignorePath);
16880
17340
  if (stats.size > MAX_GITIGNORE_SIZE) {
16881
17341
  return hardcoded;
@@ -17077,6 +17537,7 @@ function App({
17077
17537
  const [showReasoning, setShowReasoning] = useState12(false);
17078
17538
  const [perm, setPerm] = useState12(null);
17079
17539
  const [limitModal, setLimitModal] = useState12(null);
17540
+ const [loopModal, setLoopModal] = useState12(null);
17080
17541
  const [queue, setQueue] = useState12([]);
17081
17542
  const [history, setHistory] = useState12([]);
17082
17543
  const [historyIndex, setHistoryIndex] = useState12(-1);
@@ -17113,7 +17574,6 @@ function App({
17113
17574
  const [skillsActive, setSkillsActive] = useState12(0);
17114
17575
  const [memoryRecalled, setMemoryRecalled] = useState12(false);
17115
17576
  const [intentTier, setIntentTier] = useState12(null);
17116
- const skillsDirRef = useRef3(join27(process.cwd(), ".kimiflare", "skills"));
17117
17577
  const [kimiMdStale, setKimiMdStale] = useState12(false);
17118
17578
  const [gitBranch, setGitBranch] = useState12(null);
17119
17579
  const [lastSessionTopic, setLastSessionTopic] = useState12(null);
@@ -17170,10 +17630,21 @@ ${wcagWarnings.join("\n")}` }
17170
17630
  if (!cfg?.cloudMode || !initialCloudToken) return;
17171
17631
  let cancelled = false;
17172
17632
  const fetchBudget = async () => {
17173
- const { fetchCloudUsage: fetchCloudUsage2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
17174
- const usage2 = await fetchCloudUsage2(initialCloudToken, cloudDeviceId ?? initialCloudDeviceId);
17175
- if (usage2 && !cancelled) {
17176
- setCloudBudget({ remaining: usage2.remaining, limit: usage2.input_token_limit });
17633
+ try {
17634
+ const { fetchCloudUsage: fetchCloudUsage2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
17635
+ const usage2 = await fetchCloudUsage2(initialCloudToken, cloudDeviceId ?? initialCloudDeviceId);
17636
+ if (usage2 && !cancelled) {
17637
+ setCloudBudget({ remaining: usage2.remaining, limit: usage2.input_token_limit });
17638
+ }
17639
+ } catch (err) {
17640
+ if (isKillSwitchError(err) && !cancelled) {
17641
+ setCloudToken(void 0);
17642
+ setCloudDeviceId(void 0);
17643
+ setEvents((es) => [
17644
+ ...es,
17645
+ { kind: "service_ended", key: mkKey(), endedAt: err.endedAt }
17646
+ ]);
17647
+ }
17177
17648
  }
17178
17649
  };
17179
17650
  fetchBudget();
@@ -17200,6 +17671,7 @@ ${wcagWarnings.join("\n")}` }
17200
17671
  const sigintHandlerRef = useRef3(null);
17201
17672
  const permResolveRef = useRef3(null);
17202
17673
  const limitResolveRef = useRef3(null);
17674
+ const loopResolveRef = useRef3(null);
17203
17675
  const pendingToolCallsRef = useRef3(/* @__PURE__ */ new Map());
17204
17676
  const sessionIdRef = useRef3(null);
17205
17677
  const sessionCreatedAtRef = useRef3(null);
@@ -17378,7 +17850,7 @@ ${wcagWarnings.join("\n")}` }
17378
17850
  setActivePicker(null);
17379
17851
  }, [cursorOffset]);
17380
17852
  useEffect7(() => {
17381
- const modalActive = commandWizard !== null || commandPicker !== null || commandToDelete !== null || showCommandList || showLspWizard || resumeSessions !== null || checkpointSession !== null || perm !== null || limitModal !== null;
17853
+ const modalActive = commandWizard !== null || commandPicker !== null || commandToDelete !== null || showCommandList || showLspWizard || resumeSessions !== null || checkpointSession !== null || perm !== null || limitModal !== null || loopModal !== null;
17382
17854
  if (modalActive && activePicker !== null) {
17383
17855
  setActivePicker(null);
17384
17856
  }
@@ -17391,6 +17863,7 @@ ${wcagWarnings.join("\n")}` }
17391
17863
  resumeSessions,
17392
17864
  perm,
17393
17865
  limitModal,
17866
+ loopModal,
17394
17867
  activePicker
17395
17868
  ]);
17396
17869
  useEffect7(() => {
@@ -17419,7 +17892,7 @@ ${wcagWarnings.join("\n")}` }
17419
17892
  }
17420
17893
  });
17421
17894
  if (cfg.memoryEnabled) {
17422
- const dbPath = cfg.memoryDbPath ?? join27(process.cwd(), ".kimiflare", "memory.db");
17895
+ const dbPath = cfg.memoryDbPath ?? join28(process.cwd(), ".kimiflare", "memory.db");
17423
17896
  const manager = new MemoryManager({
17424
17897
  dbPath,
17425
17898
  accountId: cfg.accountId,
@@ -17468,7 +17941,7 @@ ${wcagWarnings.join("\n")}` }
17468
17941
  } catch {
17469
17942
  }
17470
17943
  })();
17471
- if (existsSync4(join27(cwd, "KIMI.md"))) {
17944
+ if (existsSync4(join28(cwd, "KIMI.md"))) {
17472
17945
  const lastRefresh = manager.getLastKimiMdRefreshTime(cwd);
17473
17946
  const driftCount = manager.countHighSignalMemoriesSince(cwd, lastRefresh);
17474
17947
  if (driftCount >= 5) {
@@ -17479,6 +17952,32 @@ ${wcagWarnings.join("\n")}` }
17479
17952
  memoryManagerRef.current?.close();
17480
17953
  memoryManagerRef.current = null;
17481
17954
  }
17955
+ const skillDbPath = cfg.memoryDbPath ?? join28(process.cwd(), ".kimiflare", "memory.db");
17956
+ const skillDb = getMemoryDb() ?? openMemoryDb(skillDbPath);
17957
+ initSkillsSchema(skillDb);
17958
+ void indexSkills({
17959
+ cwd: process.cwd(),
17960
+ db: skillDb,
17961
+ accountId: cfg.accountId,
17962
+ apiToken: cfg.apiToken,
17963
+ gateway: gatewayFromConfig(cfg),
17964
+ embeddingModel: cfg.memoryEmbeddingModel,
17965
+ cloudMode: cfg.cloudMode,
17966
+ cloudToken: cloudToken ?? initialCloudToken,
17967
+ cloudDeviceId: cloudDeviceId ?? initialCloudDeviceId
17968
+ }).then((result) => {
17969
+ if (result.indexed > 0) {
17970
+ setEvents((e) => [
17971
+ ...e,
17972
+ { kind: "info", key: mkKey(), text: `indexed ${result.indexed} skill${result.indexed === 1 ? "" : "s"}` }
17973
+ ]);
17974
+ }
17975
+ if (result.errors.length > 0) {
17976
+ for (const err of result.errors) {
17977
+ setEvents((e) => [...e, { kind: "info", key: mkKey(), text: `skill index error: ${err}` }]);
17978
+ }
17979
+ }
17980
+ });
17482
17981
  void loadCustomCommands(process.cwd()).then(({ commands, warnings }) => {
17483
17982
  customCommandsRef.current = commands;
17484
17983
  setCustomCommandsVersion((v) => v + 1);
@@ -17891,6 +18390,7 @@ ${wcagWarnings.join("\n")}` }
17891
18390
  });
17892
18391
  const hadPerm = permResolveRef.current !== null;
17893
18392
  const hadLimit = limitResolveRef.current !== null;
18393
+ const hadLoop = loopResolveRef.current !== null;
17894
18394
  if (hadPerm) {
17895
18395
  permResolveRef.current("deny");
17896
18396
  permResolveRef.current = null;
@@ -17901,6 +18401,11 @@ ${wcagWarnings.join("\n")}` }
17901
18401
  limitResolveRef.current = null;
17902
18402
  setLimitModal(null);
17903
18403
  }
18404
+ if (hadLoop) {
18405
+ loopResolveRef.current("stop");
18406
+ loopResolveRef.current = null;
18407
+ setLoopModal(null);
18408
+ }
17904
18409
  if (busyRef.current && activeScopeRef.current && !isAbortingRef.current) {
17905
18410
  isAbortingRef.current = true;
17906
18411
  supervisorRef.current.killTurn();
@@ -17915,7 +18420,7 @@ ${wcagWarnings.join("\n")}` }
17915
18420
  setTasksStartedAt(null);
17916
18421
  setTasksStartTokens(0);
17917
18422
  tasksRef.current = [];
17918
- } else if (!hadPerm && !hadLimit) {
18423
+ } else if (!hadPerm && !hadLimit && !hadLoop) {
17919
18424
  logger.info("input:ctrl+c:exiting");
17920
18425
  void lspManagerRef.current.stopAll().finally(() => exit());
17921
18426
  }
@@ -17923,7 +18428,7 @@ ${wcagWarnings.join("\n")}` }
17923
18428
  }
17924
18429
  if (key.escape) {
17925
18430
  const now2 = Date.now();
17926
- const modalOpen = perm !== null || limitModal !== null || showLspWizard || showCommandList || commandWizard !== null || commandToDelete !== null || resumeSessions !== null || checkpointSession !== null || showThemePicker;
18431
+ const modalOpen = perm !== null || limitModal !== null || loopModal !== null || showLspWizard || showCommandList || commandWizard !== null || commandToDelete !== null || resumeSessions !== null || checkpointSession !== null || showThemePicker;
17927
18432
  if (!modalOpen && busyRef.current && activeScopeRef.current && !isAbortingRef.current && now2 - lastEscapeAtRef.current > 500) {
17928
18433
  lastEscapeAtRef.current = now2;
17929
18434
  isAbortingRef.current = true;
@@ -17938,6 +18443,11 @@ ${wcagWarnings.join("\n")}` }
17938
18443
  limitResolveRef.current = null;
17939
18444
  setLimitModal(null);
17940
18445
  }
18446
+ if (loopResolveRef.current) {
18447
+ loopResolveRef.current("stop");
18448
+ loopResolveRef.current = null;
18449
+ setLoopModal(null);
18450
+ }
17941
18451
  activeScopeRef.current.abort("user_stopped");
17942
18452
  setEvents((e) => [...e, { kind: "info", key: mkKey(), text: "(interrupted)" }]);
17943
18453
  for (const [toolId] of pendingToolCallsRef.current) {
@@ -17970,10 +18480,12 @@ ${wcagWarnings.join("\n")}` }
17970
18480
  hasActiveScope: activeScopeRef.current !== null,
17971
18481
  isAborting: isAbortingRef.current,
17972
18482
  hasPerm: permResolveRef.current !== null,
17973
- hasLimit: limitResolveRef.current !== null
18483
+ hasLimit: limitResolveRef.current !== null,
18484
+ hasLoop: loopResolveRef.current !== null
17974
18485
  });
17975
18486
  const hadPerm = permResolveRef.current !== null;
17976
18487
  const hadLimit = limitResolveRef.current !== null;
18488
+ const hadLoop = loopResolveRef.current !== null;
17977
18489
  if (hadPerm) {
17978
18490
  permResolveRef.current("deny");
17979
18491
  permResolveRef.current = null;
@@ -17984,6 +18496,11 @@ ${wcagWarnings.join("\n")}` }
17984
18496
  limitResolveRef.current = null;
17985
18497
  setLimitModal(null);
17986
18498
  }
18499
+ if (hadLoop) {
18500
+ loopResolveRef.current("stop");
18501
+ loopResolveRef.current = null;
18502
+ setLoopModal(null);
18503
+ }
17987
18504
  if (busyRef.current && activeScopeRef.current && !isAbortingRef.current) {
17988
18505
  isAbortingRef.current = true;
17989
18506
  supervisorRef.current.killTurn();
@@ -18212,7 +18729,7 @@ ${wcagWarnings.join("\n")}` }
18212
18729
  lspManagerRef.current.notifyChange(path, content);
18213
18730
  } else {
18214
18731
  void import("fs/promises").then(
18215
- ({ readFile: readFile20 }) => readFile20(path, "utf8").then((c) => lspManagerRef.current.notifyChange(path, c)).catch(() => {
18732
+ ({ readFile: readFile21 }) => readFile21(path, "utf8").then((c) => lspManagerRef.current.notifyChange(path, c)).catch(() => {
18216
18733
  })
18217
18734
  );
18218
18735
  }
@@ -18303,10 +18820,21 @@ ${wcagWarnings.join("\n")}` }
18303
18820
  const token = cloudToken ?? initialCloudToken;
18304
18821
  const did = cloudDeviceId ?? initialCloudDeviceId;
18305
18822
  void (async () => {
18306
- const { fetchCloudUsage: fetchCloudUsage2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
18307
- const usage2 = await fetchCloudUsage2(token, did);
18308
- if (usage2) {
18309
- setCloudBudget({ remaining: usage2.remaining, limit: usage2.input_token_limit });
18823
+ try {
18824
+ const { fetchCloudUsage: fetchCloudUsage2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
18825
+ const usage2 = await fetchCloudUsage2(token, did);
18826
+ if (usage2) {
18827
+ setCloudBudget({ remaining: usage2.remaining, limit: usage2.input_token_limit });
18828
+ }
18829
+ } catch (err) {
18830
+ if (isKillSwitchError(err)) {
18831
+ setCloudToken(void 0);
18832
+ setCloudDeviceId(void 0);
18833
+ setEvents((es) => [
18834
+ ...es,
18835
+ { kind: "service_ended", key: mkKey(), endedAt: err.endedAt }
18836
+ ]);
18837
+ }
18310
18838
  }
18311
18839
  })();
18312
18840
  }
@@ -18353,7 +18881,7 @@ ${wcagWarnings.join("\n")}` }
18353
18881
  }
18354
18882
  }
18355
18883
  });
18356
- if (existsSync4(join27(cwd, "KIMI.md"))) {
18884
+ if (existsSync4(join28(cwd, "KIMI.md"))) {
18357
18885
  if (cacheStableRef.current) {
18358
18886
  messagesRef.current[1] = {
18359
18887
  role: "system",
@@ -18396,6 +18924,13 @@ ${wcagWarnings.join("\n")}` }
18396
18924
  setEvents(
18397
18925
  (evts) => evts.map((e2) => e2.kind === "tool" && e2.status === "running" ? { ...e2, status: "error", result: "(stopped)" } : e2)
18398
18926
  );
18927
+ } else if (isKillSwitchError(e)) {
18928
+ setCloudToken(void 0);
18929
+ setCloudDeviceId(void 0);
18930
+ setEvents((es) => [
18931
+ ...es,
18932
+ { kind: "service_ended", key: mkKey(), endedAt: e.endedAt }
18933
+ ]);
18399
18934
  } else if (cfg?.cloudMode && isCloudQuotaExhaustedError(e)) {
18400
18935
  const token = cloudToken ?? initialCloudToken;
18401
18936
  const did = cloudDeviceId ?? initialCloudDeviceId;
@@ -18460,6 +18995,8 @@ ${wcagWarnings.join("\n")}` }
18460
18995
  isAbortingRef.current = false;
18461
18996
  permResolveRef.current = null;
18462
18997
  limitResolveRef.current = null;
18998
+ loopResolveRef.current = null;
18999
+ setLoopModal(null);
18463
19000
  pendingToolCallsRef.current.clear();
18464
19001
  }
18465
19002
  }, [cfg, busy, updateAssistant, updateTool, updateGatewayMeta]);
@@ -19072,7 +19609,7 @@ ${lines.join("\n")}` }]);
19072
19609
  try {
19073
19610
  ensureSessionId();
19074
19611
  const { sessionsDir: sessionsDir3 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
19075
- const filePath = join27(sessionsDir3(), `${sessionIdRef.current}.json`);
19612
+ const filePath = join28(sessionsDir3(), `${sessionIdRef.current}.json`);
19076
19613
  await addCheckpoint(filePath, cp);
19077
19614
  setEvents((e) => [...e, { kind: "info", key: mkKey(), text: `checkpoint saved: "${label}"` }]);
19078
19615
  } catch (e) {
@@ -19093,7 +19630,7 @@ ${lines.join("\n")}` }]);
19093
19630
  void (async () => {
19094
19631
  try {
19095
19632
  const { sessionsDir: sessionsDir3 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
19096
- const file = await loadSession(join27(sessionsDir3(), `${currentId}.json`));
19633
+ const file = await loadSession(join28(sessionsDir3(), `${currentId}.json`));
19097
19634
  const cps = file.checkpoints ?? [];
19098
19635
  if (cps.length === 0) {
19099
19636
  setEvents((e) => [...e, { kind: "info", key: mkKey(), text: "no checkpoints in this session" }]);
@@ -19662,7 +20199,7 @@ ${lines.join("\n")}` }]);
19662
20199
  }
19663
20200
  }
19664
20201
  turnCounterRef.current += 1;
19665
- if (turnCounterRef.current % 15 === 0 && existsSync4(join27(process.cwd(), "KIMI.md")) && !kimiMdStale) {
20202
+ if (turnCounterRef.current % 15 === 0 && existsSync4(join28(process.cwd(), "KIMI.md")) && !kimiMdStale) {
19666
20203
  setEvents((e) => [
19667
20204
  ...e,
19668
20205
  { kind: "info", key: mkKey(), text: "Tip: Rerunning /init occasionally helps KimiFlare stay accurate as your project evolves." }
@@ -19680,16 +20217,28 @@ ${lines.join("\n")}` }]);
19680
20217
  }
19681
20218
  let skillResult;
19682
20219
  try {
19683
- skillResult = await routeSkills(skillsDirRef.current, {
19684
- cwd: process.cwd(),
19685
- prompt: trimmed,
19686
- memorySnippets: [],
19687
- // TODO: wire memory snippets when available
19688
- tier: classification.tier,
19689
- maxSkillTokens: CONTEXT_LIMIT - 1e4
19690
- // leave headroom
19691
- });
19692
- setSkillsActive(skillResult.selectedSkills.length);
20220
+ const db = getMemoryDb();
20221
+ if (db) {
20222
+ skillResult = await selectSkills(
20223
+ {
20224
+ prompt: trimmed,
20225
+ tier: classification.tier,
20226
+ maxSkillTokens: CONTEXT_LIMIT - 1e4
20227
+ // leave headroom
20228
+ },
20229
+ {
20230
+ db,
20231
+ accountId: cfg.accountId,
20232
+ apiToken: cfg.apiToken,
20233
+ embeddingModel: cfg.memoryEmbeddingModel,
20234
+ gateway: gatewayFromConfig(cfg),
20235
+ cloudMode: cfg.cloudMode,
20236
+ cloudToken: cloudToken ?? initialCloudToken,
20237
+ cloudDeviceId: cloudDeviceId ?? initialCloudDeviceId
20238
+ }
20239
+ );
20240
+ setSkillsActive(skillResult.sectionCount);
20241
+ }
19693
20242
  } catch {
19694
20243
  setSkillsActive(0);
19695
20244
  }
@@ -19701,7 +20250,6 @@ ${lines.join("\n")}` }]);
19701
20250
  const turnReasoningEffort = overrideEffort ?? effortForTier[classification.tier] ?? effortRef.current;
19702
20251
  const effectiveCodeMode = classification.tier === "heavy";
19703
20252
  setCodeMode(effectiveCodeMode);
19704
- const selectedSkills = skillResult?.selectedSkills.map((s) => ({ name: s.name, body: s.body }));
19705
20253
  if (cacheStableRef.current) {
19706
20254
  messagesRef.current[1] = {
19707
20255
  role: "system",
@@ -19710,7 +20258,7 @@ ${lines.join("\n")}` }]);
19710
20258
  tools: [...ALL_TOOLS, ...mcpToolsRef.current, ...lspToolsRef.current],
19711
20259
  model: cfg.model,
19712
20260
  mode: modeRef.current,
19713
- selectedSkills
20261
+ skillContext: skillResult?.skillContext
19714
20262
  })
19715
20263
  };
19716
20264
  } else {
@@ -19721,7 +20269,7 @@ ${lines.join("\n")}` }]);
19721
20269
  tools: [...ALL_TOOLS, ...mcpToolsRef.current, ...lspToolsRef.current],
19722
20270
  model: cfg.model,
19723
20271
  mode: modeRef.current,
19724
- selectedSkills
20272
+ skillContext: skillResult?.skillContext
19725
20273
  })
19726
20274
  };
19727
20275
  }
@@ -19731,7 +20279,7 @@ ${lines.join("\n")}` }]);
19731
20279
  kind: "meta",
19732
20280
  key: mkKey(),
19733
20281
  intentTier: classification.tier,
19734
- skillsActive: skillResult?.selectedSkills.length ?? 0,
20282
+ skillsActive: skillResult?.sectionCount ?? 0,
19735
20283
  memoryRecalled: false
19736
20284
  }
19737
20285
  ]);
@@ -19819,10 +20367,21 @@ ${lines.join("\n")}` }]);
19819
20367
  const token = cloudToken ?? initialCloudToken;
19820
20368
  const did = cloudDeviceId ?? initialCloudDeviceId;
19821
20369
  void (async () => {
19822
- const { fetchCloudUsage: fetchCloudUsage2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
19823
- const usage2 = await fetchCloudUsage2(token, did);
19824
- if (usage2) {
19825
- setCloudBudget({ remaining: usage2.remaining, limit: usage2.input_token_limit });
20370
+ try {
20371
+ const { fetchCloudUsage: fetchCloudUsage2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
20372
+ const usage2 = await fetchCloudUsage2(token, did);
20373
+ if (usage2) {
20374
+ setCloudBudget({ remaining: usage2.remaining, limit: usage2.input_token_limit });
20375
+ }
20376
+ } catch (err) {
20377
+ if (isKillSwitchError(err)) {
20378
+ setCloudToken(void 0);
20379
+ setCloudDeviceId(void 0);
20380
+ setEvents((es) => [
20381
+ ...es,
20382
+ { kind: "service_ended", key: mkKey(), endedAt: err.endedAt }
20383
+ ]);
20384
+ }
19826
20385
  }
19827
20386
  })();
19828
20387
  }
@@ -19870,6 +20429,10 @@ ${lines.join("\n")}` }]);
19870
20429
  limitResolveRef.current = resolve3;
19871
20430
  setLimitModal({ limit: 50, resolve: resolve3 });
19872
20431
  }),
20432
+ onLoopDetected: () => new Promise((resolve3) => {
20433
+ loopResolveRef.current = resolve3;
20434
+ setLoopModal({ resolve: resolve3 });
20435
+ }),
19873
20436
  onKimiMdStale: () => {
19874
20437
  if (!kimiMdStaleNudgedRef.current) {
19875
20438
  kimiMdStaleNudgedRef.current = true;
@@ -19897,6 +20460,8 @@ ${lines.join("\n")}` }]);
19897
20460
  isAbortingRef.current = false;
19898
20461
  permResolveRef.current = null;
19899
20462
  limitResolveRef.current = null;
20463
+ loopResolveRef.current = null;
20464
+ setLoopModal(null);
19900
20465
  pendingToolCallsRef.current.clear();
19901
20466
  setTasks([]);
19902
20467
  setTasksStartedAt(null);
@@ -19929,13 +20494,12 @@ ${lines.join("\n")}` }]);
19929
20494
  cloudDeviceId: cloudDeviceId ?? initialCloudDeviceId,
19930
20495
  onIterationEnd,
19931
20496
  intentClassification: classification,
19932
- selectedSkills,
19933
20497
  onFileChange: (path, content2) => {
19934
20498
  if (content2) {
19935
20499
  lspManagerRef.current.notifyChange(path, content2);
19936
20500
  } else {
19937
20501
  void import("fs/promises").then(
19938
- ({ readFile: readFile20 }) => readFile20(path, "utf8").then((c) => lspManagerRef.current.notifyChange(path, c)).catch(() => {
20502
+ ({ readFile: readFile21 }) => readFile21(path, "utf8").then((c) => lspManagerRef.current.notifyChange(path, c)).catch(() => {
19939
20503
  })
19940
20504
  );
19941
20505
  }
@@ -20045,6 +20609,13 @@ ${lines.join("\n")}` }]);
20045
20609
  setEvents(
20046
20610
  (evts) => evts.map((e2) => e2.kind === "tool" && e2.status === "running" ? { ...e2, status: "error", result: "(stopped)" } : e2)
20047
20611
  );
20612
+ } else if (isKillSwitchError(e)) {
20613
+ setCloudToken(void 0);
20614
+ setCloudDeviceId(void 0);
20615
+ setEvents((es) => [
20616
+ ...es,
20617
+ { kind: "service_ended", key: mkKey(), endedAt: e.endedAt }
20618
+ ]);
20048
20619
  } else if (cfg?.cloudMode && isCloudQuotaExhaustedError(e)) {
20049
20620
  const token = cloudToken ?? initialCloudToken;
20050
20621
  const did = cloudDeviceId ?? initialCloudDeviceId;
@@ -20140,7 +20711,7 @@ ${lines.join("\n")}` }]);
20140
20711
  }
20141
20712
  }, [usage]);
20142
20713
  if (!cfg) {
20143
- return /* @__PURE__ */ jsx25(ThemeProvider, { theme, children: /* @__PURE__ */ jsx25(
20714
+ return /* @__PURE__ */ jsx26(ThemeProvider, { theme, children: /* @__PURE__ */ jsx26(
20144
20715
  Onboarding,
20145
20716
  {
20146
20717
  onCancel: () => exit(),
@@ -20172,7 +20743,7 @@ ${lines.join("\n")}` }]);
20172
20743
  ) });
20173
20744
  }
20174
20745
  if (checkpointSession !== null) {
20175
- return /* @__PURE__ */ jsx25(ThemeProvider, { theme, children: /* @__PURE__ */ jsx25(Box23, { flexDirection: "column", children: /* @__PURE__ */ jsx25(
20746
+ return /* @__PURE__ */ jsx26(ThemeProvider, { theme, children: /* @__PURE__ */ jsx26(Box24, { flexDirection: "column", children: /* @__PURE__ */ jsx26(
20176
20747
  CheckpointPicker,
20177
20748
  {
20178
20749
  session: checkpointSession,
@@ -20182,10 +20753,10 @@ ${lines.join("\n")}` }]);
20182
20753
  ) }) });
20183
20754
  }
20184
20755
  if (resumeSessions !== null) {
20185
- return /* @__PURE__ */ jsx25(ThemeProvider, { theme, children: /* @__PURE__ */ jsx25(Box23, { flexDirection: "column", children: /* @__PURE__ */ jsx25(ResumePicker, { sessions: resumeSessions, onPick: handleResumePick }) }) });
20756
+ return /* @__PURE__ */ jsx26(ThemeProvider, { theme, children: /* @__PURE__ */ jsx26(Box24, { flexDirection: "column", children: /* @__PURE__ */ jsx26(ResumePicker, { sessions: resumeSessions, onPick: handleResumePick }) }) });
20186
20757
  }
20187
20758
  if (showRemoteDashboard) {
20188
- return /* @__PURE__ */ jsx25(ThemeProvider, { theme, children: /* @__PURE__ */ jsx25(Box23, { flexDirection: "column", children: selectedRemoteSession ? /* @__PURE__ */ jsx25(
20759
+ return /* @__PURE__ */ jsx26(ThemeProvider, { theme, children: /* @__PURE__ */ jsx26(Box24, { flexDirection: "column", children: selectedRemoteSession ? /* @__PURE__ */ jsx26(
20189
20760
  RemoteSessionDetail,
20190
20761
  {
20191
20762
  session: selectedRemoteSession,
@@ -20208,7 +20779,7 @@ ${lines.join("\n")}` }]);
20208
20779
  setShowRemoteDashboard(false);
20209
20780
  }
20210
20781
  }
20211
- ) : /* @__PURE__ */ jsx25(
20782
+ ) : /* @__PURE__ */ jsx26(
20212
20783
  RemoteDashboard,
20213
20784
  {
20214
20785
  onSelect: (session) => setSelectedRemoteSession(session),
@@ -20217,12 +20788,12 @@ ${lines.join("\n")}` }]);
20217
20788
  ) }) });
20218
20789
  }
20219
20790
  if (showLspWizard) {
20220
- return /* @__PURE__ */ jsx25(ThemeProvider, { theme, children: /* @__PURE__ */ jsx25(Box23, { flexDirection: "column", children: /* @__PURE__ */ jsx25(
20791
+ return /* @__PURE__ */ jsx26(ThemeProvider, { theme, children: /* @__PURE__ */ jsx26(Box24, { flexDirection: "column", children: /* @__PURE__ */ jsx26(
20221
20792
  LspWizard,
20222
20793
  {
20223
20794
  servers: cfg?.lspServers ?? {},
20224
20795
  currentScope: lspScope,
20225
- hasProjectDir: existsSync4(join27(process.cwd(), ".kimiflare")),
20796
+ hasProjectDir: existsSync4(join28(process.cwd(), ".kimiflare")),
20226
20797
  onDone: () => setShowLspWizard(false),
20227
20798
  onSave: (servers, enabled, scope) => {
20228
20799
  setCfg((c) => c ? { ...c, lspEnabled: enabled, lspServers: servers } : c);
@@ -20254,7 +20825,7 @@ ${lines.join("\n")}` }]);
20254
20825
  ) }) });
20255
20826
  }
20256
20827
  if (commandWizard) {
20257
- return /* @__PURE__ */ jsx25(ThemeProvider, { theme, children: /* @__PURE__ */ jsx25(Box23, { flexDirection: "column", children: /* @__PURE__ */ jsx25(
20828
+ return /* @__PURE__ */ jsx26(ThemeProvider, { theme, children: /* @__PURE__ */ jsx26(Box24, { flexDirection: "column", children: /* @__PURE__ */ jsx26(
20258
20829
  CommandWizard,
20259
20830
  {
20260
20831
  mode: commandWizard.mode,
@@ -20267,7 +20838,7 @@ ${lines.join("\n")}` }]);
20267
20838
  ) }) });
20268
20839
  }
20269
20840
  if (commandPicker) {
20270
- return /* @__PURE__ */ jsx25(ThemeProvider, { theme, children: /* @__PURE__ */ jsx25(Box23, { flexDirection: "column", children: /* @__PURE__ */ jsx25(
20841
+ return /* @__PURE__ */ jsx26(ThemeProvider, { theme, children: /* @__PURE__ */ jsx26(Box24, { flexDirection: "column", children: /* @__PURE__ */ jsx26(
20271
20842
  CommandPicker,
20272
20843
  {
20273
20844
  commands: customCommandsRef.current,
@@ -20285,14 +20856,14 @@ ${lines.join("\n")}` }]);
20285
20856
  ) }) });
20286
20857
  }
20287
20858
  if (commandToDelete) {
20288
- return /* @__PURE__ */ jsx25(ThemeProvider, { theme, children: /* @__PURE__ */ jsxs23(Box23, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
20289
- /* @__PURE__ */ jsxs23(Text24, { color: theme.accent, bold: true, children: [
20859
+ return /* @__PURE__ */ jsx26(ThemeProvider, { theme, children: /* @__PURE__ */ jsxs24(Box24, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
20860
+ /* @__PURE__ */ jsxs24(Text25, { color: theme.accent, bold: true, children: [
20290
20861
  "Delete /",
20291
20862
  commandToDelete.name,
20292
20863
  "?"
20293
20864
  ] }),
20294
- /* @__PURE__ */ jsx25(Text24, { color: theme.info.color, children: commandToDelete.filepath }),
20295
- /* @__PURE__ */ jsx25(Box23, { marginTop: 1, children: /* @__PURE__ */ jsx25(
20865
+ /* @__PURE__ */ jsx26(Text25, { color: theme.info.color, children: commandToDelete.filepath }),
20866
+ /* @__PURE__ */ jsx26(Box24, { marginTop: 1, children: /* @__PURE__ */ jsx26(
20296
20867
  SelectInput10,
20297
20868
  {
20298
20869
  items: [
@@ -20311,7 +20882,7 @@ ${lines.join("\n")}` }]);
20311
20882
  ] }) });
20312
20883
  }
20313
20884
  if (showCommandList) {
20314
- return /* @__PURE__ */ jsx25(ThemeProvider, { theme, children: /* @__PURE__ */ jsx25(Box23, { flexDirection: "column", children: /* @__PURE__ */ jsx25(
20885
+ return /* @__PURE__ */ jsx26(ThemeProvider, { theme, children: /* @__PURE__ */ jsx26(Box24, { flexDirection: "column", children: /* @__PURE__ */ jsx26(
20315
20886
  CommandList,
20316
20887
  {
20317
20888
  commands: customCommandsRef.current,
@@ -20320,12 +20891,12 @@ ${lines.join("\n")}` }]);
20320
20891
  ) }) });
20321
20892
  }
20322
20893
  if (showThemePicker) {
20323
- return /* @__PURE__ */ jsx25(ThemeProvider, { theme, children: /* @__PURE__ */ jsx25(Box23, { flexDirection: "column", children: /* @__PURE__ */ jsx25(ThemePicker, { themes: themeList(), onPick: handleThemePick }) }) });
20894
+ return /* @__PURE__ */ jsx26(ThemeProvider, { theme, children: /* @__PURE__ */ jsx26(Box24, { flexDirection: "column", children: /* @__PURE__ */ jsx26(ThemePicker, { themes: themeList(), onPick: handleThemePick }) }) });
20324
20895
  }
20325
20896
  const hasConversation = events.some((e) => e.kind === "user" || e.kind === "assistant");
20326
- return /* @__PURE__ */ jsx25(ThemeProvider, { theme, children: /* @__PURE__ */ jsxs23(Box23, { flexDirection: "column", children: [
20327
- !hasConversation && events.length === 0 ? /* @__PURE__ */ jsx25(Welcome, {}) : /* @__PURE__ */ jsx25(ChatView, { events, showReasoning, verbose, intentTier: intentTier ?? void 0 }),
20328
- perm ? /* @__PURE__ */ jsx25(
20897
+ return /* @__PURE__ */ jsx26(ThemeProvider, { theme, children: /* @__PURE__ */ jsxs24(Box24, { flexDirection: "column", children: [
20898
+ !hasConversation && events.length === 0 ? /* @__PURE__ */ jsx26(Welcome, {}) : /* @__PURE__ */ jsx26(ChatView, { events, showReasoning, verbose, intentTier: intentTier ?? void 0 }),
20899
+ perm ? /* @__PURE__ */ jsx26(
20329
20900
  PermissionModal,
20330
20901
  {
20331
20902
  tool: perm.tool,
@@ -20339,7 +20910,7 @@ ${lines.join("\n")}` }]);
20339
20910
  submitRef.current(text);
20340
20911
  }
20341
20912
  }
20342
- ) : limitModal ? /* @__PURE__ */ jsx25(
20913
+ ) : limitModal ? /* @__PURE__ */ jsx26(
20343
20914
  LimitModal,
20344
20915
  {
20345
20916
  limit: limitModal.limit,
@@ -20349,8 +20920,20 @@ ${lines.join("\n")}` }]);
20349
20920
  setLimitModal(null);
20350
20921
  }
20351
20922
  }
20352
- ) : /* @__PURE__ */ jsxs23(Box23, { flexDirection: "column", marginTop: 1, children: [
20353
- tasks.length > 0 && /* @__PURE__ */ jsx25(
20923
+ ) : loopModal ? /* @__PURE__ */ jsx26(
20924
+ LimitModal,
20925
+ {
20926
+ limit: 50,
20927
+ title: "Agent stuck in a loop",
20928
+ description: "The agent kept calling the same tools with identical arguments. What would you like to do?",
20929
+ onDecide: (d) => {
20930
+ loopModal.resolve(d);
20931
+ loopResolveRef.current = null;
20932
+ setLoopModal(null);
20933
+ }
20934
+ }
20935
+ ) : /* @__PURE__ */ jsxs24(Box24, { flexDirection: "column", marginTop: 1, children: [
20936
+ tasks.length > 0 && /* @__PURE__ */ jsx26(
20354
20937
  TaskList,
20355
20938
  {
20356
20939
  tasks,
@@ -20358,11 +20941,11 @@ ${lines.join("\n")}` }]);
20358
20941
  tokensDelta: Math.max(0, (usage?.prompt_tokens ?? 0) - tasksStartTokens)
20359
20942
  }
20360
20943
  ),
20361
- queue.length > 0 && /* @__PURE__ */ jsx25(Box23, { flexDirection: "column", marginBottom: 1, children: queue.map((q, i) => /* @__PURE__ */ jsxs23(Text24, { color: theme.info.color, dimColor: theme.info.dim, children: [
20944
+ queue.length > 0 && /* @__PURE__ */ jsx26(Box24, { flexDirection: "column", marginBottom: 1, children: queue.map((q, i) => /* @__PURE__ */ jsxs24(Text25, { color: theme.info.color, dimColor: theme.info.dim, children: [
20362
20945
  "\u23F3 ",
20363
20946
  q.display
20364
20947
  ] }, `queue_${i}`)) }),
20365
- /* @__PURE__ */ jsx25(
20948
+ /* @__PURE__ */ jsx26(
20366
20949
  StatusBar,
20367
20950
  {
20368
20951
  usage,
@@ -20385,7 +20968,7 @@ ${lines.join("\n")}` }]);
20385
20968
  intentTier: intentTier ?? void 0
20386
20969
  }
20387
20970
  ),
20388
- activePicker?.kind === "file" && /* @__PURE__ */ jsx25(
20971
+ activePicker?.kind === "file" && /* @__PURE__ */ jsx26(
20389
20972
  FilePicker,
20390
20973
  {
20391
20974
  items: filteredFileItems,
@@ -20394,7 +20977,7 @@ ${lines.join("\n")}` }]);
20394
20977
  recentFiles: new Set(recentFilesRef.current.keys())
20395
20978
  }
20396
20979
  ),
20397
- activePicker?.kind === "slash" && /* @__PURE__ */ jsx25(
20980
+ activePicker?.kind === "slash" && /* @__PURE__ */ jsx26(
20398
20981
  SlashPicker,
20399
20982
  {
20400
20983
  items: filteredSlashItems,
@@ -20402,9 +20985,9 @@ ${lines.join("\n")}` }]);
20402
20985
  query: pickerQuery ?? ""
20403
20986
  }
20404
20987
  ),
20405
- /* @__PURE__ */ jsxs23(Box23, { marginTop: 1, children: [
20406
- /* @__PURE__ */ jsx25(Text24, { color: theme.prompt ?? theme.accent, children: "\u203A " }),
20407
- /* @__PURE__ */ jsx25(
20988
+ /* @__PURE__ */ jsxs24(Box24, { marginTop: 1, children: [
20989
+ /* @__PURE__ */ jsx26(Text25, { color: theme.prompt ?? theme.accent, children: "\u203A " }),
20990
+ /* @__PURE__ */ jsx26(
20408
20991
  CustomTextInput,
20409
20992
  {
20410
20993
  value: input,
@@ -20461,7 +21044,7 @@ ${lines.join("\n")}` }]);
20461
21044
  }
20462
21045
  async function renderApp(cfg, updateResult, lspScope = "global", lspProjectPath = null, cloudToken, cloudDeviceId) {
20463
21046
  const instance = render(
20464
- /* @__PURE__ */ jsx25(
21047
+ /* @__PURE__ */ jsx26(
20465
21048
  App,
20466
21049
  {
20467
21050
  initialCfg: cfg,
@@ -20518,6 +21101,7 @@ var init_app = __esm({
20518
21101
  init_mode();
20519
21102
  init_classify();
20520
21103
  init_skills();
21104
+ init_db();
20521
21105
  init_manager4();
20522
21106
  init_sessions();
20523
21107
  init_image();
@@ -20695,6 +21279,7 @@ program.command("usage").description("Show Kimiflare Cloud token usage (requires
20695
21279
  console.log(`Token budget: ${usage.remaining.toLocaleString()} / ${usage.input_token_limit.toLocaleString()} remaining`);
20696
21280
  console.log(`Used: ${usage.input_tokens_used.toLocaleString()}`);
20697
21281
  console.log(`Grant expires: ${usage.expires_at}`);
21282
+ console.log("Or when the global pool of free tokens runs out.");
20698
21283
  });
20699
21284
  program.addCommand(createRemoteCommand());
20700
21285
  program.command("auth").description("Authenticate with external services").addCommand(
@@ -20735,8 +21320,15 @@ Kimiflare Cloud Authentication`);
20735
21320
  console.log(`
20736
21321
  Token budget: ${usage.remaining.toLocaleString()} / ${usage.input_token_limit.toLocaleString()} remaining`);
20737
21322
  console.log(`Grant expires: ${usage.expires_at}`);
21323
+ console.log("Or when the global pool of free tokens runs out.");
20738
21324
  }
20739
21325
  } catch (err) {
21326
+ if (isKillSwitchError(err)) {
21327
+ console.error(
21328
+ "\nKimiFlare Cloud has reached its maximum budget across all users.\nThe free credits period has ended.\n\nTo continue using KimiFlare, switch to BYOK mode:\n \u2022 kimiflare config set-key <your-cloudflare-api-key>\n \u2022 kimiflare config set-account <your-account-id>\n \u2022 Or re-run kimiflare and select BYOK\n"
21329
+ );
21330
+ process.exit(0);
21331
+ }
20740
21332
  console.error("Authentication failed:", err instanceof Error ? err.message : String(err));
20741
21333
  process.exit(1);
20742
21334
  }
@@ -20775,8 +21367,19 @@ async function main() {
20775
21367
  }
20776
21368
  cloudToken = cloudCreds.accessToken;
20777
21369
  cloudDeviceId = cloudCreds.deviceId;
21370
+ try {
21371
+ const { fetchCloudUsage: fetchCloudUsage2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
21372
+ await fetchCloudUsage2(cloudToken, cloudDeviceId);
21373
+ } catch (err) {
21374
+ if (isKillSwitchError(err)) {
21375
+ console.error(
21376
+ "\nKimiFlare Cloud has reached its maximum budget across all users.\nThe free credits period has ended.\n\nTo continue using KimiFlare, switch to BYOK mode:\n \u2022 kimiflare config set-key <your-cloudflare-api-key>\n \u2022 kimiflare config set-account <your-account-id>\n \u2022 Or re-run kimiflare and select BYOK\n"
21377
+ );
21378
+ process.exit(0);
21379
+ }
21380
+ }
20778
21381
  cfg = {
20779
- ...cfg ?? { accountId: "", apiToken: "", model: DEFAULT_MODEL, memoryEnabled: true },
21382
+ ...cfg ?? { accountId: "", apiToken: "", model: DEFAULT_MODEL, memoryEnabled: false },
20780
21383
  cloudMode: true
20781
21384
  };
20782
21385
  }
@@ -20922,6 +21525,13 @@ async function runPrintMode(opts2) {
20922
21525
  process.exitCode = 43;
20923
21526
  return;
20924
21527
  }
21528
+ if (isKillSwitchError(err)) {
21529
+ process.stderr.write(
21530
+ "\n\x1B[31m\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n\u2551 KimiFlare Cloud has reached its maximum budget across \u2551\n\u2551 all users. The free credits period has ended. \u2551\n\u2551 \u2551\n\u2551 To continue using KimiFlare, switch to BYOK mode: \u2551\n\u2551 \u2022 kimiflare config set-key <your-cloudflare-api-key> \u2551\n\u2551 \u2022 kimiflare config set-account <your-account-id> \u2551\n\u2551 \u2022 Or re-run kimiflare and select BYOK \u2551\n\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D\n\x1B[0m\n"
21531
+ );
21532
+ process.exitCode = 0;
21533
+ return;
21534
+ }
20925
21535
  if (err instanceof KimiApiError) {
20926
21536
  process.stderr.write(`
20927
21537
  \x1B[31mError: ${humanizeCloudflareError(err)}\x1B[0m