kimiflare 0.45.0 → 0.46.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -346,6 +346,38 @@ var init_lsp_config = __esm({
346
346
  }
347
347
  });
348
348
 
349
+ // src/util/logger.ts
350
+ function log(level, event, data) {
351
+ if (LEVEL_ORDER[level] < LEVEL_ORDER[globalMinLevel]) return;
352
+ const entry = {
353
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
354
+ level,
355
+ event,
356
+ data
357
+ };
358
+ console.error(JSON.stringify(entry));
359
+ }
360
+ var globalMinLevel, LEVEL_ORDER, logger;
361
+ var init_logger = __esm({
362
+ "src/util/logger.ts"() {
363
+ "use strict";
364
+ globalMinLevel = process.env.KIMIFLARE_LOG_LEVEL ?? "off";
365
+ LEVEL_ORDER = {
366
+ debug: 0,
367
+ info: 1,
368
+ warn: 2,
369
+ error: 3,
370
+ off: 4
371
+ };
372
+ logger = {
373
+ debug: (event, data) => log("debug", event, data),
374
+ info: (event, data) => log("info", event, data),
375
+ warn: (event, data) => log("warn", event, data),
376
+ error: (event, data) => log("error", event, data)
377
+ };
378
+ }
379
+ });
380
+
349
381
  // src/util/sse.ts
350
382
  async function* readSSE(stream, signal, idleTimeoutMs) {
351
383
  const reader = stream.getReader();
@@ -357,16 +389,30 @@ async function* readSSE(stream, signal, idleTimeoutMs) {
357
389
  });
358
390
  };
359
391
  signal?.addEventListener("abort", onAbort, { once: true });
392
+ const abortRace = (promise) => {
393
+ if (!signal) return promise;
394
+ return Promise.race([
395
+ promise,
396
+ new Promise((_, reject) => {
397
+ if (signal.aborted) {
398
+ reject(new DOMException("aborted", "AbortError"));
399
+ return;
400
+ }
401
+ signal.addEventListener("abort", () => reject(new DOMException("aborted", "AbortError")), { once: true });
402
+ })
403
+ ]);
404
+ };
360
405
  try {
361
406
  while (true) {
362
407
  if (signal?.aborted) throw new DOMException("aborted", "AbortError");
363
408
  if (idleTimeoutMs !== void 0 && Date.now() - lastDataAt > idleTimeoutMs) {
409
+ logger.warn("sse:idle_timeout", { idleTimeoutMs });
364
410
  throw new DOMException(
365
411
  `kimiflare: stream idle for ${idleTimeoutMs}ms \u2014 no data received from API`,
366
412
  "TimeoutError"
367
413
  );
368
414
  }
369
- const { done, value } = await reader.read();
415
+ const { done, value } = await abortRace(reader.read());
370
416
  if (done) break;
371
417
  lastDataAt = Date.now();
372
418
  buffer += decoder.decode(value, { stream: true });
@@ -399,10 +445,14 @@ function extractData(event) {
399
445
  var init_sse = __esm({
400
446
  "src/util/sse.ts"() {
401
447
  "use strict";
448
+ init_logger();
402
449
  }
403
450
  });
404
451
 
405
452
  // src/util/errors.ts
453
+ function isCloudQuotaExhaustedError(err) {
454
+ return err instanceof KimiApiError && err.httpStatus === 429 && /token quota exhausted/i.test(err.message);
455
+ }
406
456
  var KimiApiError;
407
457
  var init_errors = __esm({
408
458
  "src/util/errors.ts"() {
@@ -531,6 +581,7 @@ async function* runKimi(opts2) {
531
581
  if (opts2.reasoningEffort) {
532
582
  body.reasoning_effort = opts2.reasoningEffort;
533
583
  }
584
+ logger.debug("runKimi:request", { requestId, attempt: 0, model: opts2.model });
534
585
  for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {
535
586
  let res;
536
587
  try {
@@ -553,6 +604,7 @@ async function* runKimi(opts2) {
553
604
  });
554
605
  } catch (fetchErr) {
555
606
  const msg = fetchErr instanceof Error ? fetchErr.message : String(fetchErr);
607
+ logger.warn("runKimi:fetch_error", { requestId, attempt, error: msg });
556
608
  if (attempt < MAX_ATTEMPTS - 1) {
557
609
  const delay = 500 * 2 ** attempt + Math.random() * 250;
558
610
  await sleep(delay, opts2.signal);
@@ -583,10 +635,12 @@ async function* runKimi(opts2) {
583
635
  const meta = readGatewayMeta(res.headers);
584
636
  if (meta) yield { type: "gateway_meta", meta };
585
637
  let lastUsage = null;
638
+ logger.debug("runKimi:stream_start", { requestId });
586
639
  for await (const ev of parseStream(res.body, opts2.signal, opts2.idleTimeoutMs)) {
587
640
  if (ev.type === "usage") lastUsage = ev.usage;
588
641
  yield ev;
589
642
  }
643
+ logger.debug("runKimi:stream_end", { requestId });
590
644
  if (opts2.cloudMode && lastUsage && opts2.cloudToken) {
591
645
  const reportUrl = "https://api.kimiflare.com/v1/usage/report";
592
646
  const reportHeaders = {
@@ -808,6 +862,7 @@ var init_client = __esm({
808
862
  init_errors();
809
863
  init_version();
810
864
  init_messages();
865
+ init_logger();
811
866
  RETRYABLE_CODES = /* @__PURE__ */ new Set([3040]);
812
867
  MAX_ATTEMPTS = 5;
813
868
  DEFAULT_IDLE_TIMEOUT_MS = 6e4;
@@ -1879,6 +1934,7 @@ function isHighSignalMemory(memory) {
1879
1934
  }
1880
1935
  async function runAgentTurn(opts2) {
1881
1936
  const turnStart = performance.now();
1937
+ logger.info("turn:start", { sessionId: opts2.sessionId, codeMode: opts2.codeMode ?? false });
1882
1938
  const max = opts2.maxToolIterations ?? 50;
1883
1939
  const codeMode = opts2.codeMode ?? false;
1884
1940
  let toolDefs;
@@ -2009,6 +2065,7 @@ Use console.log() to return results. Only console.log output will be sent back t
2009
2065
  if (opts2.keepLastImageTurns !== void 0) {
2010
2066
  apiMessages = stripOldImages(apiMessages, opts2.keepLastImageTurns);
2011
2067
  }
2068
+ logger.debug("turn:api_request", { sessionId: opts2.sessionId, messageCount: apiMessages.length });
2012
2069
  const events = runKimi({
2013
2070
  accountId: opts2.accountId,
2014
2071
  apiToken: opts2.apiToken,
@@ -2023,9 +2080,15 @@ Use console.log() to return results. Only console.log output will be sent back t
2023
2080
  gateway: opts2.gateway,
2024
2081
  cloudMode: opts2.cloudMode,
2025
2082
  cloudToken: opts2.cloudToken,
2026
- cloudDeviceId: opts2.cloudDeviceId
2083
+ cloudDeviceId: opts2.cloudDeviceId,
2084
+ idleTimeoutMs: 6e4
2027
2085
  });
2086
+ let gotFirstChunk = false;
2028
2087
  for await (const ev of events) {
2088
+ if (!gotFirstChunk) {
2089
+ gotFirstChunk = true;
2090
+ logger.debug("turn:api_first_chunk", { sessionId: opts2.sessionId });
2091
+ }
2029
2092
  switch (ev.type) {
2030
2093
  case "gateway_meta":
2031
2094
  gatewayMeta = ev.meta;
@@ -2103,6 +2166,7 @@ Use console.log() to return results. Only console.log output will be sent back t
2103
2166
  if (budgetExhausted) {
2104
2167
  throw new BudgetExhaustedError();
2105
2168
  }
2169
+ logger.info("turn:complete", { sessionId: opts2.sessionId, durationMs: Math.round(performance.now() - turnStart) });
2106
2170
  return;
2107
2171
  }
2108
2172
  for (const tc of toolCalls) {
@@ -2226,12 +2290,14 @@ ${sandboxResult.output}` : `${warningPrefix}${sandboxResult.output}`;
2226
2290
  recentToolCalls.push(loopSignature);
2227
2291
  if (recentToolCalls.length > LOOP_WINDOW) recentToolCalls.shift();
2228
2292
  } else {
2293
+ logger.debug("turn:tool_start", { sessionId: opts2.sessionId, tool: tc.function.name, toolCallId: tc.id });
2229
2294
  const result = await opts2.executor.run(
2230
2295
  { id: tc.id, name: tc.function.name, arguments: tc.function.arguments },
2231
2296
  opts2.callbacks.askPermission,
2232
2297
  { cwd: opts2.cwd, signal: opts2.signal, onTasks: opts2.callbacks.onTasks, coauthor: opts2.coauthor, memoryManager: opts2.memoryManager, sessionId: opts2.sessionId, githubToken: opts2.githubToken },
2233
2298
  opts2.onFileChange
2234
2299
  );
2300
+ logger.debug("turn:tool_end", { sessionId: opts2.sessionId, tool: tc.function.name, toolCallId: tc.id, ok: result.ok });
2235
2301
  toolResults.push(result);
2236
2302
  opts2.messages.push({
2237
2303
  role: "tool",
@@ -2346,6 +2412,7 @@ var init_loop = __esm({
2346
2412
  init_extractors();
2347
2413
  init_strip_reasoning();
2348
2414
  init_code_mode();
2415
+ init_logger();
2349
2416
  BudgetExhaustedError = class extends Error {
2350
2417
  constructor(message2 = "Cumulative input token budget exhausted") {
2351
2418
  super(message2);
@@ -2883,9 +2950,9 @@ function runBash(args, ctx) {
2883
2950
  const timeout = Math.min(Math.max(1e3, args.timeout_ms ?? DEFAULT_TIMEOUT), MAX_TIMEOUT);
2884
2951
  const command = injectCoauthor(args.command, ctx.coauthor);
2885
2952
  return new Promise((resolve2, reject) => {
2953
+ logger.debug("bash:spawn", { command: args.command.slice(0, 200), cwd: ctx.cwd });
2886
2954
  const child = spawn("bash", ["-lc", command], {
2887
2955
  cwd: ctx.cwd,
2888
- signal: ctx.signal,
2889
2956
  env: {
2890
2957
  ...process.env,
2891
2958
  GIT_EDITOR: "true"
@@ -2894,10 +2961,18 @@ function runBash(args, ctx) {
2894
2961
  let stdout = "";
2895
2962
  let stderr = "";
2896
2963
  let killedByTimeout = false;
2964
+ let killedByAbort = false;
2897
2965
  const timer = setTimeout(() => {
2898
2966
  killedByTimeout = true;
2967
+ logger.warn("bash:kill_timeout", { command: args.command.slice(0, 200) });
2899
2968
  child.kill("SIGKILL");
2900
2969
  }, timeout);
2970
+ const onAbort = () => {
2971
+ killedByAbort = true;
2972
+ logger.warn("bash:kill_abort", { command: args.command.slice(0, 200) });
2973
+ child.kill("SIGKILL");
2974
+ };
2975
+ ctx.signal?.addEventListener("abort", onAbort, { once: true });
2901
2976
  child.stdout.on("data", (d) => {
2902
2977
  stdout += d.toString("utf8");
2903
2978
  });
@@ -2906,11 +2981,15 @@ function runBash(args, ctx) {
2906
2981
  });
2907
2982
  child.on("error", (e) => {
2908
2983
  clearTimeout(timer);
2984
+ ctx.signal?.removeEventListener("abort", onAbort);
2985
+ logger.error("bash:error", { error: e.message });
2909
2986
  reject(e);
2910
2987
  });
2911
2988
  child.on("close", (code, signal) => {
2912
2989
  clearTimeout(timer);
2913
- const header = killedByTimeout ? `(timed out after ${timeout}ms)` : `exit=${code ?? "?"}${signal ? ` signal=${signal}` : ""}`;
2990
+ ctx.signal?.removeEventListener("abort", onAbort);
2991
+ logger.debug("bash:close", { code, signal, killedByTimeout, killedByAbort });
2992
+ const header = killedByTimeout ? `(timed out after ${timeout}ms)` : killedByAbort ? `(aborted \u2014 sent SIGKILL)` : `exit=${code ?? "?"}${signal ? ` signal=${signal}` : ""}`;
2914
2993
  const parts = [header];
2915
2994
  if (stdout) parts.push(`--- stdout ---
2916
2995
  ${stdout.trimEnd()}`);
@@ -2930,6 +3009,7 @@ var DEFAULT_TIMEOUT, MAX_TIMEOUT, bashTool;
2930
3009
  var init_bash = __esm({
2931
3010
  "src/tools/bash.ts"() {
2932
3011
  "use strict";
3012
+ init_logger();
2933
3013
  DEFAULT_TIMEOUT = 12e4;
2934
3014
  MAX_TIMEOUT = 6e5;
2935
3015
  bashTool = {
@@ -5333,7 +5413,7 @@ function filterSessions(sessions, start, end) {
5333
5413
  return sessions.filter((s) => s.date >= start && s.date <= end);
5334
5414
  }
5335
5415
  async function runCostCommand(opts2) {
5336
- const log = await loadLog();
5416
+ const log2 = await loadLog();
5337
5417
  let startDate;
5338
5418
  let endDate;
5339
5419
  let prevStart;
@@ -5355,7 +5435,7 @@ async function runCostCommand(opts2) {
5355
5435
  prevEnd = daysAgo(8);
5356
5436
  }
5357
5437
  if (opts2.session) {
5358
- const session = log.sessions.find((s) => s.id === opts2.session);
5438
+ const session = log2.sessions.find((s) => s.id === opts2.session);
5359
5439
  if (!session) {
5360
5440
  console.error(`Session ${opts2.session} not found.`);
5361
5441
  process.exit(1);
@@ -5363,8 +5443,8 @@ async function runCostCommand(opts2) {
5363
5443
  console.log(JSON.stringify(session, null, 2));
5364
5444
  return;
5365
5445
  }
5366
- const sessions = filterSessions(log.sessions, startDate, endDate);
5367
- const prevSessions = filterSessions(log.sessions, prevStart, prevEnd);
5446
+ const sessions = filterSessions(log2.sessions, startDate, endDate);
5447
+ const prevSessions = filterSessions(log2.sessions, prevStart, prevEnd);
5368
5448
  for (const s of sessions) {
5369
5449
  if (!s.category || opts2.reclassify) {
5370
5450
  const result = await classifyFromSessionFile(s.id);
@@ -5631,6 +5711,69 @@ var init_tui_auth = __esm({
5631
5711
  }
5632
5712
  });
5633
5713
 
5714
+ // src/agent/supervisor.ts
5715
+ var TurnSupervisor;
5716
+ var init_supervisor = __esm({
5717
+ "src/agent/supervisor.ts"() {
5718
+ "use strict";
5719
+ init_loop();
5720
+ init_logger();
5721
+ TurnSupervisor = class {
5722
+ currentTurn = null;
5723
+ _phase = "idle";
5724
+ _killRequested = false;
5725
+ get phase() {
5726
+ return this._phase;
5727
+ }
5728
+ get isRunning() {
5729
+ return this._phase !== "idle";
5730
+ }
5731
+ get killRequested() {
5732
+ return this._killRequested;
5733
+ }
5734
+ startTurn(opts2, callbacks) {
5735
+ if (this.isRunning) {
5736
+ logger.warn("supervisor:start_rejected", { reason: "turn_already_running", phase: this._phase });
5737
+ throw new Error("TurnSupervisor: turn already in progress");
5738
+ }
5739
+ this._phase = "streaming";
5740
+ this._killRequested = false;
5741
+ logger.debug("supervisor:turn_start", { sessionId: opts2.sessionId });
5742
+ this.currentTurn = runAgentTurn(opts2).then(async () => {
5743
+ this._phase = "idle";
5744
+ if (this._killRequested) {
5745
+ logger.debug("supervisor:turn_killed", { sessionId: opts2.sessionId });
5746
+ } else {
5747
+ logger.debug("supervisor:turn_done", { sessionId: opts2.sessionId });
5748
+ }
5749
+ await callbacks?.onDone?.();
5750
+ }).catch(async (error) => {
5751
+ this._phase = "idle";
5752
+ const err = error;
5753
+ logger.warn("supervisor:turn_error", {
5754
+ sessionId: opts2.sessionId,
5755
+ error: err.message ?? String(err),
5756
+ name: err.name
5757
+ });
5758
+ await callbacks?.onError?.(err);
5759
+ }).finally(() => {
5760
+ this.currentTurn = null;
5761
+ this._killRequested = false;
5762
+ });
5763
+ }
5764
+ /** Request that the current turn be killed. This does NOT directly abort
5765
+ * the turn — the caller must abort the AbortScope that was passed to
5766
+ * `startTurn`. This method only records the intent so the supervisor
5767
+ * knows the turn was intentionally killed rather than failing. */
5768
+ killTurn() {
5769
+ if (!this.isRunning) return;
5770
+ this._killRequested = true;
5771
+ logger.debug("supervisor:kill_requested", { phase: this._phase });
5772
+ }
5773
+ };
5774
+ }
5775
+ });
5776
+
5634
5777
  // src/agent/compact.ts
5635
5778
  function indexOfNthUserFromEnd(messages, n) {
5636
5779
  let seen = 0;
@@ -5686,7 +5829,8 @@ ${transcript}` }
5686
5829
  signal: opts2.signal,
5687
5830
  temperature: 0.1,
5688
5831
  reasoningEffort: "low",
5689
- gateway: opts2.gateway
5832
+ gateway: opts2.gateway,
5833
+ idleTimeoutMs: 6e4
5690
5834
  });
5691
5835
  for await (const ev of events) {
5692
5836
  if (ev.type === "text") summary += ev.delta;
@@ -7174,6 +7318,75 @@ var init_lsp = __esm({
7174
7318
  }
7175
7319
  });
7176
7320
 
7321
+ // src/util/abort-scope.ts
7322
+ var AbortScope;
7323
+ var init_abort_scope = __esm({
7324
+ "src/util/abort-scope.ts"() {
7325
+ "use strict";
7326
+ AbortScope = class _AbortScope {
7327
+ controller;
7328
+ parent;
7329
+ children = /* @__PURE__ */ new Set();
7330
+ parentListener;
7331
+ _isAborted = false;
7332
+ _reason;
7333
+ constructor(parent) {
7334
+ this.controller = new AbortController();
7335
+ this.parent = parent;
7336
+ if (parent) {
7337
+ this.parentListener = () => {
7338
+ this.abort(parent.reason ?? "parent_aborted");
7339
+ };
7340
+ parent.signal.addEventListener("abort", this.parentListener, { once: true });
7341
+ parent.children.add(this);
7342
+ }
7343
+ }
7344
+ get signal() {
7345
+ return this.controller.signal;
7346
+ }
7347
+ get isAborted() {
7348
+ return this._isAborted;
7349
+ }
7350
+ get reason() {
7351
+ return this._reason;
7352
+ }
7353
+ abort(reason) {
7354
+ if (this._isAborted) return;
7355
+ this._isAborted = true;
7356
+ this._reason = reason;
7357
+ for (const child of this.children) {
7358
+ child.abort(reason ?? "parent_aborted");
7359
+ }
7360
+ this.children.clear();
7361
+ this.controller.abort(reason);
7362
+ if (this.parent && this.parentListener) {
7363
+ this.parent.signal.removeEventListener("abort", this.parentListener);
7364
+ this.parent.children.delete(this);
7365
+ this.parent = void 0;
7366
+ }
7367
+ }
7368
+ createChild() {
7369
+ if (this._isAborted) {
7370
+ const child = new _AbortScope();
7371
+ child._isAborted = true;
7372
+ child._reason = this._reason ?? "parent_already_aborted";
7373
+ child.controller.abort(child._reason);
7374
+ return child;
7375
+ }
7376
+ return new _AbortScope(this);
7377
+ }
7378
+ /** Detach from parent without aborting. Useful when a child outlives its parent. */
7379
+ detach() {
7380
+ if (this.parent && this.parentListener) {
7381
+ this.parent.signal.removeEventListener("abort", this.parentListener);
7382
+ this.parent.children.delete(this);
7383
+ this.parent = void 0;
7384
+ }
7385
+ }
7386
+ };
7387
+ }
7388
+ });
7389
+
7177
7390
  // src/ui/theme-context.tsx
7178
7391
  import { createContext, useContext } from "react";
7179
7392
  import { jsx } from "react/jsx-runtime";
@@ -7423,9 +7636,16 @@ function humanizeInfo(text, tier) {
7423
7636
  }
7424
7637
  if (text === "(interrupted)") {
7425
7638
  return pick(tier, {
7426
- light: "Stopped",
7427
- medium: "Interrupted",
7428
- heavy: "Halted"
7639
+ light: "Stopped \u2014 say 'go on' if you want me to continue",
7640
+ medium: "Interrupted \u2014 say 'go on' if you want me to continue",
7641
+ heavy: "Halted \u2014 say 'go on' if you want me to resume"
7642
+ });
7643
+ }
7644
+ if (text === "(preempted)") {
7645
+ return pick(tier, {
7646
+ light: "Switching gears\u2026",
7647
+ medium: "Switching to your new message\u2026",
7648
+ heavy: "Switching to your new message\u2026"
7429
7649
  });
7430
7650
  }
7431
7651
  if (text.startsWith("mode: ")) {
@@ -7896,11 +8116,68 @@ var init_markdown = __esm({
7896
8116
  }
7897
8117
  });
7898
8118
 
8119
+ // src/ui/cloud-quota-message.tsx
8120
+ import { Box as Box4, Text as Text4 } from "ink";
8121
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
8122
+ function formatTokens(n) {
8123
+ if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
8124
+ if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
8125
+ return String(n);
8126
+ }
8127
+ function CloudQuotaMessage({ used, limit, expiresAt }) {
8128
+ const theme = useTheme();
8129
+ const expires = expiresAt ? new Date(expiresAt) : null;
8130
+ const start = expires ? new Date(expires.getTime() - 7 * 24 * 60 * 60 * 1e3) : null;
8131
+ const fmt = (d) => d.toLocaleDateString("en-US", { month: "short", day: "numeric" });
8132
+ const dateRange = start && expires ? `${fmt(start)} \u2192 ${fmt(expires)}` : "this week";
8133
+ return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginY: 1, children: [
8134
+ /* @__PURE__ */ jsx5(Text4, { bold: true, color: theme.accent, children: "You've used your free allocation for this week." }),
8135
+ /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginTop: 1, children: [
8136
+ /* @__PURE__ */ jsxs4(Text4, { color: theme.info.color, children: [
8137
+ "Free tier ran from ",
8138
+ dateRange,
8139
+ ", courtesy of Cloudflare"
8140
+ ] }),
8141
+ /* @__PURE__ */ jsx5(Text4, { color: theme.info.color, children: "Workers AI credits. Thanks for trying kimiflare." })
8142
+ ] }),
8143
+ /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginTop: 1, children: [
8144
+ /* @__PURE__ */ jsx5(Text4, { bold: true, children: "Keep going with your own Cloudflare API key:" }),
8145
+ /* @__PURE__ */ jsxs4(Box4, { paddingLeft: 2, flexDirection: "column", children: [
8146
+ /* @__PURE__ */ jsx5(Text4, { color: theme.info.color, children: "\u2192 Set one: kimiflare config set-key <your-key>" }),
8147
+ /* @__PURE__ */ jsx5(Text4, { color: theme.info.color, children: "\u2192 Get one: https://dash.cloudflare.com/profile/api-tokens" }),
8148
+ /* @__PURE__ */ jsx5(Text4, { color: theme.info.color, children: "\u2192 Pricing: https://developers.cloudflare.com/workers-ai/platform/pricing/" }),
8149
+ /* @__PURE__ */ jsx5(Text4, { color: theme.muted?.color ?? theme.info.color, dimColor: theme.muted?.dim ?? true, children: "(~$0.95/M input tokens, ~$4.00/M output tokens)" })
8150
+ ] })
8151
+ ] }),
8152
+ /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginTop: 1, children: [
8153
+ /* @__PURE__ */ jsx5(Text4, { color: theme.info.color, children: "Or wait for hosted plans \u2014 drop your email at" }),
8154
+ /* @__PURE__ */ jsx5(Text4, { color: theme.info.color, children: "kimiflare.dev/notify and I'll ping you when they're live." })
8155
+ ] }),
8156
+ /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginTop: 1, children: [
8157
+ /* @__PURE__ */ jsx5(Text4, { color: theme.info.color, children: "Want a bit more credit? DM me on X: x.com/sinasanm" }),
8158
+ /* @__PURE__ */ jsx5(Text4, { color: theme.info.color, children: "Chances are I might be able to hook you up." })
8159
+ ] }),
8160
+ /* @__PURE__ */ jsx5(Box4, { marginTop: 1, children: /* @__PURE__ */ jsxs4(Text4, { color: theme.muted?.color ?? theme.info.color, dimColor: theme.muted?.dim ?? true, children: [
8161
+ "Used: ",
8162
+ formatTokens(used),
8163
+ " / ",
8164
+ formatTokens(limit),
8165
+ " tokens this week."
8166
+ ] }) })
8167
+ ] });
8168
+ }
8169
+ var init_cloud_quota_message = __esm({
8170
+ "src/ui/cloud-quota-message.tsx"() {
8171
+ "use strict";
8172
+ init_theme_context();
8173
+ }
8174
+ });
8175
+
7899
8176
  // src/ui/chat.tsx
7900
8177
  import React4 from "react";
7901
- import { Box as Box4, Text as Text4, Static } from "ink";
8178
+ import { Box as Box5, Text as Text5, Static } from "ink";
7902
8179
  import Spinner2 from "ink-spinner";
7903
- import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
8180
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
7904
8181
  function toolSignature(name, args) {
7905
8182
  return `${name}:${args}`;
7906
8183
  }
@@ -7912,6 +8189,7 @@ var init_chat = __esm({
7912
8189
  init_markdown();
7913
8190
  init_theme_context();
7914
8191
  init_narrator();
8192
+ init_cloud_quota_message();
7915
8193
  ChatView = React4.memo(function ChatView2({ events, showReasoning, verbose, intentTier }) {
7916
8194
  const theme = useTheme();
7917
8195
  const finalized = [];
@@ -7938,17 +8216,17 @@ var init_chat = __esm({
7938
8216
  finalized.push({ id: e.key, evt: e, showSeparator });
7939
8217
  }
7940
8218
  }
7941
- return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
7942
- /* @__PURE__ */ jsx5(Static, { items: finalized, children: (item) => /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
7943
- item.showSeparator && /* @__PURE__ */ jsx5(Box4, { marginY: 1, children: /* @__PURE__ */ jsx5(Text4, { color: theme.info.color, children: "\u2500".repeat(40) }) }),
7944
- /* @__PURE__ */ jsx5(EventView, { evt: item.evt, showReasoning, verbose, repeatedSigs, intentTier })
8219
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
8220
+ /* @__PURE__ */ jsx6(Static, { items: finalized, children: (item) => /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
8221
+ item.showSeparator && /* @__PURE__ */ jsx6(Box5, { marginY: 1, children: /* @__PURE__ */ jsx6(Text5, { color: theme.info.color, children: "\u2500".repeat(40) }) }),
8222
+ /* @__PURE__ */ jsx6(EventView, { evt: item.evt, showReasoning, verbose, repeatedSigs, intentTier })
7945
8223
  ] }, item.id) }),
7946
8224
  active.map((e, i) => {
7947
8225
  const prevEvt = i > 0 ? active[i - 1] : finalized[finalized.length - 1]?.evt;
7948
8226
  const showSeparator = e.kind === "user" && prevEvt && (prevEvt.kind === "assistant" || prevEvt.kind === "tool");
7949
- return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
7950
- showSeparator && /* @__PURE__ */ jsx5(Box4, { marginY: 1, children: /* @__PURE__ */ jsx5(Text4, { color: theme.info.color, children: "\u2500".repeat(40) }) }),
7951
- /* @__PURE__ */ jsx5(EventView, { evt: e, showReasoning, verbose, repeatedSigs, intentTier })
8227
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
8228
+ showSeparator && /* @__PURE__ */ jsx6(Box5, { marginY: 1, children: /* @__PURE__ */ jsx6(Text5, { color: theme.info.color, children: "\u2500".repeat(40) }) }),
8229
+ /* @__PURE__ */ jsx6(EventView, { evt: e, showReasoning, verbose, repeatedSigs, intentTier })
7952
8230
  ] }, e.key);
7953
8231
  })
7954
8232
  ] });
@@ -7962,47 +8240,71 @@ var init_chat = __esm({
7962
8240
  }) {
7963
8241
  const theme = useTheme();
7964
8242
  if (evt.kind === "user") {
7965
- return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
7966
- /* @__PURE__ */ jsxs4(Box4, { children: [
7967
- /* @__PURE__ */ jsxs4(Text4, { bold: true, color: theme.user, children: [
8243
+ if (evt.queued) {
8244
+ const mutedColor = theme.muted?.color ?? theme.info.color;
8245
+ return /* @__PURE__ */ jsx6(Box5, { flexDirection: "column", children: /* @__PURE__ */ jsxs5(Box5, { children: [
8246
+ /* @__PURE__ */ jsxs5(Text5, { italic: true, color: mutedColor, children: [
8247
+ "\xB7\xB7\xB7",
8248
+ " "
8249
+ ] }),
8250
+ /* @__PURE__ */ jsx6(Text5, { italic: true, color: mutedColor, children: evt.text }),
8251
+ /* @__PURE__ */ jsxs5(Text5, { italic: true, color: mutedColor, children: [
8252
+ " ",
8253
+ "(queued)"
8254
+ ] })
8255
+ ] }) });
8256
+ }
8257
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
8258
+ /* @__PURE__ */ jsxs5(Box5, { children: [
8259
+ /* @__PURE__ */ jsxs5(Text5, { bold: true, color: theme.user, children: [
7968
8260
  "\u203A",
7969
8261
  " "
7970
8262
  ] }),
7971
- /* @__PURE__ */ jsx5(Text4, { bold: true, children: evt.text })
8263
+ /* @__PURE__ */ jsx6(Text5, { bold: true, children: evt.text })
7972
8264
  ] }),
7973
- evt.images && evt.images.length > 0 && /* @__PURE__ */ jsx5(Box4, { paddingLeft: 2, children: /* @__PURE__ */ jsxs4(Text4, { color: theme.info.color, children: [
8265
+ evt.images && evt.images.length > 0 && /* @__PURE__ */ jsx6(Box5, { paddingLeft: 2, children: /* @__PURE__ */ jsxs5(Text5, { color: theme.info.color, children: [
7974
8266
  "\u{1F5BC}\uFE0F ",
7975
8267
  evt.images.join(", ")
7976
8268
  ] }) })
7977
8269
  ] });
7978
8270
  }
7979
8271
  if (evt.kind === "assistant") {
7980
- return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", paddingLeft: 2, children: [
7981
- showReasoning && evt.reasoning ? /* @__PURE__ */ jsx5(Box4, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs4(Text4, { color: theme.reasoning.color, children: [
8272
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", paddingLeft: 2, children: [
8273
+ showReasoning && evt.reasoning ? /* @__PURE__ */ jsx6(Box5, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs5(Text5, { color: theme.reasoning.color, children: [
7982
8274
  "thinking\u2026",
7983
8275
  " ",
7984
8276
  evt.reasoning.length > 400 ? evt.reasoning.slice(0, 400) + "\u2026" : evt.reasoning
7985
8277
  ] }) }) : null,
7986
- evt.text ? /* @__PURE__ */ jsx5(MD, { text: evt.text }) : null,
7987
- evt.streaming && /* @__PURE__ */ jsx5(Text4, { color: theme.spinner, children: /* @__PURE__ */ jsx5(Spinner2, { type: "dots" }) })
8278
+ evt.text ? /* @__PURE__ */ jsx6(MD, { text: evt.text }) : null,
8279
+ evt.streaming && /* @__PURE__ */ jsx6(Text5, { color: theme.spinner, children: /* @__PURE__ */ jsx6(Spinner2, { type: "dots" }) })
7988
8280
  ] });
7989
8281
  }
7990
8282
  if (evt.kind === "tool") {
7991
8283
  const isRepeated = repeatedSigs?.has(toolSignature(evt.name, evt.args)) ?? false;
7992
- return /* @__PURE__ */ jsx5(ToolView, { evt, verbose, isRepeated, intentTier });
8284
+ return /* @__PURE__ */ jsx6(ToolView, { evt, verbose, isRepeated, intentTier });
7993
8285
  }
7994
8286
  if (evt.kind === "info") {
7995
- return /* @__PURE__ */ jsxs4(Text4, { color: theme.info.color, children: [
8287
+ return /* @__PURE__ */ jsxs5(Text5, { color: theme.info.color, children: [
7996
8288
  "\xB7 ",
7997
8289
  humanizeInfo(evt.text, intentTier)
7998
8290
  ] });
7999
8291
  }
8000
8292
  if (evt.kind === "memory") {
8001
- return /* @__PURE__ */ jsxs4(Text4, { color: theme.info.color, children: [
8293
+ return /* @__PURE__ */ jsxs5(Text5, { color: theme.info.color, children: [
8002
8294
  "\u25C8 ",
8003
8295
  humanizeMemory(evt.text, intentTier)
8004
8296
  ] });
8005
8297
  }
8298
+ if (evt.kind === "cloud_quota_exhausted") {
8299
+ return /* @__PURE__ */ jsx6(
8300
+ CloudQuotaMessage,
8301
+ {
8302
+ used: evt.used,
8303
+ limit: evt.limit,
8304
+ expiresAt: evt.expiresAt
8305
+ }
8306
+ );
8307
+ }
8006
8308
  if (evt.kind === "meta") {
8007
8309
  const metaParts = [];
8008
8310
  if (evt.skillsActive !== void 0 && evt.skillsActive > 0) {
@@ -8013,9 +8315,9 @@ var init_chat = __esm({
8013
8315
  }
8014
8316
  const metaText = humanizeMeta(metaParts, intentTier ?? evt.intentTier);
8015
8317
  if (!metaText) return null;
8016
- return /* @__PURE__ */ jsx5(Text4, { color: theme.info.color, dimColor: true, children: metaText });
8318
+ return /* @__PURE__ */ jsx6(Text5, { color: theme.info.color, dimColor: true, children: metaText });
8017
8319
  }
8018
- return /* @__PURE__ */ jsxs4(Text4, { color: theme.error, children: [
8320
+ return /* @__PURE__ */ jsxs5(Text5, { color: theme.error, children: [
8019
8321
  "! ",
8020
8322
  evt.text
8021
8323
  ] });
@@ -8043,9 +8345,9 @@ var init_pricing = __esm({
8043
8345
 
8044
8346
  // src/ui/status.tsx
8045
8347
  import { useEffect as useEffect2, useState as useState2 } from "react";
8046
- import { Box as Box5, Text as Text5 } from "ink";
8348
+ import { Box as Box6, Text as Text6 } from "ink";
8047
8349
  import Spinner3 from "ink-spinner";
8048
- import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
8350
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
8049
8351
  function StatusBar({ model, usage, sessionUsage, thinking, turnStartedAt, mode, effort, contextLimit, hasUpdate, latestVersion, gatewayMeta, codeMode, cloudMode, cloudBudget, skillsActive, memoryRecalled, phase, currentTool, lastActivityAt, kimiMdStale, gitBranch, intentTier }) {
8050
8352
  const theme = useTheme();
8051
8353
  const [now2, setNow] = useState2(Date.now());
@@ -8071,44 +8373,44 @@ function StatusBar({ model, usage, sessionUsage, thinking, turnStartedAt, mode,
8071
8373
  const phaseLabel = phase === "generating" ? humanizePhase("generating", intentTier) : phase === "executing" ? `${humanizePhase("executing", intentTier)} ${currentTool ?? ""}` : phase === "waiting" ? humanizePhase("waiting", intentTier) : humanizePhase("generating", intentTier);
8072
8374
  const idleMs = lastActivityAt && thinking ? now2 - lastActivityAt : 0;
8073
8375
  const idleLabel = idleMs > 3e4 ? ` (idle ${formatElapsed2(Math.floor(idleMs / 1e3))})` : "";
8074
- return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
8075
- /* @__PURE__ */ jsxs5(Box5, { children: [
8076
- /* @__PURE__ */ jsxs5(Text5, { color: modeColor, bold: true, children: [
8376
+ return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
8377
+ /* @__PURE__ */ jsxs6(Box6, { children: [
8378
+ /* @__PURE__ */ jsxs6(Text6, { color: modeColor, bold: true, children: [
8077
8379
  "[",
8078
8380
  mode,
8079
8381
  "]"
8080
8382
  ] }),
8081
- /* @__PURE__ */ jsx6(Text5, { children: " " }),
8082
- thinking ? /* @__PURE__ */ jsxs5(Text5, { color: theme.spinner, children: [
8083
- /* @__PURE__ */ jsx6(Spinner3, { type: "dots" }),
8383
+ /* @__PURE__ */ jsx7(Text6, { children: " " }),
8384
+ thinking ? /* @__PURE__ */ jsxs6(Text6, { color: theme.spinner, children: [
8385
+ /* @__PURE__ */ jsx7(Spinner3, { type: "dots" }),
8084
8386
  " ",
8085
8387
  phaseLabel,
8086
8388
  elapsed ? ` \xB7 ${elapsed}` : "",
8087
8389
  idleLabel
8088
- ] }) : /* @__PURE__ */ jsxs5(Text5, { color: theme.info.color, children: [
8390
+ ] }) : /* @__PURE__ */ jsxs6(Text6, { color: theme.info.color, children: [
8089
8391
  leftParts.join(" \xB7 "),
8090
8392
  " \xB7 ready"
8091
8393
  ] })
8092
8394
  ] }),
8093
- labelParts.length > 0 && /* @__PURE__ */ jsx6(Box5, { children: /* @__PURE__ */ jsx6(Text5, { color: theme.info.color, dimColor: true, children: labelParts.join(" \xB7 ") }) }),
8094
- usage && /* @__PURE__ */ jsxs5(Box5, { children: [
8095
- /* @__PURE__ */ jsx6(Text5, { color: theme.info.color, children: buildRightParts(usage, contextLimit, sessionUsage, gatewayMeta, cloudMode, cloudBudget).join(" \xB7 ") }),
8096
- warn ? /* @__PURE__ */ jsxs5(Text5, { color: theme.warn, bold: true, children: [
8395
+ labelParts.length > 0 && /* @__PURE__ */ jsx7(Box6, { children: /* @__PURE__ */ jsx7(Text6, { color: theme.info.color, dimColor: true, children: labelParts.join(" \xB7 ") }) }),
8396
+ usage && /* @__PURE__ */ jsxs6(Box6, { children: [
8397
+ /* @__PURE__ */ jsx7(Text6, { color: theme.info.color, children: buildRightParts(usage, contextLimit, sessionUsage, gatewayMeta, cloudMode, cloudBudget).join(" \xB7 ") }),
8398
+ warn ? /* @__PURE__ */ jsxs6(Text6, { color: theme.warn, bold: true, children: [
8097
8399
  " \xB7 ",
8098
8400
  "/compact recommended"
8099
8401
  ] }) : null,
8100
- hasUpdate ? /* @__PURE__ */ jsxs5(Text5, { color: theme.warn, bold: true, children: [
8402
+ hasUpdate ? /* @__PURE__ */ jsxs6(Text6, { color: theme.warn, bold: true, children: [
8101
8403
  " \xB7 ",
8102
8404
  "update available",
8103
8405
  latestVersion ? ` \u2192 ${latestVersion}` : "",
8104
8406
  " \xB7 run /update"
8105
8407
  ] }) : null,
8106
- kimiMdStale ? /* @__PURE__ */ jsxs5(Text5, { color: theme.warn, bold: true, children: [
8408
+ kimiMdStale ? /* @__PURE__ */ jsxs6(Text6, { color: theme.warn, bold: true, children: [
8107
8409
  " \xB7 ",
8108
8410
  "\u26A0 KIMI.md stale \xB7 run /init"
8109
8411
  ] }) : null
8110
8412
  ] }),
8111
- !thinking && /* @__PURE__ */ jsx6(Box5, { children: /* @__PURE__ */ jsx6(Text5, { color: theme.muted?.color ?? theme.info.color, dimColor: theme.muted?.dim, children: "tip: shift+tab cycles mode" }) })
8413
+ !thinking && /* @__PURE__ */ jsx7(Box6, { children: /* @__PURE__ */ jsx7(Text6, { color: theme.muted?.color ?? theme.info.color, dimColor: theme.muted?.dim, children: "tip: shift+tab cycles mode" }) })
8112
8414
  ] });
8113
8415
  }
8114
8416
  function buildRightParts(usage, contextLimit, sessionUsage, gatewayMeta, cloudMode, cloudBudget) {
@@ -8137,13 +8439,13 @@ function buildRightParts(usage, contextLimit, sessionUsage, gatewayMeta, cloudMo
8137
8439
  }
8138
8440
  }
8139
8441
  if (cloudMode && cloudBudget) {
8140
- parts.push(`${formatTokens(cloudBudget.remaining)}/${formatTokens(cloudBudget.limit)} tokens`);
8442
+ parts.push(`${formatTokens2(cloudBudget.remaining)}/${formatTokens2(cloudBudget.limit)} tokens`);
8141
8443
  }
8142
8444
  const gatewayCache = formatGatewayCacheStatus(gatewayMeta);
8143
8445
  if (gatewayCache) parts.push(gatewayCache);
8144
8446
  return parts;
8145
8447
  }
8146
- function formatTokens(n) {
8448
+ function formatTokens2(n) {
8147
8449
  if (n >= 1e9) return `${(n / 1e9).toFixed(1)}B`;
8148
8450
  if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
8149
8451
  if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
@@ -8174,9 +8476,9 @@ var init_status = __esm({
8174
8476
  });
8175
8477
 
8176
8478
  // src/ui/permission.tsx
8177
- import { Box as Box6, Text as Text6 } from "ink";
8479
+ import { Box as Box7, Text as Text7 } from "ink";
8178
8480
  import SelectInput from "ink-select-input";
8179
- import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
8481
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
8180
8482
  function PermissionModal({ tool, args, onDecide }) {
8181
8483
  const theme = useTheme();
8182
8484
  const render2 = tool.render?.(args);
@@ -8185,21 +8487,21 @@ function PermissionModal({ tool, args, onDecide }) {
8185
8487
  { label: "Allow for this session", value: "allow_session" },
8186
8488
  { label: "Deny", value: "deny" }
8187
8489
  ];
8188
- return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", borderStyle: "round", borderColor: theme.permission, paddingX: 1, children: [
8189
- /* @__PURE__ */ jsx7(Text6, { color: theme.permission, bold: true, children: "Permission requested" }),
8190
- /* @__PURE__ */ jsxs6(Text6, { children: [
8490
+ return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", borderStyle: "round", borderColor: theme.permission, paddingX: 1, children: [
8491
+ /* @__PURE__ */ jsx8(Text7, { color: theme.permission, bold: true, children: "Permission requested" }),
8492
+ /* @__PURE__ */ jsxs7(Text7, { children: [
8191
8493
  "tool: ",
8192
- /* @__PURE__ */ jsx7(Text6, { color: theme.tool, children: tool.name })
8494
+ /* @__PURE__ */ jsx8(Text7, { color: theme.tool, children: tool.name })
8193
8495
  ] }),
8194
- render2?.title ? /* @__PURE__ */ jsxs6(Text6, { children: [
8496
+ render2?.title ? /* @__PURE__ */ jsxs7(Text7, { children: [
8195
8497
  "action: ",
8196
8498
  render2.title
8197
8499
  ] }) : null,
8198
- render2?.diff ? /* @__PURE__ */ jsx7(Box6, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx7(DiffView, { ...render2.diff }) }) : /* @__PURE__ */ jsxs6(Text6, { color: theme.info.color, children: [
8500
+ render2?.diff ? /* @__PURE__ */ jsx8(Box7, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx8(DiffView, { ...render2.diff }) }) : /* @__PURE__ */ jsxs7(Text7, { color: theme.info.color, children: [
8199
8501
  "args: ",
8200
8502
  JSON.stringify(args)
8201
8503
  ] }),
8202
- /* @__PURE__ */ jsx7(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx7(SelectInput, { items, onSelect: (item) => onDecide(item.value) }) })
8504
+ /* @__PURE__ */ jsx8(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx8(SelectInput, { items, onSelect: (item) => onDecide(item.value) }) })
8203
8505
  ] });
8204
8506
  }
8205
8507
  var init_permission = __esm({
@@ -8211,27 +8513,27 @@ var init_permission = __esm({
8211
8513
  });
8212
8514
 
8213
8515
  // src/ui/limit-modal.tsx
8214
- import { Box as Box7, Text as Text7 } from "ink";
8516
+ import { Box as Box8, Text as Text8 } from "ink";
8215
8517
  import SelectInput2 from "ink-select-input";
8216
- import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
8518
+ import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
8217
8519
  function LimitModal({ limit, onDecide }) {
8218
8520
  const theme = useTheme();
8219
8521
  const items = [
8220
8522
  { label: "Continue", value: "continue" },
8221
8523
  { label: "Stop", value: "stop" }
8222
8524
  ];
8223
- return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", borderStyle: "round", borderColor: theme.error, paddingX: 1, children: [
8224
- /* @__PURE__ */ jsxs7(Text7, { color: theme.error, bold: true, children: [
8525
+ return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", borderStyle: "round", borderColor: theme.error, paddingX: 1, children: [
8526
+ /* @__PURE__ */ jsxs8(Text8, { color: theme.error, bold: true, children: [
8225
8527
  "Tool-call limit reached (",
8226
8528
  limit,
8227
8529
  ")"
8228
8530
  ] }),
8229
- /* @__PURE__ */ jsxs7(Text7, { dimColor: true, children: [
8531
+ /* @__PURE__ */ jsxs8(Text8, { dimColor: true, children: [
8230
8532
  "This session has made ",
8231
8533
  limit,
8232
8534
  " tool calls. What would you like to do?"
8233
8535
  ] }),
8234
- /* @__PURE__ */ jsx8(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx8(
8536
+ /* @__PURE__ */ jsx9(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx9(
8235
8537
  SelectInput2,
8236
8538
  {
8237
8539
  items,
@@ -8249,9 +8551,9 @@ var init_limit_modal = __esm({
8249
8551
 
8250
8552
  // src/ui/resume-picker.tsx
8251
8553
  import { useState as useState3 } from "react";
8252
- import { Box as Box8, Text as Text8, useWindowSize } from "ink";
8554
+ import { Box as Box9, Text as Text9, useWindowSize } from "ink";
8253
8555
  import SelectInput3 from "ink-select-input";
8254
- import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
8556
+ import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
8255
8557
  function ResumePicker({ sessions, onPick }) {
8256
8558
  const theme = useTheme();
8257
8559
  const { rows } = useWindowSize();
@@ -8260,10 +8562,10 @@ function ResumePicker({ sessions, onPick }) {
8260
8562
  const totalPages = Math.max(1, Math.ceil(sessions.length / pageSize));
8261
8563
  const safePage = Math.min(page, totalPages - 1);
8262
8564
  if (sessions.length === 0) {
8263
- return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
8264
- /* @__PURE__ */ jsx9(Text8, { color: theme.accent, bold: true, children: "Resume a session" }),
8265
- /* @__PURE__ */ jsx9(Text8, { color: theme.info.color, children: "No saved sessions yet. Press Enter to dismiss." }),
8266
- /* @__PURE__ */ jsx9(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx9(
8565
+ return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
8566
+ /* @__PURE__ */ jsx10(Text9, { color: theme.accent, bold: true, children: "Resume a session" }),
8567
+ /* @__PURE__ */ jsx10(Text9, { color: theme.info.color, children: "No saved sessions yet. Press Enter to dismiss." }),
8568
+ /* @__PURE__ */ jsx10(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx10(
8267
8569
  SelectInput3,
8268
8570
  {
8269
8571
  items: [{ label: "(back)", value: "__cancel__" }],
@@ -8286,9 +8588,9 @@ function ResumePicker({ sessions, onPick }) {
8286
8588
  items.push({ label: "\u2192 next page", value: "__next__" });
8287
8589
  }
8288
8590
  items.push({ label: "(cancel)", value: "__cancel__" });
8289
- return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
8290
- /* @__PURE__ */ jsx9(Text8, { color: theme.accent, bold: true, children: "Resume a session" }),
8291
- /* @__PURE__ */ jsxs8(Text8, { color: theme.info.color, children: [
8591
+ return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
8592
+ /* @__PURE__ */ jsx10(Text9, { color: theme.accent, bold: true, children: "Resume a session" }),
8593
+ /* @__PURE__ */ jsxs9(Text9, { color: theme.info.color, children: [
8292
8594
  "Arrow keys to select, Enter to confirm. Page ",
8293
8595
  safePage + 1,
8294
8596
  " of ",
@@ -8297,7 +8599,7 @@ function ResumePicker({ sessions, onPick }) {
8297
8599
  sessions.length,
8298
8600
  " total)"
8299
8601
  ] }),
8300
- /* @__PURE__ */ jsx9(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx9(
8602
+ /* @__PURE__ */ jsx10(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx10(
8301
8603
  SelectInput3,
8302
8604
  {
8303
8605
  items,
@@ -8338,9 +8640,9 @@ var init_resume_picker = __esm({
8338
8640
 
8339
8641
  // src/ui/task-list.tsx
8340
8642
  import { useEffect as useEffect3, useRef, useState as useState4 } from "react";
8341
- import { Box as Box9, Text as Text9 } from "ink";
8643
+ import { Box as Box10, Text as Text10 } from "ink";
8342
8644
  import Spinner4 from "ink-spinner";
8343
- import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
8645
+ import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
8344
8646
  function TaskList({ tasks, startedAt, tokensDelta }) {
8345
8647
  const theme = useTheme();
8346
8648
  const [now2, setNow] = useState4(Date.now());
@@ -8364,21 +8666,21 @@ function TaskList({ tasks, startedAt, tokensDelta }) {
8364
8666
  const allDone = done === total;
8365
8667
  const header = active ? active.title : allDone ? `${total} tasks done` : `${done}/${total}`;
8366
8668
  const elapsed = startedAt ? formatElapsed3(now2 - startedAt) : null;
8367
- const headerStats = [elapsed, tokensDelta > 0 ? `\u2191 ${formatTokens2(tokensDelta)} tokens` : null].filter(Boolean).join(" \xB7 ");
8669
+ const headerStats = [elapsed, tokensDelta > 0 ? `\u2191 ${formatTokens3(tokensDelta)} tokens` : null].filter(Boolean).join(" \xB7 ");
8368
8670
  const visibleTasks = tasks.slice(0, MAX_VISIBLE);
8369
8671
  const hiddenPending = Math.max(0, tasks.length - visibleTasks.length);
8370
- return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", marginBottom: 1, children: [
8371
- /* @__PURE__ */ jsxs9(Box9, { children: [
8372
- /* @__PURE__ */ jsx10(Text9, { color: allDone ? "green" : theme.accent, bold: true, children: header }),
8373
- headerStats && /* @__PURE__ */ jsxs9(Text9, { color: theme.info.color, children: [
8672
+ return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", marginBottom: 1, children: [
8673
+ /* @__PURE__ */ jsxs10(Box10, { children: [
8674
+ /* @__PURE__ */ jsx11(Text10, { color: allDone ? "green" : theme.accent, bold: true, children: header }),
8675
+ headerStats && /* @__PURE__ */ jsxs10(Text10, { color: theme.info.color, children: [
8374
8676
  " ",
8375
8677
  "(",
8376
8678
  headerStats,
8377
8679
  ")"
8378
8680
  ] })
8379
8681
  ] }),
8380
- visibleTasks.map((t) => /* @__PURE__ */ jsx10(TaskRow, { task: t }, t.id)),
8381
- hiddenPending > 0 && /* @__PURE__ */ jsxs9(Text9, { color: theme.info.color, children: [
8682
+ visibleTasks.map((t) => /* @__PURE__ */ jsx11(TaskRow, { task: t }, t.id)),
8683
+ hiddenPending > 0 && /* @__PURE__ */ jsxs10(Text10, { color: theme.info.color, children: [
8382
8684
  " ",
8383
8685
  "\u2026 +",
8384
8686
  hiddenPending,
@@ -8389,21 +8691,21 @@ function TaskList({ tasks, startedAt, tokensDelta }) {
8389
8691
  function TaskRow({ task }) {
8390
8692
  const theme = useTheme();
8391
8693
  if (task.status === "completed") {
8392
- return /* @__PURE__ */ jsxs9(Text9, { color: theme.info.color, children: [
8694
+ return /* @__PURE__ */ jsxs10(Text10, { color: theme.info.color, children: [
8393
8695
  " ",
8394
8696
  "\u2713 ",
8395
- /* @__PURE__ */ jsx10(Text9, { strikethrough: true, children: task.title })
8697
+ /* @__PURE__ */ jsx11(Text10, { strikethrough: true, children: task.title })
8396
8698
  ] });
8397
8699
  }
8398
8700
  if (task.status === "in_progress") {
8399
- return /* @__PURE__ */ jsxs9(Text9, { color: theme.accent, bold: true, children: [
8701
+ return /* @__PURE__ */ jsxs10(Text10, { color: theme.accent, bold: true, children: [
8400
8702
  " ",
8401
- /* @__PURE__ */ jsx10(Spinner4, { type: "dots" }),
8703
+ /* @__PURE__ */ jsx11(Spinner4, { type: "dots" }),
8402
8704
  " ",
8403
8705
  task.title
8404
8706
  ] });
8405
8707
  }
8406
- return /* @__PURE__ */ jsxs9(Text9, { color: theme.info.color, children: [
8708
+ return /* @__PURE__ */ jsxs10(Text10, { color: theme.info.color, children: [
8407
8709
  " ",
8408
8710
  "\u2610 ",
8409
8711
  task.title
@@ -8416,7 +8718,7 @@ function formatElapsed3(ms) {
8416
8718
  if (m === 0) return `${s}s`;
8417
8719
  return `${m}m ${s}s`;
8418
8720
  }
8419
- function formatTokens2(n) {
8721
+ function formatTokens3(n) {
8420
8722
  if (n < 1e3) return String(n);
8421
8723
  return `${(n / 1e3).toFixed(1)}k`;
8422
8724
  }
@@ -8951,8 +9253,8 @@ var init_source = __esm({
8951
9253
 
8952
9254
  // src/ui/text-input.tsx
8953
9255
  import { useState as useState5, useEffect as useEffect4, useRef as useRef2 } from "react";
8954
- import { Text as Text10, useInput } from "ink";
8955
- import { jsx as jsx11 } from "react/jsx-runtime";
9256
+ import { Text as Text11, useInput } from "ink";
9257
+ import { jsx as jsx12 } from "react/jsx-runtime";
8956
9258
  function shouldTreatAsPaste(input) {
8957
9259
  if (input.length >= PASTE_CHAR_THRESHOLD) return true;
8958
9260
  const newlines = (input.match(/\n/g) ?? []).length;
@@ -9162,7 +9464,7 @@ function CustomTextInput({
9162
9464
  } else if (cursorOffset === displayValue.length) {
9163
9465
  renderedValue += source_default.inverse(" ");
9164
9466
  }
9165
- return /* @__PURE__ */ jsx11(Text10, { children: renderedValue });
9467
+ return /* @__PURE__ */ jsx12(Text11, { children: renderedValue });
9166
9468
  }
9167
9469
  function findPasteTokenEndingAt(value, pos, pastes) {
9168
9470
  if (pos <= 0 || value[pos - 1] !== "]") return -1;
@@ -9185,12 +9487,12 @@ var init_text_input = __esm({
9185
9487
 
9186
9488
  // src/ui/onboarding.tsx
9187
9489
  import { useState as useState6, useEffect as useEffect5, useCallback } from "react";
9188
- import { Box as Box10, Text as Text11, useInput as useInput2 } from "ink";
9490
+ import { Box as Box11, Text as Text12, useInput as useInput2 } from "ink";
9189
9491
  import SelectInput4 from "ink-select-input";
9190
9492
  import Spinner5 from "ink-spinner";
9191
9493
  import { exec } from "child_process";
9192
9494
  import { promisify as promisify2 } from "util";
9193
- import { Fragment, jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
9495
+ import { Fragment, jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
9194
9496
  function openBrowser(url) {
9195
9497
  const platform3 = process.platform;
9196
9498
  const cmd = platform3 === "darwin" ? `open "${url}"` : platform3 === "win32" ? `start "" "${url}"` : `xdg-open "${url}"`;
@@ -9346,24 +9648,24 @@ function Onboarding({ onDone, onCancel }) {
9346
9648
  const byokSteps = ["accountId", "apiToken", "model", "confirm"];
9347
9649
  const stepIndex = step === "mode" ? 1 : step === "cloudAuth" ? 2 : byokSteps.indexOf(step) + 2;
9348
9650
  const totalSteps = mode === "cloud" ? 2 : byokSteps.length + 1;
9349
- return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", paddingY: 1, children: [
9350
- /* @__PURE__ */ jsxs10(Box10, { marginBottom: 1, children: [
9351
- /* @__PURE__ */ jsx12(Text11, { bold: true, color: theme.palette.primary, children: "kimiflare" }),
9352
- /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
9651
+ return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", paddingY: 1, children: [
9652
+ /* @__PURE__ */ jsxs11(Box11, { marginBottom: 1, children: [
9653
+ /* @__PURE__ */ jsx13(Text12, { bold: true, color: theme.palette.primary, children: "kimiflare" }),
9654
+ /* @__PURE__ */ jsxs11(Text12, { color: theme.info.color, children: [
9353
9655
  " ",
9354
9656
  "Terminal coding agent"
9355
9657
  ] })
9356
9658
  ] }),
9357
- /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
9659
+ /* @__PURE__ */ jsxs11(Text12, { color: theme.info.color, children: [
9358
9660
  "Step ",
9359
9661
  stepIndex,
9360
9662
  " of ",
9361
9663
  totalSteps
9362
9664
  ] }),
9363
- /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, flexDirection: "column", children: [
9364
- step === "mode" && /* @__PURE__ */ jsxs10(Fragment, { children: [
9365
- /* @__PURE__ */ jsx12(Text11, { children: "How do you want to connect?" }),
9366
- /* @__PURE__ */ jsx12(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx12(
9665
+ /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, flexDirection: "column", children: [
9666
+ step === "mode" && /* @__PURE__ */ jsxs11(Fragment, { children: [
9667
+ /* @__PURE__ */ jsx13(Text12, { children: "How do you want to connect?" }),
9668
+ /* @__PURE__ */ jsx13(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx13(
9367
9669
  SelectInput4,
9368
9670
  {
9369
9671
  items: [
@@ -9374,19 +9676,19 @@ function Onboarding({ onDone, onCancel }) {
9374
9676
  }
9375
9677
  ) })
9376
9678
  ] }),
9377
- step === "cloudAuth" && cloudAuth?.phase === "ready" && /* @__PURE__ */ jsxs10(Fragment, { children: [
9378
- /* @__PURE__ */ jsx12(Text11, { children: "Authenticating with Kimiflare Cloud..." }),
9379
- /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, flexDirection: "column", children: [
9380
- /* @__PURE__ */ jsx12(Text11, { children: "1. Open this URL in your browser:" }),
9381
- /* @__PURE__ */ jsx12(Text11, { color: theme.palette.primary, children: cloudAuth.codes.authUrl })
9679
+ step === "cloudAuth" && cloudAuth?.phase === "ready" && /* @__PURE__ */ jsxs11(Fragment, { children: [
9680
+ /* @__PURE__ */ jsx13(Text12, { children: "Authenticating with Kimiflare Cloud..." }),
9681
+ /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, flexDirection: "column", children: [
9682
+ /* @__PURE__ */ jsx13(Text12, { children: "1. Open this URL in your browser:" }),
9683
+ /* @__PURE__ */ jsx13(Text12, { color: theme.palette.primary, children: cloudAuth.codes.authUrl })
9382
9684
  ] }),
9383
- /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
9384
- /* @__PURE__ */ jsx12(Text11, { children: "2. " }),
9385
- /* @__PURE__ */ jsx12(Text11, { bold: true, children: "[Press Enter to open browser]" })
9685
+ /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, children: [
9686
+ /* @__PURE__ */ jsx13(Text12, { children: "2. " }),
9687
+ /* @__PURE__ */ jsx13(Text12, { bold: true, children: "[Press Enter to open browser]" })
9386
9688
  ] }),
9387
- /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
9388
- /* @__PURE__ */ jsx12(Text11, { color: theme.palette.primary, children: "\u203A " }),
9389
- /* @__PURE__ */ jsx12(
9689
+ /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, children: [
9690
+ /* @__PURE__ */ jsx13(Text12, { color: theme.palette.primary, children: "\u203A " }),
9691
+ /* @__PURE__ */ jsx13(
9390
9692
  CustomTextInput,
9391
9693
  {
9392
9694
  value: "",
@@ -9397,28 +9699,28 @@ function Onboarding({ onDone, onCancel }) {
9397
9699
  )
9398
9700
  ] })
9399
9701
  ] }),
9400
- step === "cloudAuth" && cloudAuth?.phase === "polling" && /* @__PURE__ */ jsxs10(Fragment, { children: [
9401
- /* @__PURE__ */ jsxs10(Text11, { children: [
9402
- /* @__PURE__ */ jsx12(Text11, { color: theme.spinner, children: /* @__PURE__ */ jsx12(Spinner5, { type: "dots" }) }),
9702
+ step === "cloudAuth" && cloudAuth?.phase === "polling" && /* @__PURE__ */ jsxs11(Fragment, { children: [
9703
+ /* @__PURE__ */ jsxs11(Text12, { children: [
9704
+ /* @__PURE__ */ jsx13(Text12, { color: theme.spinner, children: /* @__PURE__ */ jsx13(Spinner5, { type: "dots" }) }),
9403
9705
  " ",
9404
9706
  "Waiting for authentication..."
9405
9707
  ] }),
9406
- /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
9708
+ /* @__PURE__ */ jsxs11(Text12, { color: theme.info.color, children: [
9407
9709
  "Expires in ",
9408
9710
  formatRemaining(POLL_TIMEOUT_MS - (Date.now() - cloudAuth.startTime))
9409
9711
  ] }),
9410
- /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
9712
+ /* @__PURE__ */ jsxs11(Text12, { color: theme.info.color, children: [
9411
9713
  "URL: ",
9412
9714
  cloudAuth.codes.authUrl
9413
9715
  ] })
9414
9716
  ] }),
9415
- step === "cloudAuth" && cloudAuth?.phase === "success" && /* @__PURE__ */ jsxs10(Fragment, { children: [
9416
- /* @__PURE__ */ jsx12(Text11, { color: theme.palette.success, children: "Authenticated!" }),
9417
- /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, flexDirection: "column", children: [
9418
- /* @__PURE__ */ jsxs10(Text11, { children: [
9717
+ step === "cloudAuth" && cloudAuth?.phase === "success" && /* @__PURE__ */ jsxs11(Fragment, { children: [
9718
+ /* @__PURE__ */ jsx13(Text12, { color: theme.palette.success, children: "Authenticated!" }),
9719
+ /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, flexDirection: "column", children: [
9720
+ /* @__PURE__ */ jsxs11(Text12, { children: [
9419
9721
  "Token budget:",
9420
9722
  " ",
9421
- /* @__PURE__ */ jsxs10(Text11, { bold: true, children: [
9723
+ /* @__PURE__ */ jsxs11(Text12, { bold: true, children: [
9422
9724
  cloudAuth.usage.remaining.toLocaleString(),
9423
9725
  " /",
9424
9726
  " ",
@@ -9427,15 +9729,15 @@ function Onboarding({ onDone, onCancel }) {
9427
9729
  " ",
9428
9730
  "remaining"
9429
9731
  ] }),
9430
- /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
9732
+ /* @__PURE__ */ jsxs11(Text12, { color: theme.info.color, children: [
9431
9733
  "Grant expires: ",
9432
9734
  cloudAuth.usage.expires_at
9433
9735
  ] })
9434
9736
  ] }),
9435
- /* @__PURE__ */ jsx12(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text11, { children: "[Press Enter to continue]" }) }),
9436
- /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
9437
- /* @__PURE__ */ jsx12(Text11, { color: theme.palette.primary, children: "\u203A " }),
9438
- /* @__PURE__ */ jsx12(
9737
+ /* @__PURE__ */ jsx13(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx13(Text12, { children: "[Press Enter to continue]" }) }),
9738
+ /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, children: [
9739
+ /* @__PURE__ */ jsx13(Text12, { color: theme.palette.primary, children: "\u203A " }),
9740
+ /* @__PURE__ */ jsx13(
9439
9741
  CustomTextInput,
9440
9742
  {
9441
9743
  value: "",
@@ -9446,10 +9748,10 @@ function Onboarding({ onDone, onCancel }) {
9446
9748
  )
9447
9749
  ] })
9448
9750
  ] }),
9449
- step === "cloudAuth" && cloudAuth?.phase === "error" && /* @__PURE__ */ jsxs10(Fragment, { children: [
9450
- /* @__PURE__ */ jsx12(Text11, { color: theme.palette.error, children: "Authentication failed" }),
9451
- /* @__PURE__ */ jsx12(Text11, { color: theme.info.color, children: cloudAuth.message }),
9452
- /* @__PURE__ */ jsx12(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx12(
9751
+ step === "cloudAuth" && cloudAuth?.phase === "error" && /* @__PURE__ */ jsxs11(Fragment, { children: [
9752
+ /* @__PURE__ */ jsx13(Text12, { color: theme.palette.error, children: "Authentication failed" }),
9753
+ /* @__PURE__ */ jsx13(Text12, { color: theme.info.color, children: cloudAuth.message }),
9754
+ /* @__PURE__ */ jsx13(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx13(
9453
9755
  SelectInput4,
9454
9756
  {
9455
9757
  items: [
@@ -9465,11 +9767,11 @@ function Onboarding({ onDone, onCancel }) {
9465
9767
  }
9466
9768
  ) })
9467
9769
  ] }),
9468
- step === "accountId" && /* @__PURE__ */ jsxs10(Fragment, { children: [
9469
- /* @__PURE__ */ jsx12(Text11, { children: "Enter your Cloudflare Account ID" }),
9470
- /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
9471
- /* @__PURE__ */ jsx12(Text11, { color: theme.palette.primary, children: "\u203A " }),
9472
- /* @__PURE__ */ jsx12(
9770
+ step === "accountId" && /* @__PURE__ */ jsxs11(Fragment, { children: [
9771
+ /* @__PURE__ */ jsx13(Text12, { children: "Enter your Cloudflare Account ID" }),
9772
+ /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, children: [
9773
+ /* @__PURE__ */ jsx13(Text12, { color: theme.palette.primary, children: "\u203A " }),
9774
+ /* @__PURE__ */ jsx13(
9473
9775
  CustomTextInput,
9474
9776
  {
9475
9777
  value: accountId,
@@ -9479,12 +9781,12 @@ function Onboarding({ onDone, onCancel }) {
9479
9781
  )
9480
9782
  ] })
9481
9783
  ] }),
9482
- step === "apiToken" && /* @__PURE__ */ jsxs10(Fragment, { children: [
9483
- /* @__PURE__ */ jsx12(Text11, { children: "Enter your Cloudflare API Token" }),
9484
- /* @__PURE__ */ jsx12(Text11, { color: theme.info.color, children: "Create one at https://dash.cloudflare.com/profile/api-tokens" }),
9485
- /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
9486
- /* @__PURE__ */ jsx12(Text11, { color: theme.palette.primary, children: "\u203A " }),
9487
- /* @__PURE__ */ jsx12(
9784
+ step === "apiToken" && /* @__PURE__ */ jsxs11(Fragment, { children: [
9785
+ /* @__PURE__ */ jsx13(Text12, { children: "Enter your Cloudflare API Token" }),
9786
+ /* @__PURE__ */ jsx13(Text12, { color: theme.info.color, children: "Create one at https://dash.cloudflare.com/profile/api-tokens" }),
9787
+ /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, children: [
9788
+ /* @__PURE__ */ jsx13(Text12, { color: theme.palette.primary, children: "\u203A " }),
9789
+ /* @__PURE__ */ jsx13(
9488
9790
  CustomTextInput,
9489
9791
  {
9490
9792
  value: apiToken,
@@ -9495,15 +9797,15 @@ function Onboarding({ onDone, onCancel }) {
9495
9797
  )
9496
9798
  ] })
9497
9799
  ] }),
9498
- step === "model" && /* @__PURE__ */ jsxs10(Fragment, { children: [
9499
- /* @__PURE__ */ jsx12(Text11, { children: "Model ID (press Enter for default)" }),
9500
- /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
9800
+ step === "model" && /* @__PURE__ */ jsxs11(Fragment, { children: [
9801
+ /* @__PURE__ */ jsx13(Text12, { children: "Model ID (press Enter for default)" }),
9802
+ /* @__PURE__ */ jsxs11(Text12, { color: theme.info.color, children: [
9501
9803
  "default: ",
9502
9804
  DEFAULT_MODEL
9503
9805
  ] }),
9504
- /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
9505
- /* @__PURE__ */ jsx12(Text11, { color: theme.palette.primary, children: "\u203A " }),
9506
- /* @__PURE__ */ jsx12(
9806
+ /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, children: [
9807
+ /* @__PURE__ */ jsx13(Text12, { color: theme.palette.primary, children: "\u203A " }),
9808
+ /* @__PURE__ */ jsx13(
9507
9809
  CustomTextInput,
9508
9810
  {
9509
9811
  value: model,
@@ -9513,10 +9815,10 @@ function Onboarding({ onDone, onCancel }) {
9513
9815
  )
9514
9816
  ] })
9515
9817
  ] }),
9516
- step === "confirm" && /* @__PURE__ */ jsxs10(Fragment, { children: [
9517
- /* @__PURE__ */ jsx12(Text11, { children: "Ready to save configuration" }),
9518
- /* @__PURE__ */ jsxs10(
9519
- Box10,
9818
+ step === "confirm" && /* @__PURE__ */ jsxs11(Fragment, { children: [
9819
+ /* @__PURE__ */ jsx13(Text12, { children: "Ready to save configuration" }),
9820
+ /* @__PURE__ */ jsxs11(
9821
+ Box11,
9520
9822
  {
9521
9823
  flexDirection: "column",
9522
9824
  marginTop: 1,
@@ -9525,25 +9827,25 @@ function Onboarding({ onDone, onCancel }) {
9525
9827
  borderColor: theme.info.color,
9526
9828
  paddingX: 1,
9527
9829
  children: [
9528
- /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
9830
+ /* @__PURE__ */ jsxs11(Text12, { color: theme.info.color, children: [
9529
9831
  "Account ID: ",
9530
9832
  accountId
9531
9833
  ] }),
9532
- /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
9834
+ /* @__PURE__ */ jsxs11(Text12, { color: theme.info.color, children: [
9533
9835
  "API Token: ",
9534
9836
  "\u2022".repeat(apiToken.length)
9535
9837
  ] }),
9536
- /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
9838
+ /* @__PURE__ */ jsxs11(Text12, { color: theme.info.color, children: [
9537
9839
  "Model: ",
9538
9840
  model
9539
9841
  ] })
9540
9842
  ]
9541
9843
  }
9542
9844
  ),
9543
- /* @__PURE__ */ jsx12(Text11, { children: "Press Enter to confirm, or Ctrl+C to cancel" }),
9544
- /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
9545
- /* @__PURE__ */ jsx12(Text11, { color: theme.palette.primary, children: "\u203A " }),
9546
- /* @__PURE__ */ jsx12(
9845
+ /* @__PURE__ */ jsx13(Text12, { children: "Press Enter to confirm, or Ctrl+C to cancel" }),
9846
+ /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, children: [
9847
+ /* @__PURE__ */ jsx13(Text12, { color: theme.palette.primary, children: "\u203A " }),
9848
+ /* @__PURE__ */ jsx13(
9547
9849
  CustomTextInput,
9548
9850
  {
9549
9851
  value: "",
@@ -9554,7 +9856,7 @@ function Onboarding({ onDone, onCancel }) {
9554
9856
  )
9555
9857
  ] })
9556
9858
  ] }),
9557
- savedPath && /* @__PURE__ */ jsxs10(Text11, { color: theme.palette.success, children: [
9859
+ savedPath && /* @__PURE__ */ jsxs11(Text12, { color: theme.palette.success, children: [
9558
9860
  "Config saved to ",
9559
9861
  savedPath
9560
9862
  ] })
@@ -9574,34 +9876,34 @@ var init_onboarding = __esm({
9574
9876
  });
9575
9877
 
9576
9878
  // src/ui/welcome.tsx
9577
- import { Box as Box11, Text as Text12 } from "ink";
9578
- import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
9879
+ import { Box as Box12, Text as Text13 } from "ink";
9880
+ import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
9579
9881
  function Welcome({ accountId, cloudMode }) {
9580
9882
  const theme = useTheme();
9581
- return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", marginBottom: 1, children: [
9582
- /* @__PURE__ */ jsxs11(Box11, { marginBottom: 1, children: [
9583
- /* @__PURE__ */ jsx13(Text12, { bold: true, color: theme.accent, children: "kimiflare" }),
9584
- /* @__PURE__ */ jsxs11(Text12, { color: theme.info.color, children: [
9883
+ return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", marginBottom: 1, children: [
9884
+ /* @__PURE__ */ jsxs12(Box12, { marginBottom: 1, children: [
9885
+ /* @__PURE__ */ jsx14(Text13, { bold: true, color: theme.accent, children: "kimiflare" }),
9886
+ /* @__PURE__ */ jsxs12(Text13, { color: theme.info.color, children: [
9585
9887
  " ",
9586
9888
  "Ready when you are."
9587
9889
  ] })
9588
9890
  ] }),
9589
- accountId && !cloudMode && /* @__PURE__ */ jsx13(Box11, { marginBottom: 1, children: /* @__PURE__ */ jsxs11(Text12, { color: theme.info.color, children: [
9891
+ accountId && !cloudMode && /* @__PURE__ */ jsx14(Box12, { marginBottom: 1, children: /* @__PURE__ */ jsxs12(Text13, { color: theme.info.color, children: [
9590
9892
  " ",
9591
9893
  "Check your Cloudflare billing: https://dash.cloudflare.com/",
9592
9894
  accountId,
9593
9895
  "/billing/billable-usage"
9594
9896
  ] }) }),
9595
- /* @__PURE__ */ jsx13(Box11, { flexDirection: "column", children: SUGGESTIONS.map((s, i) => /* @__PURE__ */ jsxs11(Box11, { children: [
9596
- /* @__PURE__ */ jsxs11(Text12, { color: theme.info.color, children: [
9897
+ /* @__PURE__ */ jsx14(Box12, { flexDirection: "column", children: SUGGESTIONS.map((s, i) => /* @__PURE__ */ jsxs12(Box12, { children: [
9898
+ /* @__PURE__ */ jsxs12(Text13, { color: theme.info.color, children: [
9597
9899
  " ",
9598
9900
  "\u203A",
9599
9901
  " "
9600
9902
  ] }),
9601
- /* @__PURE__ */ jsx13(Text12, { color: theme.user, children: s })
9903
+ /* @__PURE__ */ jsx14(Text13, { color: theme.user, children: s })
9602
9904
  ] }, i)) }),
9603
- /* @__PURE__ */ jsx13(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx13(Text12, { color: theme.info.color, children: "Type a message or /help for commands \xB7 ctrl-c to exit \xB7 shift+tab to cycle modes" }) }),
9604
- /* @__PURE__ */ jsx13(Box11, { children: /* @__PURE__ */ jsx13(Text12, { color: theme.info.color, children: "Tip: type /hello to send feedback to the creator" }) })
9905
+ /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, children: "Type a message or /help for commands \xB7 ctrl-c to exit \xB7 shift+tab to cycle modes" }) }),
9906
+ /* @__PURE__ */ jsx14(Box12, { children: /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, children: "Tip: type /hello to send feedback to the creator" }) })
9605
9907
  ] });
9606
9908
  }
9607
9909
  var SUGGESTIONS;
@@ -9722,9 +10024,9 @@ var init_tui_deploy = __esm({
9722
10024
 
9723
10025
  // src/ui/remote-dashboard.tsx
9724
10026
  import { useEffect as useEffect6, useState as useState7 } from "react";
9725
- import { Box as Box12, Text as Text13, useInput as useInput3 } from "ink";
10027
+ import { Box as Box13, Text as Text14, useInput as useInput3 } from "ink";
9726
10028
  import SelectInput5 from "ink-select-input";
9727
- import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
10029
+ import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
9728
10030
  function RemoteDashboard({ onSelect, onCancel }) {
9729
10031
  const theme = useTheme();
9730
10032
  const [sessions, setSessions] = useState7([]);
@@ -9780,30 +10082,30 @@ function RemoteDashboard({ onSelect, onCancel }) {
9780
10082
  value: s.sessionId
9781
10083
  }));
9782
10084
  if (loading) {
9783
- return /* @__PURE__ */ jsx14(Box12, { flexDirection: "column", padding: 1, children: /* @__PURE__ */ jsx14(Text13, { color: theme.accent, children: "Loading remote sessions..." }) });
10085
+ return /* @__PURE__ */ jsx15(Box13, { flexDirection: "column", padding: 1, children: /* @__PURE__ */ jsx15(Text14, { color: theme.accent, children: "Loading remote sessions..." }) });
9784
10086
  }
9785
10087
  if (error) {
9786
- return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", padding: 1, children: [
9787
- /* @__PURE__ */ jsxs12(Text13, { color: theme.error, children: [
10088
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", padding: 1, children: [
10089
+ /* @__PURE__ */ jsxs13(Text14, { color: theme.error, children: [
9788
10090
  "Error: ",
9789
10091
  error
9790
10092
  ] }),
9791
- /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "Press R to retry, Esc to close" })
10093
+ /* @__PURE__ */ jsx15(Text14, { dimColor: true, children: "Press R to retry, Esc to close" })
9792
10094
  ] });
9793
10095
  }
9794
10096
  if (sessions.length === 0) {
9795
- return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", padding: 1, children: [
9796
- /* @__PURE__ */ jsx14(Text13, { color: theme.accent, children: "No remote sessions yet." }),
9797
- /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "Type /remote <prompt> to start one." }),
9798
- /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "Press Esc to close" })
10097
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", padding: 1, children: [
10098
+ /* @__PURE__ */ jsx15(Text14, { color: theme.accent, children: "No remote sessions yet." }),
10099
+ /* @__PURE__ */ jsx15(Text14, { dimColor: true, children: "Type /remote <prompt> to start one." }),
10100
+ /* @__PURE__ */ jsx15(Text14, { dimColor: true, children: "Press Esc to close" })
9799
10101
  ] });
9800
10102
  }
9801
- return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", padding: 1, children: [
9802
- /* @__PURE__ */ jsxs12(Text13, { bold: true, color: theme.accent, children: [
10103
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", padding: 1, children: [
10104
+ /* @__PURE__ */ jsxs13(Text14, { bold: true, color: theme.accent, children: [
9803
10105
  "Recent remote tasks ",
9804
10106
  refreshing ? "(refreshing...)" : ""
9805
10107
  ] }),
9806
- /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(
10108
+ /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
9807
10109
  SelectInput5,
9808
10110
  {
9809
10111
  items,
@@ -9813,7 +10115,7 @@ function RemoteDashboard({ onSelect, onCancel }) {
9813
10115
  }
9814
10116
  }
9815
10117
  ) }),
9816
- /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "\u2191\u2193 navigate \u2022 Enter select \u2022 R refresh \u2022 Esc close" }) })
10118
+ /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(Text14, { dimColor: true, children: "\u2191\u2193 navigate \u2022 Enter select \u2022 R refresh \u2022 Esc close" }) })
9817
10119
  ] });
9818
10120
  }
9819
10121
  function formatSessionLine(s) {
@@ -9821,7 +10123,7 @@ function formatSessionLine(s) {
9821
10123
  const ago = formatAgo(new Date(s.updatedAt));
9822
10124
  const prompt = s.prompt.slice(0, 30) + (s.prompt.length > 30 ? "\u2026" : "");
9823
10125
  const outcome = s.prUrl ? `PR ${s.prUrl.split("/").pop()}` : s.status;
9824
- const cost = s.tokensUsed && s.tokensBudget ? ` (${formatTokens3(s.tokensUsed)}/${formatTokens3(s.tokensBudget)})` : s.tokensUsed ? ` (${formatTokens3(s.tokensUsed)})` : "";
10126
+ const cost = s.tokensUsed && s.tokensBudget ? ` (${formatTokens4(s.tokensUsed)}/${formatTokens4(s.tokensBudget)})` : s.tokensUsed ? ` (${formatTokens4(s.tokensUsed)})` : "";
9825
10127
  return `${icon} ${prompt} \u2192 ${outcome} ${ago}${cost}`;
9826
10128
  }
9827
10129
  function formatAgo(date) {
@@ -9834,7 +10136,7 @@ function formatAgo(date) {
9834
10136
  if (minutes > 0) return `${minutes}m ago`;
9835
10137
  return "just now";
9836
10138
  }
9837
- function formatTokens3(n) {
10139
+ function formatTokens4(n) {
9838
10140
  if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
9839
10141
  if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
9840
10142
  return String(n);
@@ -9866,50 +10168,50 @@ function RemoteSessionDetail({
9866
10168
  }
9867
10169
  }
9868
10170
  const isRunning = session.status === "running" || session.status === "pending";
9869
- return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", padding: 1, children: [
9870
- /* @__PURE__ */ jsx14(Text13, { bold: true, color: theme.accent, children: "Remote Session" }),
9871
- /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "column", children: [
9872
- /* @__PURE__ */ jsxs12(Text13, { children: [
10171
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", padding: 1, children: [
10172
+ /* @__PURE__ */ jsx15(Text14, { bold: true, color: theme.accent, children: "Remote Session" }),
10173
+ /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "column", children: [
10174
+ /* @__PURE__ */ jsxs13(Text14, { children: [
9873
10175
  "ID: ",
9874
10176
  session.sessionId
9875
10177
  ] }),
9876
- /* @__PURE__ */ jsxs12(Text13, { children: [
10178
+ /* @__PURE__ */ jsxs13(Text14, { children: [
9877
10179
  "Repo: ",
9878
10180
  session.repo
9879
10181
  ] }),
9880
- /* @__PURE__ */ jsxs12(Text13, { children: [
10182
+ /* @__PURE__ */ jsxs13(Text14, { children: [
9881
10183
  "Status: ",
9882
10184
  session.status
9883
10185
  ] }),
9884
- /* @__PURE__ */ jsxs12(Text13, { children: [
10186
+ /* @__PURE__ */ jsxs13(Text14, { children: [
9885
10187
  "Prompt: ",
9886
10188
  session.prompt
9887
10189
  ] }),
9888
- session.prUrl && /* @__PURE__ */ jsxs12(Text13, { children: [
10190
+ session.prUrl && /* @__PURE__ */ jsxs13(Text14, { children: [
9889
10191
  "PR: ",
9890
10192
  session.prUrl
9891
10193
  ] }),
9892
- session.errorMessage && /* @__PURE__ */ jsxs12(Text13, { color: theme.error, children: [
10194
+ session.errorMessage && /* @__PURE__ */ jsxs13(Text14, { color: theme.error, children: [
9893
10195
  "Error: ",
9894
10196
  session.errorMessage
9895
10197
  ] }),
9896
- session.tokensUsed !== void 0 && /* @__PURE__ */ jsxs12(Text13, { children: [
10198
+ session.tokensUsed !== void 0 && /* @__PURE__ */ jsxs13(Text14, { children: [
9897
10199
  "Tokens: ",
9898
- formatTokens3(session.tokensUsed),
9899
- session.tokensBudget ? ` / ${formatTokens3(session.tokensBudget)}` : ""
10200
+ formatTokens4(session.tokensUsed),
10201
+ session.tokensBudget ? ` / ${formatTokens4(session.tokensBudget)}` : ""
9900
10202
  ] }),
9901
- /* @__PURE__ */ jsxs12(Text13, { children: [
10203
+ /* @__PURE__ */ jsxs13(Text14, { children: [
9902
10204
  "Created: ",
9903
10205
  new Date(session.createdAt).toLocaleString()
9904
10206
  ] }),
9905
- session.finishedAt && /* @__PURE__ */ jsxs12(Text13, { children: [
10207
+ session.finishedAt && /* @__PURE__ */ jsxs13(Text14, { children: [
9906
10208
  "Finished: ",
9907
10209
  new Date(session.finishedAt).toLocaleString()
9908
10210
  ] })
9909
10211
  ] }),
9910
- /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "row", gap: 2, children: [
9911
- isRunning && onCancel && /* @__PURE__ */ jsx14(Text13, { color: theme.error, children: cancelling ? "Cancelling..." : "[C] Cancel session" }),
9912
- /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "Esc back" })
10212
+ /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "row", gap: 2, children: [
10213
+ isRunning && onCancel && /* @__PURE__ */ jsx15(Text14, { color: theme.error, children: cancelling ? "Cancelling..." : "[C] Cancel session" }),
10214
+ /* @__PURE__ */ jsx15(Text14, { dimColor: true, children: "Esc back" })
9913
10215
  ] })
9914
10216
  ] });
9915
10217
  }
@@ -10345,23 +10647,23 @@ async function loadLog2() {
10345
10647
  }
10346
10648
  return { version: LOG_VERSION2, days: [], sessions: [] };
10347
10649
  }
10348
- async function saveLog(log) {
10650
+ async function saveLog(log2) {
10349
10651
  await mkdir10(usageDir2(), { recursive: true });
10350
- await writeFile11(usagePath2(), JSON.stringify(log, null, 2), "utf8");
10652
+ await writeFile11(usagePath2(), JSON.stringify(log2, null, 2), "utf8");
10351
10653
  }
10352
- function getOrCreateDay(log, date) {
10353
- let day = log.days.find((d) => d.date === date);
10654
+ function getOrCreateDay(log2, date) {
10655
+ let day = log2.days.find((d) => d.date === date);
10354
10656
  if (!day) {
10355
10657
  day = { date, promptTokens: 0, completionTokens: 0, cachedTokens: 0, cost: 0 };
10356
- log.days.push(day);
10658
+ log2.days.push(day);
10357
10659
  }
10358
10660
  return day;
10359
10661
  }
10360
- function getOrCreateSession(log, sessionId, date) {
10361
- let session = log.sessions.find((s) => s.id === sessionId);
10662
+ function getOrCreateSession(log2, sessionId, date) {
10663
+ let session = log2.sessions.find((s) => s.id === sessionId);
10362
10664
  if (!session) {
10363
10665
  session = { id: sessionId, date, promptTokens: 0, completionTokens: 0, cachedTokens: 0, cost: 0 };
10364
- log.sessions.push(session);
10666
+ log2.sessions.push(session);
10365
10667
  }
10366
10668
  return session;
10367
10669
  }
@@ -10410,23 +10712,23 @@ async function fetchGatewayUsageSnapshot(lookup) {
10410
10712
  }) : void 0;
10411
10713
  return toGatewaySnapshot(match, lookup.meta);
10412
10714
  }
10413
- function pruneUsageLog(log) {
10715
+ function pruneUsageLog(log2) {
10414
10716
  const dayCutoff = cutoffDate(RETENTION.usageDayMaxAgeDays);
10415
10717
  const sessionCutoff = cutoffDate(RETENTION.usageSessionMaxAgeDays);
10416
- const days = log.days.filter((d) => d.date >= dayCutoff);
10417
- let sessions = log.sessions.filter((s) => s.date >= sessionCutoff);
10718
+ const days = log2.days.filter((d) => d.date >= dayCutoff);
10719
+ let sessions = log2.sessions.filter((s) => s.date >= sessionCutoff);
10418
10720
  if (sessions.length > RETENTION.usageSessionMaxCount) {
10419
10721
  sessions = sessions.sort((a, b) => b.date < a.date ? -1 : b.date > a.date ? 1 : 0).slice(0, RETENTION.usageSessionMaxCount);
10420
10722
  }
10421
- return { ...log, days, sessions };
10723
+ return { ...log2, days, sessions };
10422
10724
  }
10423
10725
  async function recordUsage(sessionId, usage, gateway) {
10424
- const log = pruneUsageLog(await loadLog2());
10726
+ const log2 = pruneUsageLog(await loadLog2());
10425
10727
  const date = today2();
10426
10728
  const gatewaySnapshot = gateway ? await fetchGatewayUsageSnapshot(gateway).catch(() => gatewaySnapshotFromMeta(gateway.meta)) : void 0;
10427
10729
  const cost = calculateCost(usage.prompt_tokens, usage.completion_tokens, usage.prompt_tokens_details?.cached_tokens ?? 0);
10428
10730
  const totalCost = gatewaySnapshot?.cost ?? cost.total;
10429
- const day = getOrCreateDay(log, date);
10731
+ const day = getOrCreateDay(log2, date);
10430
10732
  day.promptTokens += usage.prompt_tokens;
10431
10733
  day.completionTokens += usage.completion_tokens;
10432
10734
  day.cachedTokens += usage.prompt_tokens_details?.cached_tokens ?? 0;
@@ -10436,7 +10738,7 @@ async function recordUsage(sessionId, usage, gateway) {
10436
10738
  day.gatewayCachedRequests = (day.gatewayCachedRequests ?? 0) + (gatewaySnapshot.cached ? 1 : 0);
10437
10739
  day.gatewayCost = (day.gatewayCost ?? 0) + (gatewaySnapshot.cost ?? 0);
10438
10740
  }
10439
- const session = getOrCreateSession(log, sessionId, date);
10741
+ const session = getOrCreateSession(log2, sessionId, date);
10440
10742
  session.promptTokens += usage.prompt_tokens;
10441
10743
  session.completionTokens += usage.completion_tokens;
10442
10744
  session.cachedTokens += usage.prompt_tokens_details?.cached_tokens ?? 0;
@@ -10447,14 +10749,14 @@ async function recordUsage(sessionId, usage, gateway) {
10447
10749
  session.gatewayCost = (session.gatewayCost ?? 0) + (gatewaySnapshot.cost ?? 0);
10448
10750
  session.gatewayLogs = [...session.gatewayLogs ?? [], gatewaySnapshot].slice(-100);
10449
10751
  }
10450
- await saveLog(log);
10752
+ await saveLog(log2);
10451
10753
  }
10452
10754
  async function getCostReport(sessionId) {
10453
- const log = pruneUsageLog(await loadLog2());
10755
+ const log2 = pruneUsageLog(await loadLog2());
10454
10756
  const date = today2();
10455
10757
  const currentMonth = date.slice(0, 7);
10456
- const session = sessionId ? log.sessions.find((s) => s.id === sessionId) ?? { date, promptTokens: 0, completionTokens: 0, cachedTokens: 0, cost: 0 } : { date, promptTokens: 0, completionTokens: 0, cachedTokens: 0, cost: 0 };
10457
- const todayUsage = log.days.find((d) => d.date === date) ?? { date, promptTokens: 0, completionTokens: 0, cachedTokens: 0, cost: 0 };
10758
+ const session = sessionId ? log2.sessions.find((s) => s.id === sessionId) ?? { date, promptTokens: 0, completionTokens: 0, cachedTokens: 0, cost: 0 } : { date, promptTokens: 0, completionTokens: 0, cachedTokens: 0, cost: 0 };
10759
+ const todayUsage = log2.days.find((d) => d.date === date) ?? { date, promptTokens: 0, completionTokens: 0, cachedTokens: 0, cost: 0 };
10458
10760
  const monthUsage = {
10459
10761
  date: currentMonth,
10460
10762
  promptTokens: 0,
@@ -10462,7 +10764,7 @@ async function getCostReport(sessionId) {
10462
10764
  cachedTokens: 0,
10463
10765
  cost: 0
10464
10766
  };
10465
- for (const d of log.days) {
10767
+ for (const d of log2.days) {
10466
10768
  if (d.date.startsWith(currentMonth)) {
10467
10769
  monthUsage.promptTokens += d.promptTokens;
10468
10770
  monthUsage.completionTokens += d.completionTokens;
@@ -10480,7 +10782,7 @@ async function getCostReport(sessionId) {
10480
10782
  cachedTokens: 0,
10481
10783
  cost: 0
10482
10784
  };
10483
- for (const d of log.days) {
10785
+ for (const d of log2.days) {
10484
10786
  allTime.promptTokens += d.promptTokens;
10485
10787
  allTime.completionTokens += d.completionTokens;
10486
10788
  allTime.cachedTokens += d.cachedTokens;
@@ -12148,9 +12450,9 @@ var init_save = __esm({
12148
12450
 
12149
12451
  // src/ui/command-wizard.tsx
12150
12452
  import { useState as useState8 } from "react";
12151
- import { Box as Box13, Text as Text14, useInput as useInput4, useWindowSize as useWindowSize2 } from "ink";
12453
+ import { Box as Box14, Text as Text15, useInput as useInput4, useWindowSize as useWindowSize2 } from "ink";
12152
12454
  import SelectInput6 from "ink-select-input";
12153
- import { Fragment as Fragment2, jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
12455
+ import { Fragment as Fragment2, jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
12154
12456
  function CommandWizard({ mode, initial, existingNames, builtinNames, onDone, onSave }) {
12155
12457
  const theme = useTheme();
12156
12458
  const [step, setStep] = useState8("name");
@@ -12274,8 +12576,8 @@ ${template}`;
12274
12576
  const renderStep = () => {
12275
12577
  switch (step) {
12276
12578
  case "name":
12277
- return /* @__PURE__ */ jsxs13(Fragment2, { children: [
12278
- /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
12579
+ return /* @__PURE__ */ jsxs14(Fragment2, { children: [
12580
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.accent, bold: true, children: [
12279
12581
  mode === "create" ? "Create" : "Edit",
12280
12582
  " custom command \u2014 Name (",
12281
12583
  stepIndex,
@@ -12283,8 +12585,8 @@ ${template}`;
12283
12585
  totalSteps,
12284
12586
  ")"
12285
12587
  ] }),
12286
- error && /* @__PURE__ */ jsx15(Text14, { color: theme.error, children: error }),
12287
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
12588
+ error && /* @__PURE__ */ jsx16(Text15, { color: theme.error, children: error }),
12589
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
12288
12590
  CustomTextInput,
12289
12591
  {
12290
12592
  value: name,
@@ -12293,11 +12595,11 @@ ${template}`;
12293
12595
  focus: true
12294
12596
  }
12295
12597
  ) }),
12296
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "letters, numbers, _ - / only; must start with a letter" })
12598
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "letters, numbers, _ - / only; must start with a letter" })
12297
12599
  ] });
12298
12600
  case "description":
12299
- return /* @__PURE__ */ jsxs13(Fragment2, { children: [
12300
- /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
12601
+ return /* @__PURE__ */ jsxs14(Fragment2, { children: [
12602
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.accent, bold: true, children: [
12301
12603
  mode === "create" ? "Create" : "Edit",
12302
12604
  " custom command \u2014 Description (",
12303
12605
  stepIndex,
@@ -12305,7 +12607,7 @@ ${template}`;
12305
12607
  totalSteps,
12306
12608
  ")"
12307
12609
  ] }),
12308
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
12610
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
12309
12611
  CustomTextInput,
12310
12612
  {
12311
12613
  value: description,
@@ -12314,49 +12616,49 @@ ${template}`;
12314
12616
  focus: true
12315
12617
  }
12316
12618
  ) }),
12317
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Press Enter to skip" })
12619
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "Press Enter to skip" })
12318
12620
  ] });
12319
12621
  case "template": {
12320
- const guide = /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", paddingLeft: 1, children: [
12321
- /* @__PURE__ */ jsx15(Text14, { color: theme.accent, bold: true, children: "What is this?" }),
12322
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "A prompt template \u2014 instructions to the AI." }),
12323
- /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
12622
+ const guide = /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", paddingLeft: 1, children: [
12623
+ /* @__PURE__ */ jsx16(Text15, { color: theme.accent, bold: true, children: "What is this?" }),
12624
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "A prompt template \u2014 instructions to the AI." }),
12625
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
12324
12626
  "When you type /",
12325
12627
  name || "yourcommand",
12326
12628
  " later, this gets sent to the model."
12327
12629
  ] }),
12328
- /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "column", children: [
12329
- /* @__PURE__ */ jsx15(Text14, { color: theme.accent, bold: true, children: "Variables" }),
12330
- /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
12630
+ /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, flexDirection: "column", children: [
12631
+ /* @__PURE__ */ jsx16(Text15, { color: theme.accent, bold: true, children: "Variables" }),
12632
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
12331
12633
  " ",
12332
12634
  "$1, $2 ... \u2192 arguments you type"
12333
12635
  ] }),
12334
- /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
12636
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
12335
12637
  " ",
12336
12638
  "$ARGUMENTS \u2192 everything after the command"
12337
12639
  ] })
12338
12640
  ] }),
12339
- /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "column", children: [
12340
- /* @__PURE__ */ jsx15(Text14, { color: theme.accent, bold: true, children: "Dynamic inlines" }),
12341
- /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
12641
+ /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, flexDirection: "column", children: [
12642
+ /* @__PURE__ */ jsx16(Text15, { color: theme.accent, bold: true, children: "Dynamic inlines" }),
12643
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
12342
12644
  " ",
12343
12645
  "!`git diff` \u2192 shell output inlined"
12344
12646
  ] }),
12345
- /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
12647
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
12346
12648
  " ",
12347
12649
  "@README.md \u2192 file contents inlined"
12348
12650
  ] })
12349
12651
  ] }),
12350
- /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "column", children: [
12351
- /* @__PURE__ */ jsx15(Text14, { color: theme.accent, bold: true, children: "Example" }),
12352
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Review this PR diff:" }),
12353
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "!`git diff main...HEAD`" }),
12354
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Focus on: $1" })
12652
+ /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, flexDirection: "column", children: [
12653
+ /* @__PURE__ */ jsx16(Text15, { color: theme.accent, bold: true, children: "Example" }),
12654
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "Review this PR diff:" }),
12655
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "!`git diff main...HEAD`" }),
12656
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "Focus on: $1" })
12355
12657
  ] })
12356
12658
  ] });
12357
- const inputArea = /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", flexGrow: 1, children: [
12358
- error && /* @__PURE__ */ jsx15(Text14, { color: theme.error, children: error }),
12359
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
12659
+ const inputArea = /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", flexGrow: 1, children: [
12660
+ error && /* @__PURE__ */ jsx16(Text15, { color: theme.error, children: error }),
12661
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
12360
12662
  CustomTextInput,
12361
12663
  {
12362
12664
  value: template,
@@ -12366,13 +12668,13 @@ ${template}`;
12366
12668
  enablePaste: true
12367
12669
  }
12368
12670
  ) }),
12369
- columns < 100 && /* @__PURE__ */ jsxs13(Fragment2, { children: [
12370
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Paste multi-line templates with Ctrl+V." }),
12371
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Variables: $1 $2 ... $ARGUMENTS Shell: !`cmd` File: @path" })
12671
+ columns < 100 && /* @__PURE__ */ jsxs14(Fragment2, { children: [
12672
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "Paste multi-line templates with Ctrl+V." }),
12673
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "Variables: $1 $2 ... $ARGUMENTS Shell: !`cmd` File: @path" })
12372
12674
  ] })
12373
12675
  ] });
12374
- return /* @__PURE__ */ jsxs13(Fragment2, { children: [
12375
- /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
12676
+ return /* @__PURE__ */ jsxs14(Fragment2, { children: [
12677
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.accent, bold: true, children: [
12376
12678
  mode === "create" ? "Create" : "Edit",
12377
12679
  " custom command \u2014 Template (",
12378
12680
  stepIndex,
@@ -12380,10 +12682,10 @@ ${template}`;
12380
12682
  totalSteps,
12381
12683
  ")"
12382
12684
  ] }),
12383
- columns >= 100 ? /* @__PURE__ */ jsxs13(Box13, { flexDirection: "row", marginTop: 1, children: [
12384
- /* @__PURE__ */ jsx15(Box13, { flexDirection: "column", width: "50%", children: inputArea }),
12385
- /* @__PURE__ */ jsx15(Box13, { flexDirection: "column", width: "50%", children: guide })
12386
- ] }) : /* @__PURE__ */ jsx15(Box13, { flexDirection: "column", marginTop: 1, children: inputArea })
12685
+ columns >= 100 ? /* @__PURE__ */ jsxs14(Box14, { flexDirection: "row", marginTop: 1, children: [
12686
+ /* @__PURE__ */ jsx16(Box14, { flexDirection: "column", width: "50%", children: inputArea }),
12687
+ /* @__PURE__ */ jsx16(Box14, { flexDirection: "column", width: "50%", children: guide })
12688
+ ] }) : /* @__PURE__ */ jsx16(Box14, { flexDirection: "column", marginTop: 1, children: inputArea })
12387
12689
  ] });
12388
12690
  }
12389
12691
  case "advanced": {
@@ -12392,8 +12694,8 @@ ${template}`;
12392
12694
  { label: "Skip", value: "skip", key: "skip" },
12393
12695
  { label: "\u2190 Cancel", value: "cancel", key: "cancel" }
12394
12696
  ];
12395
- return /* @__PURE__ */ jsxs13(Fragment2, { children: [
12396
- /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
12697
+ return /* @__PURE__ */ jsxs14(Fragment2, { children: [
12698
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.accent, bold: true, children: [
12397
12699
  mode === "create" ? "Create" : "Edit",
12398
12700
  " custom command \u2014 Options (",
12399
12701
  stepIndex,
@@ -12401,7 +12703,7 @@ ${template}`;
12401
12703
  totalSteps,
12402
12704
  ")"
12403
12705
  ] }),
12404
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
12706
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
12405
12707
  SelectInput6,
12406
12708
  {
12407
12709
  items,
@@ -12421,16 +12723,16 @@ ${template}`;
12421
12723
  { label: cmdMode === "auto" ? "auto \xB7 current" : "auto", value: "auto", key: "auto" },
12422
12724
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
12423
12725
  ];
12424
- return /* @__PURE__ */ jsxs13(Fragment2, { children: [
12425
- /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
12726
+ return /* @__PURE__ */ jsxs14(Fragment2, { children: [
12727
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.accent, bold: true, children: [
12426
12728
  "Mode override (",
12427
12729
  stepIndex,
12428
12730
  "/",
12429
12731
  totalSteps,
12430
12732
  ")"
12431
12733
  ] }),
12432
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Saved to file but not yet enforced at runtime" }),
12433
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
12734
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "Saved to file but not yet enforced at runtime" }),
12735
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
12434
12736
  SelectInput6,
12435
12737
  {
12436
12738
  items,
@@ -12450,15 +12752,15 @@ ${template}`;
12450
12752
  { label: cmdEffort === "high" ? "high \xB7 current" : "high", value: "high", key: "high" },
12451
12753
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
12452
12754
  ];
12453
- return /* @__PURE__ */ jsxs13(Fragment2, { children: [
12454
- /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
12755
+ return /* @__PURE__ */ jsxs14(Fragment2, { children: [
12756
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.accent, bold: true, children: [
12455
12757
  "Reasoning effort (",
12456
12758
  stepIndex,
12457
12759
  "/",
12458
12760
  totalSteps,
12459
12761
  ")"
12460
12762
  ] }),
12461
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
12763
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
12462
12764
  SelectInput6,
12463
12765
  {
12464
12766
  items,
@@ -12471,15 +12773,15 @@ ${template}`;
12471
12773
  ] });
12472
12774
  }
12473
12775
  case "model":
12474
- return /* @__PURE__ */ jsxs13(Fragment2, { children: [
12475
- /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
12776
+ return /* @__PURE__ */ jsxs14(Fragment2, { children: [
12777
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.accent, bold: true, children: [
12476
12778
  "Model override (",
12477
12779
  stepIndex,
12478
12780
  "/",
12479
12781
  totalSteps,
12480
12782
  ")"
12481
12783
  ] }),
12482
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
12784
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
12483
12785
  CustomTextInput,
12484
12786
  {
12485
12787
  value: cmdModel ?? "",
@@ -12488,7 +12790,7 @@ ${template}`;
12488
12790
  focus: true
12489
12791
  }
12490
12792
  ) }),
12491
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Press Enter to skip" })
12793
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "Press Enter to skip" })
12492
12794
  ] });
12493
12795
  case "location": {
12494
12796
  const items = [
@@ -12496,15 +12798,15 @@ ${template}`;
12496
12798
  { label: source === "global" ? "Global \xB7 current" : "Global", value: "global", key: "global" },
12497
12799
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
12498
12800
  ];
12499
- return /* @__PURE__ */ jsxs13(Fragment2, { children: [
12500
- /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
12801
+ return /* @__PURE__ */ jsxs14(Fragment2, { children: [
12802
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.accent, bold: true, children: [
12501
12803
  "Save location (",
12502
12804
  stepIndex,
12503
12805
  "/",
12504
12806
  totalSteps,
12505
12807
  ")"
12506
12808
  ] }),
12507
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
12809
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
12508
12810
  SelectInput6,
12509
12811
  {
12510
12812
  items,
@@ -12514,7 +12816,7 @@ ${template}`;
12514
12816
  }
12515
12817
  }
12516
12818
  ) }),
12517
- /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: "Project: .kimiflare/commands/ Global: ~/.config/kimiflare/commands/" })
12819
+ /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: "Project: .kimiflare/commands/ Global: ~/.config/kimiflare/commands/" })
12518
12820
  ] });
12519
12821
  }
12520
12822
  case "confirm": {
@@ -12522,8 +12824,8 @@ ${template}`;
12522
12824
  { label: "Save", value: "save", key: "save" },
12523
12825
  { label: "Cancel", value: "cancel", key: "cancel" }
12524
12826
  ];
12525
- return /* @__PURE__ */ jsxs13(Fragment2, { children: [
12526
- /* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
12827
+ return /* @__PURE__ */ jsxs14(Fragment2, { children: [
12828
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.accent, bold: true, children: [
12527
12829
  mode === "create" ? "Create" : "Edit",
12528
12830
  " custom command \u2014 Confirm (",
12529
12831
  stepIndex,
@@ -12531,13 +12833,13 @@ ${template}`;
12531
12833
  totalSteps,
12532
12834
  ")"
12533
12835
  ] }),
12534
- /* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, children: [
12836
+ /* @__PURE__ */ jsxs14(Text15, { color: theme.info.color, children: [
12535
12837
  source === "project" ? ".kimiflare/commands/" : "~/.config/kimiflare/commands/",
12536
12838
  name,
12537
12839
  ".md"
12538
12840
  ] }),
12539
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, flexDirection: "column", children: previewContent().split("\n").map((line, i) => /* @__PURE__ */ jsx15(Text14, { color: theme.info.color, children: line || " " }, i)) }),
12540
- /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(
12841
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, flexDirection: "column", children: previewContent().split("\n").map((line, i) => /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, children: line || " " }, i)) }),
12842
+ /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
12541
12843
  SelectInput6,
12542
12844
  {
12543
12845
  items,
@@ -12548,7 +12850,7 @@ ${template}`;
12548
12850
  }
12549
12851
  }
12550
12852
  };
12551
- return /* @__PURE__ */ jsx15(Box13, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: renderStep() });
12853
+ return /* @__PURE__ */ jsx16(Box14, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: renderStep() });
12552
12854
  }
12553
12855
  var NAME_RE;
12554
12856
  var init_command_wizard = __esm({
@@ -12993,9 +13295,9 @@ var init_context_generator = __esm({
12993
13295
  });
12994
13296
 
12995
13297
  // src/ui/command-picker.tsx
12996
- import { Box as Box14, Text as Text15 } from "ink";
13298
+ import { Box as Box15, Text as Text16 } from "ink";
12997
13299
  import SelectInput7 from "ink-select-input";
12998
- import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
13300
+ import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
12999
13301
  function CommandPicker({ commands, title, onPick }) {
13000
13302
  const theme = useTheme();
13001
13303
  const items = commands.map((cmd) => ({
@@ -13004,10 +13306,10 @@ function CommandPicker({ commands, title, onPick }) {
13004
13306
  key: cmd.name
13005
13307
  }));
13006
13308
  items.push({ label: "\u2190 Cancel", value: null, key: "__cancel__" });
13007
- return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
13008
- /* @__PURE__ */ jsx16(Text15, { color: theme.accent, bold: true, children: title }),
13009
- /* @__PURE__ */ jsx16(Text15, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select." }),
13010
- /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
13309
+ return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
13310
+ /* @__PURE__ */ jsx17(Text16, { color: theme.accent, bold: true, children: title }),
13311
+ /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select." }),
13312
+ /* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
13011
13313
  SelectInput7,
13012
13314
  {
13013
13315
  items,
@@ -13030,8 +13332,8 @@ var init_command_picker = __esm({
13030
13332
  });
13031
13333
 
13032
13334
  // src/ui/command-list.tsx
13033
- import { Box as Box15, Text as Text16, useInput as useInput5 } from "ink";
13034
- import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
13335
+ import { Box as Box16, Text as Text17, useInput as useInput5 } from "ink";
13336
+ import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
13035
13337
  function CommandList({ commands, onDone }) {
13036
13338
  const theme = useTheme();
13037
13339
  useInput5((_input, key) => {
@@ -13039,55 +13341,55 @@ function CommandList({ commands, onDone }) {
13039
13341
  onDone();
13040
13342
  }
13041
13343
  });
13042
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
13043
- /* @__PURE__ */ jsx17(Text16, { color: theme.accent, bold: true, children: "Custom commands" }),
13044
- /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, dimColor: false, children: "Esc to close." }),
13045
- /* @__PURE__ */ jsxs15(Box15, { marginTop: 1, flexDirection: "column", children: [
13046
- commands.length === 0 && /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, children: "No custom commands found." }),
13047
- commands.map((cmd) => /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", marginBottom: 1, children: [
13048
- /* @__PURE__ */ jsxs15(Text16, { color: theme.accent, bold: true, children: [
13344
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
13345
+ /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Custom commands" }),
13346
+ /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Esc to close." }),
13347
+ /* @__PURE__ */ jsxs16(Box16, { marginTop: 1, flexDirection: "column", children: [
13348
+ commands.length === 0 && /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, children: "No custom commands found." }),
13349
+ commands.map((cmd) => /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", marginBottom: 1, children: [
13350
+ /* @__PURE__ */ jsxs16(Text17, { color: theme.accent, bold: true, children: [
13049
13351
  "/",
13050
13352
  cmd.name
13051
13353
  ] }),
13052
- /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
13354
+ /* @__PURE__ */ jsxs16(Text17, { color: theme.info.color, children: [
13053
13355
  " ",
13054
13356
  "source: ",
13055
13357
  cmd.source
13056
13358
  ] }),
13057
- /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
13359
+ /* @__PURE__ */ jsxs16(Text17, { color: theme.info.color, children: [
13058
13360
  " ",
13059
13361
  "path: ",
13060
13362
  cmd.filepath
13061
13363
  ] }),
13062
- cmd.description && /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
13364
+ cmd.description && /* @__PURE__ */ jsxs16(Text17, { color: theme.info.color, children: [
13063
13365
  " ",
13064
13366
  "desc: ",
13065
13367
  cmd.description
13066
13368
  ] }),
13067
- cmd.mode && /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
13369
+ cmd.mode && /* @__PURE__ */ jsxs16(Text17, { color: theme.info.color, children: [
13068
13370
  " ",
13069
13371
  "mode: ",
13070
13372
  cmd.mode
13071
13373
  ] }),
13072
- cmd.effort && /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
13374
+ cmd.effort && /* @__PURE__ */ jsxs16(Text17, { color: theme.info.color, children: [
13073
13375
  " ",
13074
13376
  "effort: ",
13075
13377
  cmd.effort
13076
13378
  ] }),
13077
- cmd.model && /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
13379
+ cmd.model && /* @__PURE__ */ jsxs16(Text17, { color: theme.info.color, children: [
13078
13380
  " ",
13079
13381
  "model: ",
13080
13382
  cmd.model
13081
13383
  ] }),
13082
- /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
13384
+ /* @__PURE__ */ jsxs16(Text17, { color: theme.info.color, children: [
13083
13385
  " ",
13084
13386
  "template:"
13085
13387
  ] }),
13086
- cmd.template.split("\n").slice(0, 5).map((line, i) => /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
13388
+ cmd.template.split("\n").slice(0, 5).map((line, i) => /* @__PURE__ */ jsxs16(Text17, { color: theme.info.color, children: [
13087
13389
  " ",
13088
13390
  line || " "
13089
13391
  ] }, i)),
13090
- cmd.template.split("\n").length > 5 && /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, children: [
13392
+ cmd.template.split("\n").length > 5 && /* @__PURE__ */ jsxs16(Text17, { color: theme.info.color, children: [
13091
13393
  " ",
13092
13394
  "..."
13093
13395
  ] })
@@ -13104,10 +13406,10 @@ var init_command_list = __esm({
13104
13406
 
13105
13407
  // src/ui/lsp-wizard.tsx
13106
13408
  import { useState as useState9 } from "react";
13107
- import { Box as Box16, Text as Text17 } from "ink";
13409
+ import { Box as Box17, Text as Text18 } from "ink";
13108
13410
  import SelectInput8 from "ink-select-input";
13109
13411
  import { spawn as spawn3 } from "child_process";
13110
- import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
13412
+ import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
13111
13413
  function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
13112
13414
  const theme = useTheme();
13113
13415
  const [page, setPage] = useState9("main");
@@ -13218,10 +13520,10 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
13218
13520
  { label: "(close)", value: "__close__", key: "__close__" }
13219
13521
  ];
13220
13522
  if (page === "main") {
13221
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
13222
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "LSP Servers" }),
13223
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select." }),
13224
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
13523
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
13524
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: "LSP Servers" }),
13525
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select." }),
13526
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
13225
13527
  SelectInput8,
13226
13528
  {
13227
13529
  items: mainItems,
@@ -13249,10 +13551,10 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
13249
13551
  }),
13250
13552
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
13251
13553
  ];
13252
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
13253
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Add LSP Server" }),
13254
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Select a language server to configure." }),
13255
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
13554
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
13555
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: "Add LSP Server" }),
13556
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, dimColor: false, children: "Select a language server to configure." }),
13557
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
13256
13558
  SelectInput8,
13257
13559
  {
13258
13560
  items,
@@ -13280,18 +13582,18 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
13280
13582
  { label: isSuccess ? "Save to config \u2713" : "Save anyway", value: "save", key: "save" },
13281
13583
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
13282
13584
  ];
13283
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
13284
- /* @__PURE__ */ jsxs16(Text17, { color: theme.accent, bold: true, children: [
13585
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
13586
+ /* @__PURE__ */ jsxs17(Text18, { color: theme.accent, bold: true, children: [
13285
13587
  "Install ",
13286
13588
  selectedPreset.name
13287
13589
  ] }),
13288
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: selectedPreset.installHint }),
13289
- /* @__PURE__ */ jsxs16(Box16, { marginTop: 1, flexDirection: "column", children: [
13290
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Command:" }),
13291
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, children: selectedPreset.installCommand || "(none required)" })
13590
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, dimColor: false, children: selectedPreset.installHint }),
13591
+ /* @__PURE__ */ jsxs17(Box17, { marginTop: 1, flexDirection: "column", children: [
13592
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, dimColor: false, children: "Command:" }),
13593
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, children: selectedPreset.installCommand || "(none required)" })
13292
13594
  ] }),
13293
- installState.output && /* @__PURE__ */ jsx18(Box16, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx18(Text17, { color: isSuccess ? theme.accent : theme.error, children: installState.output.slice(-500) }) }),
13294
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
13595
+ installState.output && /* @__PURE__ */ jsx19(Box17, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx19(Text18, { color: isSuccess ? theme.accent : theme.error, children: installState.output.slice(-500) }) }),
13596
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
13295
13597
  SelectInput8,
13296
13598
  {
13297
13599
  items,
@@ -13309,16 +13611,16 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
13309
13611
  }
13310
13612
  }
13311
13613
  ) }),
13312
- isSuccess && /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(Text17, { color: theme.accent, children: "Server saved. Run /lsp reload to start it." }) })
13614
+ isSuccess && /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(Text18, { color: theme.accent, children: "Server saved. Run /lsp reload to start it." }) })
13313
13615
  ] });
13314
13616
  }
13315
13617
  if (page === "custom-name") {
13316
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
13317
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Custom LSP Server \u2014 Name" }),
13318
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Enter a name for this server (e.g., my-server)." }),
13319
- /* @__PURE__ */ jsxs16(Box16, { marginTop: 1, children: [
13320
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, children: "\u203A " }),
13321
- /* @__PURE__ */ jsx18(
13618
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
13619
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: "Custom LSP Server \u2014 Name" }),
13620
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, dimColor: false, children: "Enter a name for this server (e.g., my-server)." }),
13621
+ /* @__PURE__ */ jsxs17(Box17, { marginTop: 1, children: [
13622
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, children: "\u203A " }),
13623
+ /* @__PURE__ */ jsx19(
13322
13624
  CustomTextInput,
13323
13625
  {
13324
13626
  value: customName,
@@ -13332,7 +13634,7 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
13332
13634
  }
13333
13635
  )
13334
13636
  ] }),
13335
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
13637
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
13336
13638
  SelectInput8,
13337
13639
  {
13338
13640
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
@@ -13342,12 +13644,12 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
13342
13644
  ] });
13343
13645
  }
13344
13646
  if (page === "custom-command") {
13345
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
13346
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Custom LSP Server \u2014 Command" }),
13347
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Enter the command to start the server (space-separated)." }),
13348
- /* @__PURE__ */ jsxs16(Box16, { marginTop: 1, children: [
13349
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, children: "\u203A " }),
13350
- /* @__PURE__ */ jsx18(
13647
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
13648
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: "Custom LSP Server \u2014 Command" }),
13649
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, dimColor: false, children: "Enter the command to start the server (space-separated)." }),
13650
+ /* @__PURE__ */ jsxs17(Box17, { marginTop: 1, children: [
13651
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, children: "\u203A " }),
13652
+ /* @__PURE__ */ jsx19(
13351
13653
  CustomTextInput,
13352
13654
  {
13353
13655
  value: customCommand,
@@ -13361,7 +13663,7 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
13361
13663
  }
13362
13664
  )
13363
13665
  ] }),
13364
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
13666
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
13365
13667
  SelectInput8,
13366
13668
  {
13367
13669
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
@@ -13385,10 +13687,10 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
13385
13687
  },
13386
13688
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
13387
13689
  ];
13388
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
13389
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Save LSP Config" }),
13390
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Where should this server configuration be saved?" }),
13391
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
13690
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
13691
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: "Save LSP Config" }),
13692
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, dimColor: false, children: "Where should this server configuration be saved?" }),
13693
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
13392
13694
  SelectInput8,
13393
13695
  {
13394
13696
  items,
@@ -13407,10 +13709,10 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
13407
13709
  if (page === "edit") {
13408
13710
  const keys = Object.keys(servers);
13409
13711
  if (keys.length === 0) {
13410
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
13411
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Edit LSP Server" }),
13412
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, children: "No servers configured." }),
13413
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
13712
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
13713
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: "Edit LSP Server" }),
13714
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, children: "No servers configured." }),
13715
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
13414
13716
  SelectInput8,
13415
13717
  {
13416
13718
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
@@ -13431,10 +13733,10 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
13431
13733
  }),
13432
13734
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
13433
13735
  ];
13434
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
13435
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Edit LSP Server" }),
13436
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Select a server to toggle enabled/disabled." }),
13437
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
13736
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
13737
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: "Edit LSP Server" }),
13738
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, dimColor: false, children: "Select a server to toggle enabled/disabled." }),
13739
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
13438
13740
  SelectInput8,
13439
13741
  {
13440
13742
  items,
@@ -13452,10 +13754,10 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
13452
13754
  if (page === "delete") {
13453
13755
  const keys = Object.keys(servers);
13454
13756
  if (keys.length === 0) {
13455
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
13456
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Delete LSP Server" }),
13457
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, children: "No servers configured." }),
13458
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
13757
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
13758
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: "Delete LSP Server" }),
13759
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, children: "No servers configured." }),
13760
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
13459
13761
  SelectInput8,
13460
13762
  {
13461
13763
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
@@ -13472,10 +13774,10 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
13472
13774
  })),
13473
13775
  { label: "\u2190 Back", value: "__back__", key: "__back__" }
13474
13776
  ];
13475
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
13476
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Delete LSP Server" }),
13477
- /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Select a server to remove from config." }),
13478
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
13777
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
13778
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: "Delete LSP Server" }),
13779
+ /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, dimColor: false, children: "Select a server to remove from config." }),
13780
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
13479
13781
  SelectInput8,
13480
13782
  {
13481
13783
  items,
@@ -13492,14 +13794,14 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
13492
13794
  }
13493
13795
  if (page === "list") {
13494
13796
  const keys = Object.keys(servers);
13495
- return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
13496
- /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: "Configured LSP Servers" }),
13497
- 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) => {
13797
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
13798
+ /* @__PURE__ */ jsx19(Text18, { color: theme.accent, bold: true, children: "Configured LSP Servers" }),
13799
+ keys.length === 0 ? /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, children: "No servers configured." }) : /* @__PURE__ */ jsx19(Box17, { marginTop: 1, flexDirection: "column", children: keys.map((k) => {
13498
13800
  const s = servers[k];
13499
13801
  const status = s.enabled !== false ? "enabled" : "disabled";
13500
- return /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, children: ` ${k.padEnd(16)} ${status} ${s.command.join(" ")}` }, k);
13802
+ return /* @__PURE__ */ jsx19(Text18, { color: theme.info.color, children: ` ${k.padEnd(16)} ${status} ${s.command.join(" ")}` }, k);
13501
13803
  }) }),
13502
- /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
13804
+ /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
13503
13805
  SelectInput8,
13504
13806
  {
13505
13807
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
@@ -13626,9 +13928,9 @@ var init_lsp_wizard = __esm({
13626
13928
  });
13627
13929
 
13628
13930
  // src/ui/theme-picker.tsx
13629
- import { Box as Box17, Text as Text18 } from "ink";
13931
+ import { Box as Box18, Text as Text19 } from "ink";
13630
13932
  import SelectInput9 from "ink-select-input";
13631
- import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
13933
+ import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
13632
13934
  function PaletteSwatches({ palette }) {
13633
13935
  const colors = [
13634
13936
  palette.primary,
@@ -13636,7 +13938,7 @@ function PaletteSwatches({ palette }) {
13636
13938
  palette.success,
13637
13939
  palette.error
13638
13940
  ];
13639
- return /* @__PURE__ */ jsx19(Box17, { children: colors.map((c, i) => /* @__PURE__ */ jsx19(Text18, { color: c, children: "\u2588" }, i)) });
13941
+ return /* @__PURE__ */ jsx20(Box18, { children: colors.map((c, i) => /* @__PURE__ */ jsx20(Text19, { color: c, children: "\u2588" }, i)) });
13640
13942
  }
13641
13943
  function ThemePicker({ themes, onPick }) {
13642
13944
  const current = useTheme();
@@ -13644,9 +13946,9 @@ function ThemePicker({ themes, onPick }) {
13644
13946
  ...themes.map((t) => ({ label: t.label, value: t.name })),
13645
13947
  { label: "< Back", value: "__back__" }
13646
13948
  ];
13647
- return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: current.accent, paddingX: 1, children: [
13648
- /* @__PURE__ */ jsx19(Text18, { color: current.accent, bold: true, children: "Pick a theme (restart to apply)" }),
13649
- /* @__PURE__ */ jsx19(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx19(
13949
+ return /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", borderStyle: "round", borderColor: current.accent, paddingX: 1, children: [
13950
+ /* @__PURE__ */ jsx20(Text19, { color: current.accent, bold: true, children: "Pick a theme (restart to apply)" }),
13951
+ /* @__PURE__ */ jsx20(Box18, { marginTop: 1, children: /* @__PURE__ */ jsx20(
13650
13952
  SelectInput9,
13651
13953
  {
13652
13954
  items,
@@ -13661,9 +13963,9 @@ function ThemePicker({ themes, onPick }) {
13661
13963
  itemComponent: ({ label, isSelected }) => {
13662
13964
  const t = themes.find((x) => x.label === label);
13663
13965
  const color = t?.accent ?? current.accent;
13664
- return /* @__PURE__ */ jsxs17(Box17, { children: [
13665
- /* @__PURE__ */ jsx19(Text18, { color, bold: isSelected, dimColor: !isSelected, children: label }),
13666
- t && /* @__PURE__ */ jsx19(Box17, { marginLeft: 1, children: /* @__PURE__ */ jsx19(PaletteSwatches, { palette: t.palette }) })
13966
+ return /* @__PURE__ */ jsxs18(Box18, { children: [
13967
+ /* @__PURE__ */ jsx20(Text19, { color, bold: isSelected, dimColor: !isSelected, children: label }),
13968
+ t && /* @__PURE__ */ jsx20(Box18, { marginLeft: 1, children: /* @__PURE__ */ jsx20(PaletteSwatches, { palette: t.palette }) })
13667
13969
  ] });
13668
13970
  }
13669
13971
  }
@@ -14850,8 +15152,8 @@ var init_lsp_nudge = __esm({
14850
15152
  });
14851
15153
 
14852
15154
  // src/ui/file-picker.tsx
14853
- import { Box as Box18, Text as Text19 } from "ink";
14854
- import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
15155
+ import { Box as Box19, Text as Text20 } from "ink";
15156
+ import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
14855
15157
  function FilePicker({ items, selectedIndex, query }) {
14856
15158
  const theme = useTheme();
14857
15159
  let startIndex = 0;
@@ -14861,12 +15163,12 @@ function FilePicker({ items, selectedIndex, query }) {
14861
15163
  const visible = items.slice(startIndex, startIndex + VISIBLE_LIMIT);
14862
15164
  const hasMoreAbove = startIndex > 0;
14863
15165
  const hasMoreBelow = items.length > startIndex + VISIBLE_LIMIT;
14864
- return /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
14865
- /* @__PURE__ */ jsx20(Text19, { color: theme.accent, bold: true, children: query ? `Files matching "${query}"` : "Mention a file" }),
14866
- /* @__PURE__ */ jsx20(Text19, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select, Esc to cancel." }),
14867
- /* @__PURE__ */ jsxs18(Box18, { marginTop: 1, flexDirection: "column", children: [
14868
- visible.length === 0 && /* @__PURE__ */ jsx20(Text19, { color: theme.info.color, children: "No matches" }),
14869
- hasMoreAbove && /* @__PURE__ */ jsxs18(Text19, { color: theme.info.color, children: [
15166
+ return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
15167
+ /* @__PURE__ */ jsx21(Text20, { color: theme.accent, bold: true, children: query ? `Files matching "${query}"` : "Mention a file" }),
15168
+ /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select, Esc to cancel." }),
15169
+ /* @__PURE__ */ jsxs19(Box19, { marginTop: 1, flexDirection: "column", children: [
15170
+ visible.length === 0 && /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, children: "No matches" }),
15171
+ hasMoreAbove && /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
14870
15172
  "\u2026 ",
14871
15173
  startIndex,
14872
15174
  " more above"
@@ -14875,12 +15177,12 @@ function FilePicker({ items, selectedIndex, query }) {
14875
15177
  const actualIndex = startIndex + i;
14876
15178
  const isSelected = actualIndex === selectedIndex;
14877
15179
  const label = item.isDirectory ? `${item.name}/` : item.name;
14878
- return /* @__PURE__ */ jsxs18(Text19, { color: isSelected ? theme.accent : void 0, bold: isSelected, children: [
15180
+ return /* @__PURE__ */ jsxs19(Text20, { color: isSelected ? theme.accent : void 0, bold: isSelected, children: [
14879
15181
  isSelected ? "\u203A " : " ",
14880
15182
  label
14881
15183
  ] }, item.name);
14882
15184
  }),
14883
- hasMoreBelow && /* @__PURE__ */ jsxs18(Text19, { color: theme.info.color, children: [
15185
+ hasMoreBelow && /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
14884
15186
  "\u2026 ",
14885
15187
  items.length - (startIndex + VISIBLE_LIMIT),
14886
15188
  " more below"
@@ -14898,8 +15200,8 @@ var init_file_picker = __esm({
14898
15200
  });
14899
15201
 
14900
15202
  // src/ui/slash-picker.tsx
14901
- import { Box as Box19, Text as Text20 } from "ink";
14902
- import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
15203
+ import { Box as Box20, Text as Text21 } from "ink";
15204
+ import { jsx as jsx22, jsxs as jsxs20 } from "react/jsx-runtime";
14903
15205
  function sourceBadge(source) {
14904
15206
  if (source === "builtin") return "";
14905
15207
  if (source === "project") return "project";
@@ -14919,12 +15221,12 @@ function SlashPicker({ items, selectedIndex, query }) {
14919
15221
  const hasMoreBelow = items.length > startIndex + VISIBLE_LIMIT2;
14920
15222
  const longestLabel = visible.reduce((m, it) => Math.max(m, commandLabel(it).length), 0);
14921
15223
  const nameColWidth = Math.max(NAME_COL_MIN_WIDTH, longestLabel + NAME_DESC_GAP);
14922
- return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
14923
- /* @__PURE__ */ jsx21(Text20, { color: theme.accent, bold: true, children: query ? `Commands matching "/${query}"` : "Slash commands" }),
14924
- /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, children: "Arrow keys to navigate, Enter to select, Esc to cancel." }),
14925
- /* @__PURE__ */ jsxs19(Box19, { marginTop: 1, flexDirection: "column", children: [
14926
- visible.length === 0 && /* @__PURE__ */ jsx21(Text20, { color: theme.info.color, children: "No matches" }),
14927
- hasMoreAbove && /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
15224
+ return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
15225
+ /* @__PURE__ */ jsx22(Text21, { color: theme.accent, bold: true, children: query ? `Commands matching "/${query}"` : "Slash commands" }),
15226
+ /* @__PURE__ */ jsx22(Text21, { color: theme.info.color, children: "Arrow keys to navigate, Enter to select, Esc to cancel." }),
15227
+ /* @__PURE__ */ jsxs20(Box20, { marginTop: 1, flexDirection: "column", children: [
15228
+ visible.length === 0 && /* @__PURE__ */ jsx22(Text21, { color: theme.info.color, children: "No matches" }),
15229
+ hasMoreAbove && /* @__PURE__ */ jsxs20(Text21, { color: theme.info.color, children: [
14928
15230
  "\u2026 ",
14929
15231
  startIndex,
14930
15232
  " more above"
@@ -14934,16 +15236,16 @@ function SlashPicker({ items, selectedIndex, query }) {
14934
15236
  const isSelected = actualIndex === selectedIndex;
14935
15237
  const nameCol = commandLabel(item).padEnd(nameColWidth);
14936
15238
  const badge = sourceBadge(item.source);
14937
- return /* @__PURE__ */ jsxs19(Text20, { color: isSelected ? theme.accent : void 0, bold: isSelected, children: [
15239
+ return /* @__PURE__ */ jsxs20(Text21, { color: isSelected ? theme.accent : void 0, bold: isSelected, children: [
14938
15240
  isSelected ? "\u203A " : " ",
14939
15241
  nameCol,
14940
- /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
15242
+ /* @__PURE__ */ jsxs20(Text21, { color: theme.info.color, children: [
14941
15243
  item.description,
14942
15244
  badge && ` [${badge}]`
14943
15245
  ] })
14944
15246
  ] }, item.name);
14945
15247
  }),
14946
- hasMoreBelow && /* @__PURE__ */ jsxs19(Text20, { color: theme.info.color, children: [
15248
+ hasMoreBelow && /* @__PURE__ */ jsxs20(Text21, { color: theme.info.color, children: [
14947
15249
  "\u2026 ",
14948
15250
  items.length - (startIndex + VISIBLE_LIMIT2),
14949
15251
  " more below"
@@ -15066,15 +15368,15 @@ function filterSessions2(sessions, start, end) {
15066
15368
  return sessions.filter((s) => s.date >= start && s.date <= end);
15067
15369
  }
15068
15370
  async function getCategoryReportText(sessionId) {
15069
- const log = await loadLog3();
15371
+ const log2 = await loadLog3();
15070
15372
  const startDate = daysAgo2(7);
15071
15373
  const endDate = today3();
15072
15374
  const prevStart = daysAgo2(14);
15073
15375
  const prevEnd = daysAgo2(8);
15074
- const sessions = filterSessions2(log.sessions, startDate, endDate);
15075
- const prevSessions = filterSessions2(log.sessions, prevStart, prevEnd);
15376
+ const sessions = filterSessions2(log2.sessions, startDate, endDate);
15377
+ const prevSessions = filterSessions2(log2.sessions, prevStart, prevEnd);
15076
15378
  if (sessionId) {
15077
- const session = log.sessions.find((s) => s.id === sessionId);
15379
+ const session = log2.sessions.find((s) => s.id === sessionId);
15078
15380
  if (session && !session.category) {
15079
15381
  const result = await classifyFromSessionFile(sessionId);
15080
15382
  session.category = result.category;
@@ -15123,7 +15425,7 @@ __export(app_exports, {
15123
15425
  shouldOpenSlashPicker: () => shouldOpenSlashPicker
15124
15426
  });
15125
15427
  import React13, { useState as useState10, useRef as useRef3, useEffect as useEffect7, useCallback as useCallback2 } from "react";
15126
- import { Box as Box20, Text as Text21, useApp, useInput as useInput6, render } from "ink";
15428
+ import { Box as Box21, Text as Text22, useApp, useInput as useInput6, render } from "ink";
15127
15429
  import SelectInput10 from "ink-select-input";
15128
15430
  import { existsSync as existsSync3, statSync as statSync4 } from "fs";
15129
15431
  import { join as join26 } from "path";
@@ -15133,7 +15435,7 @@ import { spawn as spawn4 } from "child_process";
15133
15435
  import { platform as platform2 } from "os";
15134
15436
  import fg4 from "fast-glob";
15135
15437
  import { readFileSync as readFileSync3 } from "fs";
15136
- import { jsx as jsx22, jsxs as jsxs20 } from "react/jsx-runtime";
15438
+ import { jsx as jsx23, jsxs as jsxs21 } from "react/jsx-runtime";
15137
15439
  function buildFilePickerIgnoreList(cwd) {
15138
15440
  const hardcoded = [
15139
15441
  // Dependencies
@@ -15299,7 +15601,7 @@ function detectGitBranch() {
15299
15601
  return null;
15300
15602
  }
15301
15603
  }
15302
- function formatTokens4(n) {
15604
+ function formatTokens5(n) {
15303
15605
  if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
15304
15606
  if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
15305
15607
  return String(n);
@@ -15482,7 +15784,11 @@ ${wcagWarnings.join("\n")}` }
15482
15784
  );
15483
15785
  const executorRef = useRef3(new ToolExecutor(ALL_TOOLS));
15484
15786
  const activeAsstIdRef = useRef3(null);
15485
- const activeControllerRef = useRef3(null);
15787
+ const sessionScopeRef = useRef3(new AbortScope());
15788
+ const activeScopeRef = useRef3(null);
15789
+ const supervisorRef = useRef3(new TurnSupervisor());
15790
+ const isAbortingRef = useRef3(false);
15791
+ const lastEscapeAtRef = useRef3(0);
15486
15792
  const permResolveRef = useRef3(null);
15487
15793
  const limitResolveRef = useRef3(null);
15488
15794
  const pendingToolCallsRef = useRef3(/* @__PURE__ */ new Map());
@@ -15515,9 +15821,6 @@ ${wcagWarnings.join("\n")}` }
15515
15821
  const flushTimeoutRef = useRef3(null);
15516
15822
  const customCommandsRef = useRef3([]);
15517
15823
  const pickerCancelRef = useRef3(null);
15518
- useEffect7(() => {
15519
- busyRef.current = busy;
15520
- }, [busy]);
15521
15824
  const pickerAnchor = activePicker?.anchor ?? null;
15522
15825
  const pickerKind = activePicker?.kind ?? null;
15523
15826
  const pickerQuery = React13.useMemo(() => {
@@ -16156,18 +16459,28 @@ ${wcagWarnings.join("\n")}` }
16156
16459
  limitResolveRef.current = null;
16157
16460
  setLimitModal(null);
16158
16461
  }
16159
- if (busyRef.current && activeControllerRef.current) {
16160
- activeControllerRef.current.abort();
16462
+ if (busyRef.current && activeScopeRef.current && !isAbortingRef.current) {
16463
+ isAbortingRef.current = true;
16464
+ supervisorRef.current.killTurn();
16465
+ activeScopeRef.current.abort("user_stopped");
16161
16466
  setQueue([]);
16162
16467
  setEvents((e) => [...e, { kind: "info", key: mkKey(), text: "(interrupted)" }]);
16468
+ setTasks([]);
16469
+ setTasksStartedAt(null);
16470
+ setTasksStartTokens(0);
16471
+ tasksRef.current = [];
16163
16472
  } else if (!hadPerm && !hadLimit) {
16164
16473
  void lspManagerRef.current.stopAll().finally(() => exit());
16165
16474
  }
16166
16475
  return;
16167
16476
  }
16168
16477
  if (key.escape) {
16478
+ const now2 = Date.now();
16169
16479
  const modalOpen = perm !== null || limitModal !== null || showLspWizard || showCommandList || commandWizard !== null || commandToDelete !== null || resumeSessions !== null || showThemePicker;
16170
- if (!modalOpen && busyRef.current && activeControllerRef.current) {
16480
+ if (!modalOpen && busyRef.current && activeScopeRef.current && !isAbortingRef.current && now2 - lastEscapeAtRef.current > 500) {
16481
+ lastEscapeAtRef.current = now2;
16482
+ isAbortingRef.current = true;
16483
+ supervisorRef.current.killTurn();
16171
16484
  if (permResolveRef.current) {
16172
16485
  permResolveRef.current("deny");
16173
16486
  permResolveRef.current = null;
@@ -16178,9 +16491,13 @@ ${wcagWarnings.join("\n")}` }
16178
16491
  limitResolveRef.current = null;
16179
16492
  setLimitModal(null);
16180
16493
  }
16181
- activeControllerRef.current.abort();
16494
+ activeScopeRef.current.abort("user_stopped");
16182
16495
  setQueue([]);
16183
16496
  setEvents((e) => [...e, { kind: "info", key: mkKey(), text: "(interrupted)" }]);
16497
+ setTasks([]);
16498
+ setTasksStartedAt(null);
16499
+ setTasksStartTokens(0);
16500
+ tasksRef.current = [];
16184
16501
  return;
16185
16502
  }
16186
16503
  }
@@ -16265,9 +16582,10 @@ ${wcagWarnings.join("\n")}` }
16265
16582
  return;
16266
16583
  }
16267
16584
  setBusy(true);
16585
+ busyRef.current = true;
16268
16586
  setTurnStartedAt(Date.now());
16269
- const controller = new AbortController();
16270
- activeControllerRef.current = controller;
16587
+ const turnScope = sessionScopeRef.current.createChild();
16588
+ activeScopeRef.current = turnScope;
16271
16589
  try {
16272
16590
  if (compiledContextRef.current) {
16273
16591
  const store = artifactStoreRef.current;
@@ -16305,7 +16623,7 @@ ${wcagWarnings.join("\n")}` }
16305
16623
  apiToken: cfg.apiToken,
16306
16624
  model: cfg.model,
16307
16625
  messages: messagesRef.current,
16308
- signal: controller.signal,
16626
+ signal: turnScope.signal,
16309
16627
  gateway: gatewayFromConfig(cfg)
16310
16628
  });
16311
16629
  if (result.replacedCount === 0) {
@@ -16340,11 +16658,12 @@ ${wcagWarnings.join("\n")}` }
16340
16658
  }
16341
16659
  } finally {
16342
16660
  setBusy(false);
16661
+ busyRef.current = false;
16343
16662
  setTurnStartedAt(null);
16344
16663
  setTurnPhase("waiting");
16345
16664
  setCurrentToolName(null);
16346
16665
  setLastActivityAt(null);
16347
- activeControllerRef.current = null;
16666
+ activeScopeRef.current = null;
16348
16667
  permResolveRef.current = null;
16349
16668
  limitResolveRef.current = null;
16350
16669
  pendingToolCallsRef.current.clear();
@@ -16365,9 +16684,10 @@ ${wcagWarnings.join("\n")}` }
16365
16684
  setEvents((e) => [...e, { kind: "user", key: mkKey(), text: isRefresh ? `/init (refreshing ${targetFilename})` : "/init" }]);
16366
16685
  messagesRef.current.push({ role: "user", content: sanitizeString(prompt) });
16367
16686
  setBusy(true);
16687
+ busyRef.current = true;
16368
16688
  setTurnStartedAt(Date.now());
16369
- const controller = new AbortController();
16370
- activeControllerRef.current = controller;
16689
+ const turnScope = sessionScopeRef.current.createChild();
16690
+ activeScopeRef.current = turnScope;
16371
16691
  const initClassification = classifyIntent(prompt);
16372
16692
  const initEffortForTier = {
16373
16693
  light: "low",
@@ -16387,7 +16707,7 @@ ${wcagWarnings.join("\n")}` }
16387
16707
  tools: [...ALL_TOOLS, ...mcpToolsRef.current, ...lspToolsRef.current],
16388
16708
  executor: executorRef.current,
16389
16709
  cwd,
16390
- signal: controller.signal,
16710
+ signal: turnScope.signal,
16391
16711
  reasoningEffort: initReasoningEffort,
16392
16712
  intentClassification: initClassification,
16393
16713
  coauthor: cfg.coauthor !== false ? { name: cfg.coauthorName || "kimiflare", email: cfg.coauthorEmail || "kimiflare@proton.me" } : void 0,
@@ -16555,13 +16875,42 @@ ${wcagWarnings.join("\n")}` }
16555
16875
  messagesRef.current.push({
16556
16876
  role: "tool",
16557
16877
  tool_call_id: tcId,
16558
- content: "(interrupted)",
16878
+ content: "(stopped)",
16559
16879
  name: tcName
16560
16880
  });
16561
16881
  }
16562
16882
  setEvents(
16563
- (evts) => evts.map((e2) => e2.kind === "tool" && e2.status === "running" ? { ...e2, status: "error", result: "(interrupted)" } : e2)
16883
+ (evts) => evts.map((e2) => e2.kind === "tool" && e2.status === "running" ? { ...e2, status: "error", result: "(stopped)" } : e2)
16564
16884
  );
16885
+ } else if (cfg?.cloudMode && isCloudQuotaExhaustedError(e)) {
16886
+ const token = cloudToken ?? initialCloudToken;
16887
+ const did = cloudDeviceId ?? initialCloudDeviceId;
16888
+ let used = 0;
16889
+ let limit = 0;
16890
+ let expiresAt = "";
16891
+ if (token) {
16892
+ try {
16893
+ const { fetchCloudUsage: fetchCloudUsage2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
16894
+ const usage2 = await fetchCloudUsage2(token, did);
16895
+ if (usage2) {
16896
+ used = usage2.input_tokens_used;
16897
+ limit = usage2.input_token_limit;
16898
+ expiresAt = usage2.expires_at;
16899
+ }
16900
+ } catch {
16901
+ }
16902
+ }
16903
+ if (!limit) {
16904
+ const m = e.message.match(/Used ([\d,]+)\s*\/\s*([\d,]+)/);
16905
+ if (m && m[1] && m[2]) {
16906
+ used = parseInt(m[1].replace(/,/g, ""), 10);
16907
+ limit = parseInt(m[2].replace(/,/g, ""), 10);
16908
+ }
16909
+ }
16910
+ setEvents((es) => [
16911
+ ...es,
16912
+ { kind: "cloud_quota_exhausted", key: mkKey(), used, limit, expiresAt }
16913
+ ]);
16565
16914
  } else {
16566
16915
  setEvents((es) => [
16567
16916
  ...es,
@@ -16573,12 +16922,13 @@ ${wcagWarnings.join("\n")}` }
16573
16922
  const asstId = activeAsstIdRef.current;
16574
16923
  if (asstId !== null) updateAssistant(asstId, () => ({ streaming: false }));
16575
16924
  setBusy(false);
16925
+ busyRef.current = false;
16576
16926
  setTurnStartedAt(null);
16577
16927
  setTurnPhase("waiting");
16578
16928
  setCurrentToolName(null);
16579
16929
  setLastActivityAt(null);
16580
16930
  activeAsstIdRef.current = null;
16581
- activeControllerRef.current = null;
16931
+ activeScopeRef.current = null;
16582
16932
  permResolveRef.current = null;
16583
16933
  limitResolveRef.current = null;
16584
16934
  pendingToolCallsRef.current.clear();
@@ -17385,7 +17735,7 @@ ${lines.join("\n")}` }]);
17385
17735
  setEvents((e) => [
17386
17736
  ...e,
17387
17737
  { kind: "info", key: mkKey(), text: `Starting remote session for ${repo.owner}/${repo.name}...` },
17388
- { kind: "info", key: mkKey(), text: `Budget: ${formatTokens4(budget)} tokens. TTL: ${ttl} min.` }
17738
+ { kind: "info", key: mkKey(), text: `Budget: ${formatTokens5(budget)} tokens. TTL: ${ttl} min.` }
17389
17739
  ]);
17390
17740
  try {
17391
17741
  const data = await startRemoteSession({
@@ -17402,7 +17752,7 @@ ${lines.join("\n")}` }]);
17402
17752
  for await (const ev of streamRemoteProgress(
17403
17753
  finalCfg.remoteWorkerUrl,
17404
17754
  data.sessionId,
17405
- activeControllerRef.current?.signal
17755
+ activeScopeRef.current?.signal
17406
17756
  )) {
17407
17757
  const event = ev;
17408
17758
  if (event.type === "text_delta") {
@@ -17529,7 +17879,7 @@ ${lines.join("\n")}` }]);
17529
17879
  [reloadCustomCommands, setEvents]
17530
17880
  );
17531
17881
  const processMessage = useCallback2(
17532
- async (text, displayText) => {
17882
+ async (text, displayText, opts2) => {
17533
17883
  if (!cfg) return;
17534
17884
  let trimmed = text.trim();
17535
17885
  if (!trimmed) return;
@@ -17597,7 +17947,15 @@ ${lines.join("\n")}` }]);
17597
17947
  await sessionStartRecallRef.current;
17598
17948
  sessionStartRecallRef.current = null;
17599
17949
  }
17600
- setEvents((e) => [...e, { kind: "user", key: mkKey(), text: display, images: images.length > 0 ? images : void 0 }]);
17950
+ if (opts2?.queuedKey) {
17951
+ setEvents(
17952
+ (evts) => evts.map(
17953
+ (e) => e.kind === "user" && e.key === opts2.queuedKey ? { ...e, text: display, images: images.length > 0 ? images : void 0, queued: false } : e
17954
+ )
17955
+ );
17956
+ } else {
17957
+ setEvents((e) => [...e, { kind: "user", key: mkKey(), text: display, images: images.length > 0 ? images : void 0 }]);
17958
+ }
17601
17959
  const nudge = maybeLspNudge(display, cfg?.lspEnabled ?? false, cfg?.lspServers ?? {});
17602
17960
  if (nudge) {
17603
17961
  setEvents((e) => [...e, { kind: "info", key: mkKey(), text: nudge }]);
@@ -17622,6 +17980,7 @@ ${lines.join("\n")}` }]);
17622
17980
  ]);
17623
17981
  }
17624
17982
  setBusy(true);
17983
+ busyRef.current = true;
17625
17984
  gatewayMetaRef.current = null;
17626
17985
  setGatewayMeta(null);
17627
17986
  setTurnStartedAt(Date.now());
@@ -17684,8 +18043,8 @@ ${lines.join("\n")}` }]);
17684
18043
  memoryRecalled: false
17685
18044
  }
17686
18045
  ]);
17687
- const controller = new AbortController();
17688
- activeControllerRef.current = controller;
18046
+ const turnScope = sessionScopeRef.current.createChild();
18047
+ activeScopeRef.current = turnScope;
17689
18048
  const sharedCallbacks = {
17690
18049
  onAssistantStart: () => {
17691
18050
  const id = nextAssistantId++;
@@ -17825,8 +18184,32 @@ ${lines.join("\n")}` }]);
17825
18184
  }
17826
18185
  }
17827
18186
  };
17828
- try {
17829
- await runAgentTurn({
18187
+ const cleanupTurn = () => {
18188
+ setCodeMode(false);
18189
+ const asstId = activeAsstIdRef.current;
18190
+ if (asstId !== null) updateAssistant(asstId, () => ({ streaming: false }));
18191
+ setBusy(false);
18192
+ busyRef.current = false;
18193
+ setTurnStartedAt(null);
18194
+ setTurnPhase("waiting");
18195
+ setCurrentToolName(null);
18196
+ setLastActivityAt(null);
18197
+ activeAsstIdRef.current = null;
18198
+ activeScopeRef.current = null;
18199
+ isAbortingRef.current = false;
18200
+ permResolveRef.current = null;
18201
+ limitResolveRef.current = null;
18202
+ pendingToolCallsRef.current.clear();
18203
+ setTasks([]);
18204
+ setTasksStartedAt(null);
18205
+ setTasksStartTokens(0);
18206
+ tasksRef.current = [];
18207
+ setEvents(
18208
+ (evts) => evts.map((e) => e.kind === "tool" && e.status === "running" ? { ...e, status: "error", result: "(stopped)" } : e)
18209
+ );
18210
+ };
18211
+ supervisorRef.current.startTurn(
18212
+ {
17830
18213
  accountId: cfg.accountId,
17831
18214
  apiToken: cfg.apiToken,
17832
18215
  model: overrideModel ?? cfg.model,
@@ -17835,7 +18218,7 @@ ${lines.join("\n")}` }]);
17835
18218
  tools: [...ALL_TOOLS, ...mcpToolsRef.current, ...lspToolsRef.current],
17836
18219
  executor: executorRef.current,
17837
18220
  cwd: process.cwd(),
17838
- signal: controller.signal,
18221
+ signal: turnScope.signal,
17839
18222
  reasoningEffort: turnReasoningEffort,
17840
18223
  coauthor: cfg.coauthor !== false ? { name: cfg.coauthorName || "kimiflare", email: cfg.coauthorEmail || "kimiflare@proton.me" } : void 0,
17841
18224
  sessionId: ensureSessionId(),
@@ -17860,146 +18243,170 @@ ${lines.join("\n")}` }]);
17860
18243
  }
17861
18244
  },
17862
18245
  callbacks: sharedCallbacks
17863
- });
17864
- await saveSessionSafe();
17865
- if (shouldCompact({ messages: messagesRef.current })) {
17866
- if (compiledContextRef.current) {
17867
- const store = artifactStoreRef.current;
17868
- const result = compactMessages2({
17869
- messages: messagesRef.current,
17870
- state: sessionStateRef.current,
17871
- store
17872
- });
17873
- if (result.metrics.rawTurnsRemoved > 0) {
17874
- messagesRef.current = result.newMessages;
17875
- sessionStateRef.current = result.newState;
17876
- setEvents((e) => [
17877
- ...e,
17878
- {
17879
- kind: "info",
17880
- key: mkKey(),
17881
- text: `auto-compacted: ${result.metrics.estimatedTokensBefore} \u2192 ${result.metrics.estimatedTokensAfter} tokens (${result.metrics.archivedArtifacts} artifacts)`
18246
+ },
18247
+ {
18248
+ onDone: async () => {
18249
+ await saveSessionSafe();
18250
+ if (turnScope.signal.aborted) {
18251
+ cleanupTurn();
18252
+ return;
18253
+ }
18254
+ if (shouldCompact({ messages: messagesRef.current })) {
18255
+ if (compiledContextRef.current) {
18256
+ const store = artifactStoreRef.current;
18257
+ const result = compactMessages2({
18258
+ messages: messagesRef.current,
18259
+ state: sessionStateRef.current,
18260
+ store
18261
+ });
18262
+ if (result.metrics.rawTurnsRemoved > 0) {
18263
+ messagesRef.current = result.newMessages;
18264
+ sessionStateRef.current = result.newState;
18265
+ setEvents((e) => [
18266
+ ...e,
18267
+ {
18268
+ kind: "info",
18269
+ key: mkKey(),
18270
+ text: `auto-compacted: ${result.metrics.estimatedTokensBefore} \u2192 ${result.metrics.estimatedTokensAfter} tokens (${result.metrics.archivedArtifacts} artifacts)`
18271
+ }
18272
+ ]);
18273
+ await saveSessionSafe();
17882
18274
  }
17883
- ]);
17884
- await saveSessionSafe();
18275
+ } else {
18276
+ try {
18277
+ const result = await compactMessages({
18278
+ accountId: cfg.accountId,
18279
+ apiToken: cfg.apiToken,
18280
+ model: cfg.model,
18281
+ messages: messagesRef.current,
18282
+ signal: turnScope.signal,
18283
+ gateway: gatewayFromConfig(cfg)
18284
+ });
18285
+ if (result.replacedCount > 0) {
18286
+ messagesRef.current = result.newMessages;
18287
+ setEvents((e) => [
18288
+ ...e,
18289
+ {
18290
+ kind: "info",
18291
+ key: mkKey(),
18292
+ text: `auto-compacted: ${result.replacedCount} messages summarized`
18293
+ }
18294
+ ]);
18295
+ await saveSessionSafe();
18296
+ }
18297
+ } catch (compactErr) {
18298
+ if (compactErr.name !== "AbortError") {
18299
+ setEvents((es) => [
18300
+ ...es,
18301
+ {
18302
+ kind: "info",
18303
+ key: mkKey(),
18304
+ text: `auto-compact failed: ${compactErr.message ?? String(compactErr)}`
18305
+ }
18306
+ ]);
18307
+ }
18308
+ }
18309
+ }
17885
18310
  }
17886
- } else {
17887
- try {
17888
- const result = await compactMessages({
17889
- accountId: cfg.accountId,
17890
- apiToken: cfg.apiToken,
17891
- model: cfg.model,
17892
- messages: messagesRef.current,
17893
- signal: controller.signal,
17894
- gateway: gatewayFromConfig(cfg)
17895
- });
17896
- if (result.replacedCount > 0) {
17897
- messagesRef.current = result.newMessages;
17898
- setEvents((e) => [
17899
- ...e,
17900
- {
17901
- kind: "info",
17902
- key: mkKey(),
17903
- text: `auto-compacted: ${result.replacedCount} messages summarized`
18311
+ const manager = memoryManagerRef.current;
18312
+ if (manager) {
18313
+ try {
18314
+ const cwd = process.cwd();
18315
+ const queryText = sessionStateRef.current.task || cwd;
18316
+ const results = await manager.recall({ text: queryText, repoPath: cwd, limit: 5 });
18317
+ if (results.length > 0) {
18318
+ const text2 = await manager.synthesizeRecalled(results);
18319
+ const lastSystemIdx = messagesRef.current.findLastIndex((m) => m.role === "system");
18320
+ const insertIdx = lastSystemIdx >= 0 ? lastSystemIdx + 1 : messagesRef.current.length;
18321
+ messagesRef.current.splice(insertIdx, 0, { role: "system", content: text2 });
18322
+ setEvents((e) => [
18323
+ ...e,
18324
+ {
18325
+ kind: "memory",
18326
+ key: mkKey(),
18327
+ text: `recalled ${results.length} memory${results.length === 1 ? "" : "ies"} after compaction`
18328
+ }
18329
+ ]);
18330
+ await saveSessionSafe();
18331
+ }
18332
+ } catch {
18333
+ }
18334
+ }
18335
+ cleanupTurn();
18336
+ },
18337
+ onError: async (e) => {
18338
+ if (e.name === "AbortError") {
18339
+ for (const [tcId, tcName] of pendingToolCallsRef.current) {
18340
+ messagesRef.current.push({
18341
+ role: "tool",
18342
+ tool_call_id: tcId,
18343
+ content: "(stopped)",
18344
+ name: tcName
18345
+ });
18346
+ }
18347
+ setEvents(
18348
+ (evts) => evts.map((e2) => e2.kind === "tool" && e2.status === "running" ? { ...e2, status: "error", result: "(stopped)" } : e2)
18349
+ );
18350
+ } else if (cfg?.cloudMode && isCloudQuotaExhaustedError(e)) {
18351
+ const token = cloudToken ?? initialCloudToken;
18352
+ const did = cloudDeviceId ?? initialCloudDeviceId;
18353
+ let used = 0;
18354
+ let limit = 0;
18355
+ let expiresAt = "";
18356
+ if (token) {
18357
+ try {
18358
+ const { fetchCloudUsage: fetchCloudUsage2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
18359
+ const usage2 = await fetchCloudUsage2(token, did);
18360
+ if (usage2) {
18361
+ used = usage2.input_tokens_used;
18362
+ limit = usage2.input_token_limit;
18363
+ expiresAt = usage2.expires_at;
17904
18364
  }
17905
- ]);
17906
- await saveSessionSafe();
18365
+ } catch {
18366
+ }
18367
+ }
18368
+ if (!limit) {
18369
+ const m = e.message.match(/Used ([\d,]+)\s*\/\s*([\d,]+)/);
18370
+ if (m && m[1] && m[2]) {
18371
+ used = parseInt(m[1].replace(/,/g, ""), 10);
18372
+ limit = parseInt(m[2].replace(/,/g, ""), 10);
18373
+ }
17907
18374
  }
17908
- } catch (compactErr) {
17909
- if (compactErr.name !== "AbortError") {
18375
+ setEvents((es) => [
18376
+ ...es,
18377
+ { kind: "cloud_quota_exhausted", key: mkKey(), used, limit, expiresAt }
18378
+ ]);
18379
+ } else {
18380
+ const isInvalidJson400 = e instanceof KimiApiError && e.httpStatus === 400 && e.message.includes("invalid escaped character");
18381
+ if (isInvalidJson400) {
18382
+ messagesRef.current.pop();
17910
18383
  setEvents((es) => [
17911
18384
  ...es,
17912
18385
  {
17913
- kind: "info",
18386
+ kind: "error",
17914
18387
  key: mkKey(),
17915
- text: `auto-compact failed: ${compactErr.message ?? String(compactErr)}`
18388
+ text: "API rejected request (invalid JSON in conversation history). Retrying may work; run /clear to reset if it persists."
17916
18389
  }
17917
18390
  ]);
17918
18391
  } else {
17919
- throw compactErr;
18392
+ setEvents((es) => [
18393
+ ...es,
18394
+ { kind: "error", key: mkKey(), text: e.message ?? String(e) }
18395
+ ]);
17920
18396
  }
17921
18397
  }
18398
+ cleanupTurn();
17922
18399
  }
17923
18400
  }
17924
- const manager = memoryManagerRef.current;
17925
- if (manager) {
17926
- try {
17927
- const cwd = process.cwd();
17928
- const queryText = sessionStateRef.current.task || cwd;
17929
- const results = await manager.recall({ text: queryText, repoPath: cwd, limit: 5 });
17930
- if (results.length > 0) {
17931
- const text2 = await manager.synthesizeRecalled(results);
17932
- const lastSystemIdx = messagesRef.current.findLastIndex((m) => m.role === "system");
17933
- const insertIdx = lastSystemIdx >= 0 ? lastSystemIdx + 1 : messagesRef.current.length;
17934
- messagesRef.current.splice(insertIdx, 0, { role: "system", content: text2 });
17935
- setEvents((e) => [
17936
- ...e,
17937
- {
17938
- kind: "memory",
17939
- key: mkKey(),
17940
- text: `recalled ${results.length} memory${results.length === 1 ? "" : "ies"} after compaction`
17941
- }
17942
- ]);
17943
- await saveSessionSafe();
17944
- }
17945
- } catch {
17946
- }
17947
- }
17948
- } catch (e) {
17949
- if (e.name === "AbortError") {
17950
- for (const [tcId, tcName] of pendingToolCallsRef.current) {
17951
- messagesRef.current.push({
17952
- role: "tool",
17953
- tool_call_id: tcId,
17954
- content: "(interrupted)",
17955
- name: tcName
17956
- });
17957
- }
17958
- setEvents(
17959
- (evts) => evts.map((e2) => e2.kind === "tool" && e2.status === "running" ? { ...e2, status: "error", result: "(interrupted)" } : e2)
17960
- );
17961
- } else {
17962
- const isInvalidJson400 = e instanceof KimiApiError && e.httpStatus === 400 && e.message.includes("invalid escaped character");
17963
- if (isInvalidJson400) {
17964
- messagesRef.current.pop();
17965
- setEvents((es) => [
17966
- ...es,
17967
- {
17968
- kind: "error",
17969
- key: mkKey(),
17970
- text: "API rejected request (invalid JSON in conversation history). Retrying may work; run /clear to reset if it persists."
17971
- }
17972
- ]);
17973
- } else {
17974
- setEvents((es) => [
17975
- ...es,
17976
- { kind: "error", key: mkKey(), text: e.message ?? String(e) }
17977
- ]);
17978
- }
17979
- }
17980
- } finally {
17981
- setCodeMode(false);
17982
- const asstId = activeAsstIdRef.current;
17983
- if (asstId !== null) updateAssistant(asstId, () => ({ streaming: false }));
17984
- setBusy(false);
17985
- setTurnStartedAt(null);
17986
- setTurnPhase("waiting");
17987
- setCurrentToolName(null);
17988
- setLastActivityAt(null);
17989
- activeAsstIdRef.current = null;
17990
- activeControllerRef.current = null;
17991
- permResolveRef.current = null;
17992
- limitResolveRef.current = null;
17993
- pendingToolCallsRef.current.clear();
17994
- }
18401
+ );
17995
18402
  },
17996
18403
  [cfg, handleSlash, updateAssistant, updateTool, saveSessionSafe, updateGatewayMeta]
17997
18404
  );
17998
18405
  useEffect7(() => {
17999
- if (!busy && queue.length > 0) {
18406
+ if (!busy && queue.length > 0 && supervisorRef.current.phase === "idle") {
18000
18407
  const next = queue[0];
18001
18408
  setQueue((q) => q.slice(1));
18002
- processMessage(next.full, next.display);
18409
+ processMessage(next.full, next.display, { queuedKey: next.key });
18003
18410
  }
18004
18411
  }, [busy, queue, processMessage]);
18005
18412
  const submit = useCallback2(
@@ -18008,8 +18415,20 @@ ${lines.join("\n")}` }]);
18008
18415
  if (!trimmedFull) return;
18009
18416
  const trimmedDisplay = (display ?? full).trim() || trimmedFull;
18010
18417
  const historyEntry = trimmedDisplay;
18011
- if (busy) {
18012
- setQueue((q) => [...q, { full: trimmedFull, display: trimmedDisplay }]);
18418
+ if (busyRef.current) {
18419
+ if (activeScopeRef.current && !isAbortingRef.current) {
18420
+ isAbortingRef.current = true;
18421
+ supervisorRef.current.killTurn();
18422
+ activeScopeRef.current.abort("new_message");
18423
+ setEvents((e) => [...e, { kind: "info", key: mkKey(), text: "(preempted)" }]);
18424
+ setTasks([]);
18425
+ setTasksStartedAt(null);
18426
+ setTasksStartTokens(0);
18427
+ tasksRef.current = [];
18428
+ }
18429
+ const key = mkKey();
18430
+ setEvents((e) => [...e, { kind: "user", key, text: trimmedDisplay, queued: true }]);
18431
+ setQueue((q) => [...q, { full: trimmedFull, display: trimmedDisplay, key }]);
18013
18432
  setHistory((h) => h.length > 0 && h[h.length - 1] === historyEntry ? h : [...h, historyEntry]);
18014
18433
  setInput("");
18015
18434
  setHistoryIndex(-1);
@@ -18020,7 +18439,7 @@ ${lines.join("\n")}` }]);
18020
18439
  setHistoryIndex(-1);
18021
18440
  processMessage(trimmedFull, trimmedDisplay !== trimmedFull ? trimmedDisplay : void 0);
18022
18441
  },
18023
- [busy, processMessage]
18442
+ [processMessage]
18024
18443
  );
18025
18444
  submitRef.current = submit;
18026
18445
  useEffect7(() => {
@@ -18038,7 +18457,7 @@ ${lines.join("\n")}` }]);
18038
18457
  }
18039
18458
  }, [usage]);
18040
18459
  if (!cfg) {
18041
- return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(
18460
+ return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsx23(
18042
18461
  Onboarding,
18043
18462
  {
18044
18463
  onCancel: () => exit(),
@@ -18070,10 +18489,10 @@ ${lines.join("\n")}` }]);
18070
18489
  ) });
18071
18490
  }
18072
18491
  if (resumeSessions !== null) {
18073
- return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx22(ResumePicker, { sessions: resumeSessions, onPick: handleResumePick }) }) });
18492
+ return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsx23(Box21, { flexDirection: "column", children: /* @__PURE__ */ jsx23(ResumePicker, { sessions: resumeSessions, onPick: handleResumePick }) }) });
18074
18493
  }
18075
18494
  if (showRemoteDashboard) {
18076
- return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: selectedRemoteSession ? /* @__PURE__ */ jsx22(
18495
+ return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsx23(Box21, { flexDirection: "column", children: selectedRemoteSession ? /* @__PURE__ */ jsx23(
18077
18496
  RemoteSessionDetail,
18078
18497
  {
18079
18498
  session: selectedRemoteSession,
@@ -18096,7 +18515,7 @@ ${lines.join("\n")}` }]);
18096
18515
  setShowRemoteDashboard(false);
18097
18516
  }
18098
18517
  }
18099
- ) : /* @__PURE__ */ jsx22(
18518
+ ) : /* @__PURE__ */ jsx23(
18100
18519
  RemoteDashboard,
18101
18520
  {
18102
18521
  onSelect: (session) => setSelectedRemoteSession(session),
@@ -18105,7 +18524,7 @@ ${lines.join("\n")}` }]);
18105
18524
  ) }) });
18106
18525
  }
18107
18526
  if (showLspWizard) {
18108
- return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx22(
18527
+ return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsx23(Box21, { flexDirection: "column", children: /* @__PURE__ */ jsx23(
18109
18528
  LspWizard,
18110
18529
  {
18111
18530
  servers: cfg?.lspServers ?? {},
@@ -18142,7 +18561,7 @@ ${lines.join("\n")}` }]);
18142
18561
  ) }) });
18143
18562
  }
18144
18563
  if (commandWizard) {
18145
- return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx22(
18564
+ return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsx23(Box21, { flexDirection: "column", children: /* @__PURE__ */ jsx23(
18146
18565
  CommandWizard,
18147
18566
  {
18148
18567
  mode: commandWizard.mode,
@@ -18155,7 +18574,7 @@ ${lines.join("\n")}` }]);
18155
18574
  ) }) });
18156
18575
  }
18157
18576
  if (commandPicker) {
18158
- return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx22(
18577
+ return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsx23(Box21, { flexDirection: "column", children: /* @__PURE__ */ jsx23(
18159
18578
  CommandPicker,
18160
18579
  {
18161
18580
  commands: customCommandsRef.current,
@@ -18173,14 +18592,14 @@ ${lines.join("\n")}` }]);
18173
18592
  ) }) });
18174
18593
  }
18175
18594
  if (commandToDelete) {
18176
- return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
18177
- /* @__PURE__ */ jsxs20(Text21, { color: theme.accent, bold: true, children: [
18595
+ return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
18596
+ /* @__PURE__ */ jsxs21(Text22, { color: theme.accent, bold: true, children: [
18178
18597
  "Delete /",
18179
18598
  commandToDelete.name,
18180
18599
  "?"
18181
18600
  ] }),
18182
- /* @__PURE__ */ jsx22(Text21, { color: theme.info.color, children: commandToDelete.filepath }),
18183
- /* @__PURE__ */ jsx22(Box20, { marginTop: 1, children: /* @__PURE__ */ jsx22(
18601
+ /* @__PURE__ */ jsx23(Text22, { color: theme.info.color, children: commandToDelete.filepath }),
18602
+ /* @__PURE__ */ jsx23(Box21, { marginTop: 1, children: /* @__PURE__ */ jsx23(
18184
18603
  SelectInput10,
18185
18604
  {
18186
18605
  items: [
@@ -18199,7 +18618,7 @@ ${lines.join("\n")}` }]);
18199
18618
  ] }) });
18200
18619
  }
18201
18620
  if (showCommandList) {
18202
- return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx22(
18621
+ return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsx23(Box21, { flexDirection: "column", children: /* @__PURE__ */ jsx23(
18203
18622
  CommandList,
18204
18623
  {
18205
18624
  commands: customCommandsRef.current,
@@ -18208,12 +18627,12 @@ ${lines.join("\n")}` }]);
18208
18627
  ) }) });
18209
18628
  }
18210
18629
  if (showThemePicker) {
18211
- return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx22(ThemePicker, { themes: themeList(), onPick: handleThemePick }) }) });
18630
+ return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsx23(Box21, { flexDirection: "column", children: /* @__PURE__ */ jsx23(ThemePicker, { themes: themeList(), onPick: handleThemePick }) }) });
18212
18631
  }
18213
18632
  const hasConversation = events.some((e) => e.kind === "user" || e.kind === "assistant");
18214
- return /* @__PURE__ */ jsx22(ThemeProvider, { theme, children: /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", children: [
18215
- !hasConversation && events.length === 0 ? /* @__PURE__ */ jsx22(Welcome, { accountId: cfg.accountId, cloudMode: cfg.cloudMode }) : /* @__PURE__ */ jsx22(ChatView, { events, showReasoning, verbose, intentTier: intentTier ?? void 0 }),
18216
- perm ? /* @__PURE__ */ jsx22(
18633
+ return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", children: [
18634
+ !hasConversation && events.length === 0 ? /* @__PURE__ */ jsx23(Welcome, { accountId: cfg.accountId, cloudMode: cfg.cloudMode }) : /* @__PURE__ */ jsx23(ChatView, { events, showReasoning, verbose, intentTier: intentTier ?? void 0 }),
18635
+ perm ? /* @__PURE__ */ jsx23(
18217
18636
  PermissionModal,
18218
18637
  {
18219
18638
  tool: perm.tool,
@@ -18224,7 +18643,7 @@ ${lines.join("\n")}` }]);
18224
18643
  setPerm(null);
18225
18644
  }
18226
18645
  }
18227
- ) : limitModal ? /* @__PURE__ */ jsx22(
18646
+ ) : limitModal ? /* @__PURE__ */ jsx23(
18228
18647
  LimitModal,
18229
18648
  {
18230
18649
  limit: limitModal.limit,
@@ -18234,8 +18653,8 @@ ${lines.join("\n")}` }]);
18234
18653
  setLimitModal(null);
18235
18654
  }
18236
18655
  }
18237
- ) : /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", marginTop: 1, children: [
18238
- tasks.length > 0 && /* @__PURE__ */ jsx22(
18656
+ ) : /* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", marginTop: 1, children: [
18657
+ tasks.length > 0 && /* @__PURE__ */ jsx23(
18239
18658
  TaskList,
18240
18659
  {
18241
18660
  tasks,
@@ -18243,11 +18662,11 @@ ${lines.join("\n")}` }]);
18243
18662
  tokensDelta: Math.max(0, (usage?.prompt_tokens ?? 0) - tasksStartTokens)
18244
18663
  }
18245
18664
  ),
18246
- queue.length > 0 && /* @__PURE__ */ jsx22(Box20, { flexDirection: "column", marginBottom: 1, children: queue.map((q, i) => /* @__PURE__ */ jsxs20(Text21, { color: theme.info.color, children: [
18665
+ queue.length > 0 && /* @__PURE__ */ jsx23(Box21, { flexDirection: "column", marginBottom: 1, children: queue.map((q, i) => /* @__PURE__ */ jsxs21(Text22, { color: theme.info.color, dimColor: theme.info.dim, children: [
18247
18666
  "\u23F3 ",
18248
18667
  q.display
18249
18668
  ] }, `queue_${i}`)) }),
18250
- /* @__PURE__ */ jsx22(
18669
+ /* @__PURE__ */ jsx23(
18251
18670
  StatusBar,
18252
18671
  {
18253
18672
  model: cfg.model,
@@ -18274,7 +18693,7 @@ ${lines.join("\n")}` }]);
18274
18693
  intentTier: intentTier ?? void 0
18275
18694
  }
18276
18695
  ),
18277
- activePicker?.kind === "file" && /* @__PURE__ */ jsx22(
18696
+ activePicker?.kind === "file" && /* @__PURE__ */ jsx23(
18278
18697
  FilePicker,
18279
18698
  {
18280
18699
  items: filteredFileItems,
@@ -18282,7 +18701,7 @@ ${lines.join("\n")}` }]);
18282
18701
  query: pickerQuery ?? ""
18283
18702
  }
18284
18703
  ),
18285
- activePicker?.kind === "slash" && /* @__PURE__ */ jsx22(
18704
+ activePicker?.kind === "slash" && /* @__PURE__ */ jsx23(
18286
18705
  SlashPicker,
18287
18706
  {
18288
18707
  items: filteredSlashItems,
@@ -18290,9 +18709,9 @@ ${lines.join("\n")}` }]);
18290
18709
  query: pickerQuery ?? ""
18291
18710
  }
18292
18711
  ),
18293
- /* @__PURE__ */ jsxs20(Box20, { marginTop: 1, children: [
18294
- /* @__PURE__ */ jsx22(Text21, { color: theme.prompt ?? theme.accent, children: "\u203A " }),
18295
- /* @__PURE__ */ jsx22(
18712
+ /* @__PURE__ */ jsxs21(Box21, { marginTop: 1, children: [
18713
+ /* @__PURE__ */ jsx23(Text22, { color: theme.prompt ?? theme.accent, children: "\u203A " }),
18714
+ /* @__PURE__ */ jsx23(
18296
18715
  CustomTextInput,
18297
18716
  {
18298
18717
  value: input,
@@ -18349,7 +18768,7 @@ ${lines.join("\n")}` }]);
18349
18768
  }
18350
18769
  async function renderApp(cfg, updateResult, lspScope = "global", lspProjectPath = null, cloudToken, cloudDeviceId) {
18351
18770
  const instance = render(
18352
- /* @__PURE__ */ jsx22(
18771
+ /* @__PURE__ */ jsx23(
18353
18772
  App,
18354
18773
  {
18355
18774
  initialCfg: cfg,
@@ -18371,6 +18790,7 @@ var init_app = __esm({
18371
18790
  "src/app.tsx"() {
18372
18791
  "use strict";
18373
18792
  init_loop();
18793
+ init_supervisor();
18374
18794
  init_system_prompt();
18375
18795
  init_compact();
18376
18796
  init_compaction();
@@ -18381,6 +18801,7 @@ var init_app = __esm({
18381
18801
  init_lsp();
18382
18802
  init_messages();
18383
18803
  init_errors();
18804
+ init_abort_scope();
18384
18805
  init_chat();
18385
18806
  init_status();
18386
18807
  init_permission();