kimiflare 0.33.0 → 0.34.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -9,6 +9,15 @@ var __export = (target, all) => {
9
9
  };
10
10
 
11
11
  // src/config.ts
12
+ var config_exports = {};
13
+ __export(config_exports, {
14
+ DEFAULT_MODEL: () => DEFAULT_MODEL,
15
+ DEFAULT_REASONING_EFFORT: () => DEFAULT_REASONING_EFFORT,
16
+ EFFORTS: () => EFFORTS,
17
+ configPath: () => configPath,
18
+ loadConfig: () => loadConfig,
19
+ saveConfig: () => saveConfig
20
+ });
12
21
  import { readFile, mkdir, writeFile, chmod } from "fs/promises";
13
22
  import { homedir } from "os";
14
23
  import { join } from "path";
@@ -74,7 +83,7 @@ async function loadConfig() {
74
83
  const envCacheStable = process.env.KIMIFLARE_CACHE_STABLE_PROMPTS;
75
84
  const cacheStablePrompts = envCacheStable === "0" || envCacheStable === "false" ? false : true;
76
85
  const envCompiled = process.env.KIMIFLARE_COMPILED_CONTEXT;
77
- const compiledContext = envCompiled === "1" || envCompiled === "true" ? true : false;
86
+ const compiledContext = envCompiled === "0" || envCompiled === "false" ? false : true;
78
87
  const envImageTurns = process.env.KIMIFLARE_IMAGE_HISTORY_TURNS;
79
88
  const imageHistoryTurns = envImageTurns ? parseInt(envImageTurns, 10) : void 0;
80
89
  const envMemoryEnabled = readBooleanEnv("KIMIFLARE_MEMORY_ENABLED");
@@ -83,6 +92,7 @@ async function loadConfig() {
83
92
  const envMemoryMaxEntries = readNumberEnv("KIMIFLARE_MEMORY_MAX_ENTRIES");
84
93
  const envMemoryEmbeddingModel = process.env.KIMIFLARE_MEMORY_EMBEDDING_MODEL;
85
94
  const envPlumbingModel = process.env.KIMIFLARE_PLUMBING_MODEL;
95
+ const envMemoryExtractionModel = process.env.KIMIFLARE_MEMORY_EXTRACTION_MODEL;
86
96
  const envCodeMode = readBooleanEnv("KIMIFLARE_CODE_MODE");
87
97
  const envCostAttribution = readBooleanEnv("KIMI_COST_ATTRIBUTION");
88
98
  const envFilePicker = readBooleanEnv("KIMIFLARE_FILE_PICKER");
@@ -103,14 +113,15 @@ async function loadConfig() {
103
113
  cacheStablePrompts,
104
114
  compiledContext,
105
115
  imageHistoryTurns: Number.isNaN(imageHistoryTurns) ? void 0 : imageHistoryTurns,
106
- memoryEnabled: envMemoryEnabled,
116
+ memoryEnabled: envMemoryEnabled ?? true,
107
117
  memoryDbPath: envMemoryDbPath,
108
118
  memoryMaxAgeDays: envMemoryMaxAgeDays,
109
119
  memoryMaxEntries: envMemoryMaxEntries,
110
120
  memoryEmbeddingModel: envMemoryEmbeddingModel,
111
121
  plumbingModel: envPlumbingModel,
112
- codeMode: envCodeMode,
113
- costAttribution: envCostAttribution ?? false,
122
+ memoryExtractionModel: envMemoryExtractionModel,
123
+ codeMode: envCodeMode ?? true,
124
+ costAttribution: envCostAttribution ?? true,
114
125
  filePicker: envFilePicker ?? true
115
126
  };
116
127
  }
@@ -135,14 +146,15 @@ async function loadConfig() {
135
146
  cacheStablePrompts: parsed.cacheStablePrompts ?? cacheStablePrompts,
136
147
  compiledContext: parsed.compiledContext ?? compiledContext,
137
148
  imageHistoryTurns: Number.isNaN(imageHistoryTurns) ? parsed.imageHistoryTurns : imageHistoryTurns,
138
- memoryEnabled: envMemoryEnabled ?? parsed.memoryEnabled,
149
+ memoryEnabled: envMemoryEnabled ?? parsed.memoryEnabled ?? true,
139
150
  memoryDbPath: envMemoryDbPath ?? parsed.memoryDbPath,
140
151
  memoryMaxAgeDays: envMemoryMaxAgeDays ?? parsed.memoryMaxAgeDays,
141
152
  memoryMaxEntries: envMemoryMaxEntries ?? parsed.memoryMaxEntries,
142
153
  memoryEmbeddingModel: envMemoryEmbeddingModel ?? parsed.memoryEmbeddingModel,
143
154
  plumbingModel: envPlumbingModel ?? parsed.plumbingModel,
144
- codeMode: envCodeMode ?? parsed.codeMode,
145
- costAttribution: envCostAttribution ?? parsed.costAttribution ?? false,
155
+ memoryExtractionModel: envMemoryExtractionModel ?? parsed.memoryExtractionModel,
156
+ codeMode: envCodeMode ?? parsed.codeMode ?? true,
157
+ costAttribution: envCostAttribution ?? parsed.costAttribution ?? true,
146
158
  filePicker: envFilePicker ?? parsed.filePicker ?? true
147
159
  };
148
160
  }
@@ -544,44 +556,51 @@ async function* parseStream(body, signal) {
544
556
  lastUsage = chunk.usage;
545
557
  yield { type: "usage", usage: chunk.usage };
546
558
  }
559
+ if (typeof chunk.response === "string") {
560
+ const resp = chunk.response;
561
+ if (resp.length) {
562
+ yield { type: "text", delta: resp };
563
+ }
564
+ }
547
565
  const choice = chunk.choices?.[0];
548
- if (!choice) continue;
549
- const d = choice.delta;
550
- if (d) {
551
- if (typeof d.reasoning_content === "string" && d.reasoning_content.length) {
552
- yield { type: "reasoning", delta: d.reasoning_content };
553
- }
554
- if (typeof d.content === "string" && d.content.length) {
555
- yield { type: "text", delta: d.content };
556
- }
557
- if (Array.isArray(d.tool_calls)) {
558
- for (const tc of d.tool_calls) {
559
- const idx = typeof tc.index === "number" ? tc.index : 0;
560
- let buf = toolCalls.get(idx);
561
- const incomingName = tc.function?.name ?? null;
562
- const incomingId = tc.id ?? null;
563
- if (!buf) {
564
- buf = { id: incomingId ?? `tc_${idx}`, name: incomingName ?? "", args: "" };
565
- toolCalls.set(idx, buf);
566
- if (buf.name) {
567
- yield { type: "tool_call_start", index: idx, id: buf.id, name: buf.name };
566
+ if (choice) {
567
+ const d = choice.delta;
568
+ if (d) {
569
+ if (typeof d.reasoning_content === "string" && d.reasoning_content.length) {
570
+ yield { type: "reasoning", delta: d.reasoning_content };
571
+ }
572
+ if (typeof d.content === "string" && d.content.length) {
573
+ yield { type: "text", delta: d.content };
574
+ }
575
+ if (Array.isArray(d.tool_calls)) {
576
+ for (const tc of d.tool_calls) {
577
+ const idx = typeof tc.index === "number" ? tc.index : 0;
578
+ let buf = toolCalls.get(idx);
579
+ const incomingName = tc.function?.name ?? null;
580
+ const incomingId = tc.id ?? null;
581
+ if (!buf) {
582
+ buf = { id: incomingId ?? `tc_${idx}`, name: incomingName ?? "", args: "" };
583
+ toolCalls.set(idx, buf);
584
+ if (buf.name) {
585
+ yield { type: "tool_call_start", index: idx, id: buf.id, name: buf.name };
586
+ }
587
+ } else {
588
+ if (!buf.name && incomingName) {
589
+ buf.name = incomingName;
590
+ yield { type: "tool_call_start", index: idx, id: buf.id, name: buf.name };
591
+ }
592
+ if (buf.id.startsWith("tc_") && incomingId) buf.id = incomingId;
568
593
  }
569
- } else {
570
- if (!buf.name && incomingName) {
571
- buf.name = incomingName;
572
- yield { type: "tool_call_start", index: idx, id: buf.id, name: buf.name };
594
+ const argDelta = tc.function?.arguments;
595
+ if (typeof argDelta === "string" && argDelta.length) {
596
+ buf.args += argDelta;
597
+ yield { type: "tool_call_args", index: idx, argsDelta: argDelta };
573
598
  }
574
- if (buf.id.startsWith("tc_") && incomingId) buf.id = incomingId;
575
- }
576
- const argDelta = tc.function?.arguments;
577
- if (typeof argDelta === "string" && argDelta.length) {
578
- buf.args += argDelta;
579
- yield { type: "tool_call_args", index: idx, argsDelta: argDelta };
580
599
  }
581
600
  }
582
601
  }
602
+ if (choice.finish_reason) finishReason = choice.finish_reason;
583
603
  }
584
- if (choice.finish_reason) finishReason = choice.finish_reason;
585
604
  }
586
605
  for (const [idx, buf] of [...toolCalls.entries()].sort((a, b) => a[0] - b[0])) {
587
606
  if (!buf.name) continue;
@@ -933,7 +952,10 @@ async function logTurnDebug(ctx) {
933
952
  toolSavingsPct: toolTotalRaw > 0 ? Math.round((toolTotalRaw - toolTotalReduced) / toolTotalRaw * 100) : 0,
934
953
  cacheDiagnostics,
935
954
  compaction: ctx.compaction,
936
- shadowStrip: ctx.shadowStrip
955
+ shadowStrip: ctx.shadowStrip,
956
+ durationMs: ctx.durationMs,
957
+ intentClassification: ctx.intentClassification,
958
+ codeMode: ctx.codeMode
937
959
  });
938
960
  }
939
961
  var LOG_VERSION;
@@ -953,10 +975,129 @@ function safeJsonParse(text) {
953
975
  return null;
954
976
  }
955
977
  }
956
- var EXTRACTORS;
978
+ function truncate(str, max) {
979
+ if (str.length <= max) return str;
980
+ return str.slice(0, max) + "\u2026";
981
+ }
982
+ async function callLlm(messages, llmOpts, maxTokens = 64) {
983
+ if (!llmOpts) return "";
984
+ const events = runKimi({
985
+ accountId: llmOpts.accountId,
986
+ apiToken: llmOpts.apiToken,
987
+ model: llmOpts.model,
988
+ messages,
989
+ temperature: 0.1,
990
+ maxCompletionTokens: maxTokens,
991
+ gateway: llmOpts.gateway,
992
+ signal: llmOpts.signal
993
+ });
994
+ let text = "";
995
+ for await (const ev of events) {
996
+ if (ev.type === "text") text += ev.delta;
997
+ }
998
+ return text.trim().replace(/^["']|["']$/g, "").replace(/\s+/g, " ").toLowerCase();
999
+ }
1000
+ async function synthesizeEditEvent(file, toolName, toolArgs, assistantMessage, llmOpts) {
1001
+ if (!llmOpts) return null;
1002
+ const oldString = typeof toolArgs.old_string === "string" ? toolArgs.old_string : "";
1003
+ const newString = typeof toolArgs.new_string === "string" ? toolArgs.new_string : "";
1004
+ const fullContent = typeof toolArgs.content === "string" ? toolArgs.content : "";
1005
+ const isWrite = toolName === "write";
1006
+ const before = isWrite ? "(new file)" : truncate(oldString, 600);
1007
+ const after = isWrite ? truncate(fullContent, 600) : truncate(newString, 600);
1008
+ const intent = assistantMessage ? assistantMessage.slice(-300).trim() : "";
1009
+ const changeContext = `File: ${file}
1010
+ Tool: ${toolName}
1011
+
1012
+ Before:
1013
+ ${before}
1014
+
1015
+ After:
1016
+ ${after}${intent ? `
1017
+
1018
+ Context: ${intent}` : ""}`;
1019
+ const summary1 = await callLlm(
1020
+ [
1021
+ { role: "system", content: EDIT_SYNTHESIS_SYSTEM },
1022
+ { role: "user", content: `${changeContext}
1023
+
1024
+ Summary:` }
1025
+ ],
1026
+ llmOpts
1027
+ );
1028
+ if (summary1.length >= 10 && summary1.length <= 200) {
1029
+ const verdict = await callLlm(
1030
+ [
1031
+ { role: "system", content: VERIFIER_SYSTEM },
1032
+ {
1033
+ role: "user",
1034
+ content: `${changeContext}
1035
+
1036
+ Proposed summary: "${summary1}"
1037
+
1038
+ Is this accurate?`
1039
+ }
1040
+ ],
1041
+ llmOpts,
1042
+ 8
1043
+ );
1044
+ if (verdict.startsWith("yes")) return summary1;
1045
+ }
1046
+ const retrySystem = `${EDIT_SYNTHESIS_SYSTEM}
1047
+
1048
+ CRITICAL: The previous summary was rejected. Be specific. Include concrete details from the After section.`;
1049
+ const summary2 = await callLlm(
1050
+ [
1051
+ { role: "system", content: retrySystem },
1052
+ { role: "user", content: `${changeContext}
1053
+
1054
+ Summary:` }
1055
+ ],
1056
+ llmOpts
1057
+ );
1058
+ if (summary2.length >= 10 && summary2.length <= 200) {
1059
+ const verdict2 = await callLlm(
1060
+ [
1061
+ { role: "system", content: VERIFIER_SYSTEM },
1062
+ {
1063
+ role: "user",
1064
+ content: `${changeContext}
1065
+
1066
+ Proposed summary: "${summary2}"
1067
+
1068
+ Is this accurate?`
1069
+ }
1070
+ ],
1071
+ llmOpts,
1072
+ 8
1073
+ );
1074
+ if (verdict2.startsWith("yes")) return summary2;
1075
+ }
1076
+ return null;
1077
+ }
1078
+ var EDIT_SYNTHESIS_SYSTEM, VERIFIER_SYSTEM, EXTRACTORS;
957
1079
  var init_extractors = __esm({
958
1080
  "src/memory/extractors.ts"() {
959
1081
  "use strict";
1082
+ init_client();
1083
+ EDIT_SYNTHESIS_SYSTEM = `You summarize a SINGLE code edit. Write ONE concise sentence (max 20 words) describing exactly what changed.
1084
+
1085
+ Rules:
1086
+ - Use ONLY the Before/After diff below.
1087
+ - For new files: describe the file's content or purpose. Never say just "added a new file".
1088
+ - For edits: describe the specific code change.
1089
+
1090
+ Examples:
1091
+ - Created test-memory.md containing the text "Memory test".
1092
+ - Fixed race condition in loop.ts by adding AbortSignal guard.
1093
+ - Added vitest dependency and removed jest from package.json.
1094
+
1095
+ Respond with only the summary sentence. No quotes, no preamble.`;
1096
+ VERIFIER_SYSTEM = `You verify whether a summary accurately describes a code edit.
1097
+ Answer exactly "yes" if the summary correctly captures what changed in the file.
1098
+ Answer exactly "no" if the summary is vague, wrong, or misses the actual change.
1099
+
1100
+ Respond with only "yes" or "no".`;
960
1101
  EXTRACTORS = [
961
1102
  {
962
1103
  id: "package_json",
@@ -1010,9 +1151,27 @@ var init_extractors = __esm({
1010
1151
  {
1011
1152
  id: "edit_event",
1012
1153
  match: (tool, file) => (tool === "edit" || tool === "write") && !!file,
1013
- extract: (_content, file) => {
1154
+ extract: async (_content, file, ctx) => {
1014
1155
  if (!file) return null;
1015
1156
  const safeKey = file.replace(/[^a-zA-Z0-9]/g, "_");
1157
+ if (ctx?.llmOpts && (ctx.toolArgs || ctx.assistantMessage)) {
1158
+ const summary = await synthesizeEditEvent(
1159
+ file,
1160
+ ctx.toolArgs?._toolName || "edit",
1161
+ ctx.toolArgs || {},
1162
+ ctx.assistantMessage,
1163
+ ctx.llmOpts
1164
+ );
1165
+ if (summary) {
1166
+ return {
1167
+ content: summary,
1168
+ category: "event",
1169
+ importance: 3,
1170
+ topicKey: `event_edit_${safeKey}`,
1171
+ relatedFiles: [file]
1172
+ };
1173
+ }
1174
+ }
1016
1175
  return {
1017
1176
  content: `File modified: ${file}.`,
1018
1177
  category: "event",
@@ -1356,6 +1515,7 @@ var init_code_mode = __esm({
1356
1515
 
1357
1516
  // src/agent/loop.ts
1358
1517
  async function runAgentTurn(opts2) {
1518
+ const turnStart = performance.now();
1359
1519
  const max = opts2.maxToolIterations ?? 50;
1360
1520
  const codeMode = opts2.codeMode ?? false;
1361
1521
  let toolDefs;
@@ -1702,25 +1862,44 @@ ${sandboxResult.output}` : sandboxResult.output;
1702
1862
  opts2.callbacks.onToolResult?.(result);
1703
1863
  if (opts2.memoryManager) {
1704
1864
  let filePath;
1865
+ let toolArgs = {};
1705
1866
  try {
1706
- const args = JSON.parse(tc.function.arguments || "{}");
1707
- filePath = args.path;
1867
+ toolArgs = JSON.parse(tc.function.arguments || "{}");
1868
+ filePath = toolArgs.path;
1708
1869
  } catch {
1709
1870
  }
1871
+ const lastAssistant = [...opts2.messages].reverse().find(
1872
+ (m) => m.role === "assistant" && m.tool_calls && m.tool_calls.length > 0
1873
+ );
1874
+ const assistantMessage = lastAssistant?.content ?? "";
1875
+ const llmOpts = opts2.memoryManager.getExtractionLlmOpts();
1710
1876
  for (const extractor of EXTRACTORS) {
1711
1877
  if (extractor.match(tc.function.name, filePath)) {
1712
- const memory = extractor.extract(result.content, filePath);
1713
- if (memory) {
1714
- void opts2.memoryManager.remember(
1715
- memory.content,
1716
- memory.category,
1717
- memory.importance,
1718
- opts2.cwd,
1719
- opts2.sessionId ?? "unknown",
1720
- opts2.signal
1721
- ).catch(() => {
1722
- });
1723
- }
1878
+ void (async () => {
1879
+ try {
1880
+ const memory = await extractor.extract(result.content, filePath, {
1881
+ toolArgs: { ...toolArgs, _toolName: tc.function.name },
1882
+ assistantMessage: typeof assistantMessage === "string" ? assistantMessage : "",
1883
+ llmOpts: {
1884
+ ...llmOpts,
1885
+ signal: opts2.signal
1886
+ }
1887
+ });
1888
+ if (memory) {
1889
+ await opts2.memoryManager.remember(
1890
+ memory.content,
1891
+ memory.category,
1892
+ memory.importance,
1893
+ opts2.cwd,
1894
+ opts2.sessionId ?? "unknown",
1895
+ opts2.signal,
1896
+ void 0,
1897
+ memory.topicKey
1898
+ );
1899
+ }
1900
+ } catch {
1901
+ }
1902
+ })();
1724
1903
  }
1725
1904
  }
1726
1905
  }
@@ -1728,6 +1907,10 @@ ${sandboxResult.output}` : sandboxResult.output;
1728
1907
  if (recentToolCalls.length > LOOP_WINDOW) recentToolCalls.shift();
1729
1908
  }
1730
1909
  }
1910
+ if (opts2.onIterationEnd) {
1911
+ opts2.messages = await opts2.onIterationEnd(opts2.messages, opts2.signal);
1912
+ if (opts2.signal.aborted) throw new DOMException("aborted", "AbortError");
1913
+ }
1731
1914
  if (opts2.sessionId && lastUsage) {
1732
1915
  void logTurnDebug({
1733
1916
  sessionId: opts2.sessionId,
@@ -1736,7 +1919,10 @@ ${sandboxResult.output}` : sandboxResult.output;
1736
1919
  previousMessages,
1737
1920
  toolResults,
1738
1921
  usage: lastUsage,
1739
- shadowStrip: shadowStripMetrics
1922
+ shadowStrip: shadowStripMetrics,
1923
+ durationMs: Math.round(performance.now() - turnStart),
1924
+ intentClassification: opts2.intentClassification,
1925
+ codeMode: opts2.codeMode
1740
1926
  });
1741
1927
  }
1742
1928
  if (budgetExhausted) {
@@ -3531,6 +3717,229 @@ var init_update_check = __esm({
3531
3717
  }
3532
3718
  });
3533
3719
 
3720
+ // src/remote/session-store.ts
3721
+ import { readFile as readFile8, writeFile as writeFile6, mkdir as mkdir6, readdir as readdir2 } from "fs/promises";
3722
+ import { homedir as homedir6 } from "os";
3723
+ import { join as join9 } from "path";
3724
+ function remoteDir() {
3725
+ const xdg = process.env.XDG_DATA_HOME || join9(homedir6(), ".config");
3726
+ return join9(xdg, "kimiflare", "remote");
3727
+ }
3728
+ async function saveRemoteSession(session) {
3729
+ const dir = remoteDir();
3730
+ await mkdir6(dir, { recursive: true });
3731
+ const path = join9(dir, `${session.sessionId}.json`);
3732
+ await writeFile6(path, JSON.stringify(session, null, 2) + "\n", "utf8");
3733
+ }
3734
+ async function loadRemoteSession(sessionId) {
3735
+ try {
3736
+ const path = join9(remoteDir(), `${sessionId}.json`);
3737
+ const raw = await readFile8(path, "utf8");
3738
+ return JSON.parse(raw);
3739
+ } catch {
3740
+ return null;
3741
+ }
3742
+ }
3743
+ async function listRemoteSessions() {
3744
+ const dir = remoteDir();
3745
+ try {
3746
+ const files = await readdir2(dir);
3747
+ const sessions = [];
3748
+ for (const file of files) {
3749
+ if (!file.endsWith(".json")) continue;
3750
+ try {
3751
+ const raw = await readFile8(join9(dir, file), "utf8");
3752
+ sessions.push(JSON.parse(raw));
3753
+ } catch {
3754
+ }
3755
+ }
3756
+ return sessions.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
3757
+ } catch {
3758
+ return [];
3759
+ }
3760
+ }
3761
+ async function getMostRecentRemoteSession() {
3762
+ const sessions = await listRemoteSessions();
3763
+ return sessions[0] ?? null;
3764
+ }
3765
+ var init_session_store = __esm({
3766
+ "src/remote/session-store.ts"() {
3767
+ "use strict";
3768
+ }
3769
+ });
3770
+
3771
+ // src/remote/deploy.ts
3772
+ import { execSync } from "child_process";
3773
+ import { join as join10, dirname as dirname5 } from "path";
3774
+ import { fileURLToPath as fileURLToPath3 } from "url";
3775
+ import { randomBytes } from "crypto";
3776
+ function generateSecret() {
3777
+ return randomBytes(32).toString("hex");
3778
+ }
3779
+ function runCapture(cmd, cwd) {
3780
+ return execSync(cmd, { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }).trim();
3781
+ }
3782
+ async function* deployForTui() {
3783
+ yield { message: "Checking prerequisites..." };
3784
+ try {
3785
+ runCapture("wrangler --version");
3786
+ } catch {
3787
+ yield { message: "wrangler not found. Install: npm install -g wrangler", error: true };
3788
+ yield { message: "Then run: wrangler login", error: true };
3789
+ throw new Error("wrangler not installed");
3790
+ }
3791
+ yield { message: "wrangler OK" };
3792
+ try {
3793
+ runCapture("wrangler whoami");
3794
+ } catch {
3795
+ yield { message: "wrangler not authenticated. Run: wrangler login", error: true };
3796
+ throw new Error("wrangler not authenticated");
3797
+ }
3798
+ yield { message: "wrangler authenticated" };
3799
+ try {
3800
+ runCapture("docker --version");
3801
+ } catch {
3802
+ yield { message: "Docker not found. Install: https://docs.docker.com/get-docker/", error: true };
3803
+ throw new Error("docker not installed");
3804
+ }
3805
+ yield { message: "Docker OK" };
3806
+ yield { message: "Building remote agent bundle..." };
3807
+ try {
3808
+ runCapture("npm run build:remote-agent", join10(REMOTE_DIR, ".."));
3809
+ yield { message: "Agent bundle built" };
3810
+ } catch (err) {
3811
+ yield { message: `Build failed: ${err instanceof Error ? err.message : String(err)}`, error: true };
3812
+ throw err;
3813
+ }
3814
+ yield { message: "Deploying Worker to Cloudflare..." };
3815
+ try {
3816
+ runCapture("wrangler deploy", WORKER_DIR);
3817
+ yield { message: "Worker deployed" };
3818
+ } catch (err) {
3819
+ yield { message: `Deploy failed: ${err instanceof Error ? err.message : String(err)}`, error: true };
3820
+ throw err;
3821
+ }
3822
+ let workerUrl;
3823
+ try {
3824
+ const info = runCapture("wrangler info", WORKER_DIR);
3825
+ const match = info.match(/https:\/\/[^\s]+\.workers\.dev/);
3826
+ if (match) workerUrl = match[0];
3827
+ } catch {
3828
+ }
3829
+ if (!workerUrl) {
3830
+ yield { message: "Could not auto-detect Worker URL", error: true };
3831
+ throw new Error("Worker URL not found");
3832
+ }
3833
+ yield { message: `Worker URL: ${workerUrl}` };
3834
+ const authSecret = generateSecret();
3835
+ const cfg = await loadConfig();
3836
+ const cfToken = process.env.CF_API_TOKEN ?? cfg?.apiToken;
3837
+ if (!cfToken) {
3838
+ yield { message: "CF_API_TOKEN not found. Set CF_API_TOKEN env var or apiToken in config", error: true };
3839
+ throw new Error("CF_API_TOKEN missing");
3840
+ }
3841
+ yield { message: "Setting Worker secrets..." };
3842
+ try {
3843
+ execSync(`wrangler secret put REMOTE_AUTH_SECRET`, {
3844
+ cwd: WORKER_DIR,
3845
+ input: authSecret,
3846
+ stdio: ["pipe", "pipe", "pipe"]
3847
+ });
3848
+ execSync(`wrangler secret put CF_API_TOKEN`, {
3849
+ cwd: WORKER_DIR,
3850
+ input: cfToken,
3851
+ stdio: ["pipe", "pipe", "pipe"]
3852
+ });
3853
+ yield { message: "Secrets set" };
3854
+ } catch (err) {
3855
+ yield { message: `Secret setup failed: ${err instanceof Error ? err.message : String(err)}`, error: true };
3856
+ throw err;
3857
+ }
3858
+ const imageTag = "ghcr.io/sinameraji/kimiflare-remote-agent:latest";
3859
+ yield { message: "Building container image..." };
3860
+ try {
3861
+ runCapture(`docker build -t ${imageTag} .`, REMOTE_DIR);
3862
+ yield { message: "Image built" };
3863
+ } catch (err) {
3864
+ yield { message: `Image build failed: ${err instanceof Error ? err.message : String(err)}`, error: true };
3865
+ throw err;
3866
+ }
3867
+ yield { message: `Pushing ${imageTag}...` };
3868
+ try {
3869
+ runCapture(`docker push ${imageTag}`, REMOTE_DIR);
3870
+ yield { message: "Image pushed" };
3871
+ } catch (err) {
3872
+ yield { message: `Push failed: ${err instanceof Error ? err.message : String(err)}`, error: true };
3873
+ yield { message: "Make sure you're logged into ghcr.io: docker login ghcr.io -u USERNAME -p GITHUB_TOKEN", error: true };
3874
+ throw err;
3875
+ }
3876
+ const nextCfg = {
3877
+ ...cfg ?? { accountId: "", apiToken: "", model: "@cf/moonshotai/kimi-k2.6" },
3878
+ remoteWorkerUrl: workerUrl,
3879
+ remoteAuthSecret: authSecret
3880
+ };
3881
+ await saveConfig(nextCfg);
3882
+ yield { message: "Config saved" };
3883
+ yield { message: "Remote infrastructure ready!", done: true };
3884
+ return { workerUrl, authSecret };
3885
+ }
3886
+ async function runDeploy() {
3887
+ console.log("kimiflare remote deploy\n");
3888
+ try {
3889
+ for await (const step of deployForTui()) {
3890
+ console.log(step.message);
3891
+ if (step.done) break;
3892
+ if (step.error) process.exit(1);
3893
+ }
3894
+ console.log("\nDeploy complete!");
3895
+ } catch (err) {
3896
+ console.error(`Deploy failed: ${err instanceof Error ? err.message : String(err)}`);
3897
+ process.exit(1);
3898
+ }
3899
+ }
3900
+ async function checkDeployStatus() {
3901
+ let wrangler = false;
3902
+ let wranglerAuth = false;
3903
+ let docker = false;
3904
+ let workerUrl;
3905
+ try {
3906
+ execSync("wrangler --version", { stdio: "pipe" });
3907
+ wrangler = true;
3908
+ } catch {
3909
+ }
3910
+ if (wrangler) {
3911
+ try {
3912
+ execSync("wrangler whoami", { stdio: "pipe" });
3913
+ wranglerAuth = true;
3914
+ } catch {
3915
+ }
3916
+ }
3917
+ try {
3918
+ execSync("docker --version", { stdio: "pipe" });
3919
+ docker = true;
3920
+ } catch {
3921
+ }
3922
+ const cfg = await loadConfig();
3923
+ if (cfg?.remoteWorkerUrl) {
3924
+ try {
3925
+ const res = await fetch(`${cfg.remoteWorkerUrl}/health`, { signal: AbortSignal.timeout(5e3) });
3926
+ if (res.ok) workerUrl = cfg.remoteWorkerUrl;
3927
+ } catch {
3928
+ }
3929
+ }
3930
+ return { wrangler, wranglerAuth, docker, workerUrl };
3931
+ }
3932
+ var __dirname, REMOTE_DIR, WORKER_DIR;
3933
+ var init_deploy = __esm({
3934
+ "src/remote/deploy.ts"() {
3935
+ "use strict";
3936
+ init_config();
3937
+ __dirname = dirname5(fileURLToPath3(import.meta.url));
3938
+ REMOTE_DIR = join10(__dirname, "..", "..", "..", "remote");
3939
+ WORKER_DIR = join10(REMOTE_DIR, "worker");
3940
+ }
3941
+ });
3942
+
3534
3943
  // src/cost-attribution/types.ts
3535
3944
  var ALL_CATEGORIES;
3536
3945
  var init_types = __esm({
@@ -3950,12 +4359,12 @@ var init_heuristic = __esm({
3950
4359
  });
3951
4360
 
3952
4361
  // src/cost-attribution/classify-from-session.ts
3953
- import { readFile as readFile8 } from "fs/promises";
3954
- import { join as join9 } from "path";
3955
- import { homedir as homedir6 } from "os";
4362
+ import { readFile as readFile9 } from "fs/promises";
4363
+ import { join as join11 } from "path";
4364
+ import { homedir as homedir7 } from "os";
3956
4365
  function sessionsDir() {
3957
- const xdg = process.env.XDG_DATA_HOME || join9(homedir6(), ".local", "share");
3958
- return join9(xdg, "kimiflare", "sessions");
4366
+ const xdg = process.env.XDG_DATA_HOME || join11(homedir7(), ".local", "share");
4367
+ return join11(xdg, "kimiflare", "sessions");
3959
4368
  }
3960
4369
  function parseToolCalls(calls) {
3961
4370
  return calls.map((c) => {
@@ -3969,7 +4378,7 @@ function parseToolCalls(calls) {
3969
4378
  }
3970
4379
  async function classifyFromSessionFile(sessionId) {
3971
4380
  try {
3972
- const raw = await readFile8(join9(sessionsDir(), `${sessionId}.json`), "utf8");
4381
+ const raw = await readFile9(join11(sessionsDir(), `${sessionId}.json`), "utf8");
3973
4382
  const session = JSON.parse(raw);
3974
4383
  const messages = session.messages ?? [];
3975
4384
  const turns = [];
@@ -4002,15 +4411,15 @@ var cli_exports = {};
4002
4411
  __export(cli_exports, {
4003
4412
  runCostCommand: () => runCostCommand
4004
4413
  });
4005
- import { readFile as readFile9 } from "fs/promises";
4006
- import { join as join10 } from "path";
4007
- import { homedir as homedir7 } from "os";
4414
+ import { readFile as readFile10 } from "fs/promises";
4415
+ import { join as join12 } from "path";
4416
+ import { homedir as homedir8 } from "os";
4008
4417
  function usageDir() {
4009
- const xdg = process.env.XDG_DATA_HOME || join10(homedir7(), ".local", "share");
4010
- return join10(xdg, "kimiflare");
4418
+ const xdg = process.env.XDG_DATA_HOME || join12(homedir8(), ".local", "share");
4419
+ return join12(xdg, "kimiflare");
4011
4420
  }
4012
4421
  function usagePath() {
4013
- return join10(usageDir(), "usage.json");
4422
+ return join12(usageDir(), "usage.json");
4014
4423
  }
4015
4424
  function today() {
4016
4425
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
@@ -4022,7 +4431,7 @@ function daysAgo(n) {
4022
4431
  }
4023
4432
  async function loadLog() {
4024
4433
  try {
4025
- const raw = await readFile9(usagePath(), "utf8");
4434
+ const raw = await readFile10(usagePath(), "utf8");
4026
4435
  return JSON.parse(raw);
4027
4436
  } catch {
4028
4437
  return { version: 1, days: [], sessions: [] };
@@ -4108,6 +4517,94 @@ var init_cli = __esm({
4108
4517
  }
4109
4518
  });
4110
4519
 
4520
+ // src/remote/tui-auth.ts
4521
+ var tui_auth_exports = {};
4522
+ __export(tui_auth_exports, {
4523
+ authGitHubForTui: () => authGitHubForTui
4524
+ });
4525
+ function sleep2(ms) {
4526
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
4527
+ }
4528
+ async function* authGitHubForTui() {
4529
+ yield { message: "Starting GitHub OAuth device flow..." };
4530
+ const deviceRes = await fetch(GITHUB_DEVICE_AUTH_URL, {
4531
+ method: "POST",
4532
+ headers: {
4533
+ Accept: "application/json",
4534
+ "Content-Type": "application/x-www-form-urlencoded"
4535
+ },
4536
+ body: new URLSearchParams({ client_id: CLIENT_ID, scope: "repo" })
4537
+ });
4538
+ if (!deviceRes.ok) {
4539
+ yield { message: `Failed to request device code: ${deviceRes.status}`, error: true };
4540
+ throw new Error("Device code request failed");
4541
+ }
4542
+ const deviceData = await deviceRes.json();
4543
+ yield {
4544
+ message: `Open ${deviceData.verification_uri} and enter code: ${deviceData.user_code}`,
4545
+ url: deviceData.verification_uri,
4546
+ code: deviceData.user_code
4547
+ };
4548
+ const startTime = Date.now();
4549
+ const expiresIn = deviceData.expires_in * 1e3;
4550
+ const interval = deviceData.interval * 1e3;
4551
+ while (Date.now() - startTime < expiresIn) {
4552
+ await sleep2(interval);
4553
+ const tokenRes = await fetch(GITHUB_ACCESS_TOKEN_URL, {
4554
+ method: "POST",
4555
+ headers: {
4556
+ Accept: "application/json",
4557
+ "Content-Type": "application/x-www-form-urlencoded"
4558
+ },
4559
+ body: new URLSearchParams({
4560
+ client_id: CLIENT_ID,
4561
+ device_code: deviceData.device_code,
4562
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code"
4563
+ })
4564
+ });
4565
+ if (!tokenRes.ok) continue;
4566
+ const tokenData = await tokenRes.json();
4567
+ if (tokenData.error === "authorization_pending") {
4568
+ continue;
4569
+ }
4570
+ if (tokenData.error === "slow_down") {
4571
+ await sleep2(interval * 2);
4572
+ continue;
4573
+ }
4574
+ if (tokenData.error) {
4575
+ yield { message: `OAuth error: ${tokenData.error}`, error: true };
4576
+ throw new Error(tokenData.error);
4577
+ }
4578
+ if (tokenData.access_token) {
4579
+ const cfg = await loadConfig() ?? {
4580
+ accountId: "",
4581
+ apiToken: "",
4582
+ model: "@cf/moonshotai/kimi-k2.6"
4583
+ };
4584
+ await saveConfig({
4585
+ ...cfg,
4586
+ githubOAuthToken: tokenData.access_token,
4587
+ githubRefreshToken: tokenData.refresh_token,
4588
+ githubTokenExpiry: tokenData.expires_in ? Date.now() + tokenData.expires_in * 1e3 : void 0
4589
+ });
4590
+ yield { message: "GitHub authentication successful!", done: true };
4591
+ return;
4592
+ }
4593
+ }
4594
+ yield { message: "Device flow expired. Please try again.", error: true };
4595
+ throw new Error("Device flow expired");
4596
+ }
4597
+ var GITHUB_DEVICE_AUTH_URL, GITHUB_ACCESS_TOKEN_URL, CLIENT_ID;
4598
+ var init_tui_auth = __esm({
4599
+ "src/remote/tui-auth.ts"() {
4600
+ "use strict";
4601
+ init_config();
4602
+ GITHUB_DEVICE_AUTH_URL = "https://github.com/login/device/code";
4603
+ GITHUB_ACCESS_TOKEN_URL = "https://github.com/login/oauth/access_token";
4604
+ CLIENT_ID = process.env.KIMIFLARE_GITHUB_CLIENT_ID ?? "Ov23liM7lJX1xE2V1sVK";
4605
+ }
4606
+ });
4607
+
4111
4608
  // src/agent/compact.ts
4112
4609
  function indexOfNthUserFromEnd(messages, n) {
4113
4610
  let seen = 0;
@@ -4929,12 +5426,12 @@ var init_connection = __esm({
4929
5426
  });
4930
5427
 
4931
5428
  // src/lsp/protocol.ts
4932
- import { pathToFileURL, fileURLToPath as fileURLToPath3 } from "url";
5429
+ import { pathToFileURL, fileURLToPath as fileURLToPath4 } from "url";
4933
5430
  function toUri(path) {
4934
5431
  return pathToFileURL(path).href;
4935
5432
  }
4936
5433
  function fromUri(uri) {
4937
- return fileURLToPath3(uri);
5434
+ return fileURLToPath4(uri);
4938
5435
  }
4939
5436
  function symbolKindName(kind) {
4940
5437
  const names = {
@@ -7569,90 +8066,440 @@ var init_help_menu = __esm({
7569
8066
  }
7570
8067
  });
7571
8068
 
7572
- // src/sessions.ts
7573
- var sessions_exports = {};
7574
- __export(sessions_exports, {
7575
- listSessions: () => listSessions,
7576
- loadSession: () => loadSession,
7577
- makeSessionId: () => makeSessionId,
7578
- pruneSessions: () => pruneSessions,
7579
- saveSession: () => saveSession
8069
+ // src/remote/worker-client.ts
8070
+ var worker_client_exports = {};
8071
+ __export(worker_client_exports, {
8072
+ cancelRemoteSession: () => cancelRemoteSession,
8073
+ getRemoteStatus: () => getRemoteStatus,
8074
+ startRemoteSession: () => startRemoteSession,
8075
+ streamRemoteProgress: () => streamRemoteProgress
7580
8076
  });
7581
- import { readFile as readFile10, writeFile as writeFile6, mkdir as mkdir6, readdir as readdir2, stat as stat3 } from "fs/promises";
7582
- import { homedir as homedir8 } from "os";
7583
- import { join as join11 } from "path";
7584
- function sessionsDir2() {
7585
- const xdg = process.env.XDG_DATA_HOME || join11(homedir8(), ".local", "share");
7586
- return join11(xdg, "kimiflare", "sessions");
7587
- }
7588
- function sanitize(text) {
7589
- return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
7590
- }
7591
- function makeSessionId(firstPrompt) {
7592
- const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
7593
- const slug = sanitize(firstPrompt) || "session";
7594
- return `${ts}_${slug}`;
7595
- }
7596
- async function saveSession(file) {
7597
- const dir = sessionsDir2();
7598
- await mkdir6(dir, { recursive: true });
7599
- const path = join11(dir, `${file.id}.json`);
7600
- await writeFile6(path, JSON.stringify(file, null, 2), "utf8");
7601
- return path;
7602
- }
7603
- async function pruneSessions() {
7604
- const dir = sessionsDir2();
7605
- const files = await listFilesByMtime(dir, /\.json$/);
7606
- return pruneFiles(files, RETENTION.sessionMaxAgeDays, RETENTION.sessionMaxCount);
8077
+ async function startRemoteSession(opts2) {
8078
+ const workerUrl = opts2.cfg.remoteWorkerUrl;
8079
+ if (!workerUrl) {
8080
+ throw new Error("Remote worker URL not configured. Set remoteWorkerUrl in config.");
8081
+ }
8082
+ const githubToken = opts2.cfg.githubOAuthToken;
8083
+ if (!githubToken) {
8084
+ throw new Error("GitHub token not found. Run `kimiflare auth github` first.");
8085
+ }
8086
+ const res = await fetch(`${workerUrl}/remote/start`, {
8087
+ method: "POST",
8088
+ headers: {
8089
+ "Content-Type": "application/json",
8090
+ Authorization: `Bearer ${opts2.cfg.remoteAuthSecret ?? ""}`
8091
+ },
8092
+ body: JSON.stringify({
8093
+ prompt: opts2.prompt,
8094
+ repo: opts2.repo,
8095
+ githubToken,
8096
+ accountId: opts2.cfg.accountId,
8097
+ apiToken: opts2.cfg.apiToken,
8098
+ model: opts2.cfg.model,
8099
+ reasoningEffort: opts2.cfg.reasoningEffort,
8100
+ ttlMinutes: opts2.ttlMinutes ?? opts2.cfg.remoteTtlMinutes,
8101
+ tokensBudget: opts2.tokensBudget ?? opts2.cfg.remoteMaxInputTokens
8102
+ })
8103
+ });
8104
+ if (!res.ok) {
8105
+ const text = await res.text();
8106
+ throw new Error(`Failed to start remote session: ${res.status} ${text}`);
8107
+ }
8108
+ const data = await res.json();
8109
+ await saveRemoteSession({
8110
+ sessionId: data.sessionId,
8111
+ prompt: opts2.prompt,
8112
+ repo: `${opts2.repo.owner}/${opts2.repo.name}`,
8113
+ workerUrl,
8114
+ status: "running",
8115
+ branch: `kimiflare/remote/${data.sessionId}`,
8116
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
8117
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
8118
+ });
8119
+ return data;
7607
8120
  }
7608
- async function listSessions(limit = 30) {
7609
- const dir = sessionsDir2();
7610
- let entries;
7611
- try {
7612
- entries = await readdir2(dir);
7613
- } catch {
7614
- return [];
8121
+ async function* streamRemoteProgress(workerUrl, sessionId, signal) {
8122
+ const res = await fetch(`${workerUrl}/remote/stream/${sessionId}`, { signal });
8123
+ if (!res.ok) {
8124
+ throw new Error(`Failed to connect to stream: ${res.status}`);
7615
8125
  }
7616
- const summaries = [];
7617
- for (const name of entries) {
7618
- if (!name.endsWith(".json")) continue;
7619
- const path = join11(dir, name);
8126
+ if (!res.body) {
8127
+ throw new Error("No response body");
8128
+ }
8129
+ for await (const line of readSSE(res.body, signal)) {
7620
8130
  try {
7621
- const [s, raw] = await Promise.all([stat3(path), readFile10(path, "utf8")]);
7622
- const parsed = JSON.parse(raw);
7623
- const firstUser = parsed.messages.find((m) => m.role === "user");
7624
- const firstPrompt = typeof firstUser?.content === "string" ? firstUser.content : firstUser?.content ? firstUser.content.find((p) => p.type === "text")?.text ?? "(no prompt)" : "(no prompt)";
7625
- summaries.push({
7626
- id: parsed.id,
7627
- filePath: path,
7628
- cwd: parsed.cwd,
7629
- firstPrompt: firstPrompt.slice(0, 80),
7630
- messageCount: parsed.messages.filter((m) => m.role !== "system").length,
7631
- updatedAt: parsed.updatedAt ?? s.mtime.toISOString()
7632
- });
8131
+ yield JSON.parse(line);
7633
8132
  } catch {
7634
8133
  }
7635
8134
  }
7636
- summaries.sort((a, b) => b.updatedAt < a.updatedAt ? -1 : 1);
7637
- return summaries.slice(0, limit);
7638
8135
  }
7639
- async function loadSession(filePath) {
7640
- const raw = await readFile10(filePath, "utf8");
7641
- return JSON.parse(raw);
8136
+ async function getRemoteStatus(workerUrl, sessionId, authSecret) {
8137
+ const res = await fetch(`${workerUrl}/remote/status/${sessionId}`, {
8138
+ headers: authSecret ? { Authorization: `Bearer ${authSecret}` } : {}
8139
+ });
8140
+ if (!res.ok) {
8141
+ const text = await res.text();
8142
+ throw new Error(`Failed to get status: ${res.status} ${text}`);
8143
+ }
8144
+ return res.json();
7642
8145
  }
7643
- var init_sessions = __esm({
7644
- "src/sessions.ts"() {
8146
+ async function cancelRemoteSession(workerUrl, sessionId, authSecret) {
8147
+ const res = await fetch(`${workerUrl}/remote/cancel/${sessionId}`, {
8148
+ method: "POST",
8149
+ headers: authSecret ? { Authorization: `Bearer ${authSecret}` } : {}
8150
+ });
8151
+ if (!res.ok) {
8152
+ const text = await res.text();
8153
+ throw new Error(`Failed to cancel session: ${res.status} ${text}`);
8154
+ }
8155
+ }
8156
+ var init_worker_client = __esm({
8157
+ "src/remote/worker-client.ts"() {
7645
8158
  "use strict";
7646
- init_storage_limits();
8159
+ init_session_store();
8160
+ init_sse();
7647
8161
  }
7648
8162
  });
7649
8163
 
7650
- // src/util/image.ts
7651
- import { readFile as readFile11 } from "fs/promises";
7652
- import { basename as basename3 } from "path";
7653
- async function encodeImageFile(filePath) {
7654
- const buf = await readFile11(filePath);
7655
- if (buf.byteLength > MAX_IMAGE_BYTES) {
8164
+ // src/remote/tui-deploy.ts
8165
+ var init_tui_deploy = __esm({
8166
+ "src/remote/tui-deploy.ts"() {
8167
+ "use strict";
8168
+ init_deploy();
8169
+ }
8170
+ });
8171
+
8172
+ // src/ui/remote-dashboard.tsx
8173
+ import { useEffect as useEffect4, useState as useState7 } from "react";
8174
+ import { Box as Box12, Text as Text13, useInput as useInput3 } from "ink";
8175
+ import SelectInput4 from "ink-select-input";
8176
+ import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
8177
+ function RemoteDashboard({ onSelect, onCancel }) {
8178
+ const theme = useTheme();
8179
+ const [sessions, setSessions] = useState7([]);
8180
+ const [loading, setLoading] = useState7(true);
8181
+ const [error, setError] = useState7(null);
8182
+ const [refreshing, setRefreshing] = useState7(false);
8183
+ useEffect4(() => {
8184
+ loadSessions();
8185
+ }, []);
8186
+ async function loadSessions() {
8187
+ try {
8188
+ setRefreshing(true);
8189
+ const list = await listRemoteSessions();
8190
+ const updated = await Promise.all(
8191
+ list.map(async (s) => {
8192
+ if (s.status === "running" || s.status === "pending") {
8193
+ try {
8194
+ const status = await getRemoteStatus(s.workerUrl, s.sessionId);
8195
+ return {
8196
+ ...s,
8197
+ status: status.status,
8198
+ prUrl: status.prUrl ?? s.prUrl,
8199
+ tokensUsed: status.tokensUsed ?? s.tokensUsed,
8200
+ tokensBudget: status.tokensBudget ?? s.tokensBudget,
8201
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
8202
+ };
8203
+ } catch {
8204
+ return s;
8205
+ }
8206
+ }
8207
+ return s;
8208
+ })
8209
+ );
8210
+ setSessions(updated.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()));
8211
+ setError(null);
8212
+ } catch (err) {
8213
+ setError(err instanceof Error ? err.message : String(err));
8214
+ } finally {
8215
+ setLoading(false);
8216
+ setRefreshing(false);
8217
+ }
8218
+ }
8219
+ useInput3((input, key) => {
8220
+ if (input === "r" || input === "R") {
8221
+ void loadSessions();
8222
+ }
8223
+ if (key.escape && onCancel) {
8224
+ onCancel();
8225
+ }
8226
+ });
8227
+ const items = sessions.map((s) => ({
8228
+ label: formatSessionLine(s),
8229
+ value: s.sessionId
8230
+ }));
8231
+ if (loading) {
8232
+ return /* @__PURE__ */ jsx14(Box12, { flexDirection: "column", padding: 1, children: /* @__PURE__ */ jsx14(Text13, { color: theme.accent, children: "Loading remote sessions..." }) });
8233
+ }
8234
+ if (error) {
8235
+ return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", padding: 1, children: [
8236
+ /* @__PURE__ */ jsxs12(Text13, { color: theme.error, children: [
8237
+ "Error: ",
8238
+ error
8239
+ ] }),
8240
+ /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "Press R to retry, Esc to close" })
8241
+ ] });
8242
+ }
8243
+ if (sessions.length === 0) {
8244
+ return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", padding: 1, children: [
8245
+ /* @__PURE__ */ jsx14(Text13, { color: theme.accent, children: "No remote sessions yet." }),
8246
+ /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "Type /remote <prompt> to start one." }),
8247
+ /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "Press Esc to close" })
8248
+ ] });
8249
+ }
8250
+ return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", padding: 1, children: [
8251
+ /* @__PURE__ */ jsxs12(Text13, { bold: true, color: theme.accent, children: [
8252
+ "Recent remote tasks ",
8253
+ refreshing ? "(refreshing...)" : ""
8254
+ ] }),
8255
+ /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(
8256
+ SelectInput4,
8257
+ {
8258
+ items,
8259
+ onSelect: (item) => {
8260
+ const session = sessions.find((s) => s.sessionId === item.value);
8261
+ if (session) onSelect?.(session);
8262
+ }
8263
+ }
8264
+ ) }),
8265
+ /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "\u2191\u2193 navigate \u2022 Enter select \u2022 R refresh \u2022 Esc close" }) })
8266
+ ] });
8267
+ }
8268
+ function formatSessionLine(s) {
8269
+ const icon = s.status === "done" ? "\u2705" : s.status === "error" ? "\u274C" : s.status === "cancelled" ? "\u23F9\uFE0F" : s.status === "running" ? "\u23F3" : "\u23F8";
8270
+ const ago = formatAgo(new Date(s.updatedAt));
8271
+ const prompt = s.prompt.slice(0, 30) + (s.prompt.length > 30 ? "\u2026" : "");
8272
+ const outcome = s.prUrl ? `PR ${s.prUrl.split("/").pop()}` : s.status;
8273
+ const cost = s.tokensUsed && s.tokensBudget ? ` (${formatTokens2(s.tokensUsed)}/${formatTokens2(s.tokensBudget)})` : s.tokensUsed ? ` (${formatTokens2(s.tokensUsed)})` : "";
8274
+ return `${icon} ${prompt} \u2192 ${outcome} ${ago}${cost}`;
8275
+ }
8276
+ function formatAgo(date) {
8277
+ const ms = Date.now() - date.getTime();
8278
+ const minutes = Math.floor(ms / 6e4);
8279
+ const hours = Math.floor(minutes / 60);
8280
+ const days = Math.floor(hours / 24);
8281
+ if (days > 0) return `${days}d ago`;
8282
+ if (hours > 0) return `${hours}h ago`;
8283
+ if (minutes > 0) return `${minutes}m ago`;
8284
+ return "just now";
8285
+ }
8286
+ function formatTokens2(n) {
8287
+ if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
8288
+ if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
8289
+ return String(n);
8290
+ }
8291
+ function RemoteSessionDetail({
8292
+ session,
8293
+ onBack,
8294
+ onCancel
8295
+ }) {
8296
+ const theme = useTheme();
8297
+ const [cancelling, setCancelling] = useState7(false);
8298
+ useInput3((input, key) => {
8299
+ if (key.escape) {
8300
+ onBack();
8301
+ }
8302
+ if ((input === "c" || input === "C") && onCancel && (session.status === "running" || session.status === "pending")) {
8303
+ void handleCancel();
8304
+ }
8305
+ });
8306
+ async function handleCancel() {
8307
+ if (!onCancel) return;
8308
+ setCancelling(true);
8309
+ try {
8310
+ await cancelRemoteSession(session.workerUrl, session.sessionId);
8311
+ onCancel(session);
8312
+ } catch {
8313
+ } finally {
8314
+ setCancelling(false);
8315
+ }
8316
+ }
8317
+ const isRunning = session.status === "running" || session.status === "pending";
8318
+ return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", padding: 1, children: [
8319
+ /* @__PURE__ */ jsx14(Text13, { bold: true, color: theme.accent, children: "Remote Session" }),
8320
+ /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "column", children: [
8321
+ /* @__PURE__ */ jsxs12(Text13, { children: [
8322
+ "ID: ",
8323
+ session.sessionId
8324
+ ] }),
8325
+ /* @__PURE__ */ jsxs12(Text13, { children: [
8326
+ "Repo: ",
8327
+ session.repo
8328
+ ] }),
8329
+ /* @__PURE__ */ jsxs12(Text13, { children: [
8330
+ "Status: ",
8331
+ session.status
8332
+ ] }),
8333
+ /* @__PURE__ */ jsxs12(Text13, { children: [
8334
+ "Prompt: ",
8335
+ session.prompt
8336
+ ] }),
8337
+ session.prUrl && /* @__PURE__ */ jsxs12(Text13, { children: [
8338
+ "PR: ",
8339
+ session.prUrl
8340
+ ] }),
8341
+ session.errorMessage && /* @__PURE__ */ jsxs12(Text13, { color: theme.error, children: [
8342
+ "Error: ",
8343
+ session.errorMessage
8344
+ ] }),
8345
+ session.tokensUsed !== void 0 && /* @__PURE__ */ jsxs12(Text13, { children: [
8346
+ "Tokens: ",
8347
+ formatTokens2(session.tokensUsed),
8348
+ session.tokensBudget ? ` / ${formatTokens2(session.tokensBudget)}` : ""
8349
+ ] }),
8350
+ /* @__PURE__ */ jsxs12(Text13, { children: [
8351
+ "Created: ",
8352
+ new Date(session.createdAt).toLocaleString()
8353
+ ] }),
8354
+ session.finishedAt && /* @__PURE__ */ jsxs12(Text13, { children: [
8355
+ "Finished: ",
8356
+ new Date(session.finishedAt).toLocaleString()
8357
+ ] })
8358
+ ] }),
8359
+ /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "row", gap: 2, children: [
8360
+ isRunning && onCancel && /* @__PURE__ */ jsx14(Text13, { color: theme.error, children: cancelling ? "Cancelling..." : "[C] Cancel session" }),
8361
+ /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "Esc back" })
8362
+ ] })
8363
+ ] });
8364
+ }
8365
+ var init_remote_dashboard = __esm({
8366
+ "src/ui/remote-dashboard.tsx"() {
8367
+ "use strict";
8368
+ init_theme_context();
8369
+ init_session_store();
8370
+ init_worker_client();
8371
+ }
8372
+ });
8373
+
8374
+ // src/intent/classify.ts
8375
+ function classifyIntent(prompt) {
8376
+ let intentScore = 0;
8377
+ let matchedIntent = "other";
8378
+ for (const [intent, pattern] of Object.entries(INTENT_PATTERNS)) {
8379
+ const matches = (prompt.match(pattern) || []).length;
8380
+ if (matches > intentScore) {
8381
+ intentScore = matches;
8382
+ matchedIntent = intent;
8383
+ }
8384
+ }
8385
+ const hasFileMentions = (prompt.match(/@\w+|\b[\w/-]+\.(ts|tsx|js|jsx|py|go|rs)\b/g) || []).length;
8386
+ const hasMutatingVerb = /\b(add|create|write|edit|delete|remove|rename|migrate|implement)\b/i.test(prompt);
8387
+ const isQuestion = prompt.trim().endsWith("?") || /\b(what|how|why|is|does|can)\b/i.test(prompt.split(" ")[0] || "");
8388
+ const rawScore = Math.min(
8389
+ 1,
8390
+ intentScore * 0.25 + (hasFileMentions > 2 ? 0.3 : hasFileMentions * 0.1) + (hasMutatingVerb ? 0.25 : 0) + (isQuestion ? 0 : 0.1)
8391
+ );
8392
+ const tier = rawScore < 0.3 ? "light" : rawScore < 0.65 ? "medium" : "heavy";
8393
+ return {
8394
+ intent: matchedIntent,
8395
+ rawScore,
8396
+ tier,
8397
+ confidence: 0.5 + (intentScore > 0 ? 0.3 : 0) + (hasFileMentions > 0 ? 0.1 : 0)
8398
+ };
8399
+ }
8400
+ var INTENT_PATTERNS;
8401
+ var init_classify = __esm({
8402
+ "src/intent/classify.ts"() {
8403
+ "use strict";
8404
+ INTENT_PATTERNS = {
8405
+ qa: /\b(what|how|why|explain|describe|what's|what is)\b/i,
8406
+ diagnose: /\b(broken|failing|error|bug|crash|why.*fail|not working)\b/i,
8407
+ verify: /\b(correct|right|verify|review|check|is this|does this)\b/i,
8408
+ polish: /\b(rename|refactor|extract|move|clean|lint|format)\b/i,
8409
+ small_edit: /\b(add|change|update|fix|remove|delete)\b.+\b(line|here|this|variable|function)\b/i,
8410
+ feature_bounded: /\b(add|implement|create|support)\b.+\b(flag|option|param|arg|field)\b/i,
8411
+ feature_exploratory: /\b(add|implement|migrate|integrate|build)\b.+\b(module|system|auth|oauth|framework|service)\b/i,
8412
+ explore: /\b(how.*work|architecture|structure|where.*used|find.*all|understand)\b/i,
8413
+ meta: /\b(plan|design|strategy|ontology|roadmap|approach)\b/i
8414
+ };
8415
+ }
8416
+ });
8417
+
8418
+ // src/sessions.ts
8419
+ var sessions_exports = {};
8420
+ __export(sessions_exports, {
8421
+ listSessions: () => listSessions,
8422
+ loadSession: () => loadSession,
8423
+ makeSessionId: () => makeSessionId,
8424
+ pruneSessions: () => pruneSessions,
8425
+ saveSession: () => saveSession
8426
+ });
8427
+ import { readFile as readFile11, writeFile as writeFile7, mkdir as mkdir7, readdir as readdir3, stat as stat4 } from "fs/promises";
8428
+ import { homedir as homedir9 } from "os";
8429
+ import { join as join13 } from "path";
8430
+ function sessionsDir2() {
8431
+ const xdg = process.env.XDG_DATA_HOME || join13(homedir9(), ".local", "share");
8432
+ return join13(xdg, "kimiflare", "sessions");
8433
+ }
8434
+ function sanitize(text) {
8435
+ return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
8436
+ }
8437
+ function makeSessionId(firstPrompt) {
8438
+ const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
8439
+ const slug = sanitize(firstPrompt) || "session";
8440
+ return `${ts}_${slug}`;
8441
+ }
8442
+ async function saveSession(file) {
8443
+ const dir = sessionsDir2();
8444
+ await mkdir7(dir, { recursive: true });
8445
+ const path = join13(dir, `${file.id}.json`);
8446
+ await writeFile7(path, JSON.stringify(file, null, 2), "utf8");
8447
+ return path;
8448
+ }
8449
+ async function pruneSessions() {
8450
+ const dir = sessionsDir2();
8451
+ const files = await listFilesByMtime(dir, /\.json$/);
8452
+ return pruneFiles(files, RETENTION.sessionMaxAgeDays, RETENTION.sessionMaxCount);
8453
+ }
8454
+ async function listSessions(limit = 30, cwd) {
8455
+ const dir = sessionsDir2();
8456
+ let entries;
8457
+ try {
8458
+ entries = await readdir3(dir);
8459
+ } catch {
8460
+ return [];
8461
+ }
8462
+ const summaries = [];
8463
+ for (const name of entries) {
8464
+ if (!name.endsWith(".json")) continue;
8465
+ const path = join13(dir, name);
8466
+ try {
8467
+ const [s, raw] = await Promise.all([stat4(path), readFile11(path, "utf8")]);
8468
+ const parsed = JSON.parse(raw);
8469
+ if (cwd && parsed.cwd !== cwd) continue;
8470
+ const firstUser = parsed.messages.find((m) => m.role === "user");
8471
+ const firstPrompt = typeof firstUser?.content === "string" ? firstUser.content : firstUser?.content ? firstUser.content.find((p) => p.type === "text")?.text ?? "(no prompt)" : "(no prompt)";
8472
+ summaries.push({
8473
+ id: parsed.id,
8474
+ filePath: path,
8475
+ cwd: parsed.cwd,
8476
+ firstPrompt: firstPrompt.slice(0, 80),
8477
+ messageCount: parsed.messages.filter((m) => m.role !== "system").length,
8478
+ updatedAt: parsed.updatedAt ?? s.mtime.toISOString()
8479
+ });
8480
+ } catch {
8481
+ }
8482
+ }
8483
+ summaries.sort((a, b) => b.updatedAt < a.updatedAt ? -1 : 1);
8484
+ return summaries.slice(0, limit);
8485
+ }
8486
+ async function loadSession(filePath) {
8487
+ const raw = await readFile11(filePath, "utf8");
8488
+ return JSON.parse(raw);
8489
+ }
8490
+ var init_sessions = __esm({
8491
+ "src/sessions.ts"() {
8492
+ "use strict";
8493
+ init_storage_limits();
8494
+ }
8495
+ });
8496
+
8497
+ // src/util/image.ts
8498
+ import { readFile as readFile12 } from "fs/promises";
8499
+ import { basename as basename3 } from "path";
8500
+ async function encodeImageFile(filePath) {
8501
+ const buf = await readFile12(filePath);
8502
+ if (buf.byteLength > MAX_IMAGE_BYTES) {
7656
8503
  throw new Error(
7657
8504
  `image too large (${(buf.byteLength / 1024 / 1024).toFixed(1)} MB); max is ${MAX_IMAGE_BYTES / 1024 / 1024} MB`
7658
8505
  );
@@ -7687,15 +8534,15 @@ var init_image = __esm({
7687
8534
  });
7688
8535
 
7689
8536
  // src/usage-tracker.ts
7690
- import { readFile as readFile12, writeFile as writeFile7, mkdir as mkdir7 } from "fs/promises";
7691
- import { homedir as homedir9 } from "os";
7692
- import { join as join12 } from "path";
8537
+ import { readFile as readFile13, writeFile as writeFile8, mkdir as mkdir8 } from "fs/promises";
8538
+ import { homedir as homedir10 } from "os";
8539
+ import { join as join14 } from "path";
7693
8540
  function usageDir2() {
7694
- const xdg = process.env.XDG_DATA_HOME || join12(homedir9(), ".local", "share");
7695
- return join12(xdg, "kimiflare");
8541
+ const xdg = process.env.XDG_DATA_HOME || join14(homedir10(), ".local", "share");
8542
+ return join14(xdg, "kimiflare");
7696
8543
  }
7697
8544
  function usagePath2() {
7698
- return join12(usageDir2(), "usage.json");
8545
+ return join14(usageDir2(), "usage.json");
7699
8546
  }
7700
8547
  function today2() {
7701
8548
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
@@ -7706,7 +8553,7 @@ function cutoffDate(daysBack) {
7706
8553
  }
7707
8554
  async function loadLog2() {
7708
8555
  try {
7709
- const raw = await readFile12(usagePath2(), "utf8");
8556
+ const raw = await readFile13(usagePath2(), "utf8");
7710
8557
  const parsed = JSON.parse(raw);
7711
8558
  if (parsed.version === LOG_VERSION2) return parsed;
7712
8559
  } catch {
@@ -7714,8 +8561,8 @@ async function loadLog2() {
7714
8561
  return { version: LOG_VERSION2, days: [], sessions: [] };
7715
8562
  }
7716
8563
  async function saveLog(log) {
7717
- await mkdir7(usageDir2(), { recursive: true });
7718
- await writeFile7(usagePath2(), JSON.stringify(log, null, 2), "utf8");
8564
+ await mkdir8(usageDir2(), { recursive: true });
8565
+ await writeFile8(usagePath2(), JSON.stringify(log, null, 2), "utf8");
7719
8566
  }
7720
8567
  function getOrCreateDay(log, date) {
7721
8568
  let day = log.days.find((d) => d.date === date);
@@ -7921,7 +8768,7 @@ __export(db_exports, {
7921
8768
  updateMemoryEmbedding: () => updateMemoryEmbedding
7922
8769
  });
7923
8770
  import Database from "better-sqlite3";
7924
- import { dirname as dirname5 } from "path";
8771
+ import { dirname as dirname6 } from "path";
7925
8772
  import { mkdirSync, statSync as statSync2 } from "fs";
7926
8773
  function initSchema(db) {
7927
8774
  db.exec(`
@@ -8006,7 +8853,7 @@ function openMemoryDb(dbPath) {
8006
8853
  if (dbInstance) {
8007
8854
  dbInstance.close();
8008
8855
  }
8009
- mkdirSync(dirname5(dbPath), { recursive: true });
8856
+ mkdirSync(dirname6(dbPath), { recursive: true });
8010
8857
  dbInstance = new Database(dbPath);
8011
8858
  dbInstance.pragma("journal_mode = WAL");
8012
8859
  dbInstance.pragma("foreign_keys = ON");
@@ -8300,7 +9147,7 @@ function truncateForEmbedding(text) {
8300
9147
  if (text.length <= MAX_EMBED_CHARS) return text;
8301
9148
  return text.slice(0, MAX_EMBED_CHARS);
8302
9149
  }
8303
- async function sleep2(ms) {
9150
+ async function sleep3(ms) {
8304
9151
  return new Promise((resolve2) => setTimeout(resolve2, ms));
8305
9152
  }
8306
9153
  async function fetchWithRetry(url, init, retries = 3) {
@@ -8311,7 +9158,7 @@ async function fetchWithRetry(url, init, retries = 3) {
8311
9158
  if (res.ok) return res;
8312
9159
  if (res.status === 429 || res.status >= 500) {
8313
9160
  const delay = 1e3 * 2 ** i;
8314
- await sleep2(delay);
9161
+ await sleep3(delay);
8315
9162
  continue;
8316
9163
  }
8317
9164
  const errText = await res.text().catch(() => "unknown error");
@@ -8319,7 +9166,7 @@ async function fetchWithRetry(url, init, retries = 3) {
8319
9166
  } catch (e) {
8320
9167
  lastError = e;
8321
9168
  if (i < retries - 1) {
8322
- await sleep2(1e3 * 2 ** i);
9169
+ await sleep3(1e3 * 2 ** i);
8323
9170
  }
8324
9171
  }
8325
9172
  }
@@ -8711,6 +9558,18 @@ Return a JSON array of strings. Example:
8711
9558
  gateway: this.opts.gateway
8712
9559
  };
8713
9560
  }
9561
+ get extractionLlmOpts() {
9562
+ return {
9563
+ accountId: this.opts.accountId,
9564
+ apiToken: this.opts.apiToken,
9565
+ model: this.opts.extractionModel ?? "@cf/meta/llama-3.2-3b-instruct",
9566
+ gateway: this.opts.gateway
9567
+ };
9568
+ }
9569
+ /** Expose extraction LLM opts so the agent loop can pass them to extractors. */
9570
+ getExtractionLlmOpts() {
9571
+ return this.extractionLlmOpts;
9572
+ }
8714
9573
  shouldRedact() {
8715
9574
  return this.opts.redactSecrets !== false;
8716
9575
  }
@@ -8718,7 +9577,7 @@ Return a JSON array of strings. Example:
8718
9577
  * Store a memory with verification, topic-key normalization, hypothetical queries,
8719
9578
  * secret redaction, and supersession.
8720
9579
  */
8721
- async remember(content, category, importance, repoPath, sessionId, signal, agentRole) {
9580
+ async remember(content, category, importance, repoPath, sessionId, signal, agentRole, topicKey) {
8722
9581
  if (!this.db) throw new Error("Memory DB not open");
8723
9582
  let safeContent = this.shouldRedact() ? redactSecrets(content) : content;
8724
9583
  if (!safeContent.trim()) {
@@ -8731,10 +9590,10 @@ Return a JSON array of strings. Example:
8731
9590
  if (verified.corrected_content) {
8732
9591
  safeContent = verified.corrected_content;
8733
9592
  }
8734
- const topicKey = this.normalizeTopicKey(safeContent, repoPath);
9593
+ const resolvedTopicKey = topicKey?.trim() || this.normalizeTopicKey(safeContent, repoPath);
8735
9594
  const supersededIds = [];
8736
- if (topicKey) {
8737
- const existing = findMemoriesByTopicKey(this.db, repoPath, topicKey);
9595
+ if (resolvedTopicKey) {
9596
+ const existing = findMemoriesByTopicKey(this.db, repoPath, resolvedTopicKey);
8738
9597
  for (const old of existing) {
8739
9598
  supersedeMemory(this.db, old.id, "pending");
8740
9599
  supersededIds.push(old.id);
@@ -8755,7 +9614,7 @@ Return a JSON array of strings. Example:
8755
9614
  sourceSessionId: sessionId,
8756
9615
  repoPath,
8757
9616
  importance: Math.max(1, Math.min(5, importance)),
8758
- topicKey: topicKey ?? void 0,
9617
+ topicKey: resolvedTopicKey ?? void 0,
8759
9618
  agentRole
8760
9619
  };
8761
9620
  const memory = insertMemory(this.db, input, embeddings[0]);
@@ -8933,16 +9792,16 @@ Context: This memory was explicitly provided by the user during a conversation.`
8933
9792
  });
8934
9793
 
8935
9794
  // src/util/state.ts
8936
- import { readFile as readFile13, writeFile as writeFile8, mkdir as mkdir8 } from "fs/promises";
8937
- import { homedir as homedir10 } from "os";
8938
- import { join as join14 } from "path";
9795
+ import { readFile as readFile14, writeFile as writeFile9, mkdir as mkdir9 } from "fs/promises";
9796
+ import { homedir as homedir11 } from "os";
9797
+ import { join as join16 } from "path";
8939
9798
  function statePath() {
8940
- const xdg = process.env.XDG_CONFIG_HOME || join14(homedir10(), ".config");
8941
- return join14(xdg, "kimiflare", "state.json");
9799
+ const xdg = process.env.XDG_CONFIG_HOME || join16(homedir11(), ".config");
9800
+ return join16(xdg, "kimiflare", "state.json");
8942
9801
  }
8943
9802
  async function readState() {
8944
9803
  try {
8945
- const raw = await readFile13(statePath(), "utf8");
9804
+ const raw = await readFile14(statePath(), "utf8");
8946
9805
  return JSON.parse(raw);
8947
9806
  } catch {
8948
9807
  return {};
@@ -8950,8 +9809,8 @@ async function readState() {
8950
9809
  }
8951
9810
  async function writeState(state) {
8952
9811
  const path = statePath();
8953
- await mkdir8(join14(path, ".."), { recursive: true });
8954
- await writeFile8(path, JSON.stringify(state, null, 2) + "\n", "utf8");
9812
+ await mkdir9(join16(path, ".."), { recursive: true });
9813
+ await writeFile9(path, JSON.stringify(state, null, 2) + "\n", "utf8");
8955
9814
  }
8956
9815
  async function markCreatorMessageSeen(version) {
8957
9816
  const state = await readState();
@@ -9024,15 +9883,15 @@ var init_frontmatter = __esm({
9024
9883
 
9025
9884
  // src/commands/loader.ts
9026
9885
  import { open, realpath } from "fs/promises";
9027
- import { homedir as homedir11 } from "os";
9028
- import { join as join15, relative as relative4, sep as sep2 } from "path";
9886
+ import { homedir as homedir12 } from "os";
9887
+ import { join as join17, relative as relative4, sep as sep2 } from "path";
9029
9888
  import fg3 from "fast-glob";
9030
9889
  function projectCommandsDir(cwd = process.cwd()) {
9031
- return join15(cwd, ".kimiflare", "commands");
9890
+ return join17(cwd, ".kimiflare", "commands");
9032
9891
  }
9033
9892
  function globalCommandsDir() {
9034
- const xdg = process.env.XDG_CONFIG_HOME || join15(homedir11(), ".config");
9035
- return join15(xdg, "kimiflare", "commands");
9893
+ const xdg = process.env.XDG_CONFIG_HOME || join17(homedir12(), ".config");
9894
+ return join17(xdg, "kimiflare", "commands");
9036
9895
  }
9037
9896
  async function loadCustomCommands(cwd = process.cwd()) {
9038
9897
  const warnings = [];
@@ -9394,6 +10253,7 @@ var init_builtins = __esm({
9394
10253
  { name: "compact", description: "Summarize old turns to free context", source: "builtin" },
9395
10254
  { name: "clear", description: "Clear current conversation", source: "builtin" },
9396
10255
  { name: "init", description: "Scan repo and write KIMI.md", source: "builtin" },
10256
+ { name: "remote", argHint: "<prompt>", description: "Run a remote session on Cloudflare", source: "builtin" },
9397
10257
  { name: "update", description: "Check for updates", source: "builtin" },
9398
10258
  { name: "hello", description: "Send a voice note to the creator", source: "builtin" },
9399
10259
  { name: "logout", description: "Clear stored credentials", source: "builtin" },
@@ -9407,8 +10267,8 @@ var init_builtins = __esm({
9407
10267
  });
9408
10268
 
9409
10269
  // src/commands/save.ts
9410
- import { mkdir as mkdir9, writeFile as writeFile9, unlink as unlink2 } from "fs/promises";
9411
- import { dirname as dirname6 } from "path";
10270
+ import { mkdir as mkdir10, writeFile as writeFile10, unlink as unlink2 } from "fs/promises";
10271
+ import { dirname as dirname7 } from "path";
9412
10272
  async function saveCustomCommand(opts2) {
9413
10273
  const dir = opts2.source === "project" ? projectCommandsDir(opts2.cwd) : globalCommandsDir();
9414
10274
  const filepath = `${dir}/${opts2.name}.md`;
@@ -9419,8 +10279,8 @@ async function saveCustomCommand(opts2) {
9419
10279
  if (opts2.effort) data.effort = opts2.effort;
9420
10280
  const frontmatter = serializeFrontmatter(data);
9421
10281
  const content = frontmatter + opts2.template;
9422
- await mkdir9(dirname6(filepath), { recursive: true });
9423
- await writeFile9(filepath, content, "utf8");
10282
+ await mkdir10(dirname7(filepath), { recursive: true });
10283
+ await writeFile10(filepath, content, "utf8");
9424
10284
  return { filepath };
9425
10285
  }
9426
10286
  async function deleteCustomCommand(cmd) {
@@ -9435,21 +10295,21 @@ var init_save = __esm({
9435
10295
  });
9436
10296
 
9437
10297
  // src/ui/command-wizard.tsx
9438
- import { useState as useState7 } from "react";
9439
- import { Box as Box12, Text as Text13, useInput as useInput3, useWindowSize as useWindowSize2 } from "ink";
9440
- import SelectInput4 from "ink-select-input";
9441
- import { Fragment as Fragment2, jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
10298
+ import { useState as useState8 } from "react";
10299
+ import { Box as Box13, Text as Text14, useInput as useInput4, useWindowSize as useWindowSize2 } from "ink";
10300
+ import SelectInput5 from "ink-select-input";
10301
+ import { Fragment as Fragment2, jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
9442
10302
  function CommandWizard({ mode, initial, existingNames, builtinNames, onDone, onSave }) {
9443
10303
  const theme = useTheme();
9444
- const [step, setStep] = useState7("name");
9445
- const [name, setName] = useState7(initial?.name ?? "");
9446
- const [description, setDescription] = useState7(initial?.description ?? "");
9447
- const [template, setTemplate] = useState7(initial?.template ?? "");
9448
- const [cmdMode, setCmdMode] = useState7(initial?.mode);
9449
- const [cmdEffort, setCmdEffort] = useState7(initial?.effort);
9450
- const [cmdModel, setCmdModel] = useState7(initial?.model);
9451
- const [source, setSource] = useState7(initial?.source ?? "project");
9452
- const [error, setError] = useState7(null);
10304
+ const [step, setStep] = useState8("name");
10305
+ const [name, setName] = useState8(initial?.name ?? "");
10306
+ const [description, setDescription] = useState8(initial?.description ?? "");
10307
+ const [template, setTemplate] = useState8(initial?.template ?? "");
10308
+ const [cmdMode, setCmdMode] = useState8(initial?.mode);
10309
+ const [cmdEffort, setCmdEffort] = useState8(initial?.effort);
10310
+ const [cmdModel, setCmdModel] = useState8(initial?.model);
10311
+ const [source, setSource] = useState8(initial?.source ?? "project");
10312
+ const [error, setError] = useState8(null);
9453
10313
  const { columns } = useWindowSize2();
9454
10314
  const totalSteps = 5;
9455
10315
  const stepIndex = step === "name" ? 1 : step === "description" ? 2 : step === "template" ? 3 : step === "advanced" || step === "mode" || step === "effort" || step === "model" ? 4 : step === "location" ? 4 : 5;
@@ -9462,7 +10322,7 @@ function CommandWizard({ mode, initial, existingNames, builtinNames, onDone, onS
9462
10322
  if (existingNames.includes(trimmed) && !isEditingSelf(trimmed)) return `/${trimmed} already exists`;
9463
10323
  return null;
9464
10324
  };
9465
- useInput3((_input, key) => {
10325
+ useInput4((_input, key) => {
9466
10326
  if (key.escape) {
9467
10327
  onDone();
9468
10328
  }
@@ -9562,8 +10422,8 @@ ${template}`;
9562
10422
  const renderStep = () => {
9563
10423
  switch (step) {
9564
10424
  case "name":
9565
- return /* @__PURE__ */ jsxs12(Fragment2, { children: [
9566
- /* @__PURE__ */ jsxs12(Text13, { color: theme.accent, bold: true, children: [
10425
+ return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10426
+ /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
9567
10427
  mode === "create" ? "Create" : "Edit",
9568
10428
  " custom command \u2014 Name (",
9569
10429
  stepIndex,
@@ -9571,8 +10431,8 @@ ${template}`;
9571
10431
  totalSteps,
9572
10432
  ")"
9573
10433
  ] }),
9574
- error && /* @__PURE__ */ jsx14(Text13, { color: theme.error, children: error }),
9575
- /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(
10434
+ error && /* @__PURE__ */ jsx15(Text14, { color: theme.error, children: error }),
10435
+ /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
9576
10436
  CustomTextInput,
9577
10437
  {
9578
10438
  value: name,
@@ -9581,11 +10441,11 @@ ${template}`;
9581
10441
  focus: true
9582
10442
  }
9583
10443
  ) }),
9584
- /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, children: "letters, numbers, _ - / only; must start with a letter" })
10444
+ /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "letters, numbers, _ - / only; must start with a letter" })
9585
10445
  ] });
9586
10446
  case "description":
9587
- return /* @__PURE__ */ jsxs12(Fragment2, { children: [
9588
- /* @__PURE__ */ jsxs12(Text13, { color: theme.accent, bold: true, children: [
10447
+ return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10448
+ /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
9589
10449
  mode === "create" ? "Create" : "Edit",
9590
10450
  " custom command \u2014 Description (",
9591
10451
  stepIndex,
@@ -9593,7 +10453,7 @@ ${template}`;
9593
10453
  totalSteps,
9594
10454
  ")"
9595
10455
  ] }),
9596
- /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(
10456
+ /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
9597
10457
  CustomTextInput,
9598
10458
  {
9599
10459
  value: description,
@@ -9602,49 +10462,49 @@ ${template}`;
9602
10462
  focus: true
9603
10463
  }
9604
10464
  ) }),
9605
- /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, children: "Press Enter to skip" })
10465
+ /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Press Enter to skip" })
9606
10466
  ] });
9607
10467
  case "template": {
9608
- const guide = /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", paddingLeft: 1, children: [
9609
- /* @__PURE__ */ jsx14(Text13, { color: theme.accent, bold: true, children: "What is this?" }),
9610
- /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, children: "A prompt template \u2014 instructions to the AI." }),
9611
- /* @__PURE__ */ jsxs12(Text13, { color: theme.info.color, children: [
10468
+ const guide = /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", paddingLeft: 1, children: [
10469
+ /* @__PURE__ */ jsx15(Text14, { color: theme.accent, bold: true, children: "What is this?" }),
10470
+ /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "A prompt template \u2014 instructions to the AI." }),
10471
+ /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
9612
10472
  "When you type /",
9613
10473
  name || "yourcommand",
9614
10474
  " later, this gets sent to the model."
9615
10475
  ] }),
9616
- /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "column", children: [
9617
- /* @__PURE__ */ jsx14(Text13, { color: theme.accent, bold: true, children: "Variables" }),
9618
- /* @__PURE__ */ jsxs12(Text13, { color: theme.info.color, children: [
10476
+ /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "column", children: [
10477
+ /* @__PURE__ */ jsx15(Text14, { color: theme.accent, bold: true, children: "Variables" }),
10478
+ /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
9619
10479
  " ",
9620
10480
  "$1, $2 ... \u2192 arguments you type"
9621
10481
  ] }),
9622
- /* @__PURE__ */ jsxs12(Text13, { color: theme.info.color, children: [
10482
+ /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
9623
10483
  " ",
9624
10484
  "$ARGUMENTS \u2192 everything after the command"
9625
10485
  ] })
9626
10486
  ] }),
9627
- /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "column", children: [
9628
- /* @__PURE__ */ jsx14(Text13, { color: theme.accent, bold: true, children: "Dynamic inlines" }),
9629
- /* @__PURE__ */ jsxs12(Text13, { color: theme.info.color, children: [
10487
+ /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "column", children: [
10488
+ /* @__PURE__ */ jsx15(Text14, { color: theme.accent, bold: true, children: "Dynamic inlines" }),
10489
+ /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
9630
10490
  " ",
9631
10491
  "!`git diff` \u2192 shell output inlined"
9632
10492
  ] }),
9633
- /* @__PURE__ */ jsxs12(Text13, { color: theme.info.color, children: [
10493
+ /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
9634
10494
  " ",
9635
10495
  "@README.md \u2192 file contents inlined"
9636
10496
  ] })
9637
10497
  ] }),
9638
- /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "column", children: [
9639
- /* @__PURE__ */ jsx14(Text13, { color: theme.accent, bold: true, children: "Example" }),
9640
- /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, children: "Review this PR diff:" }),
9641
- /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, children: "!`git diff main...HEAD`" }),
9642
- /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, children: "Focus on: $1" })
10498
+ /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "column", children: [
10499
+ /* @__PURE__ */ jsx15(Text14, { color: theme.accent, bold: true, children: "Example" }),
10500
+ /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Review this PR diff:" }),
10501
+ /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "!`git diff main...HEAD`" }),
10502
+ /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Focus on: $1" })
9643
10503
  ] })
9644
10504
  ] });
9645
- const inputArea = /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", flexGrow: 1, children: [
9646
- error && /* @__PURE__ */ jsx14(Text13, { color: theme.error, children: error }),
9647
- /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(
10505
+ const inputArea = /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", flexGrow: 1, children: [
10506
+ error && /* @__PURE__ */ jsx15(Text14, { color: theme.error, children: error }),
10507
+ /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
9648
10508
  CustomTextInput,
9649
10509
  {
9650
10510
  value: template,
@@ -9654,13 +10514,13 @@ ${template}`;
9654
10514
  enablePaste: true
9655
10515
  }
9656
10516
  ) }),
9657
- columns < 100 && /* @__PURE__ */ jsxs12(Fragment2, { children: [
9658
- /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, children: "Paste multi-line templates with Ctrl+V." }),
9659
- /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, children: "Variables: $1 $2 ... $ARGUMENTS Shell: !`cmd` File: @path" })
10517
+ columns < 100 && /* @__PURE__ */ jsxs13(Fragment2, { children: [
10518
+ /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Paste multi-line templates with Ctrl+V." }),
10519
+ /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Variables: $1 $2 ... $ARGUMENTS Shell: !`cmd` File: @path" })
9660
10520
  ] })
9661
10521
  ] });
9662
- return /* @__PURE__ */ jsxs12(Fragment2, { children: [
9663
- /* @__PURE__ */ jsxs12(Text13, { color: theme.accent, bold: true, children: [
10522
+ return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10523
+ /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
9664
10524
  mode === "create" ? "Create" : "Edit",
9665
10525
  " custom command \u2014 Template (",
9666
10526
  stepIndex,
@@ -9668,10 +10528,10 @@ ${template}`;
9668
10528
  totalSteps,
9669
10529
  ")"
9670
10530
  ] }),
9671
- columns >= 100 ? /* @__PURE__ */ jsxs12(Box12, { flexDirection: "row", marginTop: 1, children: [
9672
- /* @__PURE__ */ jsx14(Box12, { flexDirection: "column", width: "50%", children: inputArea }),
9673
- /* @__PURE__ */ jsx14(Box12, { flexDirection: "column", width: "50%", children: guide })
9674
- ] }) : /* @__PURE__ */ jsx14(Box12, { flexDirection: "column", marginTop: 1, children: inputArea })
10531
+ columns >= 100 ? /* @__PURE__ */ jsxs13(Box13, { flexDirection: "row", marginTop: 1, children: [
10532
+ /* @__PURE__ */ jsx15(Box13, { flexDirection: "column", width: "50%", children: inputArea }),
10533
+ /* @__PURE__ */ jsx15(Box13, { flexDirection: "column", width: "50%", children: guide })
10534
+ ] }) : /* @__PURE__ */ jsx15(Box13, { flexDirection: "column", marginTop: 1, children: inputArea })
9675
10535
  ] });
9676
10536
  }
9677
10537
  case "advanced": {
@@ -9680,8 +10540,8 @@ ${template}`;
9680
10540
  { label: "Skip", value: "skip", key: "skip" },
9681
10541
  { label: "\u2190 Cancel", value: "cancel", key: "cancel" }
9682
10542
  ];
9683
- return /* @__PURE__ */ jsxs12(Fragment2, { children: [
9684
- /* @__PURE__ */ jsxs12(Text13, { color: theme.accent, bold: true, children: [
10543
+ return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10544
+ /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
9685
10545
  mode === "create" ? "Create" : "Edit",
9686
10546
  " custom command \u2014 Options (",
9687
10547
  stepIndex,
@@ -9689,8 +10549,8 @@ ${template}`;
9689
10549
  totalSteps,
9690
10550
  ")"
9691
10551
  ] }),
9692
- /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(
9693
- SelectInput4,
10552
+ /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
10553
+ SelectInput5,
9694
10554
  {
9695
10555
  items,
9696
10556
  onSelect: (item) => {
@@ -9709,17 +10569,17 @@ ${template}`;
9709
10569
  { label: cmdMode === "auto" ? "auto \xB7 current" : "auto", value: "auto", key: "auto" },
9710
10570
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
9711
10571
  ];
9712
- return /* @__PURE__ */ jsxs12(Fragment2, { children: [
9713
- /* @__PURE__ */ jsxs12(Text13, { color: theme.accent, bold: true, children: [
10572
+ return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10573
+ /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
9714
10574
  "Mode override (",
9715
10575
  stepIndex,
9716
10576
  "/",
9717
10577
  totalSteps,
9718
10578
  ")"
9719
10579
  ] }),
9720
- /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, children: "Saved to file but not yet enforced at runtime" }),
9721
- /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(
9722
- SelectInput4,
10580
+ /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Saved to file but not yet enforced at runtime" }),
10581
+ /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
10582
+ SelectInput5,
9723
10583
  {
9724
10584
  items,
9725
10585
  onSelect: (item) => {
@@ -9738,16 +10598,16 @@ ${template}`;
9738
10598
  { label: cmdEffort === "high" ? "high \xB7 current" : "high", value: "high", key: "high" },
9739
10599
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
9740
10600
  ];
9741
- return /* @__PURE__ */ jsxs12(Fragment2, { children: [
9742
- /* @__PURE__ */ jsxs12(Text13, { color: theme.accent, bold: true, children: [
10601
+ return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10602
+ /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
9743
10603
  "Reasoning effort (",
9744
10604
  stepIndex,
9745
10605
  "/",
9746
10606
  totalSteps,
9747
10607
  ")"
9748
10608
  ] }),
9749
- /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(
9750
- SelectInput4,
10609
+ /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
10610
+ SelectInput5,
9751
10611
  {
9752
10612
  items,
9753
10613
  onSelect: (item) => {
@@ -9759,15 +10619,15 @@ ${template}`;
9759
10619
  ] });
9760
10620
  }
9761
10621
  case "model":
9762
- return /* @__PURE__ */ jsxs12(Fragment2, { children: [
9763
- /* @__PURE__ */ jsxs12(Text13, { color: theme.accent, bold: true, children: [
10622
+ return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10623
+ /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
9764
10624
  "Model override (",
9765
10625
  stepIndex,
9766
10626
  "/",
9767
10627
  totalSteps,
9768
10628
  ")"
9769
10629
  ] }),
9770
- /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(
10630
+ /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
9771
10631
  CustomTextInput,
9772
10632
  {
9773
10633
  value: cmdModel ?? "",
@@ -9776,7 +10636,7 @@ ${template}`;
9776
10636
  focus: true
9777
10637
  }
9778
10638
  ) }),
9779
- /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, children: "Press Enter to skip" })
10639
+ /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Press Enter to skip" })
9780
10640
  ] });
9781
10641
  case "location": {
9782
10642
  const items = [
@@ -9784,16 +10644,16 @@ ${template}`;
9784
10644
  { label: source === "global" ? "Global \xB7 current" : "Global", value: "global", key: "global" },
9785
10645
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
9786
10646
  ];
9787
- return /* @__PURE__ */ jsxs12(Fragment2, { children: [
9788
- /* @__PURE__ */ jsxs12(Text13, { color: theme.accent, bold: true, children: [
10647
+ return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10648
+ /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
9789
10649
  "Save location (",
9790
10650
  stepIndex,
9791
10651
  "/",
9792
10652
  totalSteps,
9793
10653
  ")"
9794
10654
  ] }),
9795
- /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(
9796
- SelectInput4,
10655
+ /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
10656
+ SelectInput5,
9797
10657
  {
9798
10658
  items,
9799
10659
  onSelect: (item) => {
@@ -9802,7 +10662,7 @@ ${template}`;
9802
10662
  }
9803
10663
  }
9804
10664
  ) }),
9805
- /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, children: "Project: .kimiflare/commands/ Global: ~/.config/kimiflare/commands/" })
10665
+ /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Project: .kimiflare/commands/ Global: ~/.config/kimiflare/commands/" })
9806
10666
  ] });
9807
10667
  }
9808
10668
  case "confirm": {
@@ -9810,8 +10670,8 @@ ${template}`;
9810
10670
  { label: "Save", value: "save", key: "save" },
9811
10671
  { label: "Cancel", value: "cancel", key: "cancel" }
9812
10672
  ];
9813
- return /* @__PURE__ */ jsxs12(Fragment2, { children: [
9814
- /* @__PURE__ */ jsxs12(Text13, { color: theme.accent, bold: true, children: [
10673
+ return /* @__PURE__ */ jsxs13(Fragment2, { children: [
10674
+ /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
9815
10675
  mode === "create" ? "Create" : "Edit",
9816
10676
  " custom command \u2014 Confirm (",
9817
10677
  stepIndex,
@@ -9819,14 +10679,14 @@ ${template}`;
9819
10679
  totalSteps,
9820
10680
  ")"
9821
10681
  ] }),
9822
- /* @__PURE__ */ jsxs12(Text13, { color: theme.info.color, children: [
10682
+ /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
9823
10683
  source === "project" ? ".kimiflare/commands/" : "~/.config/kimiflare/commands/",
9824
10684
  name,
9825
10685
  ".md"
9826
10686
  ] }),
9827
- /* @__PURE__ */ jsx14(Box12, { marginTop: 1, flexDirection: "column", children: previewContent().split("\n").map((line, i) => /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, children: line || " " }, i)) }),
9828
- /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(
9829
- SelectInput4,
10687
+ /* @__PURE__ */ jsx15(Box13, { marginTop: 1, flexDirection: "column", children: previewContent().split("\n").map((line, i) => /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: line || " " }, i)) }),
10688
+ /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
10689
+ SelectInput5,
9830
10690
  {
9831
10691
  items,
9832
10692
  onSelect: (item) => handleConfirm(item.value)
@@ -9836,7 +10696,7 @@ ${template}`;
9836
10696
  }
9837
10697
  }
9838
10698
  };
9839
- return /* @__PURE__ */ jsx14(Box12, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: renderStep() });
10699
+ return /* @__PURE__ */ jsx15(Box13, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: renderStep() });
9840
10700
  }
9841
10701
  var NAME_RE;
9842
10702
  var init_command_wizard = __esm({
@@ -9849,9 +10709,9 @@ var init_command_wizard = __esm({
9849
10709
  });
9850
10710
 
9851
10711
  // src/ui/command-picker.tsx
9852
- import { Box as Box13, Text as Text14 } from "ink";
9853
- import SelectInput5 from "ink-select-input";
9854
- import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
10712
+ import { Box as Box14, Text as Text15 } from "ink";
10713
+ import SelectInput6 from "ink-select-input";
10714
+ import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
9855
10715
  function CommandPicker({ commands, title, onPick }) {
9856
10716
  const theme = useTheme();
9857
10717
  const items = commands.map((cmd) => ({
@@ -9860,11 +10720,11 @@ function CommandPicker({ commands, title, onPick }) {
9860
10720
  key: cmd.name
9861
10721
  }));
9862
10722
  items.push({ label: "\u2190 Cancel", value: null, key: "__cancel__" });
9863
- return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
9864
- /* @__PURE__ */ jsx15(Text14, { color: theme.accent, bold: true, children: title }),
9865
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select." }),
9866
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
9867
- SelectInput5,
10723
+ return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10724
+ /* @__PURE__ */ jsx16(Text15, { color: theme.accent, bold: true, children: title }),
10725
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select." }),
10726
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
10727
+ SelectInput6,
9868
10728
  {
9869
10729
  items,
9870
10730
  onSelect: (item) => {
@@ -9886,64 +10746,64 @@ var init_command_picker = __esm({
9886
10746
  });
9887
10747
 
9888
10748
  // src/ui/command-list.tsx
9889
- import { Box as Box14, Text as Text15, useInput as useInput4 } from "ink";
9890
- import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
10749
+ import { Box as Box15, Text as Text16, useInput as useInput5 } from "ink";
10750
+ import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
9891
10751
  function CommandList({ commands, onDone }) {
9892
10752
  const theme = useTheme();
9893
- useInput4((_input, key) => {
10753
+ useInput5((_input, key) => {
9894
10754
  if (key.escape) {
9895
10755
  onDone();
9896
10756
  }
9897
10757
  });
9898
- return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
9899
- /* @__PURE__ */ jsx16(Text15, { color: theme.accent, bold: true, children: "Custom commands" }),
9900
- /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, dimColor: false, children: "Esc to close." }),
9901
- /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, flexDirection: "column", children: [
9902
- commands.length === 0 && /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "No custom commands found." }),
9903
- commands.map((cmd) => /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", marginBottom: 1, children: [
9904
- /* @__PURE__ */ jsxs14(Text15, { color: theme.accent, bold: true, children: [
10758
+ return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10759
+ /* @__PURE__ */ jsx17(Text16, { color: theme.accent, bold: true, children: "Custom commands" }),
10760
+ /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, dimColor: false, children: "Esc to close." }),
10761
+ /* @__PURE__ */ jsxs15(Box15, { marginTop: 1, flexDirection: "column", children: [
10762
+ commands.length === 0 && /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, children: "No custom commands found." }),
10763
+ commands.map((cmd) => /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", marginBottom: 1, children: [
10764
+ /* @__PURE__ */ jsxs15(Text16, { color: theme.accent, bold: true, children: [
9905
10765
  "/",
9906
10766
  cmd.name
9907
10767
  ] }),
9908
- /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
10768
+ /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
9909
10769
  " ",
9910
10770
  "source: ",
9911
10771
  cmd.source
9912
10772
  ] }),
9913
- /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
10773
+ /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
9914
10774
  " ",
9915
10775
  "path: ",
9916
10776
  cmd.filepath
9917
10777
  ] }),
9918
- cmd.description && /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
10778
+ cmd.description && /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
9919
10779
  " ",
9920
10780
  "desc: ",
9921
10781
  cmd.description
9922
10782
  ] }),
9923
- cmd.mode && /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
10783
+ cmd.mode && /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
9924
10784
  " ",
9925
10785
  "mode: ",
9926
10786
  cmd.mode
9927
10787
  ] }),
9928
- cmd.effort && /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
10788
+ cmd.effort && /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
9929
10789
  " ",
9930
10790
  "effort: ",
9931
10791
  cmd.effort
9932
10792
  ] }),
9933
- cmd.model && /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
10793
+ cmd.model && /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
9934
10794
  " ",
9935
10795
  "model: ",
9936
10796
  cmd.model
9937
10797
  ] }),
9938
- /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
10798
+ /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
9939
10799
  " ",
9940
10800
  "template:"
9941
10801
  ] }),
9942
- cmd.template.split("\n").slice(0, 5).map((line, i) => /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
10802
+ cmd.template.split("\n").slice(0, 5).map((line, i) => /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
9943
10803
  " ",
9944
10804
  line || " "
9945
10805
  ] }, i)),
9946
- cmd.template.split("\n").length > 5 && /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
10806
+ cmd.template.split("\n").length > 5 && /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
9947
10807
  " ",
9948
10808
  "..."
9949
10809
  ] })
@@ -9959,20 +10819,20 @@ var init_command_list = __esm({
9959
10819
  });
9960
10820
 
9961
10821
  // src/ui/lsp-wizard.tsx
9962
- import { useState as useState8 } from "react";
9963
- import { Box as Box15, Text as Text16 } from "ink";
9964
- import SelectInput6 from "ink-select-input";
10822
+ import { useState as useState9 } from "react";
10823
+ import { Box as Box16, Text as Text17 } from "ink";
10824
+ import SelectInput7 from "ink-select-input";
9965
10825
  import { spawn as spawn3 } from "child_process";
9966
- import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
10826
+ import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
9967
10827
  function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
9968
10828
  const theme = useTheme();
9969
- const [page, setPage] = useState8("main");
9970
- const [selectedPreset, setSelectedPreset] = useState8(null);
9971
- const [customName, setCustomName] = useState8("");
9972
- const [customCommand, setCustomCommand] = useState8("");
9973
- const [installState, setInstallState] = useState8({ status: "idle", output: "" });
9974
- const [pendingServers, setPendingServers] = useState8(null);
9975
- const [pendingEnabled, setPendingEnabled] = useState8(true);
10829
+ const [page, setPage] = useState9("main");
10830
+ const [selectedPreset, setSelectedPreset] = useState9(null);
10831
+ const [customName, setCustomName] = useState9("");
10832
+ const [customCommand, setCustomCommand] = useState9("");
10833
+ const [installState, setInstallState] = useState9({ status: "idle", output: "" });
10834
+ const [pendingServers, setPendingServers] = useState9(null);
10835
+ const [pendingEnabled, setPendingEnabled] = useState9(true);
9976
10836
  const runInstall = (command) => {
9977
10837
  setInstallState({ status: "running", output: "Installing..." });
9978
10838
  const child = spawn3("bash", ["-lc", command], {
@@ -10074,11 +10934,11 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
10074
10934
  { label: "(close)", value: "__close__", key: "__close__" }
10075
10935
  ];
10076
10936
  if (page === "main") {
10077
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10078
- /* @__PURE__ */ jsx17(Text16, { color: theme.accent, bold: true, children: "LSP Servers" }),
10079
- /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select." }),
10080
- /* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
10081
- SelectInput6,
10937
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10938
+ /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "LSP Servers" }),
10939
+ /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select." }),
10940
+ /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
10941
+ SelectInput7,
10082
10942
  {
10083
10943
  items: mainItems,
10084
10944
  onSelect: (item) => {
@@ -10105,11 +10965,11 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
10105
10965
  }),
10106
10966
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
10107
10967
  ];
10108
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10109
- /* @__PURE__ */ jsx17(Text16, { color: theme.accent, bold: true, children: "Add LSP Server" }),
10110
- /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, dimColor: false, children: "Select a language server to configure." }),
10111
- /* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
10112
- SelectInput6,
10968
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10969
+ /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Add LSP Server" }),
10970
+ /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Select a language server to configure." }),
10971
+ /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
10972
+ SelectInput7,
10113
10973
  {
10114
10974
  items,
10115
10975
  onSelect: (item) => {
@@ -10136,19 +10996,19 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
10136
10996
  { label: isSuccess ? "Save to config \u2713" : "Save anyway", value: "save", key: "save" },
10137
10997
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
10138
10998
  ];
10139
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10140
- /* @__PURE__ */ jsxs15(Text16, { color: theme.accent, bold: true, children: [
10999
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11000
+ /* @__PURE__ */ jsxs16(Text17, { color: theme.accent, bold: true, children: [
10141
11001
  "Install ",
10142
11002
  selectedPreset.name
10143
11003
  ] }),
10144
- /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, dimColor: false, children: selectedPreset.installHint }),
10145
- /* @__PURE__ */ jsxs15(Box15, { marginTop: 1, flexDirection: "column", children: [
10146
- /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, dimColor: false, children: "Command:" }),
10147
- /* @__PURE__ */ jsx17(Text16, { color: theme.accent, children: selectedPreset.installCommand || "(none required)" })
11004
+ /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: selectedPreset.installHint }),
11005
+ /* @__PURE__ */ jsxs16(Box16, { marginTop: 1, flexDirection: "column", children: [
11006
+ /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Command:" }),
11007
+ /* @__PURE__ */ jsx18(Text17, { color: theme.accent, children: selectedPreset.installCommand || "(none required)" })
10148
11008
  ] }),
10149
- installState.output && /* @__PURE__ */ jsx17(Box15, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx17(Text16, { color: isSuccess ? theme.accent : theme.error, children: installState.output.slice(-500) }) }),
10150
- /* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
10151
- SelectInput6,
11009
+ installState.output && /* @__PURE__ */ jsx18(Box16, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx18(Text17, { color: isSuccess ? theme.accent : theme.error, children: installState.output.slice(-500) }) }),
11010
+ /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
11011
+ SelectInput7,
10152
11012
  {
10153
11013
  items,
10154
11014
  onSelect: (item) => {
@@ -10165,16 +11025,16 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
10165
11025
  }
10166
11026
  }
10167
11027
  ) }),
10168
- isSuccess && /* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(Text16, { color: theme.accent, children: "Server saved. Run /lsp reload to start it." }) })
11028
+ isSuccess && /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(Text17, { color: theme.accent, children: "Server saved. Run /lsp reload to start it." }) })
10169
11029
  ] });
10170
11030
  }
10171
11031
  if (page === "custom-name") {
10172
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10173
- /* @__PURE__ */ jsx17(Text16, { color: theme.accent, bold: true, children: "Custom LSP Server \u2014 Name" }),
10174
- /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, dimColor: false, children: "Enter a name for this server (e.g., my-server)." }),
10175
- /* @__PURE__ */ jsxs15(Box15, { marginTop: 1, children: [
10176
- /* @__PURE__ */ jsx17(Text16, { color: theme.accent, children: "\u203A " }),
10177
- /* @__PURE__ */ jsx17(
11032
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11033
+ /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Custom LSP Server \u2014 Name" }),
11034
+ /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Enter a name for this server (e.g., my-server)." }),
11035
+ /* @__PURE__ */ jsxs16(Box16, { marginTop: 1, children: [
11036
+ /* @__PURE__ */ jsx18(Text17, { color: theme.accent, children: "\u203A " }),
11037
+ /* @__PURE__ */ jsx18(
10178
11038
  CustomTextInput,
10179
11039
  {
10180
11040
  value: customName,
@@ -10188,8 +11048,8 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
10188
11048
  }
10189
11049
  )
10190
11050
  ] }),
10191
- /* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
10192
- SelectInput6,
11051
+ /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
11052
+ SelectInput7,
10193
11053
  {
10194
11054
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
10195
11055
  onSelect: () => setPage("add")
@@ -10198,12 +11058,12 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
10198
11058
  ] });
10199
11059
  }
10200
11060
  if (page === "custom-command") {
10201
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10202
- /* @__PURE__ */ jsx17(Text16, { color: theme.accent, bold: true, children: "Custom LSP Server \u2014 Command" }),
10203
- /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, dimColor: false, children: "Enter the command to start the server (space-separated)." }),
10204
- /* @__PURE__ */ jsxs15(Box15, { marginTop: 1, children: [
10205
- /* @__PURE__ */ jsx17(Text16, { color: theme.accent, children: "\u203A " }),
10206
- /* @__PURE__ */ jsx17(
11061
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11062
+ /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Custom LSP Server \u2014 Command" }),
11063
+ /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Enter the command to start the server (space-separated)." }),
11064
+ /* @__PURE__ */ jsxs16(Box16, { marginTop: 1, children: [
11065
+ /* @__PURE__ */ jsx18(Text17, { color: theme.accent, children: "\u203A " }),
11066
+ /* @__PURE__ */ jsx18(
10207
11067
  CustomTextInput,
10208
11068
  {
10209
11069
  value: customCommand,
@@ -10217,8 +11077,8 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
10217
11077
  }
10218
11078
  )
10219
11079
  ] }),
10220
- /* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
10221
- SelectInput6,
11080
+ /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
11081
+ SelectInput7,
10222
11082
  {
10223
11083
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
10224
11084
  onSelect: () => setPage("custom-name")
@@ -10241,11 +11101,11 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
10241
11101
  },
10242
11102
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
10243
11103
  ];
10244
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10245
- /* @__PURE__ */ jsx17(Text16, { color: theme.accent, bold: true, children: "Save LSP Config" }),
10246
- /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, dimColor: false, children: "Where should this server configuration be saved?" }),
10247
- /* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
10248
- SelectInput6,
11104
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11105
+ /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Save LSP Config" }),
11106
+ /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Where should this server configuration be saved?" }),
11107
+ /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
11108
+ SelectInput7,
10249
11109
  {
10250
11110
  items,
10251
11111
  onSelect: (item) => {
@@ -10263,11 +11123,11 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
10263
11123
  if (page === "edit") {
10264
11124
  const keys = Object.keys(servers);
10265
11125
  if (keys.length === 0) {
10266
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10267
- /* @__PURE__ */ jsx17(Text16, { color: theme.accent, bold: true, children: "Edit LSP Server" }),
10268
- /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, children: "No servers configured." }),
10269
- /* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
10270
- SelectInput6,
11126
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11127
+ /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Edit LSP Server" }),
11128
+ /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, children: "No servers configured." }),
11129
+ /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
11130
+ SelectInput7,
10271
11131
  {
10272
11132
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
10273
11133
  onSelect: () => setPage("main")
@@ -10287,11 +11147,11 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
10287
11147
  }),
10288
11148
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
10289
11149
  ];
10290
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10291
- /* @__PURE__ */ jsx17(Text16, { color: theme.accent, bold: true, children: "Edit LSP Server" }),
10292
- /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, dimColor: false, children: "Select a server to toggle enabled/disabled." }),
10293
- /* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
10294
- SelectInput6,
11150
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11151
+ /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Edit LSP Server" }),
11152
+ /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Select a server to toggle enabled/disabled." }),
11153
+ /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
11154
+ SelectInput7,
10295
11155
  {
10296
11156
  items,
10297
11157
  onSelect: (item) => {
@@ -10308,11 +11168,11 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
10308
11168
  if (page === "delete") {
10309
11169
  const keys = Object.keys(servers);
10310
11170
  if (keys.length === 0) {
10311
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10312
- /* @__PURE__ */ jsx17(Text16, { color: theme.accent, bold: true, children: "Delete LSP Server" }),
10313
- /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, children: "No servers configured." }),
10314
- /* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
10315
- SelectInput6,
11171
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11172
+ /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Delete LSP Server" }),
11173
+ /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, children: "No servers configured." }),
11174
+ /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
11175
+ SelectInput7,
10316
11176
  {
10317
11177
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
10318
11178
  onSelect: () => setPage("main")
@@ -10328,11 +11188,11 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
10328
11188
  })),
10329
11189
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
10330
11190
  ];
10331
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10332
- /* @__PURE__ */ jsx17(Text16, { color: theme.accent, bold: true, children: "Delete LSP Server" }),
10333
- /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, dimColor: false, children: "Select a server to remove from config." }),
10334
- /* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
10335
- SelectInput6,
11191
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11192
+ /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Delete LSP Server" }),
11193
+ /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Select a server to remove from config." }),
11194
+ /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
11195
+ SelectInput7,
10336
11196
  {
10337
11197
  items,
10338
11198
  onSelect: (item) => {
@@ -10348,15 +11208,15 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
10348
11208
  }
10349
11209
  if (page === "list") {
10350
11210
  const keys = Object.keys(servers);
10351
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10352
- /* @__PURE__ */ jsx17(Text16, { color: theme.accent, bold: true, children: "Configured LSP Servers" }),
10353
- keys.length === 0 ? /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, children: "No servers configured." }) : /* @__PURE__ */ jsx17(Box15, { marginTop: 1, flexDirection: "column", children: keys.map((k) => {
11211
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11212
+ /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Configured LSP Servers" }),
11213
+ keys.length === 0 ? /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, children: "No servers configured." }) : /* @__PURE__ */ jsx18(Box16, { marginTop: 1, flexDirection: "column", children: keys.map((k) => {
10354
11214
  const s = servers[k];
10355
11215
  const status = s.enabled !== false ? "enabled" : "disabled";
10356
- return /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, children: ` ${k.padEnd(16)} ${status} ${s.command.join(" ")}` }, k);
11216
+ return /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, children: ` ${k.padEnd(16)} ${status} ${s.command.join(" ")}` }, k);
10357
11217
  }) }),
10358
- /* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
10359
- SelectInput6,
11218
+ /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
11219
+ SelectInput7,
10360
11220
  {
10361
11221
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
10362
11222
  onSelect: () => setPage("main")
@@ -10482,9 +11342,9 @@ var init_lsp_wizard = __esm({
10482
11342
  });
10483
11343
 
10484
11344
  // src/ui/theme-picker.tsx
10485
- import { Box as Box16, Text as Text17 } from "ink";
10486
- import SelectInput7 from "ink-select-input";
10487
- import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
11345
+ import { Box as Box17, Text as Text18 } from "ink";
11346
+ import SelectInput8 from "ink-select-input";
11347
+ import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
10488
11348
  function PaletteSwatches({ palette }) {
10489
11349
  const colors = [
10490
11350
  palette.primary,
@@ -10492,7 +11352,7 @@ function PaletteSwatches({ palette }) {
10492
11352
  palette.success,
10493
11353
  palette.error
10494
11354
  ];
10495
- return /* @__PURE__ */ jsx18(Box16, { children: colors.map((c, i) => /* @__PURE__ */ jsx18(Text17, { color: c, children: "\u2588" }, i)) });
11355
+ return /* @__PURE__ */ jsx19(Box17, { children: colors.map((c, i) => /* @__PURE__ */ jsx19(Text18, { color: c, children: "\u2588" }, i)) });
10496
11356
  }
10497
11357
  function ThemePicker({ themes, onPick, onPreview }) {
10498
11358
  const current = useTheme();
@@ -10500,10 +11360,10 @@ function ThemePicker({ themes, onPick, onPreview }) {
10500
11360
  ...themes.map((t) => ({ label: t.label, value: t.name })),
10501
11361
  { label: "< Back", value: "__back__" }
10502
11362
  ];
10503
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: current.accent, paddingX: 1, children: [
10504
- /* @__PURE__ */ jsx18(Text17, { color: current.accent, bold: true, children: "Pick a theme" }),
10505
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
10506
- SelectInput7,
11363
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: current.accent, paddingX: 1, children: [
11364
+ /* @__PURE__ */ jsx19(Text18, { color: current.accent, bold: true, children: "Pick a theme" }),
11365
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
11366
+ SelectInput8,
10507
11367
  {
10508
11368
  items,
10509
11369
  onHighlight: (item) => {
@@ -10522,9 +11382,9 @@ function ThemePicker({ themes, onPick, onPreview }) {
10522
11382
  itemComponent: ({ label, isSelected }) => {
10523
11383
  const t = themes.find((x) => x.label === label);
10524
11384
  const color = t?.accent ?? current.accent;
10525
- return /* @__PURE__ */ jsxs16(Box16, { children: [
10526
- /* @__PURE__ */ jsx18(Text17, { color, bold: isSelected, dimColor: !isSelected, children: label }),
10527
- t && /* @__PURE__ */ jsx18(Box16, { marginLeft: 1, children: /* @__PURE__ */ jsx18(PaletteSwatches, { palette: t.palette }) })
11385
+ return /* @__PURE__ */ jsxs17(Box17, { children: [
11386
+ /* @__PURE__ */ jsx19(Text18, { color, bold: isSelected, dimColor: !isSelected, children: label }),
11387
+ t && /* @__PURE__ */ jsx19(Box17, { marginLeft: 1, children: /* @__PURE__ */ jsx19(PaletteSwatches, { palette: t.palette }) })
10528
11388
  ] });
10529
11389
  }
10530
11390
  }
@@ -10668,8 +11528,8 @@ var init_lsp_nudge = __esm({
10668
11528
  });
10669
11529
 
10670
11530
  // src/ui/file-picker.tsx
10671
- import { Box as Box17, Text as Text18 } from "ink";
10672
- import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
11531
+ import { Box as Box18, Text as Text19 } from "ink";
11532
+ import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
10673
11533
  function FilePicker({ items, selectedIndex, query }) {
10674
11534
  const theme = useTheme();
10675
11535
  let startIndex = 0;
@@ -10679,12 +11539,12 @@ function FilePicker({ items, selectedIndex, query }) {
10679
11539
  const visible = items.slice(startIndex, startIndex + VISIBLE_LIMIT);
10680
11540
  const hasMoreAbove = startIndex > 0;
10681
11541
  const hasMoreBelow = items.length > startIndex + VISIBLE_LIMIT;
10682
- return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10683
- /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: query ? `Files matching "${query}"` : "Mention a file" }),
10684
- /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select, Esc to cancel." }),
10685
- /* @__PURE__ */ jsxs17(Box17, { marginTop: 1, flexDirection: "column", children: [
10686
- visible.length === 0 && /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, children: "No matches" }),
10687
- hasMoreAbove && /* @__PURE__ */ jsxs17(Text18, { color: theme.info.color, children: [
11542
+ return /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11543
+ /* @__PURE__ */ jsx20(Text19, { color: theme.accent, bold: true, children: query ? `Files matching "${query}"` : "Mention a file" }),
11544
+ /* @__PURE__ */ jsx20(Text19, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select, Esc to cancel." }),
11545
+ /* @__PURE__ */ jsxs18(Box18, { marginTop: 1, flexDirection: "column", children: [
11546
+ visible.length === 0 && /* @__PURE__ */ jsx20(Text19, { color: theme.info.color, children: "No matches" }),
11547
+ hasMoreAbove && /* @__PURE__ */ jsxs18(Text19, { color: theme.info.color, children: [
10688
11548
  "\u2026 ",
10689
11549
  startIndex,
10690
11550
  " more above"
@@ -10693,12 +11553,12 @@ function FilePicker({ items, selectedIndex, query }) {
10693
11553
  const actualIndex = startIndex + i;
10694
11554
  const isSelected = actualIndex === selectedIndex;
10695
11555
  const label = item.isDirectory ? `${item.name}/` : item.name;
10696
- return /* @__PURE__ */ jsxs17(Text18, { color: isSelected ? theme.accent : void 0, bold: isSelected, children: [
11556
+ return /* @__PURE__ */ jsxs18(Text19, { color: isSelected ? theme.accent : void 0, bold: isSelected, children: [
10697
11557
  isSelected ? "\u203A " : " ",
10698
11558
  label
10699
11559
  ] }, item.name);
10700
11560
  }),
10701
- hasMoreBelow && /* @__PURE__ */ jsxs17(Text18, { color: theme.info.color, children: [
11561
+ hasMoreBelow && /* @__PURE__ */ jsxs18(Text19, { color: theme.info.color, children: [
10702
11562
  "\u2026 ",
10703
11563
  items.length - (startIndex + VISIBLE_LIMIT),
10704
11564
  " more below"
@@ -10716,8 +11576,8 @@ var init_file_picker = __esm({
10716
11576
  });
10717
11577
 
10718
11578
  // src/ui/slash-picker.tsx
10719
- import { Box as Box18, Text as Text19 } from "ink";
10720
- import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
11579
+ import { Box as Box19, Text as Text20 } from "ink";
11580
+ import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
10721
11581
  function sourceBadge(source) {
10722
11582
  if (source === "builtin") return "";
10723
11583
  if (source === "project") return "project";
@@ -10737,12 +11597,12 @@ function SlashPicker({ items, selectedIndex, query }) {
10737
11597
  const hasMoreBelow = items.length > startIndex + VISIBLE_LIMIT2;
10738
11598
  const longestLabel = visible.reduce((m, it) => Math.max(m, commandLabel(it).length), 0);
10739
11599
  const nameColWidth = Math.max(NAME_COL_MIN_WIDTH, longestLabel + NAME_DESC_GAP);
10740
- return /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10741
- /* @__PURE__ */ jsx20(Text19, { color: theme.accent, bold: true, children: query ? `Commands matching "/${query}"` : "Slash commands" }),
10742
- /* @__PURE__ */ jsx20(Text19, { color: theme.info.color, children: "Arrow keys to navigate, Enter to select, Esc to cancel." }),
10743
- /* @__PURE__ */ jsxs18(Box18, { marginTop: 1, flexDirection: "column", children: [
10744
- visible.length === 0 && /* @__PURE__ */ jsx20(Text19, { color: theme.info.color, children: "No matches" }),
10745
- hasMoreAbove && /* @__PURE__ */ jsxs18(Text19, { color: theme.info.color, children: [
11600
+ return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11601
+ /* @__PURE__ */ jsx21(Text20, { color: theme.accent, bold: true, children: query ? `Commands matching "/${query}"` : "Slash commands" }),
11602
+ /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, children: "Arrow keys to navigate, Enter to select, Esc to cancel." }),
11603
+ /* @__PURE__ */ jsxs19(Box19, { marginTop: 1, flexDirection: "column", children: [
11604
+ visible.length === 0 && /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, children: "No matches" }),
11605
+ hasMoreAbove && /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
10746
11606
  "\u2026 ",
10747
11607
  startIndex,
10748
11608
  " more above"
@@ -10752,16 +11612,16 @@ function SlashPicker({ items, selectedIndex, query }) {
10752
11612
  const isSelected = actualIndex === selectedIndex;
10753
11613
  const nameCol = commandLabel(item).padEnd(nameColWidth);
10754
11614
  const badge = sourceBadge(item.source);
10755
- return /* @__PURE__ */ jsxs18(Text19, { color: isSelected ? theme.accent : void 0, bold: isSelected, children: [
11615
+ return /* @__PURE__ */ jsxs19(Text20, { color: isSelected ? theme.accent : void 0, bold: isSelected, children: [
10756
11616
  isSelected ? "\u203A " : " ",
10757
11617
  nameCol,
10758
- /* @__PURE__ */ jsxs18(Text19, { color: theme.info.color, children: [
11618
+ /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
10759
11619
  item.description,
10760
11620
  badge && ` [${badge}]`
10761
11621
  ] })
10762
11622
  ] }, item.name);
10763
11623
  }),
10764
- hasMoreBelow && /* @__PURE__ */ jsxs18(Text19, { color: theme.info.color, children: [
11624
+ hasMoreBelow && /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
10765
11625
  "\u2026 ",
10766
11626
  items.length - (startIndex + VISIBLE_LIMIT2),
10767
11627
  " more below"
@@ -10841,15 +11701,15 @@ var tui_report_exports = {};
10841
11701
  __export(tui_report_exports, {
10842
11702
  getCategoryReportText: () => getCategoryReportText
10843
11703
  });
10844
- import { readFile as readFile14 } from "fs/promises";
10845
- import { join as join16 } from "path";
10846
- import { homedir as homedir12 } from "os";
11704
+ import { readFile as readFile15 } from "fs/promises";
11705
+ import { join as join18 } from "path";
11706
+ import { homedir as homedir13 } from "os";
10847
11707
  function usageDir3() {
10848
- const xdg = process.env.XDG_DATA_HOME || join16(homedir12(), ".local", "share");
10849
- return join16(xdg, "kimiflare");
11708
+ const xdg = process.env.XDG_DATA_HOME || join18(homedir13(), ".local", "share");
11709
+ return join18(xdg, "kimiflare");
10850
11710
  }
10851
11711
  function usagePath3() {
10852
- return join16(usageDir3(), "usage.json");
11712
+ return join18(usageDir3(), "usage.json");
10853
11713
  }
10854
11714
  function today3() {
10855
11715
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
@@ -10861,7 +11721,7 @@ function daysAgo2(n) {
10861
11721
  }
10862
11722
  async function loadLog3() {
10863
11723
  try {
10864
- const raw = await readFile14(usagePath3(), "utf8");
11724
+ const raw = await readFile15(usagePath3(), "utf8");
10865
11725
  return JSON.parse(raw);
10866
11726
  } catch {
10867
11727
  return { version: 1, days: [], sessions: [] };
@@ -10927,17 +11787,18 @@ __export(app_exports, {
10927
11787
  shouldOpenMentionPicker: () => shouldOpenMentionPicker,
10928
11788
  shouldOpenSlashPicker: () => shouldOpenSlashPicker
10929
11789
  });
10930
- import React13, { useState as useState9, useRef as useRef3, useEffect as useEffect4, useCallback } from "react";
10931
- import { Box as Box19, Text as Text20, useApp, useInput as useInput5, render } from "ink";
10932
- import SelectInput8 from "ink-select-input";
11790
+ import React14, { useState as useState10, useRef as useRef3, useEffect as useEffect5, useCallback } from "react";
11791
+ import { Box as Box20, Text as Text21, useApp, useInput as useInput6, render } from "ink";
11792
+ import SelectInput9 from "ink-select-input";
10933
11793
  import { existsSync as existsSync2, statSync as statSync3 } from "fs";
10934
- import { join as join17 } from "path";
11794
+ import { join as join19 } from "path";
10935
11795
  import { unlink as unlink3 } from "fs/promises";
11796
+ import { execSync as execSync2 } from "child_process";
10936
11797
  import { spawn as spawn4 } from "child_process";
10937
11798
  import { platform as platform2 } from "os";
10938
11799
  import fg4 from "fast-glob";
10939
11800
  import { readFileSync as readFileSync3 } from "fs";
10940
- import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
11801
+ import { jsx as jsx22, jsxs as jsxs20 } from "react/jsx-runtime";
10941
11802
  function buildFilePickerIgnoreList(cwd) {
10942
11803
  const hardcoded = [
10943
11804
  // Dependencies
@@ -11008,7 +11869,7 @@ function buildFilePickerIgnoreList(cwd) {
11008
11869
  ];
11009
11870
  const gitignorePatterns = [];
11010
11871
  try {
11011
- const gitignorePath = join17(cwd, ".gitignore");
11872
+ const gitignorePath = join19(cwd, ".gitignore");
11012
11873
  const stats = statSync3(gitignorePath);
11013
11874
  if (stats.size > MAX_GITIGNORE_SIZE) {
11014
11875
  return hardcoded;
@@ -11082,6 +11943,26 @@ function openBrowser(url) {
11082
11943
  const child = spawn4(cmd, [url], { detached: true, stdio: "ignore" });
11083
11944
  child.unref();
11084
11945
  }
11946
+ function detectGitHubRepo(cachedRepo) {
11947
+ if (cachedRepo) {
11948
+ const parts = cachedRepo.split("/");
11949
+ if (parts.length === 2) return { owner: parts[0], name: parts[1] };
11950
+ }
11951
+ try {
11952
+ const remoteUrl = execSync2("git remote get-url origin", { cwd: process.cwd(), encoding: "utf8" }).trim();
11953
+ const httpsMatch = remoteUrl.match(/github\.com\/([^\/]+)\/([^\/]+?)(?:\.git)?$/);
11954
+ if (httpsMatch) return { owner: httpsMatch[1], name: httpsMatch[2] };
11955
+ const sshMatch = remoteUrl.match(/github\.com:([^\/]+)\/([^\/]+?)(?:\.git)?$/);
11956
+ if (sshMatch) return { owner: sshMatch[1], name: sshMatch[2] };
11957
+ } catch {
11958
+ }
11959
+ return null;
11960
+ }
11961
+ function formatTokens3(n) {
11962
+ if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
11963
+ if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
11964
+ return String(n);
11965
+ }
11085
11966
  function capEvents(prev) {
11086
11967
  if (prev.length <= MAX_EVENTS) return prev;
11087
11968
  return prev.slice(prev.length - MAX_EVENTS);
@@ -11144,10 +12025,10 @@ function App({
11144
12025
  initialLspProjectPath
11145
12026
  }) {
11146
12027
  const { exit } = useApp();
11147
- const [cfg, setCfg] = useState9(initialCfg);
11148
- const [lspScope, setLspScope] = useState9(initialLspScope);
11149
- const [lspProjectPath, setLspProjectPath] = useState9(initialLspProjectPath);
11150
- const [events, setRawEvents] = useState9([]);
12028
+ const [cfg, setCfg] = useState10(initialCfg);
12029
+ const [lspScope, setLspScope] = useState10(initialLspScope);
12030
+ const [lspProjectPath, setLspProjectPath] = useState10(initialLspProjectPath);
12031
+ const [events, setRawEvents] = useState10([]);
11151
12032
  const setEvents = useCallback(
11152
12033
  (updater) => {
11153
12034
  setRawEvents((prev) => {
@@ -11157,45 +12038,47 @@ function App({
11157
12038
  },
11158
12039
  []
11159
12040
  );
11160
- const [input, setInput] = useState9("");
11161
- const [busy, setBusy] = useState9(false);
11162
- const [usage, setUsage] = useState9(null);
11163
- const [sessionUsage, setSessionUsage] = useState9(null);
11164
- const [gatewayMeta, setGatewayMeta] = useState9(null);
11165
- const [showReasoning, setShowReasoning] = useState9(false);
11166
- const [perm, setPerm] = useState9(null);
11167
- const [queue, setQueue] = useState9([]);
11168
- const [history, setHistory] = useState9([]);
11169
- const [historyIndex, setHistoryIndex] = useState9(-1);
11170
- const [draftInput, setDraftInput] = useState9("");
11171
- const [mode, setMode] = useState9("edit");
11172
- const [codeMode, setCodeMode] = useState9(initialCfg?.codeMode ?? false);
12041
+ const [input, setInput] = useState10("");
12042
+ const [busy, setBusy] = useState10(false);
12043
+ const [usage, setUsage] = useState10(null);
12044
+ const [sessionUsage, setSessionUsage] = useState10(null);
12045
+ const [gatewayMeta, setGatewayMeta] = useState10(null);
12046
+ const [showReasoning, setShowReasoning] = useState10(false);
12047
+ const [perm, setPerm] = useState10(null);
12048
+ const [queue, setQueue] = useState10([]);
12049
+ const [history, setHistory] = useState10([]);
12050
+ const [historyIndex, setHistoryIndex] = useState10(-1);
12051
+ const [draftInput, setDraftInput] = useState10("");
12052
+ const [mode, setMode] = useState10("edit");
12053
+ const [codeMode, setCodeMode] = useState10(false);
11173
12054
  const filePickerEnabled = initialCfg?.filePicker ?? true;
11174
- const [effort, setEffort] = useState9(
12055
+ const [effort, setEffort] = useState10(
11175
12056
  initialCfg?.reasoningEffort ?? DEFAULT_REASONING_EFFORT
11176
12057
  );
11177
- const [resumeSessions, setResumeSessions] = useState9(null);
11178
- const [showHelpMenu, setShowHelpMenu] = useState9(false);
11179
- const [commandWizard, setCommandWizard] = useState9(null);
11180
- const [commandPicker, setCommandPicker] = useState9(null);
11181
- const [commandToDelete, setCommandToDelete] = useState9(null);
11182
- const [showCommandList, setShowCommandList] = useState9(false);
11183
- const [showLspWizard, setShowLspWizard] = useState9(false);
11184
- const [tasks, setTasks] = useState9([]);
11185
- const [tasksStartedAt, setTasksStartedAt] = useState9(null);
11186
- const [tasksStartTokens, setTasksStartTokens] = useState9(0);
11187
- const [turnStartedAt, setTurnStartedAt] = useState9(null);
11188
- const [verbose, setVerbose] = useState9(false);
11189
- const [hasUpdate, setHasUpdate] = useState9(initialUpdateResult?.hasUpdate ?? false);
11190
- const [latestVersion, setLatestVersion] = useState9(initialUpdateResult?.latestVersion ?? null);
11191
- const [theme, setTheme] = useState9(resolveTheme(initialCfg?.theme));
11192
- const [showThemePicker, setShowThemePicker] = useState9(false);
11193
- const [originalTheme, setOriginalTheme] = useState9(null);
11194
- const [cursorOffset, setCursorOffset] = useState9(0);
11195
- const [activePicker, setActivePicker] = useState9(null);
11196
- const [filePickerItems, setFilePickerItems] = useState9([]);
12058
+ const [resumeSessions, setResumeSessions] = useState10(null);
12059
+ const [showHelpMenu, setShowHelpMenu] = useState10(false);
12060
+ const [commandWizard, setCommandWizard] = useState10(null);
12061
+ const [commandPicker, setCommandPicker] = useState10(null);
12062
+ const [commandToDelete, setCommandToDelete] = useState10(null);
12063
+ const [showCommandList, setShowCommandList] = useState10(false);
12064
+ const [showLspWizard, setShowLspWizard] = useState10(false);
12065
+ const [showRemoteDashboard, setShowRemoteDashboard] = useState10(false);
12066
+ const [selectedRemoteSession, setSelectedRemoteSession] = useState10(null);
12067
+ const [tasks, setTasks] = useState10([]);
12068
+ const [tasksStartedAt, setTasksStartedAt] = useState10(null);
12069
+ const [tasksStartTokens, setTasksStartTokens] = useState10(0);
12070
+ const [turnStartedAt, setTurnStartedAt] = useState10(null);
12071
+ const [verbose, setVerbose] = useState10(false);
12072
+ const [hasUpdate, setHasUpdate] = useState10(initialUpdateResult?.hasUpdate ?? false);
12073
+ const [latestVersion, setLatestVersion] = useState10(initialUpdateResult?.latestVersion ?? null);
12074
+ const [theme, setTheme] = useState10(resolveTheme(initialCfg?.theme));
12075
+ const [showThemePicker, setShowThemePicker] = useState10(false);
12076
+ const [originalTheme, setOriginalTheme] = useState10(null);
12077
+ const [cursorOffset, setCursorOffset] = useState10(0);
12078
+ const [activePicker, setActivePicker] = useState10(null);
12079
+ const [filePickerItems, setFilePickerItems] = useState10([]);
11197
12080
  const filePickerLoadedRef = useRef3(false);
11198
- const [customCommandsVersion, setCustomCommandsVersion] = useState9(0);
12081
+ const [customCommandsVersion, setCustomCommandsVersion] = useState10(0);
11199
12082
  const cacheStableRef = useRef3(initialCfg?.cacheStablePrompts !== false);
11200
12083
  const messagesRef = useRef3(
11201
12084
  makePrefixMessages(cacheStableRef.current, cfg?.model ?? DEFAULT_MODEL, "edit", ALL_TOOLS)
@@ -11233,15 +12116,15 @@ function App({
11233
12116
  const pickerCancelRef = useRef3(null);
11234
12117
  const pickerAnchor = activePicker?.anchor ?? null;
11235
12118
  const pickerKind = activePicker?.kind ?? null;
11236
- const pickerQuery = React13.useMemo(() => {
12119
+ const pickerQuery = React14.useMemo(() => {
11237
12120
  if (pickerAnchor === null) return null;
11238
12121
  return input.slice(pickerAnchor + 1, cursorOffset);
11239
12122
  }, [input, cursorOffset, pickerAnchor]);
11240
- const filteredFileItems = React13.useMemo(() => {
12123
+ const filteredFileItems = React14.useMemo(() => {
11241
12124
  if (pickerKind !== "file" || pickerQuery === null) return [];
11242
12125
  return filterPickerItems(filePickerItems, pickerQuery);
11243
12126
  }, [pickerKind, filePickerItems, pickerQuery]);
11244
- const allSlashCommands = React13.useMemo(() => {
12127
+ const allSlashCommands = React14.useMemo(() => {
11245
12128
  const customs = customCommandsRef.current.filter((c) => !BUILTIN_COMMAND_NAMES.has(c.name.toLowerCase())).map((c) => ({
11246
12129
  name: c.name,
11247
12130
  description: c.description ?? "",
@@ -11249,11 +12132,11 @@ function App({
11249
12132
  }));
11250
12133
  return [...BUILTIN_COMMANDS, ...customs];
11251
12134
  }, [customCommandsVersion]);
11252
- const filteredSlashItems = React13.useMemo(() => {
12135
+ const filteredSlashItems = React14.useMemo(() => {
11253
12136
  if (pickerKind !== "slash" || pickerQuery === null) return [];
11254
12137
  return fuzzyFilter(allSlashCommands, pickerQuery, (c) => c.name).slice(0, 50);
11255
12138
  }, [pickerKind, allSlashCommands, pickerQuery]);
11256
- useEffect4(() => {
12139
+ useEffect5(() => {
11257
12140
  if (activePicker !== null) {
11258
12141
  const trigger = activePicker.kind === "file" ? "@" : "/";
11259
12142
  if (cursorOffset < activePicker.anchor) {
@@ -11310,14 +12193,14 @@ function App({
11310
12193
  return;
11311
12194
  }
11312
12195
  }, [input, cursorOffset, activePicker, filePickerEnabled]);
11313
- useEffect4(() => {
12196
+ useEffect5(() => {
11314
12197
  if (activePicker?.kind !== "file") return;
11315
12198
  const max = Math.max(0, filteredFileItems.length - 1);
11316
12199
  if (activePicker.selected > max) {
11317
12200
  setActivePicker({ ...activePicker, selected: max });
11318
12201
  }
11319
12202
  }, [filteredFileItems.length, activePicker]);
11320
- useEffect4(() => {
12203
+ useEffect5(() => {
11321
12204
  if (activePicker?.kind !== "slash") return;
11322
12205
  const max = Math.max(0, filteredSlashItems.length - 1);
11323
12206
  if (activePicker.selected > max) {
@@ -11361,7 +12244,7 @@ function App({
11361
12244
  pickerCancelRef.current = cursorOffset;
11362
12245
  setActivePicker(null);
11363
12246
  }, [cursorOffset]);
11364
- useEffect4(() => {
12247
+ useEffect5(() => {
11365
12248
  const modalActive = showHelpMenu || commandWizard !== null || commandPicker !== null || commandToDelete !== null || showCommandList || showLspWizard || resumeSessions !== null || perm !== null;
11366
12249
  if (modalActive && activePicker !== null) {
11367
12250
  setActivePicker(null);
@@ -11377,7 +12260,7 @@ function App({
11377
12260
  perm,
11378
12261
  activePicker
11379
12262
  ]);
11380
- useEffect4(() => {
12263
+ useEffect5(() => {
11381
12264
  if (!cfg) return;
11382
12265
  void Promise.resolve().then(() => (init_sessions(), sessions_exports)).then(
11383
12266
  ({ pruneSessions: pruneSessions2 }) => pruneSessions2().then((removed) => {
@@ -11403,13 +12286,14 @@ function App({
11403
12286
  }
11404
12287
  });
11405
12288
  if (cfg.memoryEnabled) {
11406
- const dbPath = cfg.memoryDbPath ?? join17(process.cwd(), ".kimiflare", "memory.db");
12289
+ const dbPath = cfg.memoryDbPath ?? join19(process.cwd(), ".kimiflare", "memory.db");
11407
12290
  const manager = new MemoryManager({
11408
12291
  dbPath,
11409
12292
  accountId: cfg.accountId,
11410
12293
  apiToken: cfg.apiToken,
11411
12294
  model: cfg.model,
11412
12295
  plumbingModel: cfg.plumbingModel,
12296
+ extractionModel: cfg.memoryExtractionModel,
11413
12297
  embeddingModel: cfg.memoryEmbeddingModel,
11414
12298
  gateway: gatewayFromConfig(cfg),
11415
12299
  maxAgeDays: cfg.memoryMaxAgeDays ?? RETENTION.memoryMaxAgeDays,
@@ -11470,7 +12354,7 @@ function App({
11470
12354
  }
11471
12355
  });
11472
12356
  }, [cfg, setEvents]);
11473
- useEffect4(() => {
12357
+ useEffect5(() => {
11474
12358
  const id = setInterval(() => {
11475
12359
  try {
11476
12360
  performance.clearMarks();
@@ -11495,7 +12379,7 @@ function App({
11495
12379
  ]);
11496
12380
  }
11497
12381
  }, [setEvents]);
11498
- useEffect4(() => {
12382
+ useEffect5(() => {
11499
12383
  if (!cfg || updateCheckedRef.current) return;
11500
12384
  updateCheckedRef.current = true;
11501
12385
  if (initialUpdateResult) {
@@ -11546,7 +12430,7 @@ function App({
11546
12430
  }
11547
12431
  });
11548
12432
  }, [cfg, initialUpdateResult]);
11549
- useEffect4(() => {
12433
+ useEffect5(() => {
11550
12434
  modeRef.current = mode;
11551
12435
  if (cacheStableRef.current) {
11552
12436
  messagesRef.current[1] = {
@@ -11573,10 +12457,10 @@ function App({
11573
12457
  executorRef.current.clearSessionPermissions();
11574
12458
  }
11575
12459
  }, [mode, cfg?.model]);
11576
- useEffect4(() => {
12460
+ useEffect5(() => {
11577
12461
  effortRef.current = effort;
11578
12462
  }, [effort]);
11579
- useEffect4(() => {
12463
+ useEffect5(() => {
11580
12464
  if (!cfg) return;
11581
12465
  const id = setInterval(() => {
11582
12466
  void checkForUpdate().then((result) => {
@@ -11731,7 +12615,7 @@ function App({
11731
12615
  ]);
11732
12616
  }
11733
12617
  }, [cfg]);
11734
- useEffect4(() => {
12618
+ useEffect5(() => {
11735
12619
  if (cfg && !mcpInitRef.current) {
11736
12620
  void initMcp();
11737
12621
  }
@@ -11769,7 +12653,85 @@ function App({
11769
12653
  } catch {
11770
12654
  }
11771
12655
  }, [cfg, ensureSessionId]);
11772
- useInput5((inputChar, key) => {
12656
+ const onIterationEnd = useCallback(
12657
+ async (messages, signal) => {
12658
+ if (signal.aborted) return messages;
12659
+ if (!shouldCompact({ messages })) return messages;
12660
+ if (compiledContextRef.current) {
12661
+ const store = artifactStoreRef.current;
12662
+ const result = compactMessages2({
12663
+ messages,
12664
+ state: sessionStateRef.current,
12665
+ store
12666
+ });
12667
+ if (result.metrics.rawTurnsRemoved > 0) {
12668
+ sessionStateRef.current = result.newState;
12669
+ setEvents((e) => [
12670
+ ...e,
12671
+ {
12672
+ kind: "info",
12673
+ key: mkKey(),
12674
+ text: `auto-compacted: ${result.metrics.estimatedTokensBefore} \u2192 ${result.metrics.estimatedTokensAfter} tokens (${result.metrics.archivedArtifacts} artifacts)`
12675
+ }
12676
+ ]);
12677
+ await saveSessionSafe();
12678
+ }
12679
+ const manager = memoryManagerRef.current;
12680
+ if (manager && !signal.aborted) {
12681
+ try {
12682
+ const cwd = process.cwd();
12683
+ const queryText = sessionStateRef.current.task || cwd;
12684
+ const results = await manager.recall({ text: queryText, repoPath: cwd, limit: 5 });
12685
+ if (results.length > 0 && !signal.aborted) {
12686
+ const text = await manager.synthesizeRecalled(results);
12687
+ const lastSystemIdx = result.newMessages.findLastIndex((m) => m.role === "system");
12688
+ const insertIdx = lastSystemIdx >= 0 ? lastSystemIdx + 1 : result.newMessages.length;
12689
+ result.newMessages.splice(insertIdx, 0, { role: "system", content: text });
12690
+ setEvents((e) => [
12691
+ ...e,
12692
+ {
12693
+ kind: "memory",
12694
+ key: mkKey(),
12695
+ text: `recalled ${results.length} memory${results.length === 1 ? "" : "ies"} after compaction`
12696
+ }
12697
+ ]);
12698
+ await saveSessionSafe();
12699
+ }
12700
+ } catch {
12701
+ }
12702
+ }
12703
+ return result.newMessages;
12704
+ }
12705
+ if (cfg && !signal.aborted) {
12706
+ try {
12707
+ const result = await compactMessages({
12708
+ accountId: cfg.accountId,
12709
+ apiToken: cfg.apiToken,
12710
+ model: cfg.model,
12711
+ messages,
12712
+ signal,
12713
+ gateway: gatewayFromConfig(cfg)
12714
+ });
12715
+ if (result.replacedCount > 0) {
12716
+ setEvents((e) => [
12717
+ ...e,
12718
+ {
12719
+ kind: "info",
12720
+ key: mkKey(),
12721
+ text: `auto-compacted: ${result.replacedCount} messages summarized`
12722
+ }
12723
+ ]);
12724
+ await saveSessionSafe();
12725
+ }
12726
+ return result.newMessages;
12727
+ } catch {
12728
+ }
12729
+ }
12730
+ return messages;
12731
+ },
12732
+ [cfg]
12733
+ );
12734
+ useInput6((inputChar, key) => {
11773
12735
  if (key.ctrl && inputChar === "c") {
11774
12736
  const hadPerm = permResolveRef.current !== null;
11775
12737
  if (hadPerm) {
@@ -11812,10 +12774,6 @@ function App({
11812
12774
  setVerbose((v) => !v);
11813
12775
  return;
11814
12776
  }
11815
- if (key.ctrl && inputChar === "m") {
11816
- setCodeMode((c) => !c);
11817
- return;
11818
- }
11819
12777
  });
11820
12778
  const flushAssistantUpdates = useCallback(() => {
11821
12779
  flushTimeoutRef.current = null;
@@ -11967,7 +12925,7 @@ function App({
11967
12925
  }
11968
12926
  }, [cfg, busy, saveSessionSafe]);
11969
12927
  const openResumePicker = useCallback(async () => {
11970
- const sessions = await listSessions(200);
12928
+ const sessions = await listSessions(200, process.cwd());
11971
12929
  setResumeSessions(sessions);
11972
12930
  }, []);
11973
12931
  const runInit = useCallback(async () => {
@@ -11977,7 +12935,7 @@ function App({
11977
12935
  return;
11978
12936
  }
11979
12937
  const cwd = process.cwd();
11980
- const existingName = ["KIMI.md", "KIMIFLARE.md", "AGENT.md"].find((n) => existsSync2(join17(cwd, n)));
12938
+ const existingName = ["KIMI.md", "KIMIFLARE.md", "AGENT.md"].find((n) => existsSync2(join19(cwd, n)));
11981
12939
  const isRefresh = existingName !== void 0;
11982
12940
  const promptParts = [
11983
12941
  isRefresh ? `Regenerate ${existingName} at the repository root to refresh project context. If the file already exists, read it first and preserve anything still accurate, updating only what has changed.` : "Generate a KIMI.md at the repository root so future agents have project context.",
@@ -12002,6 +12960,15 @@ function App({
12002
12960
  setTurnStartedAt(Date.now());
12003
12961
  const controller = new AbortController();
12004
12962
  activeControllerRef.current = controller;
12963
+ const initClassification = classifyIntent(prompt);
12964
+ const initEffortForTier = {
12965
+ light: "low",
12966
+ medium: "medium",
12967
+ heavy: "high"
12968
+ };
12969
+ const initReasoningEffort = initEffortForTier[initClassification.tier] ?? effortRef.current;
12970
+ const effectiveCodeMode = initClassification.tier === "heavy";
12971
+ setCodeMode(effectiveCodeMode);
12005
12972
  try {
12006
12973
  await runAgentTurn({
12007
12974
  accountId: cfg.accountId,
@@ -12013,17 +12980,19 @@ function App({
12013
12980
  executor: executorRef.current,
12014
12981
  cwd,
12015
12982
  signal: controller.signal,
12016
- reasoningEffort: effortRef.current,
12983
+ reasoningEffort: initReasoningEffort,
12984
+ intentClassification: initClassification,
12017
12985
  coauthor: cfg.coauthor !== false ? { name: cfg.coauthorName || "kimiflare", email: cfg.coauthorEmail || "kimiflare@proton.me" } : void 0,
12018
12986
  sessionId: ensureSessionId(),
12019
12987
  memoryManager: memoryManagerRef.current,
12020
- codeMode,
12988
+ codeMode: effectiveCodeMode,
12989
+ onIterationEnd,
12021
12990
  onFileChange: (path, content) => {
12022
12991
  if (content) {
12023
12992
  lspManagerRef.current.notifyChange(path, content);
12024
12993
  } else {
12025
12994
  void import("fs/promises").then(
12026
- ({ readFile: readFile15 }) => readFile15(path, "utf8").then((c) => lspManagerRef.current.notifyChange(path, c)).catch(() => {
12995
+ ({ readFile: readFile16 }) => readFile16(path, "utf8").then((c) => lspManagerRef.current.notifyChange(path, c)).catch(() => {
12027
12996
  })
12028
12997
  );
12029
12998
  }
@@ -12117,7 +13086,7 @@ function App({
12117
13086
  })
12118
13087
  }
12119
13088
  });
12120
- if (existsSync2(join17(cwd, "KIMI.md"))) {
13089
+ if (existsSync2(join19(cwd, "KIMI.md"))) {
12121
13090
  if (cacheStableRef.current) {
12122
13091
  messagesRef.current[1] = {
12123
13092
  role: "system",
@@ -12164,6 +13133,7 @@ function App({
12164
13133
  ]);
12165
13134
  }
12166
13135
  } finally {
13136
+ setCodeMode(false);
12167
13137
  const asstId = activeAsstIdRef.current;
12168
13138
  if (asstId !== null) updateAssistant(asstId, () => ({ streaming: false }));
12169
13139
  setBusy(false);
@@ -12774,13 +13744,177 @@ ${lines.join("\n")}` }]);
12774
13744
  ]);
12775
13745
  return true;
12776
13746
  }
13747
+ if (c === "/remote") {
13748
+ if (arg === "status" || arg === "cancel") {
13749
+ setEvents((e) => [
13750
+ ...e,
13751
+ { kind: "info", key: mkKey(), text: `Use \`kimiflare remote ${arg}\` from your shell.` }
13752
+ ]);
13753
+ return true;
13754
+ }
13755
+ const prompt = rest.join(" ").trim();
13756
+ if (!prompt) {
13757
+ setShowRemoteDashboard(true);
13758
+ return true;
13759
+ }
13760
+ const repo = detectGitHubRepo(cfg?.githubRepo);
13761
+ if (!repo) {
13762
+ setEvents((e) => [
13763
+ ...e,
13764
+ { kind: "info", key: mkKey(), text: "Could not detect GitHub repo. Run from a repo with a GitHub remote, or set githubRepo in config." }
13765
+ ]);
13766
+ return true;
13767
+ }
13768
+ (async () => {
13769
+ if (!cfg?.remoteWorkerUrl) {
13770
+ setEvents((e) => [
13771
+ ...e,
13772
+ { kind: "info", key: mkKey(), text: "Remote infrastructure not deployed yet. Setting up now (~2 min)..." }
13773
+ ]);
13774
+ try {
13775
+ for await (const step of deployForTui()) {
13776
+ setEvents((e) => [
13777
+ ...e,
13778
+ { kind: step.error ? "error" : "info", key: mkKey(), text: step.message }
13779
+ ]);
13780
+ if (step.done) break;
13781
+ }
13782
+ } catch {
13783
+ setEvents((e) => [
13784
+ ...e,
13785
+ { kind: "error", key: mkKey(), text: "Deploy failed. Fix the issue above and try /remote again." }
13786
+ ]);
13787
+ return;
13788
+ }
13789
+ const { loadConfig: reloadConfig } = await Promise.resolve().then(() => (init_config(), config_exports));
13790
+ const newCfg = await reloadConfig();
13791
+ if (newCfg) setCfg(newCfg);
13792
+ }
13793
+ const currentCfg = cfg ?? await loadConfig();
13794
+ if (!currentCfg?.remoteWorkerUrl) {
13795
+ setEvents((e) => [
13796
+ ...e,
13797
+ { kind: "error", key: mkKey(), text: "Deploy seemed to succeed but config wasn't saved. Try again." }
13798
+ ]);
13799
+ return;
13800
+ }
13801
+ if (!currentCfg.githubOAuthToken) {
13802
+ setEvents((e) => [
13803
+ ...e,
13804
+ { kind: "info", key: mkKey(), text: "GitHub not authenticated. Starting OAuth device flow..." }
13805
+ ]);
13806
+ try {
13807
+ for await (const step of authGitHubForTui()) {
13808
+ setEvents((e) => [
13809
+ ...e,
13810
+ { kind: step.error ? "error" : "info", key: mkKey(), text: step.message }
13811
+ ]);
13812
+ if (step.done) break;
13813
+ }
13814
+ } catch {
13815
+ setEvents((e) => [
13816
+ ...e,
13817
+ { kind: "error", key: mkKey(), text: "GitHub auth failed. Try `kimiflare auth github` from shell." }
13818
+ ]);
13819
+ return;
13820
+ }
13821
+ const { loadConfig: reloadConfig } = await Promise.resolve().then(() => (init_config(), config_exports));
13822
+ const newCfg = await reloadConfig();
13823
+ if (newCfg) setCfg(newCfg);
13824
+ }
13825
+ const finalCfg = await loadConfig() ?? currentCfg;
13826
+ const ttl = finalCfg.remoteTtlMinutes ?? 30;
13827
+ const budget = finalCfg.remoteMaxInputTokens ?? 5e6;
13828
+ setEvents((e) => [
13829
+ ...e,
13830
+ { kind: "info", key: mkKey(), text: `Starting remote session for ${repo.owner}/${repo.name}...` },
13831
+ { kind: "info", key: mkKey(), text: `Budget: ${formatTokens3(budget)} tokens. TTL: ${ttl} min.` }
13832
+ ]);
13833
+ try {
13834
+ const data = await startRemoteSession({
13835
+ prompt,
13836
+ repo,
13837
+ cfg: finalCfg,
13838
+ ttlMinutes: finalCfg.remoteTtlMinutes,
13839
+ tokensBudget: finalCfg.remoteMaxInputTokens
13840
+ });
13841
+ setEvents((e) => [
13842
+ ...e,
13843
+ { kind: "info", key: mkKey(), text: `Session started: ${data.sessionId}` }
13844
+ ]);
13845
+ for await (const ev of streamRemoteProgress(
13846
+ finalCfg.remoteWorkerUrl,
13847
+ data.sessionId,
13848
+ activeControllerRef.current?.signal
13849
+ )) {
13850
+ const event = ev;
13851
+ if (event.type === "text_delta") {
13852
+ setEvents((e) => [
13853
+ ...e,
13854
+ { kind: "info", key: mkKey(), text: String(event.text ?? "") }
13855
+ ]);
13856
+ } else if (event.type === "tool_call") {
13857
+ setEvents((e) => [
13858
+ ...e,
13859
+ { kind: "info", key: mkKey(), text: `\u2192 ${String(event.name ?? "")}` }
13860
+ ]);
13861
+ } else if (event.type === "done") {
13862
+ const prUrl = event.prUrl;
13863
+ const tokensUsed = event.tokensUsed;
13864
+ const tokensBudget = event.tokensBudget;
13865
+ setEvents((e) => [
13866
+ ...e,
13867
+ { kind: "info", key: mkKey(), text: prUrl ? `Done \u2014 PR: ${prUrl}` : "Done" }
13868
+ ]);
13869
+ await saveRemoteSession({
13870
+ sessionId: data.sessionId,
13871
+ prompt,
13872
+ repo: `${repo.owner}/${repo.name}`,
13873
+ workerUrl: finalCfg.remoteWorkerUrl,
13874
+ status: "done",
13875
+ prUrl,
13876
+ tokensUsed,
13877
+ tokensBudget,
13878
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
13879
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
13880
+ });
13881
+ } else if (event.type === "error") {
13882
+ const message2 = String(event.message ?? "");
13883
+ const category = event.category;
13884
+ setEvents((e) => [
13885
+ ...e,
13886
+ { kind: "error", key: mkKey(), text: `Remote error: ${message2}` }
13887
+ ]);
13888
+ await saveRemoteSession({
13889
+ sessionId: data.sessionId,
13890
+ prompt,
13891
+ repo: `${repo.owner}/${repo.name}`,
13892
+ workerUrl: finalCfg.remoteWorkerUrl,
13893
+ status: "error",
13894
+ errorCategory: category ?? "unknown",
13895
+ errorSummary: message2,
13896
+ errorMessage: message2,
13897
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
13898
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
13899
+ });
13900
+ }
13901
+ }
13902
+ } catch (err) {
13903
+ setEvents((e) => [
13904
+ ...e,
13905
+ { kind: "error", key: mkKey(), text: `Failed: ${err instanceof Error ? err.message : String(err)}` }
13906
+ ]);
13907
+ }
13908
+ })();
13909
+ return true;
13910
+ }
12777
13911
  if (c === "/help") {
12778
13912
  setShowHelpMenu(true);
12779
13913
  return true;
12780
13914
  }
12781
13915
  return false;
12782
13916
  },
12783
- [cfg, exit, usage, effort, theme, mode, openResumePicker, runCompact, runInit, initMcp, setCfg]
13917
+ [cfg, exit, usage, effort, theme, mode, openResumePicker, runCompact, runInit, initMcp, setCfg, setShowRemoteDashboard, setSelectedRemoteSession]
12784
13918
  );
12785
13919
  const handleHelpCommand = useCallback(
12786
13920
  (command) => {
@@ -12923,6 +14057,15 @@ ${lines.join("\n")}` }]);
12923
14057
  gatewayMetaRef.current = null;
12924
14058
  setGatewayMeta(null);
12925
14059
  setTurnStartedAt(Date.now());
14060
+ const classification = classifyIntent(trimmed);
14061
+ const effortForTier = {
14062
+ light: "low",
14063
+ medium: "medium",
14064
+ heavy: "high"
14065
+ };
14066
+ const turnReasoningEffort = overrideEffort ?? effortForTier[classification.tier] ?? effortRef.current;
14067
+ const effectiveCodeMode = classification.tier === "heavy";
14068
+ setCodeMode(effectiveCodeMode);
12926
14069
  const controller = new AbortController();
12927
14070
  activeControllerRef.current = controller;
12928
14071
  const sharedCallbacks = {
@@ -13036,18 +14179,20 @@ ${lines.join("\n")}` }]);
13036
14179
  executor: executorRef.current,
13037
14180
  cwd: process.cwd(),
13038
14181
  signal: controller.signal,
13039
- reasoningEffort: overrideEffort ?? effortRef.current,
14182
+ reasoningEffort: turnReasoningEffort,
13040
14183
  coauthor: cfg.coauthor !== false ? { name: cfg.coauthorName || "kimiflare", email: cfg.coauthorEmail || "kimiflare@proton.me" } : void 0,
13041
14184
  sessionId: ensureSessionId(),
13042
14185
  memoryManager: memoryManagerRef.current,
13043
14186
  keepLastImageTurns: cfg.imageHistoryTurns ?? 2,
13044
- codeMode,
14187
+ codeMode: effectiveCodeMode,
14188
+ onIterationEnd,
14189
+ intentClassification: classification,
13045
14190
  onFileChange: (path, content2) => {
13046
14191
  if (content2) {
13047
14192
  lspManagerRef.current.notifyChange(path, content2);
13048
14193
  } else {
13049
14194
  void import("fs/promises").then(
13050
- ({ readFile: readFile15 }) => readFile15(path, "utf8").then((c) => lspManagerRef.current.notifyChange(path, c)).catch(() => {
14195
+ ({ readFile: readFile16 }) => readFile16(path, "utf8").then((c) => lspManagerRef.current.notifyChange(path, c)).catch(() => {
13051
14196
  })
13052
14197
  );
13053
14198
  }
@@ -13169,6 +14314,7 @@ ${lines.join("\n")}` }]);
13169
14314
  }
13170
14315
  }
13171
14316
  } finally {
14317
+ setCodeMode(false);
13172
14318
  const asstId = activeAsstIdRef.current;
13173
14319
  if (asstId !== null) updateAssistant(asstId, () => ({ streaming: false }));
13174
14320
  setBusy(false);
@@ -13181,7 +14327,7 @@ ${lines.join("\n")}` }]);
13181
14327
  },
13182
14328
  [cfg, handleSlash, updateAssistant, updateTool, saveSessionSafe, updateGatewayMeta]
13183
14329
  );
13184
- useEffect4(() => {
14330
+ useEffect5(() => {
13185
14331
  if (!busy && queue.length > 0) {
13186
14332
  const next = queue[0];
13187
14333
  setQueue((q) => q.slice(1));
@@ -13209,7 +14355,7 @@ ${lines.join("\n")}` }]);
13209
14355
  [busy, processMessage]
13210
14356
  );
13211
14357
  submitRef.current = submit;
13212
- useEffect4(() => {
14358
+ useEffect5(() => {
13213
14359
  if (compactSuggestedRef.current) return;
13214
14360
  if (usage && usage.prompt_tokens / CONTEXT_LIMIT >= AUTO_COMPACT_SUGGEST_PCT) {
13215
14361
  compactSuggestedRef.current = true;
@@ -13224,7 +14370,7 @@ ${lines.join("\n")}` }]);
13224
14370
  }
13225
14371
  }, [usage]);
13226
14372
  if (!cfg) {
13227
- return /* @__PURE__ */ jsx21(ThemeProvider, { theme, children: /* @__PURE__ */ jsx21(
14373
+ return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(
13228
14374
  Onboarding,
13229
14375
  {
13230
14376
  onDone: (newCfg) => {
@@ -13238,10 +14384,42 @@ ${lines.join("\n")}` }]);
13238
14384
  ) });
13239
14385
  }
13240
14386
  if (resumeSessions !== null) {
13241
- return /* @__PURE__ */ jsx21(ThemeProvider, { theme, children: /* @__PURE__ */ jsx21(Box19, { flexDirection: "column", children: /* @__PURE__ */ jsx21(ResumePicker, { sessions: resumeSessions, onPick: handleResumePick }) }) });
14387
+ return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx22(ResumePicker, { sessions: resumeSessions, onPick: handleResumePick }) }) });
14388
+ }
14389
+ if (showRemoteDashboard) {
14390
+ return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: selectedRemoteSession ? /* @__PURE__ */ jsx22(
14391
+ RemoteSessionDetail,
14392
+ {
14393
+ session: selectedRemoteSession,
14394
+ onBack: () => setSelectedRemoteSession(null),
14395
+ onCancel: async (session) => {
14396
+ try {
14397
+ const { cancelRemoteSession: cancelRemoteSession2 } = await Promise.resolve().then(() => (init_worker_client(), worker_client_exports));
14398
+ await cancelRemoteSession2(session.workerUrl, session.sessionId);
14399
+ setEvents((e) => [
14400
+ ...e,
14401
+ { kind: "info", key: mkKey(), text: `Cancelled session ${session.sessionId}` }
14402
+ ]);
14403
+ } catch (err) {
14404
+ setEvents((e) => [
14405
+ ...e,
14406
+ { kind: "error", key: mkKey(), text: `Failed to cancel: ${err instanceof Error ? err.message : String(err)}` }
14407
+ ]);
14408
+ }
14409
+ setSelectedRemoteSession(null);
14410
+ setShowRemoteDashboard(false);
14411
+ }
14412
+ }
14413
+ ) : /* @__PURE__ */ jsx22(
14414
+ RemoteDashboard,
14415
+ {
14416
+ onSelect: (session) => setSelectedRemoteSession(session),
14417
+ onCancel: () => setShowRemoteDashboard(false)
14418
+ }
14419
+ ) }) });
13242
14420
  }
13243
14421
  if (showHelpMenu) {
13244
- return /* @__PURE__ */ jsx21(ThemeProvider, { theme, children: /* @__PURE__ */ jsx21(Box19, { flexDirection: "column", children: /* @__PURE__ */ jsx21(
14422
+ return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx22(
13245
14423
  HelpMenu,
13246
14424
  {
13247
14425
  customCommands: customCommandsRef.current.filter((c) => !BUILTIN_COMMAND_NAMES.has(c.name.toLowerCase())).map((c) => ({ name: c.name, description: c.description })),
@@ -13252,12 +14430,12 @@ ${lines.join("\n")}` }]);
13252
14430
  ) }) });
13253
14431
  }
13254
14432
  if (showLspWizard) {
13255
- return /* @__PURE__ */ jsx21(ThemeProvider, { theme, children: /* @__PURE__ */ jsx21(Box19, { flexDirection: "column", children: /* @__PURE__ */ jsx21(
14433
+ return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx22(
13256
14434
  LspWizard,
13257
14435
  {
13258
14436
  servers: cfg?.lspServers ?? {},
13259
14437
  currentScope: lspScope,
13260
- hasProjectDir: existsSync2(join17(process.cwd(), ".kimiflare")),
14438
+ hasProjectDir: existsSync2(join19(process.cwd(), ".kimiflare")),
13261
14439
  onDone: () => setShowLspWizard(false),
13262
14440
  onSave: (servers, enabled, scope) => {
13263
14441
  setCfg((c) => c ? { ...c, lspEnabled: enabled, lspServers: servers } : c);
@@ -13289,7 +14467,7 @@ ${lines.join("\n")}` }]);
13289
14467
  ) }) });
13290
14468
  }
13291
14469
  if (commandWizard) {
13292
- return /* @__PURE__ */ jsx21(ThemeProvider, { theme, children: /* @__PURE__ */ jsx21(Box19, { flexDirection: "column", children: /* @__PURE__ */ jsx21(
14470
+ return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx22(
13293
14471
  CommandWizard,
13294
14472
  {
13295
14473
  mode: commandWizard.mode,
@@ -13302,7 +14480,7 @@ ${lines.join("\n")}` }]);
13302
14480
  ) }) });
13303
14481
  }
13304
14482
  if (commandPicker) {
13305
- return /* @__PURE__ */ jsx21(ThemeProvider, { theme, children: /* @__PURE__ */ jsx21(Box19, { flexDirection: "column", children: /* @__PURE__ */ jsx21(
14483
+ return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx22(
13306
14484
  CommandPicker,
13307
14485
  {
13308
14486
  commands: customCommandsRef.current,
@@ -13320,15 +14498,15 @@ ${lines.join("\n")}` }]);
13320
14498
  ) }) });
13321
14499
  }
13322
14500
  if (commandToDelete) {
13323
- return /* @__PURE__ */ jsx21(ThemeProvider, { theme, children: /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
13324
- /* @__PURE__ */ jsxs19(Text20, { color: theme.accent, bold: true, children: [
14501
+ return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
14502
+ /* @__PURE__ */ jsxs20(Text21, { color: theme.accent, bold: true, children: [
13325
14503
  "Delete /",
13326
14504
  commandToDelete.name,
13327
14505
  "?"
13328
14506
  ] }),
13329
- /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, children: commandToDelete.filepath }),
13330
- /* @__PURE__ */ jsx21(Box19, { marginTop: 1, children: /* @__PURE__ */ jsx21(
13331
- SelectInput8,
14507
+ /* @__PURE__ */ jsx22(Text21, { color: theme.info.color, children: commandToDelete.filepath }),
14508
+ /* @__PURE__ */ jsx22(Box20, { marginTop: 1, children: /* @__PURE__ */ jsx22(
14509
+ SelectInput9,
13332
14510
  {
13333
14511
  items: [
13334
14512
  { label: "Yes, delete", value: "yes", key: "yes" },
@@ -13346,7 +14524,7 @@ ${lines.join("\n")}` }]);
13346
14524
  ] }) });
13347
14525
  }
13348
14526
  if (showCommandList) {
13349
- return /* @__PURE__ */ jsx21(ThemeProvider, { theme, children: /* @__PURE__ */ jsx21(Box19, { flexDirection: "column", children: /* @__PURE__ */ jsx21(
14527
+ return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx22(
13350
14528
  CommandList,
13351
14529
  {
13352
14530
  commands: customCommandsRef.current,
@@ -13355,12 +14533,12 @@ ${lines.join("\n")}` }]);
13355
14533
  ) }) });
13356
14534
  }
13357
14535
  if (showThemePicker) {
13358
- return /* @__PURE__ */ jsx21(ThemeProvider, { theme, children: /* @__PURE__ */ jsx21(Box19, { flexDirection: "column", children: /* @__PURE__ */ jsx21(ThemePicker, { themes: themeList(), onPick: handleThemePick, onPreview: (t) => setTheme(t) }) }) });
14536
+ return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx22(ThemePicker, { themes: themeList(), onPick: handleThemePick, onPreview: (t) => setTheme(t) }) }) });
13359
14537
  }
13360
14538
  const hasConversation = events.some((e) => e.kind === "user" || e.kind === "assistant");
13361
- return /* @__PURE__ */ jsx21(ThemeProvider, { theme, children: /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", children: [
13362
- !hasConversation && events.length === 0 ? /* @__PURE__ */ jsx21(Welcome, { accountId: cfg.accountId }) : /* @__PURE__ */ jsx21(ChatView, { events, showReasoning, verbose }),
13363
- perm ? /* @__PURE__ */ jsx21(
14539
+ return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", children: [
14540
+ !hasConversation && events.length === 0 ? /* @__PURE__ */ jsx22(Welcome, { accountId: cfg.accountId }) : /* @__PURE__ */ jsx22(ChatView, { events, showReasoning, verbose }),
14541
+ perm ? /* @__PURE__ */ jsx22(
13364
14542
  PermissionModal,
13365
14543
  {
13366
14544
  tool: perm.tool,
@@ -13371,8 +14549,8 @@ ${lines.join("\n")}` }]);
13371
14549
  setPerm(null);
13372
14550
  }
13373
14551
  }
13374
- ) : /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", marginTop: 1, children: [
13375
- tasks.length > 0 && /* @__PURE__ */ jsx21(
14552
+ ) : /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", marginTop: 1, children: [
14553
+ tasks.length > 0 && /* @__PURE__ */ jsx22(
13376
14554
  TaskList,
13377
14555
  {
13378
14556
  tasks,
@@ -13380,11 +14558,11 @@ ${lines.join("\n")}` }]);
13380
14558
  tokensDelta: Math.max(0, (usage?.prompt_tokens ?? 0) - tasksStartTokens)
13381
14559
  }
13382
14560
  ),
13383
- queue.length > 0 && /* @__PURE__ */ jsx21(Box19, { flexDirection: "column", marginBottom: 1, children: queue.map((q, i) => /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
14561
+ queue.length > 0 && /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", marginBottom: 1, children: queue.map((q, i) => /* @__PURE__ */ jsxs20(Text21, { color: theme.info.color, children: [
13384
14562
  "\u23F3 ",
13385
14563
  q.display
13386
14564
  ] }, `queue_${i}`)) }),
13387
- /* @__PURE__ */ jsx21(
14565
+ /* @__PURE__ */ jsx22(
13388
14566
  StatusBar,
13389
14567
  {
13390
14568
  model: cfg.model,
@@ -13401,7 +14579,7 @@ ${lines.join("\n")}` }]);
13401
14579
  codeMode
13402
14580
  }
13403
14581
  ),
13404
- activePicker?.kind === "file" && /* @__PURE__ */ jsx21(
14582
+ activePicker?.kind === "file" && /* @__PURE__ */ jsx22(
13405
14583
  FilePicker,
13406
14584
  {
13407
14585
  items: filteredFileItems,
@@ -13409,7 +14587,7 @@ ${lines.join("\n")}` }]);
13409
14587
  query: pickerQuery ?? ""
13410
14588
  }
13411
14589
  ),
13412
- activePicker?.kind === "slash" && /* @__PURE__ */ jsx21(
14590
+ activePicker?.kind === "slash" && /* @__PURE__ */ jsx22(
13413
14591
  SlashPicker,
13414
14592
  {
13415
14593
  items: filteredSlashItems,
@@ -13417,9 +14595,9 @@ ${lines.join("\n")}` }]);
13417
14595
  query: pickerQuery ?? ""
13418
14596
  }
13419
14597
  ),
13420
- /* @__PURE__ */ jsxs19(Box19, { marginTop: 1, children: [
13421
- /* @__PURE__ */ jsx21(Text20, { color: "#d699b6", children: "\u203A " }),
13422
- /* @__PURE__ */ jsx21(
14598
+ /* @__PURE__ */ jsxs20(Box20, { marginTop: 1, children: [
14599
+ /* @__PURE__ */ jsx22(Text21, { color: "#d699b6", children: "\u203A " }),
14600
+ /* @__PURE__ */ jsx22(
13423
14601
  CustomTextInput,
13424
14602
  {
13425
14603
  value: input,
@@ -13476,7 +14654,7 @@ ${lines.join("\n")}` }]);
13476
14654
  }
13477
14655
  async function renderApp(cfg, updateResult, lspScope = "global", lspProjectPath = null) {
13478
14656
  const instance = render(
13479
- /* @__PURE__ */ jsx21(
14657
+ /* @__PURE__ */ jsx22(
13480
14658
  App,
13481
14659
  {
13482
14660
  initialCfg: cfg,
@@ -13517,7 +14695,13 @@ var init_app = __esm({
13517
14695
  init_welcome();
13518
14696
  init_help_menu();
13519
14697
  init_config();
14698
+ init_worker_client();
14699
+ init_session_store();
14700
+ init_tui_deploy();
14701
+ init_tui_auth();
14702
+ init_remote_dashboard();
13520
14703
  init_mode();
14704
+ init_classify();
13521
14705
  init_sessions();
13522
14706
  init_image();
13523
14707
  init_usage_tracker();
@@ -13566,8 +14750,107 @@ init_system_prompt();
13566
14750
  init_executor();
13567
14751
  init_update_check();
13568
14752
  init_version();
14753
+ import { Command as Command2 } from "commander";
14754
+
14755
+ // src/remote/cli.ts
14756
+ init_config();
14757
+ init_session_store();
14758
+ init_deploy();
13569
14759
  import { Command } from "commander";
13570
- var program = new Command();
14760
+ function createRemoteCommand() {
14761
+ const remote = new Command("remote").description("Manage remote sessions");
14762
+ remote.command("deploy").description("Deploy the remote Worker and container image to Cloudflare").action(async () => {
14763
+ await runDeploy();
14764
+ });
14765
+ remote.command("setup").description("Check remote deployment status and prerequisites").action(async () => {
14766
+ const status = await checkDeployStatus();
14767
+ console.log("Remote deployment status:\n");
14768
+ console.log(` wrangler CLI: ${status.wrangler ? "yes" : "no"}`);
14769
+ console.log(` wrangler auth: ${status.wranglerAuth ? "yes" : "no"}`);
14770
+ console.log(` Docker: ${status.docker ? "yes" : "no"}`);
14771
+ console.log(` Worker URL: ${status.workerUrl ?? "not deployed"}`);
14772
+ console.log("\nRun `kimiflare remote deploy` to deploy.");
14773
+ });
14774
+ remote.command("list").description("List remote sessions").action(async () => {
14775
+ const sessions = await listRemoteSessions();
14776
+ if (sessions.length === 0) {
14777
+ console.log("No remote sessions found.");
14778
+ return;
14779
+ }
14780
+ console.log(`Remote sessions (${sessions.length} total):
14781
+ `);
14782
+ for (const s of sessions.slice(0, 20)) {
14783
+ const date = new Date(s.createdAt).toLocaleString();
14784
+ const statusIcon = s.status === "done" ? "\u2705" : s.status === "error" ? "\u274C" : s.status === "running" ? "\u23F3" : "\u23F9\uFE0F";
14785
+ console.log(` ${statusIcon} ${s.sessionId.slice(0, 8)}\u2026 ${s.status.padEnd(10)} ${date} ${s.prompt.slice(0, 50)}`);
14786
+ if (s.prUrl) {
14787
+ console.log(` PR: ${s.prUrl}`);
14788
+ }
14789
+ }
14790
+ });
14791
+ remote.command("status").description("Show remote session status").argument("[session-id]", "Session ID (defaults to most recent)").action(async (sessionId) => {
14792
+ const session = sessionId ? await loadRemoteSession(sessionId) : await getMostRecentRemoteSession();
14793
+ if (!session) {
14794
+ console.log(sessionId ? `Session ${sessionId} not found.` : "No remote sessions found.");
14795
+ return;
14796
+ }
14797
+ const cfg = await loadConfig();
14798
+ const workerUrl = cfg?.remoteWorkerUrl;
14799
+ if (!workerUrl) {
14800
+ console.log("Remote worker not configured.");
14801
+ return;
14802
+ }
14803
+ try {
14804
+ const res = await fetch(`${workerUrl}/remote/status/${session.sessionId}`, {
14805
+ headers: {
14806
+ Authorization: `Bearer ${cfg.remoteAuthSecret ?? ""}`
14807
+ }
14808
+ });
14809
+ if (!res.ok) {
14810
+ console.log(`Failed to fetch status: ${res.status}`);
14811
+ return;
14812
+ }
14813
+ const data = await res.json();
14814
+ console.log(`Session: ${data.sessionId}`);
14815
+ console.log(`Status: ${data.status}`);
14816
+ console.log(`Prompt: ${data.prompt}`);
14817
+ console.log(`Repo: ${data.repo?.owner}/${data.repo?.name}`);
14818
+ console.log(`Branch: ${data.branch}`);
14819
+ console.log(`Turns: ${data.currentTurn} / ${data.maxTurns}`);
14820
+ if (data.prUrl) console.log(`PR: ${data.prUrl}`);
14821
+ if (data.errorMessage) console.log(`Error: ${data.errorMessage}`);
14822
+ } catch (err) {
14823
+ console.log(`Error: ${err instanceof Error ? err.message : String(err)}`);
14824
+ }
14825
+ });
14826
+ remote.command("cancel").description("Cancel a remote session").argument("<session-id>", "Session ID").action(async (sessionId) => {
14827
+ const cfg = await loadConfig();
14828
+ const workerUrl = cfg?.remoteWorkerUrl;
14829
+ if (!workerUrl) {
14830
+ console.log("Remote worker not configured.");
14831
+ return;
14832
+ }
14833
+ try {
14834
+ const res = await fetch(`${workerUrl}/remote/cancel/${sessionId}`, {
14835
+ method: "POST",
14836
+ headers: {
14837
+ Authorization: `Bearer ${cfg.remoteAuthSecret ?? ""}`
14838
+ }
14839
+ });
14840
+ if (!res.ok) {
14841
+ console.log(`Failed to cancel: ${res.status}`);
14842
+ return;
14843
+ }
14844
+ console.log(`Session ${sessionId} cancelled.`);
14845
+ } catch (err) {
14846
+ console.log(`Error: ${err instanceof Error ? err.message : String(err)}`);
14847
+ }
14848
+ });
14849
+ return remote;
14850
+ }
14851
+
14852
+ // src/index.tsx
14853
+ var program = new Command2();
13571
14854
  program.name("kimiflare").description("Terminal coding agent powered by Kimi-K2.6 on Cloudflare Workers AI.").version(getAppVersion()).option("-p, --print <prompt>", "one-shot mode: send prompt, stream reply to stdout, exit").option("-m, --model <id>", "model id (defaults to @cf/moonshotai/kimi-k2.6)").option("--dangerously-allow-all", "auto-approve every permission prompt (print mode only)").option("--reasoning", "include reasoning in stdout (print mode only)").option("--continue-on-limit", "reset tool-call counter and continue when the 50-call limit is hit (print mode only)").option("--max-input-tokens <n>", "cumulative prompt token budget; exits 42 when exhausted (print mode only)", (v) => parseInt(v, 10));
13572
14855
  program.command("cost").description("Show cost attribution by task type (requires costAttribution enabled)").option("-w, --week", "last 7 days (default)").option("-m, --month", "last 30 days").option("-d, --day", "today only").option("-s, --session <id>", "single session detail").option("-c, --category <name>", "filter by category").option("--json", "machine-readable output").option("--reclassify", "re-run classification on all sessions").option("--local-only", "skip Cloudflare reconciliation").action(async (cmdOpts) => {
13573
14856
  const cfg = await loadConfig();
@@ -13581,6 +14864,23 @@ program.command("cost").description("Show cost attribution by task type (require
13581
14864
  const { runCostCommand: runCostCommand2 } = await Promise.resolve().then(() => (init_cli(), cli_exports));
13582
14865
  await runCostCommand2({ ...cmdOpts, config: cfg });
13583
14866
  });
14867
+ program.addCommand(createRemoteCommand());
14868
+ program.command("auth").description("Authenticate with external services").addCommand(
14869
+ new Command2("github").description("Authenticate with GitHub via OAuth device flow").action(async () => {
14870
+ const { authGitHubForTui: authGitHubForTui2 } = await Promise.resolve().then(() => (init_tui_auth(), tui_auth_exports));
14871
+ for await (const step of authGitHubForTui2()) {
14872
+ console.log(step.message);
14873
+ if (step.url && step.code) {
14874
+ console.log(`
14875
+ Open: ${step.url}`);
14876
+ console.log(`Code: ${step.code}
14877
+ `);
14878
+ }
14879
+ if (step.done) break;
14880
+ if (step.error) process.exit(1);
14881
+ }
14882
+ })
14883
+ );
13584
14884
  program.action(async () => {
13585
14885
  await main();
13586
14886
  });