kimiflare 0.50.1 → 0.52.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
@@ -915,6 +915,21 @@ function toOpenAIToolDefs(tools) {
915
915
  }
916
916
  }));
917
917
  }
918
+ function isValidStatus(s) {
919
+ return s === "pending" || s === "in_progress" || s === "completed";
920
+ }
921
+ function validateTasks(input) {
922
+ if (!Array.isArray(input)) throw new Error("tasks must be an array");
923
+ return input.map((t, i) => {
924
+ if (!t || typeof t !== "object") throw new Error(`tasks[${i}] must be an object`);
925
+ const rec = t;
926
+ const id = typeof rec.id === "string" && rec.id.length > 0 ? rec.id : String(i + 1);
927
+ const title = typeof rec.title === "string" ? rec.title.trim() : "";
928
+ if (!title) throw new Error(`tasks[${i}].title is required`);
929
+ const status = isValidStatus(rec.status) ? rec.status : "pending";
930
+ return { id, title, status };
931
+ });
932
+ }
918
933
  var init_registry = __esm({
919
934
  "src/tools/registry.ts"() {
920
935
  "use strict";
@@ -1556,8 +1571,8 @@ var require_node_gyp_build = __commonJS({
1556
1571
  var abi = process.versions.modules;
1557
1572
  var runtime = isElectron() ? "electron" : isNwjs() ? "node-webkit" : "node";
1558
1573
  var arch = process.env.npm_config_arch || os2.arch();
1559
- var platform3 = process.env.npm_config_platform || os2.platform();
1560
- var libc = process.env.LIBC || (isAlpine(platform3) ? "musl" : "glibc");
1574
+ var platform4 = process.env.npm_config_platform || os2.platform();
1575
+ var libc = process.env.LIBC || (isAlpine(platform4) ? "musl" : "glibc");
1561
1576
  var armv = process.env.ARM_VERSION || (arch === "arm64" ? "8" : vars.arm_version) || "";
1562
1577
  var uv = (process.versions.uv || "").split(".")[0];
1563
1578
  module.exports = load;
@@ -1582,7 +1597,7 @@ var require_node_gyp_build = __commonJS({
1582
1597
  var nearby = resolve3(path.dirname(process.execPath));
1583
1598
  if (nearby) return nearby;
1584
1599
  var target = [
1585
- "platform=" + platform3,
1600
+ "platform=" + platform4,
1586
1601
  "arch=" + arch,
1587
1602
  "runtime=" + runtime,
1588
1603
  "abi=" + abi,
@@ -1597,7 +1612,7 @@ var require_node_gyp_build = __commonJS({
1597
1612
  throw new Error("No native build was found for " + target + "\n loaded from: " + dir + "\n");
1598
1613
  function resolve3(dir2) {
1599
1614
  var tuples = readdirSync(path.join(dir2, "prebuilds")).map(parseTuple);
1600
- var tuple = tuples.filter(matchTuple(platform3, arch)).sort(compareTuples)[0];
1615
+ var tuple = tuples.filter(matchTuple(platform4, arch)).sort(compareTuples)[0];
1601
1616
  if (!tuple) return;
1602
1617
  var prebuilds = path.join(dir2, "prebuilds", tuple.name);
1603
1618
  var parsed = readdirSync(prebuilds).map(parseTags);
@@ -1623,17 +1638,17 @@ var require_node_gyp_build = __commonJS({
1623
1638
  function parseTuple(name) {
1624
1639
  var arr = name.split("-");
1625
1640
  if (arr.length !== 2) return;
1626
- var platform4 = arr[0];
1641
+ var platform5 = arr[0];
1627
1642
  var architectures = arr[1].split("+");
1628
- if (!platform4) return;
1643
+ if (!platform5) return;
1629
1644
  if (!architectures.length) return;
1630
1645
  if (!architectures.every(Boolean)) return;
1631
- return { name, platform: platform4, architectures };
1646
+ return { name, platform: platform5, architectures };
1632
1647
  }
1633
- function matchTuple(platform4, arch2) {
1648
+ function matchTuple(platform5, arch2) {
1634
1649
  return function(tuple) {
1635
1650
  if (tuple == null) return false;
1636
- if (tuple.platform !== platform4) return false;
1651
+ if (tuple.platform !== platform5) return false;
1637
1652
  return tuple.architectures.includes(arch2);
1638
1653
  };
1639
1654
  }
@@ -1701,8 +1716,8 @@ var require_node_gyp_build = __commonJS({
1701
1716
  if (process.env.ELECTRON_RUN_AS_NODE) return true;
1702
1717
  return typeof window !== "undefined" && window.process && window.process.type === "renderer";
1703
1718
  }
1704
- function isAlpine(platform4) {
1705
- return platform4 === "linux" && fs.existsSync("/etc/alpine-release");
1719
+ function isAlpine(platform5) {
1720
+ return platform5 === "linux" && fs.existsSync("/etc/alpine-release");
1706
1721
  }
1707
1722
  load.parseTags = parseTags;
1708
1723
  load.matchTags = matchTags;
@@ -2114,7 +2129,7 @@ var init_session_state = __esm({
2114
2129
  }
2115
2130
  });
2116
2131
 
2117
- // src/agent/compaction.ts
2132
+ // src/agent/artifact-compaction.ts
2118
2133
  function approxTokens2(n) {
2119
2134
  return Math.round(n / 4);
2120
2135
  }
@@ -2313,7 +2328,7 @@ function shouldCompact(opts2) {
2313
2328
  const { turns } = groupIntoTurns(opts2.messages);
2314
2329
  return tokens > tokenThreshold || turns.length > turnThreshold;
2315
2330
  }
2316
- function compactMessages(opts2) {
2331
+ function compactMessagesViaArtifacts(opts2) {
2317
2332
  const keepLastTurns = opts2.keepLastTurns ?? 4;
2318
2333
  const { prefix, turns } = groupIntoTurns(opts2.messages);
2319
2334
  const tokensBefore = estimatePromptTokens(opts2.messages);
@@ -2397,8 +2412,8 @@ function recallArtifacts(messages, store, state) {
2397
2412
  const recalled = store.recall(uniqueIds);
2398
2413
  return { ids: uniqueIds, recalled };
2399
2414
  }
2400
- var init_compaction = __esm({
2401
- "src/agent/compaction.ts"() {
2415
+ var init_artifact_compaction = __esm({
2416
+ "src/agent/artifact-compaction.ts"() {
2402
2417
  "use strict";
2403
2418
  init_session_state();
2404
2419
  }
@@ -2467,6 +2482,7 @@ Use console.log() to return results. Only console.log output will be sent back t
2467
2482
  let cumulativePromptTokens = 0;
2468
2483
  let iter = 0;
2469
2484
  let budgetExhausted = false;
2485
+ let loopExhausted = false;
2470
2486
  while (true) {
2471
2487
  if (budgetExhausted) {
2472
2488
  opts2.messages.push({
@@ -2474,6 +2490,12 @@ Use console.log() to return results. Only console.log output will be sent back t
2474
2490
  content: "You have reached the cumulative input token budget for this session. Please synthesize your findings and provide a final summary of what was accomplished."
2475
2491
  });
2476
2492
  }
2493
+ if (loopExhausted) {
2494
+ opts2.messages.push({
2495
+ role: "system",
2496
+ content: "You have repeatedly called the same tools with identical arguments and are stuck in a loop. Please synthesize what you know from the conversation history and provide a final answer."
2497
+ });
2498
+ }
2477
2499
  if (iter >= max) {
2478
2500
  if (opts2.callbacks.onToolLimitReached) {
2479
2501
  const decision = await opts2.callbacks.onToolLimitReached();
@@ -2651,6 +2673,7 @@ Use console.log() to return results. Only console.log output will be sent back t
2651
2673
  logger.info("turn:complete", { sessionId: opts2.sessionId, durationMs: Math.round(performance.now() - turnStart) });
2652
2674
  return;
2653
2675
  }
2676
+ let blockedCount = 0;
2654
2677
  for (const tc of toolCalls) {
2655
2678
  if (opts2.signal.aborted) throw new DOMException("aborted", "AbortError");
2656
2679
  const loopSignature = `${tc.function.name}:${stableStringify(tc.function.arguments)}`;
@@ -2673,6 +2696,7 @@ Use console.log() to return results. Only console.log output will be sent back t
2673
2696
  opts2.callbacks.onToolResult?.(loopResult);
2674
2697
  recentToolCalls.push(loopSignature);
2675
2698
  if (recentToolCalls.length > LOOP_WINDOW) recentToolCalls.shift();
2699
+ blockedCount++;
2676
2700
  continue;
2677
2701
  }
2678
2702
  if (tc.function.name === "web_fetch") {
@@ -2700,6 +2724,7 @@ Use console.log() to return results. Only console.log output will be sent back t
2700
2724
  opts2.callbacks.onToolResult?.(budgetResult);
2701
2725
  recentToolCalls.push(loopSignature);
2702
2726
  if (recentToolCalls.length > LOOP_WINDOW) recentToolCalls.shift();
2727
+ blockedCount++;
2703
2728
  continue;
2704
2729
  }
2705
2730
  if (domainCount >= WEB_FETCH_DOMAIN_THRESHOLD) {
@@ -2720,6 +2745,7 @@ Use console.log() to return results. Only console.log output will be sent back t
2720
2745
  opts2.callbacks.onToolResult?.(loopResult);
2721
2746
  recentToolCalls.push(loopSignature);
2722
2747
  if (recentToolCalls.length > LOOP_WINDOW) recentToolCalls.shift();
2748
+ blockedCount++;
2723
2749
  continue;
2724
2750
  }
2725
2751
  webFetchHistory.push({ url, domain });
@@ -2855,6 +2881,9 @@ ${sandboxResult.output}` : `${warningPrefix}${sandboxResult.output}`;
2855
2881
  if (recentToolCalls.length > LOOP_WINDOW) recentToolCalls.shift();
2856
2882
  }
2857
2883
  }
2884
+ if (blockedCount === toolCalls.length && toolCalls.length > 0) {
2885
+ loopExhausted = true;
2886
+ }
2858
2887
  if (opts2.sessionId) {
2859
2888
  const current = driftAccumulator.get(opts2.sessionId) ?? 0;
2860
2889
  if (current > 0) {
@@ -2883,6 +2912,9 @@ ${sandboxResult.output}` : `${warningPrefix}${sandboxResult.output}`;
2883
2912
  if (budgetExhausted) {
2884
2913
  throw new BudgetExhaustedError();
2885
2914
  }
2915
+ if (loopExhausted) {
2916
+ throw new AgentLoopError();
2917
+ }
2886
2918
  }
2887
2919
  }
2888
2920
  function validateToolArguments(raw) {
@@ -2894,7 +2926,7 @@ function validateToolArguments(raw) {
2894
2926
  return "{}";
2895
2927
  }
2896
2928
  }
2897
- var BudgetExhaustedError, codeModeApiCache, driftAccumulator, DRIFT_THRESHOLD, MAX_PROMPT_TOKENS, MAX_TOOL_CONTENT_CHARS;
2929
+ var BudgetExhaustedError, AgentLoopError, codeModeApiCache, driftAccumulator, DRIFT_THRESHOLD, MAX_PROMPT_TOKENS, MAX_TOOL_CONTENT_CHARS;
2898
2930
  var init_loop = __esm({
2899
2931
  "src/agent/loop.ts"() {
2900
2932
  "use strict";
@@ -2905,7 +2937,7 @@ var init_loop = __esm({
2905
2937
  init_extractors();
2906
2938
  init_strip_reasoning();
2907
2939
  init_code_mode();
2908
- init_compaction();
2940
+ init_artifact_compaction();
2909
2941
  init_logger();
2910
2942
  BudgetExhaustedError = class extends Error {
2911
2943
  constructor(message2 = "Cumulative input token budget exhausted") {
@@ -2913,6 +2945,12 @@ var init_loop = __esm({
2913
2945
  this.name = "BudgetExhaustedError";
2914
2946
  }
2915
2947
  };
2948
+ AgentLoopError = class extends Error {
2949
+ constructor(message2 = "Agent got stuck repeating the same tool calls") {
2950
+ super(message2);
2951
+ this.name = "AgentLoopError";
2952
+ }
2953
+ };
2916
2954
  codeModeApiCache = /* @__PURE__ */ new Map();
2917
2955
  driftAccumulator = /* @__PURE__ */ new Map();
2918
2956
  DRIFT_THRESHOLD = 5;
@@ -2953,88 +2991,47 @@ function isBlockedInPlanMode(toolName) {
2953
2991
  if (toolName === "browser_fetch") return true;
2954
2992
  return false;
2955
2993
  }
2956
- function tokenizeCommand(command) {
2957
- const tokens = [];
2958
- let current = "";
2959
- let inQuote = null;
2960
- for (const ch of command) {
2961
- if (inQuote) {
2962
- if (ch === inQuote) {
2963
- inQuote = null;
2964
- } else {
2965
- current += ch;
2966
- }
2994
+ function getTokens(s) {
2995
+ const toks = [];
2996
+ let cur = "";
2997
+ let q = null;
2998
+ for (const ch of s) {
2999
+ if (q) {
3000
+ if (ch === q) q = null;
3001
+ else cur += ch;
2967
3002
  } else if (ch === '"' || ch === "'") {
2968
- inQuote = ch;
3003
+ q = ch;
2969
3004
  } else if (/\s/.test(ch)) {
2970
- if (current) {
2971
- tokens.push(current);
2972
- current = "";
3005
+ if (cur) {
3006
+ toks.push(cur);
3007
+ cur = "";
2973
3008
  }
2974
3009
  } else {
2975
- current += ch;
2976
- }
2977
- }
2978
- if (current) tokens.push(current);
2979
- return tokens;
2980
- }
2981
- function splitByOperators(command, operators) {
2982
- const segments = [];
2983
- let current = "";
2984
- let inQuote = null;
2985
- for (let i = 0; i < command.length; i++) {
2986
- const ch = command[i];
2987
- if (inQuote) {
2988
- if (ch === inQuote) {
2989
- inQuote = null;
2990
- }
2991
- current += ch;
2992
- continue;
2993
- }
2994
- if (ch === '"' || ch === "'") {
2995
- inQuote = ch;
2996
- current += ch;
2997
- continue;
2998
- }
2999
- let matchedOp = false;
3000
- for (const op of operators) {
3001
- if (command.slice(i, i + op.length) === op) {
3002
- segments.push(current.trim());
3003
- current = "";
3004
- i += op.length - 1;
3005
- matchedOp = true;
3006
- break;
3007
- }
3010
+ cur += ch;
3008
3011
  }
3009
- if (matchedOp) continue;
3010
- current += ch;
3011
3012
  }
3012
- if (current.trim()) segments.push(current.trim());
3013
- return segments;
3013
+ if (cur) toks.push(cur);
3014
+ return toks;
3014
3015
  }
3015
- function isReadOnlyBashSegment(command) {
3016
- const trimmed = command.trim();
3017
- if (!trimmed) return false;
3018
- const tokens = tokenizeCommand(trimmed);
3019
- if (tokens.length === 0) return false;
3020
- const cmd = tokens[0];
3021
- const args = tokens.slice(1);
3016
+ function isReadOnlySegment(seg) {
3017
+ const toks = getTokens(seg.trim());
3018
+ if (toks.length === 0) return false;
3019
+ const [cmd, sub, ...rest] = toks;
3022
3020
  if (cmd === "git") {
3023
- const sub = args[0] ?? "";
3024
- const allowed = GIT_READONLY_SUBCOMMANDS[sub];
3021
+ const allowed = GIT_READONLY_SUBCOMMANDS[sub ?? ""];
3025
3022
  if (allowed === void 0) return false;
3026
3023
  if (allowed === true) return true;
3027
3024
  switch (sub) {
3028
3025
  case "branch":
3029
- return !args.some((a) => /^-[dDmMcC]/.test(a));
3026
+ return !rest.some((a) => /^-[dDmMcC]/.test(a));
3030
3027
  case "stash":
3031
- return args[1] === "list";
3028
+ return rest[0] === "list";
3032
3029
  case "remote":
3033
- return args[1] === "-v" || args[1] === "--verbose" || args.length === 1;
3030
+ return rest[0] === "-v" || rest[0] === "--verbose" || rest.length === 0;
3034
3031
  case "tag":
3035
- return args[1] === "-l" || args[1] === "--list" || args.length === 1;
3032
+ return rest[0] === "-l" || rest[0] === "--list" || rest.length === 0;
3036
3033
  case "config":
3037
- return args[1] === "--list" || args[1]?.startsWith("--get") === true || args.length === 1;
3034
+ return rest[0] === "--list" || rest[0]?.startsWith("--get") === true || rest.length === 0;
3038
3035
  default:
3039
3036
  return false;
3040
3037
  }
@@ -3045,10 +3042,32 @@ function isReadOnlyBash(command) {
3045
3042
  const trimmed = command.trim();
3046
3043
  if (!trimmed) return false;
3047
3044
  if (DANGEROUS_PATTERNS.test(trimmed)) return false;
3048
- const segments = splitByOperators(trimmed, ["|", "&&"]);
3049
- if (segments.length === 0) return false;
3050
- for (const segment of segments) {
3051
- if (!isReadOnlyBashSegment(segment.trim())) return false;
3045
+ const segs = [];
3046
+ let cur = "";
3047
+ let q = null;
3048
+ for (let i = 0; i < trimmed.length; i++) {
3049
+ const ch = trimmed[i];
3050
+ if (q) {
3051
+ if (ch === q) q = null;
3052
+ cur += ch;
3053
+ } else if (ch === '"' || ch === "'") {
3054
+ q = ch;
3055
+ cur += ch;
3056
+ } else if (trimmed.slice(i, i + 2) === "&&") {
3057
+ segs.push(cur);
3058
+ cur = "";
3059
+ i++;
3060
+ } else if (ch === "|") {
3061
+ segs.push(cur);
3062
+ cur = "";
3063
+ } else {
3064
+ cur += ch;
3065
+ }
3066
+ }
3067
+ if (cur.trim()) segs.push(cur);
3068
+ if (segs.length === 0) return false;
3069
+ for (const seg of segs) {
3070
+ if (!isReadOnlySegment(seg.trim())) return false;
3052
3071
  }
3053
3072
  return true;
3054
3073
  }
@@ -4178,34 +4197,12 @@ var init_browser = __esm({
4178
4197
  }
4179
4198
  });
4180
4199
 
4181
- // src/tasks-state.ts
4182
- function isValidStatus(s) {
4183
- return s === "pending" || s === "in_progress" || s === "completed";
4184
- }
4185
- function validateTasks(input) {
4186
- if (!Array.isArray(input)) throw new Error("tasks must be an array");
4187
- return input.map((t, i) => {
4188
- if (!t || typeof t !== "object") throw new Error(`tasks[${i}] must be an object`);
4189
- const rec = t;
4190
- const id = typeof rec.id === "string" && rec.id.length > 0 ? rec.id : String(i + 1);
4191
- const title = typeof rec.title === "string" ? rec.title.trim() : "";
4192
- if (!title) throw new Error(`tasks[${i}].title is required`);
4193
- const status = isValidStatus(rec.status) ? rec.status : "pending";
4194
- return { id, title, status };
4195
- });
4196
- }
4197
- var init_tasks_state = __esm({
4198
- "src/tasks-state.ts"() {
4199
- "use strict";
4200
- }
4201
- });
4202
-
4203
4200
  // src/tools/tasks.ts
4204
4201
  var tasksSetTool;
4205
4202
  var init_tasks = __esm({
4206
4203
  "src/tools/tasks.ts"() {
4207
4204
  "use strict";
4208
- init_tasks_state();
4205
+ init_registry();
4209
4206
  tasksSetTool = {
4210
4207
  name: "tasks_set",
4211
4208
  description: [
@@ -6078,13 +6075,18 @@ __export(auth_exports, {
6078
6075
  registerDevice: () => registerDevice,
6079
6076
  saveCloudCredentials: () => saveCloudCredentials
6080
6077
  });
6081
- import { readFile as readFile11, writeFile as writeFile8 } from "fs/promises";
6082
- import { homedir as homedir9 } from "os";
6078
+ import { readFile as readFile11, writeFile as writeFile8, mkdir as mkdir8 } from "fs/promises";
6079
+ import { createHash } from "crypto";
6080
+ import { homedir as homedir9, hostname, userInfo } from "os";
6083
6081
  import { join as join15 } from "path";
6084
6082
  function cloudCredPath() {
6085
6083
  const xdg = process.env.XDG_CONFIG_HOME || join15(homedir9(), ".config");
6086
6084
  return join15(xdg, "kimiflare", "cloud.json");
6087
6085
  }
6086
+ function deviceIdPath() {
6087
+ const xdg = process.env.XDG_DATA_HOME || join15(homedir9(), ".local", "share");
6088
+ return join15(xdg, "kimiflare", "device_id");
6089
+ }
6088
6090
  function generateCode() {
6089
6091
  const chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
6090
6092
  let out = "";
@@ -6093,16 +6095,51 @@ function generateCode() {
6093
6095
  }
6094
6096
  return out;
6095
6097
  }
6096
- function generateDeviceId() {
6098
+ function deriveStableDeviceId() {
6099
+ const seed = `${hostname()}:${userInfo().username}:${homedir9()}`;
6100
+ const hash = createHash("sha256").update(seed).digest();
6101
+ return hash.subarray(0, 16).toString("hex");
6102
+ }
6103
+ function generateRandomDeviceId() {
6097
6104
  const arr = new Uint8Array(16);
6098
6105
  crypto.getRandomValues(arr);
6099
6106
  return Array.from(arr, (b) => b.toString(16).padStart(2, "0")).join("");
6100
6107
  }
6101
- function generateDeviceCodes() {
6108
+ async function getOrCreateDeviceId() {
6109
+ try {
6110
+ const raw = await readFile11(deviceIdPath(), "utf8");
6111
+ const id = raw.trim();
6112
+ if (/^[0-9a-f]{32}$/i.test(id)) return id;
6113
+ } catch {
6114
+ }
6115
+ try {
6116
+ const raw = await readFile11(cloudCredPath(), "utf8");
6117
+ const parsed = JSON.parse(raw);
6118
+ if (parsed.deviceId && /^[0-9a-f]{32}$/i.test(parsed.deviceId)) {
6119
+ await persistDeviceId(parsed.deviceId);
6120
+ return parsed.deviceId;
6121
+ }
6122
+ } catch {
6123
+ }
6124
+ let deviceId;
6125
+ try {
6126
+ deviceId = deriveStableDeviceId();
6127
+ } catch {
6128
+ deviceId = generateRandomDeviceId();
6129
+ }
6130
+ await persistDeviceId(deviceId);
6131
+ return deviceId;
6132
+ }
6133
+ async function persistDeviceId(deviceId) {
6134
+ const p = deviceIdPath();
6135
+ await mkdir8(join15(p, ".."), { recursive: true });
6136
+ await writeFile8(p, deviceId, { mode: 384 });
6137
+ }
6138
+ async function generateDeviceCodes() {
6102
6139
  const deviceCode = `device-${generateCode()}-${Date.now()}`;
6103
6140
  const userCode = `${generateCode()}-${generateCode()}`;
6104
6141
  const authUrl = `${CLOUD_API_URL}/auth?code=${encodeURIComponent(userCode)}`;
6105
- const deviceId = generateDeviceId();
6142
+ const deviceId = await getOrCreateDeviceId();
6106
6143
  return { deviceCode, userCode, authUrl, deviceId };
6107
6144
  }
6108
6145
  async function registerDevice(codes) {
@@ -6157,6 +6194,10 @@ async function loadCloudCredentials() {
6157
6194
  const raw = await readFile11(cloudCredPath(), "utf8");
6158
6195
  const parsed = JSON.parse(raw);
6159
6196
  if (parsed.expiresAt && parsed.expiresAt > Date.now() / 1e3 && parsed.accessToken) {
6197
+ if (parsed.deviceId) {
6198
+ await persistDeviceId(parsed.deviceId).catch(() => {
6199
+ });
6200
+ }
6160
6201
  return parsed;
6161
6202
  }
6162
6203
  } catch {
@@ -6166,6 +6207,10 @@ async function loadCloudCredentials() {
6166
6207
  async function saveCloudCredentials(creds) {
6167
6208
  const p = cloudCredPath();
6168
6209
  await writeFile8(p, JSON.stringify(creds, null, 2), "utf8");
6210
+ if (creds.deviceId) {
6211
+ await persistDeviceId(creds.deviceId).catch(() => {
6212
+ });
6213
+ }
6169
6214
  }
6170
6215
  async function clearCloudCredentials() {
6171
6216
  try {
@@ -6173,9 +6218,14 @@ async function clearCloudCredentials() {
6173
6218
  await unlink5(cloudCredPath());
6174
6219
  } catch {
6175
6220
  }
6221
+ try {
6222
+ const { unlink: unlink5 } = await import("fs/promises");
6223
+ await unlink5(deviceIdPath());
6224
+ } catch {
6225
+ }
6176
6226
  }
6177
6227
  async function authenticateDevice(onStatus) {
6178
- const codes = generateDeviceCodes();
6228
+ const codes = await generateDeviceCodes();
6179
6229
  await registerDevice(codes);
6180
6230
  onStatus({ url: codes.authUrl, userCode: codes.userCode, polling: false });
6181
6231
  const startTime = Date.now();
@@ -8309,7 +8359,7 @@ __export(sessions_exports, {
8309
8359
  saveSession: () => saveSession,
8310
8360
  sessionsDir: () => sessionsDir2
8311
8361
  });
8312
- import { readFile as readFile12, writeFile as writeFile9, mkdir as mkdir8, readdir as readdir3, stat as stat4 } from "fs/promises";
8362
+ import { readFile as readFile12, writeFile as writeFile9, mkdir as mkdir9, readdir as readdir3, stat as stat4 } from "fs/promises";
8313
8363
  import { homedir as homedir10 } from "os";
8314
8364
  import { join as join17 } from "path";
8315
8365
  function sessionsDir2() {
@@ -8333,7 +8383,7 @@ function makeSessionId(firstPrompt) {
8333
8383
  }
8334
8384
  async function saveSession(file) {
8335
8385
  const dir = sessionsDir2();
8336
- await mkdir8(dir, { recursive: true });
8386
+ await mkdir9(dir, { recursive: true });
8337
8387
  const path = join17(dir, `${file.id}.json`);
8338
8388
  await writeFile9(path, JSON.stringify(file, null, 2), "utf8");
8339
8389
  return path;
@@ -8443,7 +8493,7 @@ var init_pricing = __esm({
8443
8493
  });
8444
8494
 
8445
8495
  // src/usage-tracker.ts
8446
- import { readFile as readFile13, writeFile as writeFile10, mkdir as mkdir9 } from "fs/promises";
8496
+ import { readFile as readFile13, writeFile as writeFile10, mkdir as mkdir10 } from "fs/promises";
8447
8497
  import { homedir as homedir11 } from "os";
8448
8498
  import { join as join18 } from "path";
8449
8499
  function usageDir2() {
@@ -8473,7 +8523,7 @@ async function loadLog2() {
8473
8523
  return { version: LOG_VERSION2, days: [], sessions: [] };
8474
8524
  }
8475
8525
  async function saveLog(log2) {
8476
- await mkdir9(usageDir2(), { recursive: true });
8526
+ await mkdir10(usageDir2(), { recursive: true });
8477
8527
  await writeFile10(usagePath2(), JSON.stringify(log2, null, 2), "utf8");
8478
8528
  }
8479
8529
  async function loadHistory() {
@@ -8502,7 +8552,7 @@ async function upsertHistoryDay(day) {
8502
8552
  entries.push(day);
8503
8553
  }
8504
8554
  const lines = entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
8505
- await mkdir9(usageDir2(), { recursive: true });
8555
+ await mkdir10(usageDir2(), { recursive: true });
8506
8556
  await writeFile10(historyPath(), lines, "utf8");
8507
8557
  }
8508
8558
  function getOrCreateDay(log2, date) {
@@ -8973,7 +9023,7 @@ var init_session = __esm({
8973
9023
  if (err.name === "AbortError") {
8974
9024
  this.emit({ type: "session.end", reason: "aborted" });
8975
9025
  this.emit({ type: "status", status: "idle" });
8976
- } else if (err instanceof BudgetExhaustedError) {
9026
+ } else if (err instanceof BudgetExhaustedError || err instanceof AgentLoopError) {
8977
9027
  this.emit({ type: "session.end", reason: "error", error: err.message });
8978
9028
  this.emit({ type: "status", status: "error" });
8979
9029
  throw err;
@@ -9429,7 +9479,7 @@ var init_supervisor = __esm({
9429
9479
  }
9430
9480
  });
9431
9481
 
9432
- // src/agent/compact.ts
9482
+ // src/agent/llm-summarize.ts
9433
9483
  function indexOfNthUserFromEnd(messages, n) {
9434
9484
  let seen = 0;
9435
9485
  for (let i = messages.length - 1; i >= 0; i--) {
@@ -9440,7 +9490,7 @@ function indexOfNthUserFromEnd(messages, n) {
9440
9490
  }
9441
9491
  return -1;
9442
9492
  }
9443
- async function compactMessages2(opts2) {
9493
+ async function summarizeMessagesViaLlm(opts2) {
9444
9494
  const keep = opts2.keepLastTurns ?? 4;
9445
9495
  const messages = opts2.messages;
9446
9496
  let prefixEnd = 0;
@@ -9502,8 +9552,8 @@ ${summary.trim()}`
9502
9552
  };
9503
9553
  }
9504
9554
  var SUMMARY_SYSTEM;
9505
- var init_compact = __esm({
9506
- "src/agent/compact.ts"() {
9555
+ var init_llm_summarize = __esm({
9556
+ "src/agent/llm-summarize.ts"() {
9507
9557
  "use strict";
9508
9558
  init_client();
9509
9559
  SUMMARY_SYSTEM = `You are summarizing a terminal coding session so it can fit back into a short context window. Produce a dense summary that captures:
@@ -10744,857 +10794,414 @@ var init_status = __esm({
10744
10794
  }
10745
10795
  });
10746
10796
 
10747
- // src/ui/permission.tsx
10748
- import { Box as Box7, Text as Text7 } from "ink";
10749
- import SelectInput from "ink-select-input";
10750
- import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
10751
- function PermissionModal({ tool, args, onDecide }) {
10752
- const theme = useTheme();
10753
- let render2;
10754
- try {
10755
- render2 = tool.render?.(args);
10756
- } catch {
10797
+ // node_modules/chalk/source/vendor/ansi-styles/index.js
10798
+ function assembleStyles() {
10799
+ const codes = /* @__PURE__ */ new Map();
10800
+ for (const [groupName, group] of Object.entries(styles)) {
10801
+ for (const [styleName, style] of Object.entries(group)) {
10802
+ styles[styleName] = {
10803
+ open: `\x1B[${style[0]}m`,
10804
+ close: `\x1B[${style[1]}m`
10805
+ };
10806
+ group[styleName] = styles[styleName];
10807
+ codes.set(style[0], style[1]);
10808
+ }
10809
+ Object.defineProperty(styles, groupName, {
10810
+ value: group,
10811
+ enumerable: false
10812
+ });
10757
10813
  }
10758
- const items = [
10759
- { label: "Allow once", value: "allow" },
10760
- { label: "Allow for this session", value: "allow_session" },
10761
- { label: "Deny", value: "deny" }
10762
- ];
10763
- return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", borderStyle: "round", borderColor: theme.permission, paddingX: 1, children: [
10764
- /* @__PURE__ */ jsx8(Text7, { color: theme.permission, bold: true, children: "Permission requested" }),
10765
- /* @__PURE__ */ jsxs7(Text7, { children: [
10766
- "tool: ",
10767
- /* @__PURE__ */ jsx8(Text7, { color: theme.tool, children: tool.name })
10768
- ] }),
10769
- render2?.title ? /* @__PURE__ */ jsxs7(Text7, { children: [
10770
- "action: ",
10771
- render2.title
10772
- ] }) : null,
10773
- render2?.diff ? /* @__PURE__ */ jsx8(Box7, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx8(DiffView, { ...render2.diff }) }) : /* @__PURE__ */ jsxs7(Text7, { color: theme.info.color, children: [
10774
- "args: ",
10775
- JSON.stringify(args)
10776
- ] }),
10777
- /* @__PURE__ */ jsx8(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx8(SelectInput, { items, onSelect: (item) => onDecide(item.value) }) })
10778
- ] });
10814
+ Object.defineProperty(styles, "codes", {
10815
+ value: codes,
10816
+ enumerable: false
10817
+ });
10818
+ styles.color.close = "\x1B[39m";
10819
+ styles.bgColor.close = "\x1B[49m";
10820
+ styles.color.ansi = wrapAnsi16();
10821
+ styles.color.ansi256 = wrapAnsi256();
10822
+ styles.color.ansi16m = wrapAnsi16m();
10823
+ styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
10824
+ styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
10825
+ styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
10826
+ Object.defineProperties(styles, {
10827
+ rgbToAnsi256: {
10828
+ value(red, green, blue) {
10829
+ if (red === green && green === blue) {
10830
+ if (red < 8) {
10831
+ return 16;
10832
+ }
10833
+ if (red > 248) {
10834
+ return 231;
10835
+ }
10836
+ return Math.round((red - 8) / 247 * 24) + 232;
10837
+ }
10838
+ return 16 + 36 * Math.round(red / 255 * 5) + 6 * Math.round(green / 255 * 5) + Math.round(blue / 255 * 5);
10839
+ },
10840
+ enumerable: false
10841
+ },
10842
+ hexToRgb: {
10843
+ value(hex) {
10844
+ const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16));
10845
+ if (!matches) {
10846
+ return [0, 0, 0];
10847
+ }
10848
+ let [colorString] = matches;
10849
+ if (colorString.length === 3) {
10850
+ colorString = [...colorString].map((character) => character + character).join("");
10851
+ }
10852
+ const integer = Number.parseInt(colorString, 16);
10853
+ return [
10854
+ /* eslint-disable no-bitwise */
10855
+ integer >> 16 & 255,
10856
+ integer >> 8 & 255,
10857
+ integer & 255
10858
+ /* eslint-enable no-bitwise */
10859
+ ];
10860
+ },
10861
+ enumerable: false
10862
+ },
10863
+ hexToAnsi256: {
10864
+ value: (hex) => styles.rgbToAnsi256(...styles.hexToRgb(hex)),
10865
+ enumerable: false
10866
+ },
10867
+ ansi256ToAnsi: {
10868
+ value(code) {
10869
+ if (code < 8) {
10870
+ return 30 + code;
10871
+ }
10872
+ if (code < 16) {
10873
+ return 90 + (code - 8);
10874
+ }
10875
+ let red;
10876
+ let green;
10877
+ let blue;
10878
+ if (code >= 232) {
10879
+ red = ((code - 232) * 10 + 8) / 255;
10880
+ green = red;
10881
+ blue = red;
10882
+ } else {
10883
+ code -= 16;
10884
+ const remainder = code % 36;
10885
+ red = Math.floor(code / 36) / 5;
10886
+ green = Math.floor(remainder / 6) / 5;
10887
+ blue = remainder % 6 / 5;
10888
+ }
10889
+ const value = Math.max(red, green, blue) * 2;
10890
+ if (value === 0) {
10891
+ return 30;
10892
+ }
10893
+ let result = 30 + (Math.round(blue) << 2 | Math.round(green) << 1 | Math.round(red));
10894
+ if (value === 2) {
10895
+ result += 60;
10896
+ }
10897
+ return result;
10898
+ },
10899
+ enumerable: false
10900
+ },
10901
+ rgbToAnsi: {
10902
+ value: (red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)),
10903
+ enumerable: false
10904
+ },
10905
+ hexToAnsi: {
10906
+ value: (hex) => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)),
10907
+ enumerable: false
10908
+ }
10909
+ });
10910
+ return styles;
10779
10911
  }
10780
- var init_permission = __esm({
10781
- "src/ui/permission.tsx"() {
10912
+ var ANSI_BACKGROUND_OFFSET, wrapAnsi16, wrapAnsi256, wrapAnsi16m, styles, modifierNames, foregroundColorNames, backgroundColorNames, colorNames, ansiStyles, ansi_styles_default;
10913
+ var init_ansi_styles = __esm({
10914
+ "node_modules/chalk/source/vendor/ansi-styles/index.js"() {
10782
10915
  "use strict";
10783
- init_diff_view();
10784
- init_theme_context();
10785
- }
10786
- });
10787
-
10788
- // src/ui/limit-modal.tsx
10789
- import { Box as Box8, Text as Text8 } from "ink";
10790
- import SelectInput2 from "ink-select-input";
10791
- import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
10792
- function LimitModal({ limit, onDecide }) {
10793
- const theme = useTheme();
10794
- const items = [
10795
- { label: "Continue", value: "continue" },
10796
- { label: "Stop", value: "stop" }
10797
- ];
10798
- return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", borderStyle: "round", borderColor: theme.error, paddingX: 1, children: [
10799
- /* @__PURE__ */ jsxs8(Text8, { color: theme.error, bold: true, children: [
10800
- "Tool-call limit reached (",
10801
- limit,
10802
- ")"
10803
- ] }),
10804
- /* @__PURE__ */ jsxs8(Text8, { dimColor: true, children: [
10805
- "This session has made ",
10806
- limit,
10807
- " tool calls. What would you like to do?"
10808
- ] }),
10809
- /* @__PURE__ */ jsx9(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx9(
10810
- SelectInput2,
10811
- {
10812
- items,
10813
- onSelect: (item) => onDecide(item.value)
10814
- }
10815
- ) })
10816
- ] });
10817
- }
10818
- var init_limit_modal = __esm({
10819
- "src/ui/limit-modal.tsx"() {
10820
- "use strict";
10821
- init_theme_context();
10916
+ ANSI_BACKGROUND_OFFSET = 10;
10917
+ wrapAnsi16 = (offset = 0) => (code) => `\x1B[${code + offset}m`;
10918
+ wrapAnsi256 = (offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`;
10919
+ wrapAnsi16m = (offset = 0) => (red, green, blue) => `\x1B[${38 + offset};2;${red};${green};${blue}m`;
10920
+ styles = {
10921
+ modifier: {
10922
+ reset: [0, 0],
10923
+ // 21 isn't widely supported and 22 does the same thing
10924
+ bold: [1, 22],
10925
+ dim: [2, 22],
10926
+ italic: [3, 23],
10927
+ underline: [4, 24],
10928
+ overline: [53, 55],
10929
+ inverse: [7, 27],
10930
+ hidden: [8, 28],
10931
+ strikethrough: [9, 29]
10932
+ },
10933
+ color: {
10934
+ black: [30, 39],
10935
+ red: [31, 39],
10936
+ green: [32, 39],
10937
+ yellow: [33, 39],
10938
+ blue: [34, 39],
10939
+ magenta: [35, 39],
10940
+ cyan: [36, 39],
10941
+ white: [37, 39],
10942
+ // Bright color
10943
+ blackBright: [90, 39],
10944
+ gray: [90, 39],
10945
+ // Alias of `blackBright`
10946
+ grey: [90, 39],
10947
+ // Alias of `blackBright`
10948
+ redBright: [91, 39],
10949
+ greenBright: [92, 39],
10950
+ yellowBright: [93, 39],
10951
+ blueBright: [94, 39],
10952
+ magentaBright: [95, 39],
10953
+ cyanBright: [96, 39],
10954
+ whiteBright: [97, 39]
10955
+ },
10956
+ bgColor: {
10957
+ bgBlack: [40, 49],
10958
+ bgRed: [41, 49],
10959
+ bgGreen: [42, 49],
10960
+ bgYellow: [43, 49],
10961
+ bgBlue: [44, 49],
10962
+ bgMagenta: [45, 49],
10963
+ bgCyan: [46, 49],
10964
+ bgWhite: [47, 49],
10965
+ // Bright color
10966
+ bgBlackBright: [100, 49],
10967
+ bgGray: [100, 49],
10968
+ // Alias of `bgBlackBright`
10969
+ bgGrey: [100, 49],
10970
+ // Alias of `bgBlackBright`
10971
+ bgRedBright: [101, 49],
10972
+ bgGreenBright: [102, 49],
10973
+ bgYellowBright: [103, 49],
10974
+ bgBlueBright: [104, 49],
10975
+ bgMagentaBright: [105, 49],
10976
+ bgCyanBright: [106, 49],
10977
+ bgWhiteBright: [107, 49]
10978
+ }
10979
+ };
10980
+ modifierNames = Object.keys(styles.modifier);
10981
+ foregroundColorNames = Object.keys(styles.color);
10982
+ backgroundColorNames = Object.keys(styles.bgColor);
10983
+ colorNames = [...foregroundColorNames, ...backgroundColorNames];
10984
+ ansiStyles = assembleStyles();
10985
+ ansi_styles_default = ansiStyles;
10822
10986
  }
10823
10987
  });
10824
10988
 
10825
- // src/util/fuzzy.ts
10826
- function fuzzyMatch(query, text) {
10827
- const queryLower = query.toLowerCase();
10828
- const textLower = text.toLowerCase();
10829
- const matchQuery = (normalizedQuery) => {
10830
- if (normalizedQuery.length === 0) return { matches: true, score: 0 };
10831
- if (normalizedQuery.length > textLower.length) return { matches: false, score: 0 };
10832
- let queryIndex = 0;
10833
- let score = 0;
10834
- let lastMatchIndex = -1;
10835
- let consecutiveMatches = 0;
10836
- for (let i = 0; i < textLower.length && queryIndex < normalizedQuery.length; i++) {
10837
- if (textLower[i] !== normalizedQuery[queryIndex]) continue;
10838
- const isWordBoundary = i === 0 || /[\s\-_./:]/.test(textLower[i - 1]);
10839
- if (lastMatchIndex === i - 1) {
10840
- consecutiveMatches++;
10841
- score -= consecutiveMatches * 5;
10842
- } else {
10843
- consecutiveMatches = 0;
10844
- if (lastMatchIndex >= 0) score += (i - lastMatchIndex - 1) * 2;
10845
- }
10846
- if (isWordBoundary) score -= 10;
10847
- score += i * 0.1;
10848
- lastMatchIndex = i;
10849
- queryIndex++;
10850
- }
10851
- if (queryIndex < normalizedQuery.length) return { matches: false, score: 0 };
10852
- if (normalizedQuery === textLower) score -= 100;
10853
- return { matches: true, score };
10854
- };
10855
- const primaryMatch = matchQuery(queryLower);
10856
- if (primaryMatch.matches) return primaryMatch;
10857
- const alphaNumericMatch = queryLower.match(/^(?<letters>[a-z]+)(?<digits>[0-9]+)$/);
10858
- const numericAlphaMatch = queryLower.match(/^(?<digits>[0-9]+)(?<letters>[a-z]+)$/);
10859
- const swappedQuery = alphaNumericMatch ? `${alphaNumericMatch.groups?.digits ?? ""}${alphaNumericMatch.groups?.letters ?? ""}` : numericAlphaMatch ? `${numericAlphaMatch.groups?.letters ?? ""}${numericAlphaMatch.groups?.digits ?? ""}` : "";
10860
- if (!swappedQuery) return primaryMatch;
10861
- const swappedMatch = matchQuery(swappedQuery);
10862
- if (!swappedMatch.matches) return primaryMatch;
10863
- return { matches: true, score: swappedMatch.score + 5 };
10989
+ // node_modules/chalk/source/vendor/supports-color/index.js
10990
+ import process2 from "process";
10991
+ import os from "os";
10992
+ import tty from "tty";
10993
+ function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process2.argv) {
10994
+ const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
10995
+ const position = argv.indexOf(prefix + flag);
10996
+ const terminatorPosition = argv.indexOf("--");
10997
+ return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
10864
10998
  }
10865
- function fuzzyFilter(items, query, getText) {
10866
- const trimmed = query.trim();
10867
- if (trimmed.length === 0) return items;
10868
- const tokens = trimmed.split(/\s+/).filter((t) => t.length > 0);
10869
- if (tokens.length === 0) return items;
10870
- const scored = [];
10871
- for (const item of items) {
10872
- const text = getText(item);
10873
- let total = 0;
10874
- let allMatch = true;
10875
- for (const token of tokens) {
10876
- const m = fuzzyMatch(token, text);
10877
- if (!m.matches) {
10878
- allMatch = false;
10879
- break;
10880
- }
10881
- total += m.score;
10999
+ function envForceColor() {
11000
+ if ("FORCE_COLOR" in env) {
11001
+ if (env.FORCE_COLOR === "true") {
11002
+ return 1;
10882
11003
  }
10883
- if (allMatch) scored.push({ item, score: total });
11004
+ if (env.FORCE_COLOR === "false") {
11005
+ return 0;
11006
+ }
11007
+ return env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);
10884
11008
  }
10885
- scored.sort((a, b) => a.score - b.score);
10886
- return scored.map((s) => s.item);
10887
11009
  }
10888
- var init_fuzzy = __esm({
10889
- "src/util/fuzzy.ts"() {
10890
- "use strict";
11010
+ function translateLevel(level) {
11011
+ if (level === 0) {
11012
+ return false;
10891
11013
  }
10892
- });
10893
-
10894
- // src/ui/resume-picker.tsx
10895
- import { useState as useState3 } from "react";
10896
- import { Box as Box9, Text as Text9, useInput } from "ink";
10897
- import SelectInput3 from "ink-select-input";
10898
- import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
10899
- function ResumePicker({ sessions, onPick }) {
10900
- const theme = useTheme();
10901
- const [page, setPage] = useState3(0);
10902
- const [selectedIndex, setSelectedIndex] = useState3(0);
10903
- const [query, setQuery] = useState3("");
10904
- const filtered = query.trim() ? fuzzyFilter(sessions, query, (s) => `${s.title ?? s.firstPrompt} ${s.id}`) : sessions;
10905
- const totalPages = Math.max(1, Math.ceil(filtered.length / PAGE_SIZE));
10906
- const safePage = Math.min(page, totalPages - 1);
10907
- const start = safePage * PAGE_SIZE;
10908
- const end = Math.min(start + PAGE_SIZE, filtered.length);
10909
- const pageSessions = filtered.slice(start, end);
10910
- useInput((input, key) => {
10911
- if (key.leftArrow && safePage > 0) {
10912
- setPage((p) => p - 1);
10913
- setSelectedIndex(0);
10914
- return;
11014
+ return {
11015
+ level,
11016
+ hasBasic: true,
11017
+ has256: level >= 2,
11018
+ has16m: level >= 3
11019
+ };
11020
+ }
11021
+ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
11022
+ const noFlagForceColor = envForceColor();
11023
+ if (noFlagForceColor !== void 0) {
11024
+ flagForceColor = noFlagForceColor;
11025
+ }
11026
+ const forceColor = sniffFlags ? flagForceColor : noFlagForceColor;
11027
+ if (forceColor === 0) {
11028
+ return 0;
11029
+ }
11030
+ if (sniffFlags) {
11031
+ if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) {
11032
+ return 3;
10915
11033
  }
10916
- if (key.rightArrow && safePage < totalPages - 1) {
10917
- setPage((p) => p + 1);
10918
- setSelectedIndex(0);
10919
- return;
11034
+ if (hasFlag("color=256")) {
11035
+ return 2;
10920
11036
  }
10921
- if (key.backspace || key.delete) {
10922
- setQuery((q) => q.slice(0, -1));
10923
- setPage(0);
10924
- setSelectedIndex(0);
10925
- return;
11037
+ }
11038
+ if ("TF_BUILD" in env && "AGENT_NAME" in env) {
11039
+ return 1;
11040
+ }
11041
+ if (haveStream && !streamIsTTY && forceColor === void 0) {
11042
+ return 0;
11043
+ }
11044
+ const min = forceColor || 0;
11045
+ if (env.TERM === "dumb") {
11046
+ return min;
11047
+ }
11048
+ if (process2.platform === "win32") {
11049
+ const osRelease = os.release().split(".");
11050
+ if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
11051
+ return Number(osRelease[2]) >= 14931 ? 3 : 2;
10926
11052
  }
10927
- if (input.length === 1 && !key.ctrl && !key.meta && !key.return && !key.escape) {
10928
- setQuery((q) => q + input);
10929
- setPage(0);
10930
- setSelectedIndex(0);
10931
- return;
11053
+ return 1;
11054
+ }
11055
+ if ("CI" in env) {
11056
+ if (["GITHUB_ACTIONS", "GITEA_ACTIONS", "CIRCLECI"].some((key) => key in env)) {
11057
+ return 3;
10932
11058
  }
10933
- if (input === "q" || key.escape) {
10934
- onPick(null);
10935
- return;
11059
+ if (["TRAVIS", "APPVEYOR", "GITLAB_CI", "BUILDKITE", "DRONE"].some((sign) => sign in env) || env.CI_NAME === "codeship") {
11060
+ return 1;
10936
11061
  }
10937
- });
10938
- if (sessions.length === 0) {
10939
- return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10940
- /* @__PURE__ */ jsx10(Text9, { color: theme.accent, bold: true, children: "Resume a session" }),
10941
- /* @__PURE__ */ jsx10(Text9, { color: theme.info.color, children: "No saved sessions yet. Press Enter to dismiss." }),
10942
- /* @__PURE__ */ jsx10(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx10(
10943
- SelectInput3,
10944
- {
10945
- items: [{ label: "(back)", value: "__cancel__" }],
10946
- onSelect: () => onPick(null)
10947
- }
10948
- ) })
10949
- ] });
11062
+ return min;
10950
11063
  }
10951
- const items = pageSessions.map((s) => ({
10952
- label: `${formatDate(s.updatedAt)} \xB7 ${s.messageCount} msgs \xB7 ${s.title ?? s.firstPrompt}`,
10953
- value: s.id
10954
- }));
10955
- return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
10956
- /* @__PURE__ */ jsx10(Text9, { color: theme.accent, bold: true, children: "Resume a session" }),
10957
- /* @__PURE__ */ jsxs9(Text9, { color: theme.info.color, children: [
10958
- query ? `Search: ${query}\u258C` : "Type to search\u2026",
10959
- " \xB7 Page ",
10960
- safePage + 1,
10961
- " of ",
10962
- totalPages,
10963
- " (",
10964
- filtered.length,
10965
- " total)"
10966
- ] }),
10967
- /* @__PURE__ */ jsx10(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx10(
10968
- SelectInput3,
10969
- {
10970
- items,
10971
- initialIndex: selectedIndex,
10972
- onHighlight: (item) => {
10973
- const idx = items.findIndex((i) => i.value === item.value);
10974
- if (idx >= 0) setSelectedIndex(idx);
10975
- },
10976
- onSelect: (item) => {
10977
- const picked = sessions.find((s) => s.id === item.value) ?? null;
10978
- onPick(picked);
10979
- }
10980
- }
10981
- ) }),
10982
- /* @__PURE__ */ jsx10(Box9, { marginTop: 1, children: /* @__PURE__ */ jsxs9(Text9, { color: theme.info.color, children: [
10983
- safePage > 0 ? "\u2190 prev " : "",
10984
- safePage < totalPages - 1 ? "\u2192 next " : "",
10985
- "q: cancel"
10986
- ] }) })
10987
- ] });
10988
- }
10989
- function formatDate(iso) {
10990
- try {
10991
- const d = new Date(iso);
10992
- return d.toLocaleString(void 0, {
10993
- month: "short",
10994
- day: "numeric",
10995
- hour: "2-digit",
10996
- minute: "2-digit"
10997
- });
10998
- } catch {
10999
- return iso;
11064
+ if ("TEAMCITY_VERSION" in env) {
11065
+ return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
11000
11066
  }
11001
- }
11002
- var PAGE_SIZE;
11003
- var init_resume_picker = __esm({
11004
- "src/ui/resume-picker.tsx"() {
11005
- "use strict";
11006
- init_fuzzy();
11007
- init_theme_context();
11008
- PAGE_SIZE = 5;
11067
+ if (env.COLORTERM === "truecolor") {
11068
+ return 3;
11009
11069
  }
11010
- });
11011
-
11012
- // src/ui/checkpoint-picker.tsx
11013
- import { useState as useState4 } from "react";
11014
- import { Box as Box10, Text as Text10, useInput as useInput2 } from "ink";
11015
- import SelectInput4 from "ink-select-input";
11016
- import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
11017
- function CheckpointPicker({ session, checkpoints, onPick }) {
11018
- const theme = useTheme();
11019
- const [selectedIndex, setSelectedIndex] = useState4(0);
11020
- useInput2((input, key) => {
11021
- if (input === "q" || key.escape) {
11022
- onPick(null);
11023
- return;
11024
- }
11025
- });
11026
- const items = [
11027
- {
11028
- label: `Resume from beginning (${session.messageCount} msgs)`,
11029
- value: "__start__"
11030
- },
11031
- ...checkpoints.map((cp) => ({
11032
- label: `Resume from: "${cp.label}" \u2014 turn ${cp.turnIndex} \xB7 ${formatDate2(cp.timestamp)}`,
11033
- value: cp.id
11034
- }))
11035
- ];
11036
- return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11037
- /* @__PURE__ */ jsx11(Text10, { color: theme.accent, bold: true, children: session.firstPrompt.slice(0, 50) }),
11038
- /* @__PURE__ */ jsxs10(Text10, { color: theme.info.color, children: [
11039
- session.messageCount,
11040
- " turns \xB7 ",
11041
- checkpoints.length,
11042
- " checkpoint",
11043
- checkpoints.length === 1 ? "" : "s"
11044
- ] }),
11045
- /* @__PURE__ */ jsx11(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx11(
11046
- SelectInput4,
11047
- {
11048
- items,
11049
- initialIndex: selectedIndex,
11050
- onHighlight: (item) => {
11051
- const idx = items.findIndex((i) => i.value === item.value);
11052
- if (idx >= 0) setSelectedIndex(idx);
11053
- },
11054
- onSelect: (item) => {
11055
- if (item.value === "__start__") {
11056
- onPick("__start__");
11057
- } else {
11058
- onPick(item.value);
11059
- }
11060
- }
11061
- }
11062
- ) }),
11063
- /* @__PURE__ */ jsx11(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text10, { color: theme.info.color, children: "q: cancel / go back" }) })
11064
- ] });
11065
- }
11066
- function formatDate2(iso) {
11067
- try {
11068
- const d = new Date(iso);
11069
- return d.toLocaleString(void 0, {
11070
- month: "short",
11071
- day: "numeric",
11072
- hour: "2-digit",
11073
- minute: "2-digit"
11074
- });
11075
- } catch {
11076
- return iso;
11070
+ if (env.TERM === "xterm-kitty") {
11071
+ return 3;
11077
11072
  }
11078
- }
11079
- var init_checkpoint_picker = __esm({
11080
- "src/ui/checkpoint-picker.tsx"() {
11081
- "use strict";
11082
- init_theme_context();
11073
+ if (env.TERM === "xterm-ghostty") {
11074
+ return 3;
11083
11075
  }
11084
- });
11085
-
11086
- // src/ui/task-list.tsx
11087
- import { useEffect as useEffect3, useRef, useState as useState5 } from "react";
11088
- import { Box as Box11, Text as Text11 } from "ink";
11089
- import Spinner4 from "ink-spinner";
11090
- import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
11091
- function TaskList({ tasks, startedAt, tokensDelta }) {
11092
- const theme = useTheme();
11093
- const [now2, setNow] = useState5(Date.now());
11094
- const [celebrating, setCelebrating] = useState5(false);
11095
- const tasksRef = useRef(tasks);
11096
- const prevAllDoneRef = useRef(false);
11097
- tasksRef.current = tasks;
11098
- useEffect3(() => {
11099
- if (startedAt === null) return;
11100
- const id = setInterval(() => {
11101
- setNow(Date.now());
11102
- const current = tasksRef.current;
11103
- if (current.length > 0 && current.every((t) => t.status === "completed")) {
11104
- clearInterval(id);
11076
+ if (env.TERM === "wezterm") {
11077
+ return 3;
11078
+ }
11079
+ if ("TERM_PROGRAM" in env) {
11080
+ const version = Number.parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
11081
+ switch (env.TERM_PROGRAM) {
11082
+ case "iTerm.app": {
11083
+ return version >= 3 ? 3 : 2;
11084
+ }
11085
+ case "Apple_Terminal": {
11086
+ return 2;
11105
11087
  }
11106
- }, 1e3);
11107
- return () => clearInterval(id);
11108
- }, [startedAt]);
11109
- useEffect3(() => {
11110
- const allDone2 = tasks.length > 0 && tasks.every((t) => t.status === "completed");
11111
- if (allDone2 && !prevAllDoneRef.current) {
11112
- setCelebrating(true);
11113
- const id = setTimeout(() => setCelebrating(false), 1500);
11114
- return () => clearTimeout(id);
11115
11088
  }
11116
- prevAllDoneRef.current = allDone2;
11117
- }, [tasks]);
11118
- if (tasks.length === 0) return null;
11119
- const active = tasks.find((t) => t.status === "in_progress");
11120
- const done = tasks.filter((t) => t.status === "completed").length;
11121
- const total = tasks.length;
11122
- const allDone = done === total;
11123
- const header = active ? active.title : allDone ? `${total} tasks done` : `${done}/${total}`;
11124
- const elapsed = startedAt ? formatElapsed3(now2 - startedAt) : null;
11125
- const headerStats = [elapsed, tokensDelta > 0 ? `\u2191 ${formatTokens3(tokensDelta)} tokens` : null].filter(Boolean).join(" \xB7 ");
11126
- const visibleTasks = tasks.slice(0, MAX_VISIBLE);
11127
- const hiddenPending = Math.max(0, tasks.length - visibleTasks.length);
11128
- return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", marginBottom: 1, children: [
11129
- /* @__PURE__ */ jsxs11(Box11, { children: [
11130
- /* @__PURE__ */ jsx12(Text11, { color: celebrating ? theme.palette.success : allDone ? "green" : theme.accent, bold: true, children: celebrating ? `\u2728 ${header}` : header }),
11131
- headerStats && /* @__PURE__ */ jsxs11(Text11, { color: theme.info.color, children: [
11132
- " ",
11133
- "(",
11134
- headerStats,
11135
- ")"
11136
- ] })
11137
- ] }),
11138
- visibleTasks.map((t) => /* @__PURE__ */ jsx12(TaskRow, { task: t }, t.id)),
11139
- hiddenPending > 0 && /* @__PURE__ */ jsxs11(Text11, { color: theme.info.color, children: [
11140
- " ",
11141
- "\u2026 +",
11142
- hiddenPending,
11143
- " more"
11144
- ] })
11145
- ] });
11146
- }
11147
- function TaskRow({ task }) {
11148
- const theme = useTheme();
11149
- if (task.status === "completed") {
11150
- return /* @__PURE__ */ jsxs11(Text11, { color: theme.info.color, children: [
11151
- " ",
11152
- "\u2713 ",
11153
- /* @__PURE__ */ jsx12(Text11, { strikethrough: true, children: task.title })
11154
- ] });
11155
11089
  }
11156
- if (task.status === "in_progress") {
11157
- return /* @__PURE__ */ jsxs11(Text11, { color: theme.accent, bold: true, children: [
11158
- " ",
11159
- /* @__PURE__ */ jsx12(Spinner4, { type: "line" }),
11160
- " ",
11161
- task.title
11162
- ] });
11090
+ if (/-256(color)?$/i.test(env.TERM)) {
11091
+ return 2;
11163
11092
  }
11164
- return /* @__PURE__ */ jsxs11(Text11, { color: theme.info.color, children: [
11165
- " ",
11166
- "\u2610 ",
11167
- task.title
11168
- ] });
11169
- }
11170
- function formatElapsed3(ms) {
11171
- const total = Math.floor(ms / 1e3);
11172
- const m = Math.floor(total / 60);
11173
- const s = total % 60;
11174
- if (m === 0) return `${s}s`;
11175
- return `${m}m ${s}s`;
11093
+ if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
11094
+ return 1;
11095
+ }
11096
+ if ("COLORTERM" in env) {
11097
+ return 1;
11098
+ }
11099
+ return min;
11176
11100
  }
11177
- function formatTokens3(n) {
11178
- if (n < 1e3) return String(n);
11179
- return `${(n / 1e3).toFixed(1)}k`;
11101
+ function createSupportsColor(stream, options = {}) {
11102
+ const level = _supportsColor(stream, {
11103
+ streamIsTTY: stream && stream.isTTY,
11104
+ ...options
11105
+ });
11106
+ return translateLevel(level);
11180
11107
  }
11181
- var MAX_VISIBLE;
11182
- var init_task_list = __esm({
11183
- "src/ui/task-list.tsx"() {
11108
+ var env, flagForceColor, supportsColor, supports_color_default;
11109
+ var init_supports_color = __esm({
11110
+ "node_modules/chalk/source/vendor/supports-color/index.js"() {
11184
11111
  "use strict";
11185
- init_theme_context();
11186
- MAX_VISIBLE = 6;
11112
+ ({ env } = process2);
11113
+ if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
11114
+ flagForceColor = 0;
11115
+ } else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
11116
+ flagForceColor = 1;
11117
+ }
11118
+ supportsColor = {
11119
+ stdout: createSupportsColor({ isTTY: tty.isatty(1) }),
11120
+ stderr: createSupportsColor({ isTTY: tty.isatty(2) })
11121
+ };
11122
+ supports_color_default = supportsColor;
11187
11123
  }
11188
11124
  });
11189
11125
 
11190
- // node_modules/chalk/source/vendor/ansi-styles/index.js
11191
- function assembleStyles() {
11192
- const codes = /* @__PURE__ */ new Map();
11193
- for (const [groupName, group] of Object.entries(styles)) {
11194
- for (const [styleName, style] of Object.entries(group)) {
11195
- styles[styleName] = {
11196
- open: `\x1B[${style[0]}m`,
11197
- close: `\x1B[${style[1]}m`
11198
- };
11199
- group[styleName] = styles[styleName];
11200
- codes.set(style[0], style[1]);
11201
- }
11202
- Object.defineProperty(styles, groupName, {
11203
- value: group,
11204
- enumerable: false
11205
- });
11126
+ // node_modules/chalk/source/utilities.js
11127
+ function stringReplaceAll(string, substring, replacer) {
11128
+ let index = string.indexOf(substring);
11129
+ if (index === -1) {
11130
+ return string;
11206
11131
  }
11207
- Object.defineProperty(styles, "codes", {
11208
- value: codes,
11209
- enumerable: false
11210
- });
11211
- styles.color.close = "\x1B[39m";
11212
- styles.bgColor.close = "\x1B[49m";
11213
- styles.color.ansi = wrapAnsi16();
11214
- styles.color.ansi256 = wrapAnsi256();
11215
- styles.color.ansi16m = wrapAnsi16m();
11216
- styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
11217
- styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
11218
- styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
11219
- Object.defineProperties(styles, {
11220
- rgbToAnsi256: {
11221
- value(red, green, blue) {
11222
- if (red === green && green === blue) {
11223
- if (red < 8) {
11224
- return 16;
11225
- }
11226
- if (red > 248) {
11227
- return 231;
11228
- }
11229
- return Math.round((red - 8) / 247 * 24) + 232;
11230
- }
11231
- return 16 + 36 * Math.round(red / 255 * 5) + 6 * Math.round(green / 255 * 5) + Math.round(blue / 255 * 5);
11232
- },
11233
- enumerable: false
11234
- },
11235
- hexToRgb: {
11236
- value(hex) {
11237
- const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16));
11238
- if (!matches) {
11239
- return [0, 0, 0];
11240
- }
11241
- let [colorString] = matches;
11242
- if (colorString.length === 3) {
11243
- colorString = [...colorString].map((character) => character + character).join("");
11244
- }
11245
- const integer = Number.parseInt(colorString, 16);
11246
- return [
11247
- /* eslint-disable no-bitwise */
11248
- integer >> 16 & 255,
11249
- integer >> 8 & 255,
11250
- integer & 255
11251
- /* eslint-enable no-bitwise */
11252
- ];
11253
- },
11254
- enumerable: false
11255
- },
11256
- hexToAnsi256: {
11257
- value: (hex) => styles.rgbToAnsi256(...styles.hexToRgb(hex)),
11258
- enumerable: false
11259
- },
11260
- ansi256ToAnsi: {
11261
- value(code) {
11262
- if (code < 8) {
11263
- return 30 + code;
11264
- }
11265
- if (code < 16) {
11266
- return 90 + (code - 8);
11267
- }
11268
- let red;
11269
- let green;
11270
- let blue;
11271
- if (code >= 232) {
11272
- red = ((code - 232) * 10 + 8) / 255;
11273
- green = red;
11274
- blue = red;
11275
- } else {
11276
- code -= 16;
11277
- const remainder = code % 36;
11278
- red = Math.floor(code / 36) / 5;
11279
- green = Math.floor(remainder / 6) / 5;
11280
- blue = remainder % 6 / 5;
11281
- }
11282
- const value = Math.max(red, green, blue) * 2;
11283
- if (value === 0) {
11284
- return 30;
11285
- }
11286
- let result = 30 + (Math.round(blue) << 2 | Math.round(green) << 1 | Math.round(red));
11287
- if (value === 2) {
11288
- result += 60;
11289
- }
11290
- return result;
11291
- },
11292
- enumerable: false
11293
- },
11294
- rgbToAnsi: {
11295
- value: (red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)),
11296
- enumerable: false
11297
- },
11298
- hexToAnsi: {
11299
- value: (hex) => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)),
11300
- enumerable: false
11301
- }
11302
- });
11303
- return styles;
11132
+ const substringLength = substring.length;
11133
+ let endIndex = 0;
11134
+ let returnValue = "";
11135
+ do {
11136
+ returnValue += string.slice(endIndex, index) + substring + replacer;
11137
+ endIndex = index + substringLength;
11138
+ index = string.indexOf(substring, endIndex);
11139
+ } while (index !== -1);
11140
+ returnValue += string.slice(endIndex);
11141
+ return returnValue;
11304
11142
  }
11305
- var ANSI_BACKGROUND_OFFSET, wrapAnsi16, wrapAnsi256, wrapAnsi16m, styles, modifierNames, foregroundColorNames, backgroundColorNames, colorNames, ansiStyles, ansi_styles_default;
11306
- var init_ansi_styles = __esm({
11307
- "node_modules/chalk/source/vendor/ansi-styles/index.js"() {
11143
+ function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
11144
+ let endIndex = 0;
11145
+ let returnValue = "";
11146
+ do {
11147
+ const gotCR = string[index - 1] === "\r";
11148
+ returnValue += string.slice(endIndex, gotCR ? index - 1 : index) + prefix + (gotCR ? "\r\n" : "\n") + postfix;
11149
+ endIndex = index + 1;
11150
+ index = string.indexOf("\n", endIndex);
11151
+ } while (index !== -1);
11152
+ returnValue += string.slice(endIndex);
11153
+ return returnValue;
11154
+ }
11155
+ var init_utilities = __esm({
11156
+ "node_modules/chalk/source/utilities.js"() {
11308
11157
  "use strict";
11309
- ANSI_BACKGROUND_OFFSET = 10;
11310
- wrapAnsi16 = (offset = 0) => (code) => `\x1B[${code + offset}m`;
11311
- wrapAnsi256 = (offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`;
11312
- wrapAnsi16m = (offset = 0) => (red, green, blue) => `\x1B[${38 + offset};2;${red};${green};${blue}m`;
11313
- styles = {
11314
- modifier: {
11315
- reset: [0, 0],
11316
- // 21 isn't widely supported and 22 does the same thing
11317
- bold: [1, 22],
11318
- dim: [2, 22],
11319
- italic: [3, 23],
11320
- underline: [4, 24],
11321
- overline: [53, 55],
11322
- inverse: [7, 27],
11323
- hidden: [8, 28],
11324
- strikethrough: [9, 29]
11325
- },
11326
- color: {
11327
- black: [30, 39],
11328
- red: [31, 39],
11329
- green: [32, 39],
11330
- yellow: [33, 39],
11331
- blue: [34, 39],
11332
- magenta: [35, 39],
11333
- cyan: [36, 39],
11334
- white: [37, 39],
11335
- // Bright color
11336
- blackBright: [90, 39],
11337
- gray: [90, 39],
11338
- // Alias of `blackBright`
11339
- grey: [90, 39],
11340
- // Alias of `blackBright`
11341
- redBright: [91, 39],
11342
- greenBright: [92, 39],
11343
- yellowBright: [93, 39],
11344
- blueBright: [94, 39],
11345
- magentaBright: [95, 39],
11346
- cyanBright: [96, 39],
11347
- whiteBright: [97, 39]
11348
- },
11349
- bgColor: {
11350
- bgBlack: [40, 49],
11351
- bgRed: [41, 49],
11352
- bgGreen: [42, 49],
11353
- bgYellow: [43, 49],
11354
- bgBlue: [44, 49],
11355
- bgMagenta: [45, 49],
11356
- bgCyan: [46, 49],
11357
- bgWhite: [47, 49],
11358
- // Bright color
11359
- bgBlackBright: [100, 49],
11360
- bgGray: [100, 49],
11361
- // Alias of `bgBlackBright`
11362
- bgGrey: [100, 49],
11363
- // Alias of `bgBlackBright`
11364
- bgRedBright: [101, 49],
11365
- bgGreenBright: [102, 49],
11366
- bgYellowBright: [103, 49],
11367
- bgBlueBright: [104, 49],
11368
- bgMagentaBright: [105, 49],
11369
- bgCyanBright: [106, 49],
11370
- bgWhiteBright: [107, 49]
11371
- }
11372
- };
11373
- modifierNames = Object.keys(styles.modifier);
11374
- foregroundColorNames = Object.keys(styles.color);
11375
- backgroundColorNames = Object.keys(styles.bgColor);
11376
- colorNames = [...foregroundColorNames, ...backgroundColorNames];
11377
- ansiStyles = assembleStyles();
11378
- ansi_styles_default = ansiStyles;
11379
11158
  }
11380
11159
  });
11381
11160
 
11382
- // node_modules/chalk/source/vendor/supports-color/index.js
11383
- import process2 from "process";
11384
- import os from "os";
11385
- import tty from "tty";
11386
- function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process2.argv) {
11387
- const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
11388
- const position = argv.indexOf(prefix + flag);
11389
- const terminatorPosition = argv.indexOf("--");
11390
- return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
11161
+ // node_modules/chalk/source/index.js
11162
+ function createChalk(options) {
11163
+ return chalkFactory(options);
11391
11164
  }
11392
- function envForceColor() {
11393
- if ("FORCE_COLOR" in env) {
11394
- if (env.FORCE_COLOR === "true") {
11395
- return 1;
11396
- }
11397
- if (env.FORCE_COLOR === "false") {
11398
- return 0;
11399
- }
11400
- return env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);
11401
- }
11402
- }
11403
- function translateLevel(level) {
11404
- if (level === 0) {
11405
- return false;
11406
- }
11407
- return {
11408
- level,
11409
- hasBasic: true,
11410
- has256: level >= 2,
11411
- has16m: level >= 3
11412
- };
11413
- }
11414
- function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
11415
- const noFlagForceColor = envForceColor();
11416
- if (noFlagForceColor !== void 0) {
11417
- flagForceColor = noFlagForceColor;
11418
- }
11419
- const forceColor = sniffFlags ? flagForceColor : noFlagForceColor;
11420
- if (forceColor === 0) {
11421
- return 0;
11422
- }
11423
- if (sniffFlags) {
11424
- if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) {
11425
- return 3;
11426
- }
11427
- if (hasFlag("color=256")) {
11428
- return 2;
11429
- }
11430
- }
11431
- if ("TF_BUILD" in env && "AGENT_NAME" in env) {
11432
- return 1;
11433
- }
11434
- if (haveStream && !streamIsTTY && forceColor === void 0) {
11435
- return 0;
11436
- }
11437
- const min = forceColor || 0;
11438
- if (env.TERM === "dumb") {
11439
- return min;
11440
- }
11441
- if (process2.platform === "win32") {
11442
- const osRelease = os.release().split(".");
11443
- if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
11444
- return Number(osRelease[2]) >= 14931 ? 3 : 2;
11445
- }
11446
- return 1;
11447
- }
11448
- if ("CI" in env) {
11449
- if (["GITHUB_ACTIONS", "GITEA_ACTIONS", "CIRCLECI"].some((key) => key in env)) {
11450
- return 3;
11451
- }
11452
- if (["TRAVIS", "APPVEYOR", "GITLAB_CI", "BUILDKITE", "DRONE"].some((sign) => sign in env) || env.CI_NAME === "codeship") {
11453
- return 1;
11454
- }
11455
- return min;
11456
- }
11457
- if ("TEAMCITY_VERSION" in env) {
11458
- return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
11459
- }
11460
- if (env.COLORTERM === "truecolor") {
11461
- return 3;
11462
- }
11463
- if (env.TERM === "xterm-kitty") {
11464
- return 3;
11465
- }
11466
- if (env.TERM === "xterm-ghostty") {
11467
- return 3;
11468
- }
11469
- if (env.TERM === "wezterm") {
11470
- return 3;
11471
- }
11472
- if ("TERM_PROGRAM" in env) {
11473
- const version = Number.parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
11474
- switch (env.TERM_PROGRAM) {
11475
- case "iTerm.app": {
11476
- return version >= 3 ? 3 : 2;
11477
- }
11478
- case "Apple_Terminal": {
11479
- return 2;
11480
- }
11481
- }
11482
- }
11483
- if (/-256(color)?$/i.test(env.TERM)) {
11484
- return 2;
11485
- }
11486
- if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
11487
- return 1;
11488
- }
11489
- if ("COLORTERM" in env) {
11490
- return 1;
11491
- }
11492
- return min;
11493
- }
11494
- function createSupportsColor(stream, options = {}) {
11495
- const level = _supportsColor(stream, {
11496
- streamIsTTY: stream && stream.isTTY,
11497
- ...options
11498
- });
11499
- return translateLevel(level);
11500
- }
11501
- var env, flagForceColor, supportsColor, supports_color_default;
11502
- var init_supports_color = __esm({
11503
- "node_modules/chalk/source/vendor/supports-color/index.js"() {
11504
- "use strict";
11505
- ({ env } = process2);
11506
- if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
11507
- flagForceColor = 0;
11508
- } else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
11509
- flagForceColor = 1;
11510
- }
11511
- supportsColor = {
11512
- stdout: createSupportsColor({ isTTY: tty.isatty(1) }),
11513
- stderr: createSupportsColor({ isTTY: tty.isatty(2) })
11514
- };
11515
- supports_color_default = supportsColor;
11516
- }
11517
- });
11518
-
11519
- // node_modules/chalk/source/utilities.js
11520
- function stringReplaceAll(string, substring, replacer) {
11521
- let index = string.indexOf(substring);
11522
- if (index === -1) {
11523
- return string;
11524
- }
11525
- const substringLength = substring.length;
11526
- let endIndex = 0;
11527
- let returnValue = "";
11528
- do {
11529
- returnValue += string.slice(endIndex, index) + substring + replacer;
11530
- endIndex = index + substringLength;
11531
- index = string.indexOf(substring, endIndex);
11532
- } while (index !== -1);
11533
- returnValue += string.slice(endIndex);
11534
- return returnValue;
11535
- }
11536
- function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
11537
- let endIndex = 0;
11538
- let returnValue = "";
11539
- do {
11540
- const gotCR = string[index - 1] === "\r";
11541
- returnValue += string.slice(endIndex, gotCR ? index - 1 : index) + prefix + (gotCR ? "\r\n" : "\n") + postfix;
11542
- endIndex = index + 1;
11543
- index = string.indexOf("\n", endIndex);
11544
- } while (index !== -1);
11545
- returnValue += string.slice(endIndex);
11546
- return returnValue;
11547
- }
11548
- var init_utilities = __esm({
11549
- "node_modules/chalk/source/utilities.js"() {
11550
- "use strict";
11551
- }
11552
- });
11553
-
11554
- // node_modules/chalk/source/index.js
11555
- function createChalk(options) {
11556
- return chalkFactory(options);
11557
- }
11558
- var stdoutColor, stderrColor, GENERATOR, STYLER, IS_EMPTY, levelMapping, styles2, applyOptions, chalkFactory, getModelAnsi, usedModels, proto, createStyler, createBuilder, applyStyle, chalk, chalkStderr, source_default;
11559
- var init_source = __esm({
11560
- "node_modules/chalk/source/index.js"() {
11561
- "use strict";
11562
- init_ansi_styles();
11563
- init_supports_color();
11564
- init_utilities();
11565
- ({ stdout: stdoutColor, stderr: stderrColor } = supports_color_default);
11566
- GENERATOR = /* @__PURE__ */ Symbol("GENERATOR");
11567
- STYLER = /* @__PURE__ */ Symbol("STYLER");
11568
- IS_EMPTY = /* @__PURE__ */ Symbol("IS_EMPTY");
11569
- levelMapping = [
11570
- "ansi",
11571
- "ansi",
11572
- "ansi256",
11573
- "ansi16m"
11574
- ];
11575
- styles2 = /* @__PURE__ */ Object.create(null);
11576
- applyOptions = (object, options = {}) => {
11577
- if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) {
11578
- throw new Error("The `level` option should be an integer from 0 to 3");
11579
- }
11580
- const colorLevel = stdoutColor ? stdoutColor.level : 0;
11581
- object.level = options.level === void 0 ? colorLevel : options.level;
11582
- };
11583
- chalkFactory = (options) => {
11584
- const chalk2 = (...strings) => strings.join(" ");
11585
- applyOptions(chalk2, options);
11586
- Object.setPrototypeOf(chalk2, createChalk.prototype);
11587
- return chalk2;
11588
- };
11589
- Object.setPrototypeOf(createChalk.prototype, Function.prototype);
11590
- for (const [styleName, style] of Object.entries(ansi_styles_default)) {
11591
- styles2[styleName] = {
11592
- get() {
11593
- const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);
11594
- Object.defineProperty(this, styleName, { value: builder });
11595
- return builder;
11596
- }
11597
- };
11165
+ var stdoutColor, stderrColor, GENERATOR, STYLER, IS_EMPTY, levelMapping, styles2, applyOptions, chalkFactory, getModelAnsi, usedModels, proto, createStyler, createBuilder, applyStyle, chalk, chalkStderr, source_default;
11166
+ var init_source = __esm({
11167
+ "node_modules/chalk/source/index.js"() {
11168
+ "use strict";
11169
+ init_ansi_styles();
11170
+ init_supports_color();
11171
+ init_utilities();
11172
+ ({ stdout: stdoutColor, stderr: stderrColor } = supports_color_default);
11173
+ GENERATOR = /* @__PURE__ */ Symbol("GENERATOR");
11174
+ STYLER = /* @__PURE__ */ Symbol("STYLER");
11175
+ IS_EMPTY = /* @__PURE__ */ Symbol("IS_EMPTY");
11176
+ levelMapping = [
11177
+ "ansi",
11178
+ "ansi",
11179
+ "ansi256",
11180
+ "ansi16m"
11181
+ ];
11182
+ styles2 = /* @__PURE__ */ Object.create(null);
11183
+ applyOptions = (object, options = {}) => {
11184
+ if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) {
11185
+ throw new Error("The `level` option should be an integer from 0 to 3");
11186
+ }
11187
+ const colorLevel = stdoutColor ? stdoutColor.level : 0;
11188
+ object.level = options.level === void 0 ? colorLevel : options.level;
11189
+ };
11190
+ chalkFactory = (options) => {
11191
+ const chalk2 = (...strings) => strings.join(" ");
11192
+ applyOptions(chalk2, options);
11193
+ Object.setPrototypeOf(chalk2, createChalk.prototype);
11194
+ return chalk2;
11195
+ };
11196
+ Object.setPrototypeOf(createChalk.prototype, Function.prototype);
11197
+ for (const [styleName, style] of Object.entries(ansi_styles_default)) {
11198
+ styles2[styleName] = {
11199
+ get() {
11200
+ const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);
11201
+ Object.defineProperty(this, styleName, { value: builder });
11202
+ return builder;
11203
+ }
11204
+ };
11598
11205
  }
11599
11206
  styles2.visible = {
11600
11207
  get() {
@@ -11708,16 +11315,20 @@ var init_source = __esm({
11708
11315
  });
11709
11316
 
11710
11317
  // src/ui/text-input.tsx
11711
- import { useState as useState6, useEffect as useEffect4, useRef as useRef2 } from "react";
11712
- import { Text as Text12, useInput as useInput3 } from "ink";
11713
- import { jsx as jsx13 } from "react/jsx-runtime";
11318
+ import { useState as useState3, useEffect as useEffect3, useRef } from "react";
11319
+ import { Text as Text7, useInput } from "ink";
11320
+ import { jsx as jsx8 } from "react/jsx-runtime";
11714
11321
  function shouldTreatAsPaste(input) {
11715
11322
  if (input.length >= PASTE_CHAR_THRESHOLD) return true;
11716
11323
  const newlines = (input.match(/\n/g) ?? []).length;
11717
11324
  return newlines >= PASTE_NEWLINE_THRESHOLD;
11718
11325
  }
11719
- function newPasteId() {
11720
- return Math.random().toString(36).slice(2, 7);
11326
+ function makePastePreview(input, lines, id) {
11327
+ const firstLine2 = input.split("\n")[0] ?? "";
11328
+ const cleaned = firstLine2.trim().replace(/\s+/g, " ");
11329
+ const preview = cleaned.length > 20 ? cleaned.slice(0, 20) + "\u2026" : cleaned;
11330
+ const text = preview || "(empty)";
11331
+ return `\u2997"${text}" (${lines} line${lines === 1 ? "" : "s"}) #${id}\u2998`;
11721
11332
  }
11722
11333
  function countLines(s) {
11723
11334
  return s.split("\n").length;
@@ -11748,23 +11359,25 @@ function CustomTextInput({
11748
11359
  onPickerUp,
11749
11360
  onPickerDown,
11750
11361
  onPickerSelect,
11751
- onPickerCancel
11362
+ onPickerCancel,
11363
+ onCancel
11752
11364
  }) {
11753
- const [internalCursor, setInternalCursor] = useState6(value.length);
11365
+ const [internalCursor, setInternalCursor] = useState3(value.length);
11754
11366
  const cursorOffset = controlledCursor ?? internalCursor;
11755
11367
  const setCursorOffset = (offset) => {
11756
11368
  setInternalCursor(offset);
11757
11369
  onCursorChange?.(offset);
11758
11370
  };
11759
- const pastesRef = useRef2(/* @__PURE__ */ new Map());
11760
- useEffect4(() => {
11371
+ const pastesRef = useRef(/* @__PURE__ */ new Map());
11372
+ const pasteCounterRef = useRef(0);
11373
+ useEffect3(() => {
11761
11374
  if (!focus) return;
11762
11375
  const next = cursorOffset > value.length ? value.length : cursorOffset;
11763
11376
  if (next !== cursorOffset) {
11764
11377
  setCursorOffset(next);
11765
11378
  }
11766
11379
  }, [value, focus, cursorOffset]);
11767
- useInput3(
11380
+ useInput(
11768
11381
  (input, key) => {
11769
11382
  if (!focus) return;
11770
11383
  if (key.ctrl && input === "c") return;
@@ -11789,6 +11402,11 @@ function CustomTextInput({
11789
11402
  return;
11790
11403
  }
11791
11404
  }
11405
+ if (key.escape) {
11406
+ onCancel?.();
11407
+ setCursorOffset(0);
11408
+ return;
11409
+ }
11792
11410
  if (key.return) {
11793
11411
  let full = value;
11794
11412
  let hasPastes = false;
@@ -11886,72 +11504,644 @@ function CustomTextInput({
11886
11504
  let toInsert = input;
11887
11505
  if (enablePaste && shouldTreatAsPaste(input)) {
11888
11506
  const lines = countLines(input);
11889
- const id = newPasteId();
11890
- const placeholder = `[pasted ${lines} line${lines === 1 ? "" : "s"} #${id}]`;
11507
+ const id = ++pasteCounterRef.current;
11508
+ const placeholder = makePastePreview(input, lines, id);
11891
11509
  pastesRef.current.set(placeholder, input);
11892
11510
  toInsert = placeholder;
11893
11511
  }
11894
- nextValue = value.slice(0, cursorOffset) + toInsert + value.slice(cursorOffset);
11895
- nextCursor = cursorOffset + toInsert.length;
11896
- }
11897
- if (nextCursor < 0) nextCursor = 0;
11898
- if (nextCursor > nextValue.length) nextCursor = nextValue.length;
11899
- if (didDelete && nextValue === "" && value !== "") {
11900
- onClearQueueItem?.(value);
11901
- }
11902
- if (nextCursor !== cursorOffset) {
11903
- setCursorOffset(nextCursor);
11904
- }
11905
- if (nextValue !== value) {
11906
- onChange(nextValue);
11512
+ nextValue = value.slice(0, cursorOffset) + toInsert + value.slice(cursorOffset);
11513
+ nextCursor = cursorOffset + toInsert.length;
11514
+ }
11515
+ if (nextCursor < 0) nextCursor = 0;
11516
+ if (nextCursor > nextValue.length) nextCursor = nextValue.length;
11517
+ if (didDelete && nextValue === "" && value !== "") {
11518
+ onClearQueueItem?.(value);
11519
+ }
11520
+ if (nextCursor !== cursorOffset) {
11521
+ setCursorOffset(nextCursor);
11522
+ }
11523
+ if (nextValue !== value) {
11524
+ onChange(nextValue);
11525
+ }
11526
+ },
11527
+ { isActive: focus }
11528
+ );
11529
+ const displayValue = mask ? mask.repeat(value.length) : value;
11530
+ let renderedValue = "";
11531
+ let i = 0;
11532
+ for (const char of displayValue) {
11533
+ renderedValue += i === cursorOffset ? source_default.inverse(char) : char;
11534
+ i++;
11535
+ }
11536
+ if (displayValue.length === 0) {
11537
+ renderedValue = source_default.inverse(" ");
11538
+ } else if (cursorOffset === displayValue.length) {
11539
+ renderedValue += source_default.inverse(" ");
11540
+ }
11541
+ return /* @__PURE__ */ jsx8(Text7, { children: renderedValue });
11542
+ }
11543
+ function findPasteTokenEndingAt(value, pos, pastes) {
11544
+ if (pos <= 0 || value[pos - 1] !== "\u2998") return -1;
11545
+ for (const placeholder of pastes.keys()) {
11546
+ if (placeholder.length > pos) continue;
11547
+ const start = pos - placeholder.length;
11548
+ if (value.slice(start, pos) === placeholder) return start;
11549
+ }
11550
+ return -1;
11551
+ }
11552
+ var PASTE_CHAR_THRESHOLD, PASTE_NEWLINE_THRESHOLD;
11553
+ var init_text_input = __esm({
11554
+ "src/ui/text-input.tsx"() {
11555
+ "use strict";
11556
+ init_source();
11557
+ PASTE_CHAR_THRESHOLD = 200;
11558
+ PASTE_NEWLINE_THRESHOLD = 1;
11559
+ }
11560
+ });
11561
+
11562
+ // src/ui/permission.tsx
11563
+ import { useState as useState4, useCallback } from "react";
11564
+ import { Box as Box7, Text as Text8, useInput as useInput2 } from "ink";
11565
+ import { platform as platform2 } from "os";
11566
+ import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
11567
+ function formatSelection(label, shortcut) {
11568
+ return `${label} [${MOD_KEY}+${shortcut}]`;
11569
+ }
11570
+ function PermissionModal({ tool, args, onDecide, onFeedback }) {
11571
+ const theme = useTheme();
11572
+ const [selectedIndex, setSelectedIndex] = useState4(0);
11573
+ const [showHelp, setShowHelp] = useState4(false);
11574
+ const [feedbackActive, setFeedbackActive] = useState4(false);
11575
+ const [feedbackValue, setFeedbackValue] = useState4("");
11576
+ let render2;
11577
+ try {
11578
+ render2 = tool.render?.(args);
11579
+ } catch {
11580
+ }
11581
+ const handleSelect = useCallback(
11582
+ (index) => {
11583
+ const opt = OPTIONS[index];
11584
+ if (!opt) return;
11585
+ if (opt.value === "deny") {
11586
+ if (onFeedback) {
11587
+ setFeedbackActive(true);
11588
+ } else {
11589
+ onDecide("deny");
11590
+ }
11591
+ } else {
11592
+ onDecide(opt.value);
11593
+ }
11594
+ },
11595
+ [onDecide, onFeedback]
11596
+ );
11597
+ const handleFeedbackSubmit = useCallback(
11598
+ (text) => {
11599
+ onDecide("deny");
11600
+ if (text.trim()) {
11601
+ onFeedback?.(text);
11602
+ }
11603
+ setFeedbackActive(false);
11604
+ setFeedbackValue("");
11605
+ },
11606
+ [onDecide, onFeedback]
11607
+ );
11608
+ const handleFeedbackCancel = useCallback(() => {
11609
+ onDecide("deny");
11610
+ setFeedbackActive(false);
11611
+ setFeedbackValue("");
11612
+ }, [onDecide]);
11613
+ useInput2(
11614
+ (inputChar, key) => {
11615
+ if (showHelp) {
11616
+ setShowHelp(false);
11617
+ return;
11618
+ }
11619
+ if (key.meta && inputChar === "1") {
11620
+ handleSelect(0);
11621
+ return;
11622
+ }
11623
+ if (key.meta && inputChar === "2") {
11624
+ handleSelect(1);
11625
+ return;
11626
+ }
11627
+ if (key.meta && inputChar === "3") {
11628
+ handleSelect(2);
11629
+ return;
11630
+ }
11631
+ if (key.upArrow || inputChar === "k") {
11632
+ setSelectedIndex((i) => Math.max(0, i - 1));
11633
+ return;
11634
+ }
11635
+ if (key.downArrow || inputChar === "j") {
11636
+ setSelectedIndex((i) => Math.min(OPTIONS.length - 1, i + 1));
11637
+ return;
11638
+ }
11639
+ if (key.return) {
11640
+ handleSelect(selectedIndex);
11641
+ return;
11642
+ }
11643
+ if (inputChar === "?") {
11644
+ setShowHelp(true);
11645
+ return;
11646
+ }
11647
+ if (key.escape) {
11648
+ onDecide("deny");
11649
+ }
11650
+ },
11651
+ { isActive: !feedbackActive }
11652
+ );
11653
+ if (showHelp) {
11654
+ return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", borderStyle: "round", borderColor: theme.permission, paddingX: 1, children: [
11655
+ /* @__PURE__ */ jsx9(Text8, { color: theme.permission, bold: true, children: "Permission modal \u2014 keyboard shortcuts" }),
11656
+ /* @__PURE__ */ jsx9(Text8, { color: theme.info.color, children: "\u2191 / \u2193 or j / k \u2014 navigate options" }),
11657
+ /* @__PURE__ */ jsxs7(Text8, { color: theme.info.color, children: [
11658
+ MOD_KEY,
11659
+ "+1 / ",
11660
+ MOD_KEY,
11661
+ "+2 / ",
11662
+ MOD_KEY,
11663
+ "+3 \u2014 select option directly"
11664
+ ] }),
11665
+ /* @__PURE__ */ jsx9(Text8, { color: theme.info.color, children: "Enter \u2014 confirm selection" }),
11666
+ /* @__PURE__ */ jsx9(Text8, { color: theme.info.color, children: "Esc \u2014 deny and close" }),
11667
+ /* @__PURE__ */ jsx9(Text8, { color: theme.info.color, children: "? \u2014 toggle this help" }),
11668
+ /* @__PURE__ */ jsx9(Text8, { color: theme.info.color, children: "When feedback input is open:" }),
11669
+ /* @__PURE__ */ jsx9(Text8, { color: theme.info.color, children: " Enter \u2014 submit feedback and deny" }),
11670
+ /* @__PURE__ */ jsx9(Text8, { color: theme.info.color, children: " Esc \u2014 deny without feedback" }),
11671
+ /* @__PURE__ */ jsx9(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx9(Text8, { color: theme.accent, children: "Press any key to close" }) })
11672
+ ] });
11673
+ }
11674
+ return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", borderStyle: "round", borderColor: theme.permission, paddingX: 1, children: [
11675
+ /* @__PURE__ */ jsx9(Text8, { color: theme.permission, bold: true, children: "Permission requested" }),
11676
+ /* @__PURE__ */ jsxs7(Text8, { children: [
11677
+ "tool: ",
11678
+ /* @__PURE__ */ jsx9(Text8, { color: theme.tool, children: tool.name })
11679
+ ] }),
11680
+ render2?.title ? /* @__PURE__ */ jsxs7(Text8, { children: [
11681
+ "action: ",
11682
+ render2.title
11683
+ ] }) : null,
11684
+ render2?.diff ? /* @__PURE__ */ jsx9(Box7, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx9(DiffView, { ...render2.diff }) }) : /* @__PURE__ */ jsxs7(Text8, { color: theme.info.color, children: [
11685
+ "args: ",
11686
+ JSON.stringify(args)
11687
+ ] }),
11688
+ /* @__PURE__ */ jsx9(Box7, { marginTop: 1, flexDirection: "column", children: OPTIONS.map((opt, i) => /* @__PURE__ */ jsxs7(
11689
+ Text8,
11690
+ {
11691
+ color: i === selectedIndex ? theme.accent : void 0,
11692
+ bold: i === selectedIndex,
11693
+ children: [
11694
+ i === selectedIndex ? "\u203A " : " ",
11695
+ formatSelection(opt.label, opt.key)
11696
+ ]
11697
+ },
11698
+ opt.value
11699
+ )) }),
11700
+ feedbackActive && /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
11701
+ /* @__PURE__ */ jsx9(Text8, { color: theme.palette.error, children: "Tell me what to do instead" }),
11702
+ /* @__PURE__ */ jsx9(Text8, { color: theme.info.color, dimColor: true, children: "Press Esc to deny without feedback" }),
11703
+ /* @__PURE__ */ jsx9(
11704
+ CustomTextInput,
11705
+ {
11706
+ value: feedbackValue,
11707
+ onChange: setFeedbackValue,
11708
+ onSubmit: handleFeedbackSubmit,
11709
+ onCancel: handleFeedbackCancel,
11710
+ focus: true
11711
+ }
11712
+ )
11713
+ ] })
11714
+ ] });
11715
+ }
11716
+ var OPTIONS, MOD_KEY;
11717
+ var init_permission = __esm({
11718
+ "src/ui/permission.tsx"() {
11719
+ "use strict";
11720
+ init_diff_view();
11721
+ init_text_input();
11722
+ init_theme_context();
11723
+ OPTIONS = [
11724
+ { value: "allow", label: "Allow once", key: 1 },
11725
+ { value: "allow_session", label: "Allow for this session", key: 2 },
11726
+ { value: "deny", label: "Something else", key: 3 }
11727
+ ];
11728
+ MOD_KEY = platform2() === "darwin" ? "\u2325" : "Alt";
11729
+ }
11730
+ });
11731
+
11732
+ // src/ui/limit-modal.tsx
11733
+ import { Box as Box8, Text as Text9 } from "ink";
11734
+ import SelectInput from "ink-select-input";
11735
+ import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
11736
+ function LimitModal({ limit, onDecide }) {
11737
+ const theme = useTheme();
11738
+ const items = [
11739
+ { label: "Continue", value: "continue" },
11740
+ { label: "Stop", value: "stop" }
11741
+ ];
11742
+ return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", borderStyle: "round", borderColor: theme.error, paddingX: 1, children: [
11743
+ /* @__PURE__ */ jsxs8(Text9, { color: theme.error, bold: true, children: [
11744
+ "Tool-call limit reached (",
11745
+ limit,
11746
+ ")"
11747
+ ] }),
11748
+ /* @__PURE__ */ jsxs8(Text9, { dimColor: true, children: [
11749
+ "This session has made ",
11750
+ limit,
11751
+ " tool calls. What would you like to do?"
11752
+ ] }),
11753
+ /* @__PURE__ */ jsx10(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx10(
11754
+ SelectInput,
11755
+ {
11756
+ items,
11757
+ onSelect: (item) => onDecide(item.value)
11758
+ }
11759
+ ) })
11760
+ ] });
11761
+ }
11762
+ var init_limit_modal = __esm({
11763
+ "src/ui/limit-modal.tsx"() {
11764
+ "use strict";
11765
+ init_theme_context();
11766
+ }
11767
+ });
11768
+
11769
+ // src/util/fuzzy.ts
11770
+ function fuzzyMatch(query, text) {
11771
+ const queryLower = query.toLowerCase();
11772
+ const textLower = text.toLowerCase();
11773
+ const matchQuery = (normalizedQuery) => {
11774
+ if (normalizedQuery.length === 0) return { matches: true, score: 0 };
11775
+ if (normalizedQuery.length > textLower.length) return { matches: false, score: 0 };
11776
+ let queryIndex = 0;
11777
+ let score = 0;
11778
+ let lastMatchIndex = -1;
11779
+ let consecutiveMatches = 0;
11780
+ for (let i = 0; i < textLower.length && queryIndex < normalizedQuery.length; i++) {
11781
+ if (textLower[i] !== normalizedQuery[queryIndex]) continue;
11782
+ const isWordBoundary = i === 0 || /[\s\-_./:]/.test(textLower[i - 1]);
11783
+ if (lastMatchIndex === i - 1) {
11784
+ consecutiveMatches++;
11785
+ score -= consecutiveMatches * 5;
11786
+ } else {
11787
+ consecutiveMatches = 0;
11788
+ if (lastMatchIndex >= 0) score += (i - lastMatchIndex - 1) * 2;
11789
+ }
11790
+ if (isWordBoundary) score -= 10;
11791
+ score += i * 0.1;
11792
+ lastMatchIndex = i;
11793
+ queryIndex++;
11794
+ }
11795
+ if (queryIndex < normalizedQuery.length) return { matches: false, score: 0 };
11796
+ if (normalizedQuery === textLower) score -= 100;
11797
+ return { matches: true, score };
11798
+ };
11799
+ const primaryMatch = matchQuery(queryLower);
11800
+ if (primaryMatch.matches) return primaryMatch;
11801
+ const alphaNumericMatch = queryLower.match(/^(?<letters>[a-z]+)(?<digits>[0-9]+)$/);
11802
+ const numericAlphaMatch = queryLower.match(/^(?<digits>[0-9]+)(?<letters>[a-z]+)$/);
11803
+ const swappedQuery = alphaNumericMatch ? `${alphaNumericMatch.groups?.digits ?? ""}${alphaNumericMatch.groups?.letters ?? ""}` : numericAlphaMatch ? `${numericAlphaMatch.groups?.letters ?? ""}${numericAlphaMatch.groups?.digits ?? ""}` : "";
11804
+ if (!swappedQuery) return primaryMatch;
11805
+ const swappedMatch = matchQuery(swappedQuery);
11806
+ if (!swappedMatch.matches) return primaryMatch;
11807
+ return { matches: true, score: swappedMatch.score + 5 };
11808
+ }
11809
+ function fuzzyFilter(items, query, getText) {
11810
+ const trimmed = query.trim();
11811
+ if (trimmed.length === 0) return items;
11812
+ const tokens = trimmed.split(/\s+/).filter((t) => t.length > 0);
11813
+ if (tokens.length === 0) return items;
11814
+ const scored = [];
11815
+ for (const item of items) {
11816
+ const text = getText(item);
11817
+ let total = 0;
11818
+ let allMatch = true;
11819
+ for (const token of tokens) {
11820
+ const m = fuzzyMatch(token, text);
11821
+ if (!m.matches) {
11822
+ allMatch = false;
11823
+ break;
11824
+ }
11825
+ total += m.score;
11826
+ }
11827
+ if (allMatch) scored.push({ item, score: total });
11828
+ }
11829
+ scored.sort((a, b) => a.score - b.score);
11830
+ return scored.map((s) => s.item);
11831
+ }
11832
+ var init_fuzzy = __esm({
11833
+ "src/util/fuzzy.ts"() {
11834
+ "use strict";
11835
+ }
11836
+ });
11837
+
11838
+ // src/ui/resume-picker.tsx
11839
+ import { useState as useState5 } from "react";
11840
+ import { Box as Box9, Text as Text10, useInput as useInput3 } from "ink";
11841
+ import SelectInput2 from "ink-select-input";
11842
+ import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
11843
+ function ResumePicker({ sessions, onPick }) {
11844
+ const theme = useTheme();
11845
+ const [page, setPage] = useState5(0);
11846
+ const [selectedIndex, setSelectedIndex] = useState5(0);
11847
+ const [query, setQuery] = useState5("");
11848
+ const filtered = query.trim() ? fuzzyFilter(sessions, query, (s) => `${s.title ?? s.firstPrompt} ${s.id}`) : sessions;
11849
+ const totalPages = Math.max(1, Math.ceil(filtered.length / PAGE_SIZE));
11850
+ const safePage = Math.min(page, totalPages - 1);
11851
+ const start = safePage * PAGE_SIZE;
11852
+ const end = Math.min(start + PAGE_SIZE, filtered.length);
11853
+ const pageSessions = filtered.slice(start, end);
11854
+ useInput3((input, key) => {
11855
+ if (key.leftArrow && safePage > 0) {
11856
+ setPage((p) => p - 1);
11857
+ setSelectedIndex(0);
11858
+ return;
11859
+ }
11860
+ if (key.rightArrow && safePage < totalPages - 1) {
11861
+ setPage((p) => p + 1);
11862
+ setSelectedIndex(0);
11863
+ return;
11864
+ }
11865
+ if (key.backspace || key.delete) {
11866
+ setQuery((q) => q.slice(0, -1));
11867
+ setPage(0);
11868
+ setSelectedIndex(0);
11869
+ return;
11870
+ }
11871
+ if (input.length === 1 && !key.ctrl && !key.meta && !key.return && !key.escape) {
11872
+ setQuery((q) => q + input);
11873
+ setPage(0);
11874
+ setSelectedIndex(0);
11875
+ return;
11876
+ }
11877
+ if (input === "q" || key.escape) {
11878
+ onPick(null);
11879
+ return;
11880
+ }
11881
+ });
11882
+ if (sessions.length === 0) {
11883
+ return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11884
+ /* @__PURE__ */ jsx11(Text10, { color: theme.accent, bold: true, children: "Resume a session" }),
11885
+ /* @__PURE__ */ jsx11(Text10, { color: theme.info.color, children: "No saved sessions yet. Press Enter to dismiss." }),
11886
+ /* @__PURE__ */ jsx11(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx11(
11887
+ SelectInput2,
11888
+ {
11889
+ items: [{ label: "(back)", value: "__cancel__" }],
11890
+ onSelect: () => onPick(null)
11891
+ }
11892
+ ) })
11893
+ ] });
11894
+ }
11895
+ const items = pageSessions.map((s) => ({
11896
+ label: `${formatDate(s.updatedAt)} \xB7 ${s.messageCount} msgs \xB7 ${s.title ?? s.firstPrompt}`,
11897
+ value: s.id
11898
+ }));
11899
+ return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11900
+ /* @__PURE__ */ jsx11(Text10, { color: theme.accent, bold: true, children: "Resume a session" }),
11901
+ /* @__PURE__ */ jsxs9(Text10, { color: theme.info.color, children: [
11902
+ query ? `Search: ${query}\u258C` : "Type to search\u2026",
11903
+ " \xB7 Page ",
11904
+ safePage + 1,
11905
+ " of ",
11906
+ totalPages,
11907
+ " (",
11908
+ filtered.length,
11909
+ " total)"
11910
+ ] }),
11911
+ /* @__PURE__ */ jsx11(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx11(
11912
+ SelectInput2,
11913
+ {
11914
+ items,
11915
+ initialIndex: selectedIndex,
11916
+ onHighlight: (item) => {
11917
+ const idx = items.findIndex((i) => i.value === item.value);
11918
+ if (idx >= 0) setSelectedIndex(idx);
11919
+ },
11920
+ onSelect: (item) => {
11921
+ const picked = sessions.find((s) => s.id === item.value) ?? null;
11922
+ onPick(picked);
11923
+ }
11907
11924
  }
11925
+ ) }),
11926
+ /* @__PURE__ */ jsx11(Box9, { marginTop: 1, children: /* @__PURE__ */ jsxs9(Text10, { color: theme.info.color, children: [
11927
+ safePage > 0 ? "\u2190 prev " : "",
11928
+ safePage < totalPages - 1 ? "\u2192 next " : "",
11929
+ "q: cancel"
11930
+ ] }) })
11931
+ ] });
11932
+ }
11933
+ function formatDate(iso) {
11934
+ try {
11935
+ const d = new Date(iso);
11936
+ return d.toLocaleString(void 0, {
11937
+ month: "short",
11938
+ day: "numeric",
11939
+ hour: "2-digit",
11940
+ minute: "2-digit"
11941
+ });
11942
+ } catch {
11943
+ return iso;
11944
+ }
11945
+ }
11946
+ var PAGE_SIZE;
11947
+ var init_resume_picker = __esm({
11948
+ "src/ui/resume-picker.tsx"() {
11949
+ "use strict";
11950
+ init_fuzzy();
11951
+ init_theme_context();
11952
+ PAGE_SIZE = 5;
11953
+ }
11954
+ });
11955
+
11956
+ // src/ui/checkpoint-picker.tsx
11957
+ import { useState as useState6 } from "react";
11958
+ import { Box as Box10, Text as Text11, useInput as useInput4 } from "ink";
11959
+ import SelectInput3 from "ink-select-input";
11960
+ import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
11961
+ function CheckpointPicker({ session, checkpoints, onPick }) {
11962
+ const theme = useTheme();
11963
+ const [selectedIndex, setSelectedIndex] = useState6(0);
11964
+ useInput4((input, key) => {
11965
+ if (input === "q" || key.escape) {
11966
+ onPick(null);
11967
+ return;
11968
+ }
11969
+ });
11970
+ const items = [
11971
+ {
11972
+ label: `Resume from beginning (${session.messageCount} msgs)`,
11973
+ value: "__start__"
11908
11974
  },
11909
- { isActive: focus }
11910
- );
11911
- const displayValue = mask ? mask.repeat(value.length) : value;
11912
- let renderedValue = "";
11913
- let i = 0;
11914
- for (const char of displayValue) {
11915
- renderedValue += i === cursorOffset ? source_default.inverse(char) : char;
11916
- i++;
11975
+ ...checkpoints.map((cp) => ({
11976
+ label: `Resume from: "${cp.label}" \u2014 turn ${cp.turnIndex} \xB7 ${formatDate2(cp.timestamp)}`,
11977
+ value: cp.id
11978
+ }))
11979
+ ];
11980
+ return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
11981
+ /* @__PURE__ */ jsx12(Text11, { color: theme.accent, bold: true, children: session.firstPrompt.slice(0, 50) }),
11982
+ /* @__PURE__ */ jsxs10(Text11, { color: theme.info.color, children: [
11983
+ session.messageCount,
11984
+ " turns \xB7 ",
11985
+ checkpoints.length,
11986
+ " checkpoint",
11987
+ checkpoints.length === 1 ? "" : "s"
11988
+ ] }),
11989
+ /* @__PURE__ */ jsx12(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx12(
11990
+ SelectInput3,
11991
+ {
11992
+ items,
11993
+ initialIndex: selectedIndex,
11994
+ onHighlight: (item) => {
11995
+ const idx = items.findIndex((i) => i.value === item.value);
11996
+ if (idx >= 0) setSelectedIndex(idx);
11997
+ },
11998
+ onSelect: (item) => {
11999
+ if (item.value === "__start__") {
12000
+ onPick("__start__");
12001
+ } else {
12002
+ onPick(item.value);
12003
+ }
12004
+ }
12005
+ }
12006
+ ) }),
12007
+ /* @__PURE__ */ jsx12(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text11, { color: theme.info.color, children: "q: cancel / go back" }) })
12008
+ ] });
12009
+ }
12010
+ function formatDate2(iso) {
12011
+ try {
12012
+ const d = new Date(iso);
12013
+ return d.toLocaleString(void 0, {
12014
+ month: "short",
12015
+ day: "numeric",
12016
+ hour: "2-digit",
12017
+ minute: "2-digit"
12018
+ });
12019
+ } catch {
12020
+ return iso;
11917
12021
  }
11918
- if (displayValue.length === 0) {
11919
- renderedValue = source_default.inverse(" ");
11920
- } else if (cursorOffset === displayValue.length) {
11921
- renderedValue += source_default.inverse(" ");
12022
+ }
12023
+ var init_checkpoint_picker = __esm({
12024
+ "src/ui/checkpoint-picker.tsx"() {
12025
+ "use strict";
12026
+ init_theme_context();
11922
12027
  }
11923
- return /* @__PURE__ */ jsx13(Text12, { children: renderedValue });
12028
+ });
12029
+
12030
+ // src/ui/task-list.tsx
12031
+ import { useEffect as useEffect4, useRef as useRef2, useState as useState7 } from "react";
12032
+ import { Box as Box11, Text as Text12 } from "ink";
12033
+ import Spinner4 from "ink-spinner";
12034
+ import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
12035
+ function TaskList({ tasks, startedAt, tokensDelta }) {
12036
+ const theme = useTheme();
12037
+ const [now2, setNow] = useState7(Date.now());
12038
+ const [celebrating, setCelebrating] = useState7(false);
12039
+ const tasksRef = useRef2(tasks);
12040
+ const prevAllDoneRef = useRef2(false);
12041
+ tasksRef.current = tasks;
12042
+ useEffect4(() => {
12043
+ if (startedAt === null) return;
12044
+ const id = setInterval(() => {
12045
+ setNow(Date.now());
12046
+ const current = tasksRef.current;
12047
+ if (current.length > 0 && current.every((t) => t.status === "completed")) {
12048
+ clearInterval(id);
12049
+ }
12050
+ }, 1e3);
12051
+ return () => clearInterval(id);
12052
+ }, [startedAt]);
12053
+ useEffect4(() => {
12054
+ const allDone2 = tasks.length > 0 && tasks.every((t) => t.status === "completed");
12055
+ if (allDone2 && !prevAllDoneRef.current) {
12056
+ setCelebrating(true);
12057
+ const id = setTimeout(() => setCelebrating(false), 1500);
12058
+ return () => clearTimeout(id);
12059
+ }
12060
+ prevAllDoneRef.current = allDone2;
12061
+ }, [tasks]);
12062
+ if (tasks.length === 0) return null;
12063
+ const active = tasks.find((t) => t.status === "in_progress");
12064
+ const done = tasks.filter((t) => t.status === "completed").length;
12065
+ const total = tasks.length;
12066
+ const allDone = done === total;
12067
+ const header = active ? active.title : allDone ? `${total} tasks done` : `${done}/${total}`;
12068
+ const elapsed = startedAt ? formatElapsed3(now2 - startedAt) : null;
12069
+ const headerStats = [elapsed, tokensDelta > 0 ? `\u2191 ${formatTokens3(tokensDelta)} tokens` : null].filter(Boolean).join(" \xB7 ");
12070
+ const visibleTasks = tasks.slice(0, MAX_VISIBLE);
12071
+ const hiddenPending = Math.max(0, tasks.length - visibleTasks.length);
12072
+ return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", marginBottom: 1, children: [
12073
+ /* @__PURE__ */ jsxs11(Box11, { children: [
12074
+ /* @__PURE__ */ jsx13(Text12, { color: celebrating ? theme.palette.success : allDone ? "green" : theme.accent, bold: true, children: celebrating ? `\u2728 ${header}` : header }),
12075
+ headerStats && /* @__PURE__ */ jsxs11(Text12, { color: theme.info.color, children: [
12076
+ " ",
12077
+ "(",
12078
+ headerStats,
12079
+ ")"
12080
+ ] })
12081
+ ] }),
12082
+ visibleTasks.map((t) => /* @__PURE__ */ jsx13(TaskRow, { task: t }, t.id)),
12083
+ hiddenPending > 0 && /* @__PURE__ */ jsxs11(Text12, { color: theme.info.color, children: [
12084
+ " ",
12085
+ "\u2026 +",
12086
+ hiddenPending,
12087
+ " more"
12088
+ ] })
12089
+ ] });
11924
12090
  }
11925
- function findPasteTokenEndingAt(value, pos, pastes) {
11926
- if (pos <= 0 || value[pos - 1] !== "]") return -1;
11927
- for (const placeholder of pastes.keys()) {
11928
- if (placeholder.length > pos) continue;
11929
- const start = pos - placeholder.length;
11930
- if (value.slice(start, pos) === placeholder) return start;
12091
+ function TaskRow({ task }) {
12092
+ const theme = useTheme();
12093
+ if (task.status === "completed") {
12094
+ return /* @__PURE__ */ jsxs11(Text12, { color: theme.info.color, children: [
12095
+ " ",
12096
+ "\u2713 ",
12097
+ /* @__PURE__ */ jsx13(Text12, { strikethrough: true, children: task.title })
12098
+ ] });
11931
12099
  }
11932
- return -1;
12100
+ if (task.status === "in_progress") {
12101
+ return /* @__PURE__ */ jsxs11(Text12, { color: theme.accent, bold: true, children: [
12102
+ " ",
12103
+ /* @__PURE__ */ jsx13(Spinner4, { type: "line" }),
12104
+ " ",
12105
+ task.title
12106
+ ] });
12107
+ }
12108
+ return /* @__PURE__ */ jsxs11(Text12, { color: theme.info.color, children: [
12109
+ " ",
12110
+ "\u2610 ",
12111
+ task.title
12112
+ ] });
11933
12113
  }
11934
- var PASTE_CHAR_THRESHOLD, PASTE_NEWLINE_THRESHOLD;
11935
- var init_text_input = __esm({
11936
- "src/ui/text-input.tsx"() {
12114
+ function formatElapsed3(ms) {
12115
+ const total = Math.floor(ms / 1e3);
12116
+ const m = Math.floor(total / 60);
12117
+ const s = total % 60;
12118
+ if (m === 0) return `${s}s`;
12119
+ return `${m}m ${s}s`;
12120
+ }
12121
+ function formatTokens3(n) {
12122
+ if (n < 1e3) return String(n);
12123
+ return `${(n / 1e3).toFixed(1)}k`;
12124
+ }
12125
+ var MAX_VISIBLE;
12126
+ var init_task_list = __esm({
12127
+ "src/ui/task-list.tsx"() {
11937
12128
  "use strict";
11938
- init_source();
11939
- PASTE_CHAR_THRESHOLD = 200;
11940
- PASTE_NEWLINE_THRESHOLD = 1;
12129
+ init_theme_context();
12130
+ MAX_VISIBLE = 6;
11941
12131
  }
11942
12132
  });
11943
12133
 
11944
12134
  // src/ui/onboarding.tsx
11945
- import { useState as useState7, useEffect as useEffect5, useCallback } from "react";
11946
- import { Box as Box12, Text as Text13, useInput as useInput4 } from "ink";
11947
- import SelectInput5 from "ink-select-input";
12135
+ import { useState as useState8, useEffect as useEffect5, useCallback as useCallback2 } from "react";
12136
+ import { Box as Box12, Text as Text13, useInput as useInput5 } from "ink";
12137
+ import SelectInput4 from "ink-select-input";
11948
12138
  import Spinner5 from "ink-spinner";
11949
12139
  import { exec } from "child_process";
11950
12140
  import { promisify as promisify2 } from "util";
11951
12141
  import { Fragment, jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
11952
12142
  function openBrowser(url) {
11953
- const platform3 = process.platform;
11954
- const cmd = platform3 === "darwin" ? `open "${url}"` : platform3 === "win32" ? `start "" "${url}"` : `xdg-open "${url}"`;
12143
+ const platform4 = process.platform;
12144
+ const cmd = platform4 === "darwin" ? `open "${url}"` : platform4 === "win32" ? `start "" "${url}"` : `xdg-open "${url}"`;
11955
12145
  exec(cmd, (err) => {
11956
12146
  if (err) {
11957
12147
  }
@@ -11965,14 +12155,14 @@ function formatRemaining(ms) {
11965
12155
  }
11966
12156
  function Onboarding({ onDone, onCancel }) {
11967
12157
  const theme = useTheme();
11968
- const [step, setStep] = useState7("mode");
11969
- const [mode, setMode] = useState7("byok");
11970
- const [accountId, setAccountId] = useState7("");
11971
- const [apiToken, setApiToken] = useState7("");
11972
- const [model, setModel] = useState7(DEFAULT_MODEL);
11973
- const [savedPath, setSavedPath] = useState7(null);
11974
- const [cloudAuth, setCloudAuth] = useState7(null);
11975
- const [pollTick, setPollTick] = useState7(0);
12158
+ const [step, setStep] = useState8("mode");
12159
+ const [mode, setMode] = useState8("byok");
12160
+ const [accountId, setAccountId] = useState8("");
12161
+ const [apiToken, setApiToken] = useState8("");
12162
+ const [model, setModel] = useState8(DEFAULT_MODEL);
12163
+ const [savedPath, setSavedPath] = useState8(null);
12164
+ const [cloudAuth, setCloudAuth] = useState8(null);
12165
+ const [pollTick, setPollTick] = useState8(0);
11976
12166
  useEffect5(() => {
11977
12167
  if (step !== "cloudAuth" || !cloudAuth) return;
11978
12168
  if (cloudAuth.phase !== "polling") return;
@@ -12015,8 +12205,8 @@ function Onboarding({ onDone, onCancel }) {
12015
12205
  clearInterval(tick);
12016
12206
  };
12017
12207
  }, [step, cloudAuth]);
12018
- useInput4(
12019
- useCallback(
12208
+ useInput5(
12209
+ useCallback2(
12020
12210
  (_input, key) => {
12021
12211
  if (key.escape && onCancel) {
12022
12212
  onCancel();
@@ -12025,9 +12215,9 @@ function Onboarding({ onDone, onCancel }) {
12025
12215
  [onCancel]
12026
12216
  )
12027
12217
  );
12028
- const startCloudAuth = useCallback(async () => {
12218
+ const startCloudAuth = useCallback2(async () => {
12029
12219
  try {
12030
- const codes = generateDeviceCodes();
12220
+ const codes = await generateDeviceCodes();
12031
12221
  await registerDevice(codes);
12032
12222
  setCloudAuth({ phase: "ready", codes });
12033
12223
  setStep("cloudAuth");
@@ -12122,7 +12312,7 @@ function Onboarding({ onDone, onCancel }) {
12122
12312
  step === "mode" && /* @__PURE__ */ jsxs12(Fragment, { children: [
12123
12313
  /* @__PURE__ */ jsx14(Text13, { children: "How do you want to connect?" }),
12124
12314
  /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(
12125
- SelectInput5,
12315
+ SelectInput4,
12126
12316
  {
12127
12317
  items: [
12128
12318
  { label: "Cloud (managed) \u2014 no API key needed", value: "cloud" },
@@ -12208,7 +12398,7 @@ function Onboarding({ onDone, onCancel }) {
12208
12398
  /* @__PURE__ */ jsx14(Text13, { color: theme.palette.error, children: "Authentication failed" }),
12209
12399
  /* @__PURE__ */ jsx14(Text13, { color: theme.info.color, children: cloudAuth.message }),
12210
12400
  /* @__PURE__ */ jsx14(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx14(
12211
- SelectInput5,
12401
+ SelectInput4,
12212
12402
  {
12213
12403
  items: [
12214
12404
  { label: "Retry", value: "retry" },
@@ -12487,25 +12677,17 @@ var init_worker_client = __esm({
12487
12677
  }
12488
12678
  });
12489
12679
 
12490
- // src/remote/tui-deploy.ts
12491
- var init_tui_deploy = __esm({
12492
- "src/remote/tui-deploy.ts"() {
12493
- "use strict";
12494
- init_deploy();
12495
- }
12496
- });
12497
-
12498
12680
  // src/ui/remote-dashboard.tsx
12499
- import { useEffect as useEffect6, useState as useState8 } from "react";
12500
- import { Box as Box14, Text as Text15, useInput as useInput5 } from "ink";
12501
- import SelectInput6 from "ink-select-input";
12681
+ import { useEffect as useEffect6, useState as useState9 } from "react";
12682
+ import { Box as Box14, Text as Text15, useInput as useInput6 } from "ink";
12683
+ import SelectInput5 from "ink-select-input";
12502
12684
  import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
12503
12685
  function RemoteDashboard({ onSelect, onCancel }) {
12504
12686
  const theme = useTheme();
12505
- const [sessions, setSessions] = useState8([]);
12506
- const [loading, setLoading] = useState8(true);
12507
- const [error, setError] = useState8(null);
12508
- const [refreshing, setRefreshing] = useState8(false);
12687
+ const [sessions, setSessions] = useState9([]);
12688
+ const [loading, setLoading] = useState9(true);
12689
+ const [error, setError] = useState9(null);
12690
+ const [refreshing, setRefreshing] = useState9(false);
12509
12691
  useEffect6(() => {
12510
12692
  loadSessions();
12511
12693
  }, []);
@@ -12542,7 +12724,7 @@ function RemoteDashboard({ onSelect, onCancel }) {
12542
12724
  setRefreshing(false);
12543
12725
  }
12544
12726
  }
12545
- useInput5((input, key) => {
12727
+ useInput6((input, key) => {
12546
12728
  if (input === "r" || input === "R") {
12547
12729
  void loadSessions();
12548
12730
  }
@@ -12579,7 +12761,7 @@ function RemoteDashboard({ onSelect, onCancel }) {
12579
12761
  refreshing ? "(refreshing...)" : ""
12580
12762
  ] }),
12581
12763
  /* @__PURE__ */ jsx16(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx16(
12582
- SelectInput6,
12764
+ SelectInput5,
12583
12765
  {
12584
12766
  items,
12585
12767
  onSelect: (item) => {
@@ -12620,8 +12802,8 @@ function RemoteSessionDetail({
12620
12802
  onCancel
12621
12803
  }) {
12622
12804
  const theme = useTheme();
12623
- const [cancelling, setCancelling] = useState8(false);
12624
- useInput5((input, key) => {
12805
+ const [cancelling, setCancelling] = useState9(false);
12806
+ useInput6((input, key) => {
12625
12807
  if (key.escape) {
12626
12808
  onBack();
12627
12809
  }
@@ -12892,7 +13074,7 @@ var init_skills = __esm({
12892
13074
  });
12893
13075
 
12894
13076
  // src/skills/manager.ts
12895
- import { mkdir as mkdir10, writeFile as writeFile11, unlink as unlink2, readFile as readFile15 } from "fs/promises";
13077
+ import { mkdir as mkdir11, writeFile as writeFile11, unlink as unlink2, readFile as readFile15 } from "fs/promises";
12896
13078
  import { join as join21 } from "path";
12897
13079
  import matter2 from "gray-matter";
12898
13080
  function getSkillDirs(cwd) {
@@ -12933,7 +13115,7 @@ ${yaml}
12933
13115
 
12934
13116
  Add your instructions here.
12935
13117
  `;
12936
- await mkdir10(dir, { recursive: true });
13118
+ await mkdir11(dir, { recursive: true });
12937
13119
  await writeFile11(filepath, content, "utf8");
12938
13120
  return { filepath };
12939
13121
  }
@@ -13015,7 +13197,7 @@ var init_image = __esm({
13015
13197
  });
13016
13198
 
13017
13199
  // src/util/state.ts
13018
- import { readFile as readFile17, writeFile as writeFile12, mkdir as mkdir11 } from "fs/promises";
13200
+ import { readFile as readFile17, writeFile as writeFile12, mkdir as mkdir12 } from "fs/promises";
13019
13201
  import { homedir as homedir13 } from "os";
13020
13202
  import { join as join22 } from "path";
13021
13203
  function statePath() {
@@ -13032,7 +13214,7 @@ async function readState() {
13032
13214
  }
13033
13215
  async function writeState(state) {
13034
13216
  const path = statePath();
13035
- await mkdir11(join22(path, ".."), { recursive: true });
13217
+ await mkdir12(join22(path, ".."), { recursive: true });
13036
13218
  await writeFile12(path, JSON.stringify(state, null, 2) + "\n", "utf8");
13037
13219
  }
13038
13220
  async function markCreatorMessageSeen(version) {
@@ -13490,7 +13672,7 @@ var init_builtins = __esm({
13490
13672
  });
13491
13673
 
13492
13674
  // src/commands/save.ts
13493
- import { mkdir as mkdir12, writeFile as writeFile13, unlink as unlink3 } from "fs/promises";
13675
+ import { mkdir as mkdir13, writeFile as writeFile13, unlink as unlink3 } from "fs/promises";
13494
13676
  import { dirname as dirname10 } from "path";
13495
13677
  async function saveCustomCommand(opts2) {
13496
13678
  const dir = opts2.source === "project" ? projectCommandsDir(opts2.cwd) : globalCommandsDir();
@@ -13502,7 +13684,7 @@ async function saveCustomCommand(opts2) {
13502
13684
  if (opts2.effort) data.effort = opts2.effort;
13503
13685
  const frontmatter = serializeFrontmatter(data);
13504
13686
  const content = frontmatter + opts2.template;
13505
- await mkdir12(dirname10(filepath), { recursive: true });
13687
+ await mkdir13(dirname10(filepath), { recursive: true });
13506
13688
  await writeFile13(filepath, content, "utf8");
13507
13689
  return { filepath };
13508
13690
  }
@@ -13518,21 +13700,21 @@ var init_save = __esm({
13518
13700
  });
13519
13701
 
13520
13702
  // src/ui/command-wizard.tsx
13521
- import { useState as useState9 } from "react";
13522
- import { Box as Box15, Text as Text16, useInput as useInput6, useWindowSize } from "ink";
13523
- import SelectInput7 from "ink-select-input";
13703
+ import { useState as useState10 } from "react";
13704
+ import { Box as Box15, Text as Text16, useInput as useInput7, useWindowSize } from "ink";
13705
+ import SelectInput6 from "ink-select-input";
13524
13706
  import { Fragment as Fragment2, jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
13525
13707
  function CommandWizard({ mode, initial, existingNames, builtinNames, onDone, onSave }) {
13526
13708
  const theme = useTheme();
13527
- const [step, setStep] = useState9("name");
13528
- const [name, setName] = useState9(initial?.name ?? "");
13529
- const [description, setDescription] = useState9(initial?.description ?? "");
13530
- const [template, setTemplate] = useState9(initial?.template ?? "");
13531
- const [cmdMode, setCmdMode] = useState9(initial?.mode);
13532
- const [cmdEffort, setCmdEffort] = useState9(initial?.effort);
13533
- const [cmdModel, setCmdModel] = useState9(initial?.model);
13534
- const [source, setSource] = useState9(initial?.source ?? "project");
13535
- const [error, setError] = useState9(null);
13709
+ const [step, setStep] = useState10("name");
13710
+ const [name, setName] = useState10(initial?.name ?? "");
13711
+ const [description, setDescription] = useState10(initial?.description ?? "");
13712
+ const [template, setTemplate] = useState10(initial?.template ?? "");
13713
+ const [cmdMode, setCmdMode] = useState10(initial?.mode);
13714
+ const [cmdEffort, setCmdEffort] = useState10(initial?.effort);
13715
+ const [cmdModel, setCmdModel] = useState10(initial?.model);
13716
+ const [source, setSource] = useState10(initial?.source ?? "project");
13717
+ const [error, setError] = useState10(null);
13536
13718
  const { columns } = useWindowSize();
13537
13719
  const totalSteps = 5;
13538
13720
  const stepIndex = step === "name" ? 1 : step === "description" ? 2 : step === "template" ? 3 : step === "advanced" || step === "mode" || step === "effort" || step === "model" ? 4 : step === "location" ? 4 : 5;
@@ -13545,7 +13727,7 @@ function CommandWizard({ mode, initial, existingNames, builtinNames, onDone, onS
13545
13727
  if (existingNames.includes(trimmed) && !isEditingSelf(trimmed)) return `/${trimmed} already exists`;
13546
13728
  return null;
13547
13729
  };
13548
- useInput6((_input, key) => {
13730
+ useInput7((_input, key) => {
13549
13731
  if (key.escape) {
13550
13732
  onDone();
13551
13733
  }
@@ -13773,7 +13955,7 @@ ${template}`;
13773
13955
  ")"
13774
13956
  ] }),
13775
13957
  /* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
13776
- SelectInput7,
13958
+ SelectInput6,
13777
13959
  {
13778
13960
  items,
13779
13961
  onSelect: (item) => {
@@ -13802,7 +13984,7 @@ ${template}`;
13802
13984
  ] }),
13803
13985
  /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, children: "Saved to file but not yet enforced at runtime" }),
13804
13986
  /* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
13805
- SelectInput7,
13987
+ SelectInput6,
13806
13988
  {
13807
13989
  items,
13808
13990
  onSelect: (item) => {
@@ -13830,7 +14012,7 @@ ${template}`;
13830
14012
  ")"
13831
14013
  ] }),
13832
14014
  /* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
13833
- SelectInput7,
14015
+ SelectInput6,
13834
14016
  {
13835
14017
  items,
13836
14018
  onSelect: (item) => {
@@ -13876,7 +14058,7 @@ ${template}`;
13876
14058
  ")"
13877
14059
  ] }),
13878
14060
  /* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
13879
- SelectInput7,
14061
+ SelectInput6,
13880
14062
  {
13881
14063
  items,
13882
14064
  onSelect: (item) => {
@@ -13909,7 +14091,7 @@ ${template}`;
13909
14091
  ] }),
13910
14092
  /* @__PURE__ */ jsx17(Box15, { marginTop: 1, flexDirection: "column", children: previewContent().split("\n").map((line, i) => /* @__PURE__ */ jsx17(Text16, { color: theme.info.color, children: line || " " }, i)) }),
13911
14093
  /* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
13912
- SelectInput7,
14094
+ SelectInput6,
13913
14095
  {
13914
14096
  items,
13915
14097
  onSelect: (item) => handleConfirm(item.value)
@@ -14365,7 +14547,7 @@ var init_context_generator = __esm({
14365
14547
 
14366
14548
  // src/ui/command-picker.tsx
14367
14549
  import { Box as Box16, Text as Text17 } from "ink";
14368
- import SelectInput8 from "ink-select-input";
14550
+ import SelectInput7 from "ink-select-input";
14369
14551
  import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
14370
14552
  function CommandPicker({ commands, title, onPick }) {
14371
14553
  const theme = useTheme();
@@ -14379,7 +14561,7 @@ function CommandPicker({ commands, title, onPick }) {
14379
14561
  /* @__PURE__ */ jsx18(Text17, { color: theme.accent, bold: true, children: title }),
14380
14562
  /* @__PURE__ */ jsx18(Text17, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select." }),
14381
14563
  /* @__PURE__ */ jsx18(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx18(
14382
- SelectInput8,
14564
+ SelectInput7,
14383
14565
  {
14384
14566
  items,
14385
14567
  onSelect: (item) => {
@@ -14401,11 +14583,11 @@ var init_command_picker = __esm({
14401
14583
  });
14402
14584
 
14403
14585
  // src/ui/command-list.tsx
14404
- import { Box as Box17, Text as Text18, useInput as useInput7 } from "ink";
14586
+ import { Box as Box17, Text as Text18, useInput as useInput8 } from "ink";
14405
14587
  import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
14406
14588
  function CommandList({ commands, onDone }) {
14407
14589
  const theme = useTheme();
14408
- useInput7((_input, key) => {
14590
+ useInput8((_input, key) => {
14409
14591
  if (key.escape) {
14410
14592
  onDone();
14411
14593
  }
@@ -14474,20 +14656,20 @@ var init_command_list = __esm({
14474
14656
  });
14475
14657
 
14476
14658
  // src/ui/lsp-wizard.tsx
14477
- import { useState as useState10 } from "react";
14659
+ import { useState as useState11 } from "react";
14478
14660
  import { Box as Box18, Text as Text19 } from "ink";
14479
- import SelectInput9 from "ink-select-input";
14661
+ import SelectInput8 from "ink-select-input";
14480
14662
  import { spawn as spawn3 } from "child_process";
14481
14663
  import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
14482
14664
  function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
14483
14665
  const theme = useTheme();
14484
- const [page, setPage] = useState10("main");
14485
- const [selectedPreset, setSelectedPreset] = useState10(null);
14486
- const [customName, setCustomName] = useState10("");
14487
- const [customCommand, setCustomCommand] = useState10("");
14488
- const [installState, setInstallState] = useState10({ status: "idle", output: "" });
14489
- const [pendingServers, setPendingServers] = useState10(null);
14490
- const [pendingEnabled, setPendingEnabled] = useState10(true);
14666
+ const [page, setPage] = useState11("main");
14667
+ const [selectedPreset, setSelectedPreset] = useState11(null);
14668
+ const [customName, setCustomName] = useState11("");
14669
+ const [customCommand, setCustomCommand] = useState11("");
14670
+ const [installState, setInstallState] = useState11({ status: "idle", output: "" });
14671
+ const [pendingServers, setPendingServers] = useState11(null);
14672
+ const [pendingEnabled, setPendingEnabled] = useState11(true);
14491
14673
  const runInstall = (command) => {
14492
14674
  setInstallState({ status: "running", output: "Installing..." });
14493
14675
  const child = spawn3("bash", ["-lc", command], {
@@ -14593,7 +14775,7 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
14593
14775
  /* @__PURE__ */ jsx20(Text19, { color: theme.accent, bold: true, children: "LSP Servers" }),
14594
14776
  /* @__PURE__ */ jsx20(Text19, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select." }),
14595
14777
  /* @__PURE__ */ jsx20(Box18, { marginTop: 1, children: /* @__PURE__ */ jsx20(
14596
- SelectInput9,
14778
+ SelectInput8,
14597
14779
  {
14598
14780
  items: mainItems,
14599
14781
  onSelect: (item) => {
@@ -14624,7 +14806,7 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
14624
14806
  /* @__PURE__ */ jsx20(Text19, { color: theme.accent, bold: true, children: "Add LSP Server" }),
14625
14807
  /* @__PURE__ */ jsx20(Text19, { color: theme.info.color, dimColor: false, children: "Select a language server to configure." }),
14626
14808
  /* @__PURE__ */ jsx20(Box18, { marginTop: 1, children: /* @__PURE__ */ jsx20(
14627
- SelectInput9,
14809
+ SelectInput8,
14628
14810
  {
14629
14811
  items,
14630
14812
  onSelect: (item) => {
@@ -14663,7 +14845,7 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
14663
14845
  ] }),
14664
14846
  installState.output && /* @__PURE__ */ jsx20(Box18, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx20(Text19, { color: isSuccess ? theme.accent : theme.error, children: installState.output.slice(-500) }) }),
14665
14847
  /* @__PURE__ */ jsx20(Box18, { marginTop: 1, children: /* @__PURE__ */ jsx20(
14666
- SelectInput9,
14848
+ SelectInput8,
14667
14849
  {
14668
14850
  items,
14669
14851
  onSelect: (item) => {
@@ -14704,7 +14886,7 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
14704
14886
  )
14705
14887
  ] }),
14706
14888
  /* @__PURE__ */ jsx20(Box18, { marginTop: 1, children: /* @__PURE__ */ jsx20(
14707
- SelectInput9,
14889
+ SelectInput8,
14708
14890
  {
14709
14891
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
14710
14892
  onSelect: () => setPage("add")
@@ -14733,7 +14915,7 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
14733
14915
  )
14734
14916
  ] }),
14735
14917
  /* @__PURE__ */ jsx20(Box18, { marginTop: 1, children: /* @__PURE__ */ jsx20(
14736
- SelectInput9,
14918
+ SelectInput8,
14737
14919
  {
14738
14920
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
14739
14921
  onSelect: () => setPage("custom-name")
@@ -14760,7 +14942,7 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
14760
14942
  /* @__PURE__ */ jsx20(Text19, { color: theme.accent, bold: true, children: "Save LSP Config" }),
14761
14943
  /* @__PURE__ */ jsx20(Text19, { color: theme.info.color, dimColor: false, children: "Where should this server configuration be saved?" }),
14762
14944
  /* @__PURE__ */ jsx20(Box18, { marginTop: 1, children: /* @__PURE__ */ jsx20(
14763
- SelectInput9,
14945
+ SelectInput8,
14764
14946
  {
14765
14947
  items,
14766
14948
  onSelect: (item) => {
@@ -14782,7 +14964,7 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
14782
14964
  /* @__PURE__ */ jsx20(Text19, { color: theme.accent, bold: true, children: "Edit LSP Server" }),
14783
14965
  /* @__PURE__ */ jsx20(Text19, { color: theme.info.color, children: "No servers configured." }),
14784
14966
  /* @__PURE__ */ jsx20(Box18, { marginTop: 1, children: /* @__PURE__ */ jsx20(
14785
- SelectInput9,
14967
+ SelectInput8,
14786
14968
  {
14787
14969
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
14788
14970
  onSelect: () => setPage("main")
@@ -14806,7 +14988,7 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
14806
14988
  /* @__PURE__ */ jsx20(Text19, { color: theme.accent, bold: true, children: "Edit LSP Server" }),
14807
14989
  /* @__PURE__ */ jsx20(Text19, { color: theme.info.color, dimColor: false, children: "Select a server to toggle enabled/disabled." }),
14808
14990
  /* @__PURE__ */ jsx20(Box18, { marginTop: 1, children: /* @__PURE__ */ jsx20(
14809
- SelectInput9,
14991
+ SelectInput8,
14810
14992
  {
14811
14993
  items,
14812
14994
  onSelect: (item) => {
@@ -14827,7 +15009,7 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
14827
15009
  /* @__PURE__ */ jsx20(Text19, { color: theme.accent, bold: true, children: "Delete LSP Server" }),
14828
15010
  /* @__PURE__ */ jsx20(Text19, { color: theme.info.color, children: "No servers configured." }),
14829
15011
  /* @__PURE__ */ jsx20(Box18, { marginTop: 1, children: /* @__PURE__ */ jsx20(
14830
- SelectInput9,
15012
+ SelectInput8,
14831
15013
  {
14832
15014
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
14833
15015
  onSelect: () => setPage("main")
@@ -14847,7 +15029,7 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
14847
15029
  /* @__PURE__ */ jsx20(Text19, { color: theme.accent, bold: true, children: "Delete LSP Server" }),
14848
15030
  /* @__PURE__ */ jsx20(Text19, { color: theme.info.color, dimColor: false, children: "Select a server to remove from config." }),
14849
15031
  /* @__PURE__ */ jsx20(Box18, { marginTop: 1, children: /* @__PURE__ */ jsx20(
14850
- SelectInput9,
15032
+ SelectInput8,
14851
15033
  {
14852
15034
  items,
14853
15035
  onSelect: (item) => {
@@ -14871,7 +15053,7 @@ function LspWizard({ servers, currentScope, hasProjectDir, onDone, onSave }) {
14871
15053
  return /* @__PURE__ */ jsx20(Text19, { color: theme.info.color, children: ` ${k.padEnd(16)} ${status} ${s.command.join(" ")}` }, k);
14872
15054
  }) }),
14873
15055
  /* @__PURE__ */ jsx20(Box18, { marginTop: 1, children: /* @__PURE__ */ jsx20(
14874
- SelectInput9,
15056
+ SelectInput8,
14875
15057
  {
14876
15058
  items: [{ label: "\u2190 Back", value: "__back__", key: "__back__" }],
14877
15059
  onSelect: () => setPage("main")
@@ -14998,7 +15180,7 @@ var init_lsp_wizard = __esm({
14998
15180
 
14999
15181
  // src/ui/theme-picker.tsx
15000
15182
  import { Box as Box19, Text as Text20 } from "ink";
15001
- import SelectInput10 from "ink-select-input";
15183
+ import SelectInput9 from "ink-select-input";
15002
15184
  import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
15003
15185
  function PaletteSwatches({ palette }) {
15004
15186
  const colors = [
@@ -15018,7 +15200,7 @@ function ThemePicker({ themes, onPick }) {
15018
15200
  return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", borderStyle: "round", borderColor: current.accent, paddingX: 1, children: [
15019
15201
  /* @__PURE__ */ jsx21(Text20, { color: current.accent, bold: true, children: "Pick a theme (restart to apply)" }),
15020
15202
  /* @__PURE__ */ jsx21(Box19, { marginTop: 1, children: /* @__PURE__ */ jsx21(
15021
- SelectInput10,
15203
+ SelectInput9,
15022
15204
  {
15023
15205
  items,
15024
15206
  onSelect: (item) => {
@@ -16441,15 +16623,15 @@ __export(app_exports, {
16441
16623
  shouldOpenMentionPicker: () => shouldOpenMentionPicker,
16442
16624
  shouldOpenSlashPicker: () => shouldOpenSlashPicker
16443
16625
  });
16444
- import React14, { useState as useState11, useRef as useRef3, useEffect as useEffect7, useCallback as useCallback2 } from "react";
16445
- import { Box as Box22, Text as Text23, useApp, useInput as useInput8, render } from "ink";
16446
- import SelectInput11 from "ink-select-input";
16626
+ import React15, { useState as useState12, useRef as useRef3, useEffect as useEffect7, useCallback as useCallback3 } from "react";
16627
+ import { Box as Box22, Text as Text23, useApp, useInput as useInput9, render } from "ink";
16628
+ import SelectInput10 from "ink-select-input";
16447
16629
  import { existsSync as existsSync4, statSync as statSync4 } from "fs";
16448
16630
  import { join as join27 } from "path";
16449
16631
  import { unlink as unlink4 } from "fs/promises";
16450
16632
  import { execSync as execSync2 } from "child_process";
16451
16633
  import { spawn as spawn4 } from "child_process";
16452
- import { platform as platform2 } from "os";
16634
+ import { platform as platform3 } from "os";
16453
16635
  import fg4 from "fast-glob";
16454
16636
  import { readFileSync as readFileSync3 } from "fs";
16455
16637
  import { jsx as jsx24, jsxs as jsxs22 } from "react/jsx-runtime";
@@ -16592,7 +16774,7 @@ function gatewayUsageLookupFromConfig(cfg, meta) {
16592
16774
  };
16593
16775
  }
16594
16776
  function openBrowser2(url) {
16595
- const cmd = platform2() === "darwin" ? "open" : platform2() === "win32" ? "start" : "xdg-open";
16777
+ const cmd = platform3() === "darwin" ? "open" : platform3() === "win32" ? "start" : "xdg-open";
16596
16778
  const child = spawn4(cmd, [url], { detached: true, stdio: "ignore" });
16597
16779
  child.unref();
16598
16780
  }
@@ -16701,13 +16883,13 @@ function App({
16701
16883
  initialCloudDeviceId
16702
16884
  }) {
16703
16885
  const { exit } = useApp();
16704
- const [cfg, setCfg] = useState11(initialCfg);
16705
- const [lspScope, setLspScope] = useState11(initialLspScope);
16706
- const [lspProjectPath, setLspProjectPath] = useState11(initialLspProjectPath);
16707
- const [cloudToken, setCloudToken] = useState11(initialCloudToken);
16708
- const [cloudDeviceId, setCloudDeviceId] = useState11(initialCloudDeviceId);
16709
- const [events, setRawEvents] = useState11([]);
16710
- const setEvents = useCallback2(
16886
+ const [cfg, setCfg] = useState12(initialCfg);
16887
+ const [lspScope, setLspScope] = useState12(initialLspScope);
16888
+ const [lspProjectPath, setLspProjectPath] = useState12(initialLspProjectPath);
16889
+ const [cloudToken, setCloudToken] = useState12(initialCloudToken);
16890
+ const [cloudDeviceId, setCloudDeviceId] = useState12(initialCloudDeviceId);
16891
+ const [events, setRawEvents] = useState12([]);
16892
+ const setEvents = useCallback3(
16711
16893
  (updater) => {
16712
16894
  setRawEvents((prev) => {
16713
16895
  const next = typeof updater === "function" ? updater(prev) : updater;
@@ -16716,55 +16898,55 @@ function App({
16716
16898
  },
16717
16899
  []
16718
16900
  );
16719
- const [input, setInput] = useState11("");
16720
- const [busy, setBusy] = useState11(false);
16721
- const [usage, setUsage] = useState11(null);
16722
- const [sessionUsage, setSessionUsage] = useState11(null);
16723
- const [gatewayMeta, setGatewayMeta] = useState11(null);
16724
- const [cloudBudget, setCloudBudget] = useState11(null);
16725
- const [showReasoning, setShowReasoning] = useState11(false);
16726
- const [perm, setPerm] = useState11(null);
16727
- const [limitModal, setLimitModal] = useState11(null);
16728
- const [queue, setQueue] = useState11([]);
16729
- const [history, setHistory] = useState11([]);
16730
- const [historyIndex, setHistoryIndex] = useState11(-1);
16731
- const [draftInput, setDraftInput] = useState11("");
16732
- const [mode, setMode] = useState11("edit");
16733
- const [codeMode, setCodeMode] = useState11(false);
16901
+ const [input, setInput] = useState12("");
16902
+ const [busy, setBusy] = useState12(false);
16903
+ const [usage, setUsage] = useState12(null);
16904
+ const [sessionUsage, setSessionUsage] = useState12(null);
16905
+ const [gatewayMeta, setGatewayMeta] = useState12(null);
16906
+ const [cloudBudget, setCloudBudget] = useState12(null);
16907
+ const [showReasoning, setShowReasoning] = useState12(false);
16908
+ const [perm, setPerm] = useState12(null);
16909
+ const [limitModal, setLimitModal] = useState12(null);
16910
+ const [queue, setQueue] = useState12([]);
16911
+ const [history, setHistory] = useState12([]);
16912
+ const [historyIndex, setHistoryIndex] = useState12(-1);
16913
+ const [draftInput, setDraftInput] = useState12("");
16914
+ const [mode, setMode] = useState12("edit");
16915
+ const [codeMode, setCodeMode] = useState12(false);
16734
16916
  const filePickerEnabled = initialCfg?.filePicker ?? true;
16735
- const [effort, setEffort] = useState11(
16917
+ const [effort, setEffort] = useState12(
16736
16918
  initialCfg?.reasoningEffort ?? DEFAULT_REASONING_EFFORT
16737
16919
  );
16738
- const [resumeSessions, setResumeSessions] = useState11(null);
16739
- const [checkpointSession, setCheckpointSession] = useState11(null);
16740
- const [checkpointList, setCheckpointList] = useState11([]);
16741
- const [commandWizard, setCommandWizard] = useState11(null);
16742
- const [commandPicker, setCommandPicker] = useState11(null);
16743
- const [commandToDelete, setCommandToDelete] = useState11(null);
16744
- const [showCommandList, setShowCommandList] = useState11(false);
16745
- const [showLspWizard, setShowLspWizard] = useState11(false);
16746
- const [showRemoteDashboard, setShowRemoteDashboard] = useState11(false);
16747
- const [selectedRemoteSession, setSelectedRemoteSession] = useState11(null);
16748
- const [tasks, setTasks] = useState11([]);
16749
- const [tasksStartedAt, setTasksStartedAt] = useState11(null);
16750
- const [tasksStartTokens, setTasksStartTokens] = useState11(0);
16751
- const [turnStartedAt, setTurnStartedAt] = useState11(null);
16752
- const [turnPhase, setTurnPhase] = useState11("waiting");
16753
- const [currentToolName, setCurrentToolName] = useState11(null);
16754
- const [lastActivityAt, setLastActivityAt] = useState11(null);
16755
- const [verbose, setVerbose] = useState11(false);
16756
- const [hasUpdate, setHasUpdate] = useState11(initialUpdateResult?.hasUpdate ?? false);
16757
- const [latestVersion, setLatestVersion] = useState11(initialUpdateResult?.latestVersion ?? null);
16758
- const [theme, setTheme] = useState11(resolveTheme(initialCfg?.theme));
16759
- const [showThemePicker, setShowThemePicker] = useState11(false);
16760
- const [originalTheme, setOriginalTheme] = useState11(null);
16761
- const [skillsActive, setSkillsActive] = useState11(0);
16762
- const [memoryRecalled, setMemoryRecalled] = useState11(false);
16763
- const [intentTier, setIntentTier] = useState11(null);
16920
+ const [resumeSessions, setResumeSessions] = useState12(null);
16921
+ const [checkpointSession, setCheckpointSession] = useState12(null);
16922
+ const [checkpointList, setCheckpointList] = useState12([]);
16923
+ const [commandWizard, setCommandWizard] = useState12(null);
16924
+ const [commandPicker, setCommandPicker] = useState12(null);
16925
+ const [commandToDelete, setCommandToDelete] = useState12(null);
16926
+ const [showCommandList, setShowCommandList] = useState12(false);
16927
+ const [showLspWizard, setShowLspWizard] = useState12(false);
16928
+ const [showRemoteDashboard, setShowRemoteDashboard] = useState12(false);
16929
+ const [selectedRemoteSession, setSelectedRemoteSession] = useState12(null);
16930
+ const [tasks, setTasks] = useState12([]);
16931
+ const [tasksStartedAt, setTasksStartedAt] = useState12(null);
16932
+ const [tasksStartTokens, setTasksStartTokens] = useState12(0);
16933
+ const [turnStartedAt, setTurnStartedAt] = useState12(null);
16934
+ const [turnPhase, setTurnPhase] = useState12("waiting");
16935
+ const [currentToolName, setCurrentToolName] = useState12(null);
16936
+ const [lastActivityAt, setLastActivityAt] = useState12(null);
16937
+ const [verbose, setVerbose] = useState12(false);
16938
+ const [hasUpdate, setHasUpdate] = useState12(initialUpdateResult?.hasUpdate ?? false);
16939
+ const [latestVersion, setLatestVersion] = useState12(initialUpdateResult?.latestVersion ?? null);
16940
+ const [theme, setTheme] = useState12(resolveTheme(initialCfg?.theme));
16941
+ const [showThemePicker, setShowThemePicker] = useState12(false);
16942
+ const [originalTheme, setOriginalTheme] = useState12(null);
16943
+ const [skillsActive, setSkillsActive] = useState12(0);
16944
+ const [memoryRecalled, setMemoryRecalled] = useState12(false);
16945
+ const [intentTier, setIntentTier] = useState12(null);
16764
16946
  const skillsDirRef = useRef3(join27(process.cwd(), ".kimiflare", "skills"));
16765
- const [kimiMdStale, setKimiMdStale] = useState11(false);
16766
- const [gitBranch, setGitBranch] = useState11(null);
16767
- const [lastSessionTopic, setLastSessionTopic] = useState11(null);
16947
+ const [kimiMdStale, setKimiMdStale] = useState12(false);
16948
+ const [gitBranch, setGitBranch] = useState12(null);
16949
+ const [lastSessionTopic, setLastSessionTopic] = useState12(null);
16768
16950
  useEffect7(() => {
16769
16951
  setGitBranch(detectGitBranch());
16770
16952
  }, []);
@@ -16829,11 +17011,11 @@ ${wcagWarnings.join("\n")}` }
16829
17011
  cancelled = true;
16830
17012
  };
16831
17013
  }, [cfg?.cloudMode, initialCloudToken]);
16832
- const [cursorOffset, setCursorOffset] = useState11(0);
16833
- const [activePicker, setActivePicker] = useState11(null);
16834
- const [filePickerItems, setFilePickerItems] = useState11([]);
17014
+ const [cursorOffset, setCursorOffset] = useState12(0);
17015
+ const [activePicker, setActivePicker] = useState12(null);
17016
+ const [filePickerItems, setFilePickerItems] = useState12([]);
16835
17017
  const filePickerLoadedRef = useRef3(false);
16836
- const [customCommandsVersion, setCustomCommandsVersion] = useState11(0);
17018
+ const [customCommandsVersion, setCustomCommandsVersion] = useState12(0);
16837
17019
  const cacheStableRef = useRef3(initialCfg?.cacheStablePrompts !== false);
16838
17020
  const messagesRef = useRef3(
16839
17021
  makePrefixMessages(cacheStableRef.current, cfg?.model ?? DEFAULT_MODEL, "edit", ALL_TOOLS)
@@ -16884,11 +17066,11 @@ ${wcagWarnings.join("\n")}` }
16884
17066
  const MAX_RECENT_FILES = 10;
16885
17067
  const pickerAnchor = activePicker?.anchor ?? null;
16886
17068
  const pickerKind = activePicker?.kind ?? null;
16887
- const pickerQuery = React14.useMemo(() => {
17069
+ const pickerQuery = React15.useMemo(() => {
16888
17070
  if (pickerAnchor === null) return null;
16889
17071
  return input.slice(pickerAnchor + 1, cursorOffset);
16890
17072
  }, [input, cursorOffset, pickerAnchor]);
16891
- const filteredFileItems = React14.useMemo(() => {
17073
+ const filteredFileItems = React15.useMemo(() => {
16892
17074
  if (pickerKind !== "file" || pickerQuery === null) return [];
16893
17075
  const items = filterPickerItems(filePickerItems, pickerQuery).slice();
16894
17076
  const now2 = Date.now();
@@ -16903,7 +17085,7 @@ ${wcagWarnings.join("\n")}` }
16903
17085
  return a.name.localeCompare(b.name);
16904
17086
  });
16905
17087
  }, [pickerKind, filePickerItems, pickerQuery]);
16906
- const allSlashCommands = React14.useMemo(() => {
17088
+ const allSlashCommands = React15.useMemo(() => {
16907
17089
  const customs = customCommandsRef.current.filter((c) => !BUILTIN_COMMAND_NAMES.has(c.name.toLowerCase())).map((c) => ({
16908
17090
  name: c.name,
16909
17091
  description: c.description ?? "",
@@ -16911,7 +17093,7 @@ ${wcagWarnings.join("\n")}` }
16911
17093
  }));
16912
17094
  return [...BUILTIN_COMMANDS, ...customs];
16913
17095
  }, [customCommandsVersion]);
16914
- const filteredSlashItems = React14.useMemo(() => {
17096
+ const filteredSlashItems = React15.useMemo(() => {
16915
17097
  if (pickerKind !== "slash" || pickerQuery === null) return [];
16916
17098
  return fuzzyFilter(allSlashCommands, pickerQuery, (c) => c.name).slice(0, 50);
16917
17099
  }, [pickerKind, allSlashCommands, pickerQuery]);
@@ -16986,14 +17168,14 @@ ${wcagWarnings.join("\n")}` }
16986
17168
  setActivePicker({ ...activePicker, selected: max });
16987
17169
  }
16988
17170
  }, [filteredSlashItems.length, activePicker]);
16989
- const handlePickerUp = useCallback2(() => {
17171
+ const handlePickerUp = useCallback3(() => {
16990
17172
  setActivePicker((p) => {
16991
17173
  if (!p) return null;
16992
17174
  const next = Math.max(0, p.selected - 1);
16993
17175
  return next === p.selected ? p : { ...p, selected: next };
16994
17176
  });
16995
17177
  }, []);
16996
- const handlePickerDown = useCallback2(() => {
17178
+ const handlePickerDown = useCallback3(() => {
16997
17179
  setActivePicker((p) => {
16998
17180
  if (!p) return null;
16999
17181
  const max = p.kind === "file" ? Math.max(0, filteredFileItems.length - 1) : Math.max(0, filteredSlashItems.length - 1);
@@ -17001,7 +17183,7 @@ ${wcagWarnings.join("\n")}` }
17001
17183
  return next === p.selected ? p : { ...p, selected: next };
17002
17184
  });
17003
17185
  }, [filteredFileItems.length, filteredSlashItems.length]);
17004
- const handlePickerSelect = useCallback2(() => {
17186
+ const handlePickerSelect = useCallback3(() => {
17005
17187
  if (!activePicker) return;
17006
17188
  if (activePicker.kind === "file") {
17007
17189
  const item2 = filteredFileItems[activePicker.selected];
@@ -17020,7 +17202,7 @@ ${wcagWarnings.join("\n")}` }
17020
17202
  setActivePicker(null);
17021
17203
  submitRef.current(value);
17022
17204
  }, [activePicker, filteredFileItems, filteredSlashItems, input, cursorOffset]);
17023
- const handlePickerCancel = useCallback2(() => {
17205
+ const handlePickerCancel = useCallback3(() => {
17024
17206
  pickerCancelRef.current = cursorOffset;
17025
17207
  setActivePicker(null);
17026
17208
  }, [cursorOffset]);
@@ -17151,7 +17333,7 @@ ${wcagWarnings.join("\n")}` }
17151
17333
  }, 3e5);
17152
17334
  return () => clearInterval(id);
17153
17335
  }, []);
17154
- const reloadCustomCommands = useCallback2(async () => {
17336
+ const reloadCustomCommands = useCallback3(async () => {
17155
17337
  const { commands, warnings } = await loadCustomCommands(process.cwd());
17156
17338
  customCommandsRef.current = commands;
17157
17339
  setCustomCommandsVersion((v) => v + 1);
@@ -17278,7 +17460,7 @@ ${wcagWarnings.join("\n")}` }
17278
17460
  }, 30 * 60 * 1e3);
17279
17461
  return () => clearInterval(id);
17280
17462
  }, [cfg]);
17281
- const initMcp = useCallback2(async () => {
17463
+ const initMcp = useCallback3(async () => {
17282
17464
  if (!cfg?.mcpServers || mcpInitRef.current) return;
17283
17465
  mcpInitRef.current = true;
17284
17466
  const manager = mcpManagerRef.current;
@@ -17339,7 +17521,7 @@ ${wcagWarnings.join("\n")}` }
17339
17521
  ]);
17340
17522
  }
17341
17523
  }, [cfg]);
17342
- const initLsp = useCallback2(async () => {
17524
+ const initLsp = useCallback3(async () => {
17343
17525
  if (!cfg?.lspEnabled || !cfg?.lspServers || lspInitRef.current) {
17344
17526
  if (lspInitRef.current) return;
17345
17527
  if (!cfg?.lspEnabled) {
@@ -17410,7 +17592,7 @@ ${wcagWarnings.join("\n")}` }
17410
17592
  void initLsp();
17411
17593
  }
17412
17594
  }, [cfg, initMcp, initLsp]);
17413
- const ensureSessionId = useCallback2(() => {
17595
+ const ensureSessionId = useCallback3(() => {
17414
17596
  if (sessionIdRef.current) return sessionIdRef.current;
17415
17597
  const firstUser = messagesRef.current.find((m) => m.role === "user");
17416
17598
  let firstText = "session";
@@ -17423,7 +17605,7 @@ ${wcagWarnings.join("\n")}` }
17423
17605
  sessionIdRef.current = makeSessionId(firstText);
17424
17606
  return sessionIdRef.current;
17425
17607
  }, []);
17426
- const saveSessionSafe = useCallback2(async () => {
17608
+ const saveSessionSafe = useCallback3(async () => {
17427
17609
  if (!cfg) return;
17428
17610
  ensureSessionId();
17429
17611
  const now2 = (/* @__PURE__ */ new Date()).toISOString();
@@ -17449,13 +17631,13 @@ ${wcagWarnings.join("\n")}` }
17449
17631
  ]);
17450
17632
  }
17451
17633
  }, [cfg, ensureSessionId]);
17452
- const onIterationEnd = useCallback2(
17634
+ const onIterationEnd = useCallback3(
17453
17635
  async (messages, signal) => {
17454
17636
  if (signal.aborted) return messages;
17455
17637
  if (!shouldCompact({ messages })) return messages;
17456
17638
  if (compiledContextRef.current) {
17457
17639
  const store = artifactStoreRef.current;
17458
- const result = compactMessages({
17640
+ const result = compactMessagesViaArtifacts({
17459
17641
  messages,
17460
17642
  state: sessionStateRef.current,
17461
17643
  store
@@ -17500,7 +17682,7 @@ ${wcagWarnings.join("\n")}` }
17500
17682
  }
17501
17683
  if (cfg && !signal.aborted) {
17502
17684
  try {
17503
- const result = await compactMessages2({
17685
+ const result = await summarizeMessagesViaLlm({
17504
17686
  accountId: cfg.accountId,
17505
17687
  apiToken: cfg.apiToken,
17506
17688
  model: cfg.model,
@@ -17527,7 +17709,7 @@ ${wcagWarnings.join("\n")}` }
17527
17709
  },
17528
17710
  [cfg]
17529
17711
  );
17530
- useInput8((inputChar, key) => {
17712
+ useInput9((inputChar, key) => {
17531
17713
  if (key.ctrl && inputChar === "c") {
17532
17714
  logger.info("input:ctrl+c", {
17533
17715
  busy: busyRef.current,
@@ -17641,7 +17823,7 @@ ${wcagWarnings.join("\n")}` }
17641
17823
  void lspManagerRef.current.stopAll().finally(() => exit());
17642
17824
  }
17643
17825
  };
17644
- const flushAssistantUpdates = useCallback2(() => {
17826
+ const flushAssistantUpdates = useCallback3(() => {
17645
17827
  flushTimeoutRef.current = null;
17646
17828
  const pending = pendingTextRef.current;
17647
17829
  if (pending.size === 0) return;
@@ -17659,7 +17841,7 @@ ${wcagWarnings.join("\n")}` }
17659
17841
  })
17660
17842
  );
17661
17843
  }, []);
17662
- const updateAssistant = useCallback2(
17844
+ const updateAssistant = useCallback3(
17663
17845
  (id, patch) => {
17664
17846
  const result = patch({ text: "", reasoning: "" });
17665
17847
  const assistantResult = result;
@@ -17688,7 +17870,7 @@ ${wcagWarnings.join("\n")}` }
17688
17870
  },
17689
17871
  [flushAssistantUpdates]
17690
17872
  );
17691
- const updateTool = useCallback2(
17873
+ const updateTool = useCallback3(
17692
17874
  (id, patch) => {
17693
17875
  setEvents(
17694
17876
  (evts) => evts.map(
@@ -17698,11 +17880,11 @@ ${wcagWarnings.join("\n")}` }
17698
17880
  },
17699
17881
  []
17700
17882
  );
17701
- const updateGatewayMeta = useCallback2((meta) => {
17883
+ const updateGatewayMeta = useCallback3((meta) => {
17702
17884
  gatewayMetaRef.current = meta;
17703
17885
  setGatewayMeta(meta);
17704
17886
  }, []);
17705
- const runCompact = useCallback2(async () => {
17887
+ const runCompact = useCallback3(async () => {
17706
17888
  if (!cfg) return;
17707
17889
  if (busy) {
17708
17890
  setEvents((e) => [...e, { kind: "info", key: mkKey(), text: "can't compact while model is running" }]);
@@ -17716,7 +17898,7 @@ ${wcagWarnings.join("\n")}` }
17716
17898
  try {
17717
17899
  if (compiledContextRef.current) {
17718
17900
  const store = artifactStoreRef.current;
17719
- const result = compactMessages({
17901
+ const result = compactMessagesViaArtifacts({
17720
17902
  messages: messagesRef.current,
17721
17903
  state: sessionStateRef.current,
17722
17904
  store
@@ -17745,7 +17927,7 @@ ${wcagWarnings.join("\n")}` }
17745
17927
  await saveSessionSafe();
17746
17928
  }
17747
17929
  } else {
17748
- const result = await compactMessages2({
17930
+ const result = await summarizeMessagesViaLlm({
17749
17931
  accountId: cfg.accountId,
17750
17932
  apiToken: cfg.apiToken,
17751
17933
  model: cfg.model,
@@ -17798,11 +17980,11 @@ ${wcagWarnings.join("\n")}` }
17798
17980
  pendingToolCallsRef.current.clear();
17799
17981
  }
17800
17982
  }, [cfg, busy, saveSessionSafe]);
17801
- const openResumePicker = useCallback2(async () => {
17983
+ const openResumePicker = useCallback3(async () => {
17802
17984
  const sessions = await listSessions(200, process.cwd());
17803
17985
  setResumeSessions(sessions);
17804
17986
  }, []);
17805
- const runInit = useCallback2(async () => {
17987
+ const runInit = useCallback3(async () => {
17806
17988
  if (!cfg) return;
17807
17989
  if (busy) {
17808
17990
  setEvents((e) => [...e, { kind: "info", key: mkKey(), text: "can't /init while model is running" }]);
@@ -18044,6 +18226,11 @@ ${wcagWarnings.join("\n")}` }
18044
18226
  ...es,
18045
18227
  { kind: "cloud_quota_exhausted", key: mkKey(), used, limit, expiresAt }
18046
18228
  ]);
18229
+ } else if (e instanceof AgentLoopError) {
18230
+ setEvents((es) => [
18231
+ ...es,
18232
+ { kind: "error", key: mkKey(), text: "The agent got stuck repeating the same actions. Here's what we know so far." }
18233
+ ]);
18047
18234
  } else {
18048
18235
  const displayText = e instanceof KimiApiError ? humanizeCloudflareError(e) : `init failed: ${e.message}`;
18049
18236
  setEvents((es) => [
@@ -18070,7 +18257,7 @@ ${wcagWarnings.join("\n")}` }
18070
18257
  pendingToolCallsRef.current.clear();
18071
18258
  }
18072
18259
  }, [cfg, busy, updateAssistant, updateTool, updateGatewayMeta]);
18073
- const handleThemePick = useCallback2(
18260
+ const handleThemePick = useCallback3(
18074
18261
  (picked) => {
18075
18262
  setShowThemePicker(false);
18076
18263
  if (!picked) return;
@@ -18088,7 +18275,7 @@ ${wcagWarnings.join("\n")}` }
18088
18275
  },
18089
18276
  []
18090
18277
  );
18091
- const doResumeSession = useCallback2(
18278
+ const doResumeSession = useCallback3(
18092
18279
  async (filePath, checkpointId) => {
18093
18280
  try {
18094
18281
  const file = checkpointId ? (await loadSessionFromCheckpoint(filePath, checkpointId)).file : await loadSession(filePath);
@@ -18140,7 +18327,7 @@ ${wcagWarnings.join("\n")}` }
18140
18327
  },
18141
18328
  []
18142
18329
  );
18143
- const handleResumePick = useCallback2(
18330
+ const handleResumePick = useCallback3(
18144
18331
  async (picked) => {
18145
18332
  setResumeSessions(null);
18146
18333
  if (!picked) return;
@@ -18162,7 +18349,7 @@ ${wcagWarnings.join("\n")}` }
18162
18349
  },
18163
18350
  [doResumeSession]
18164
18351
  );
18165
- const handleCheckpointPick = useCallback2(
18352
+ const handleCheckpointPick = useCallback3(
18166
18353
  async (checkpointId) => {
18167
18354
  const session = checkpointSession;
18168
18355
  setCheckpointSession(null);
@@ -18181,7 +18368,7 @@ ${wcagWarnings.join("\n")}` }
18181
18368
  },
18182
18369
  [checkpointSession, doResumeSession]
18183
18370
  );
18184
- const handleSlash = useCallback2(
18371
+ const handleSlash = useCallback3(
18185
18372
  (cmd) => {
18186
18373
  const raw = cmd.trim();
18187
18374
  const [head, ...rest] = raw.split(/\s+/);
@@ -19048,7 +19235,7 @@ ${lines.join("\n")}` }]);
19048
19235
  },
19049
19236
  [cfg, exit, usage, theme, mode, openResumePicker, runCompact, runInit, initMcp, setCfg, setShowRemoteDashboard, setSelectedRemoteSession]
19050
19237
  );
19051
- const handleCommandSave = useCallback2(
19238
+ const handleCommandSave = useCallback3(
19052
19239
  async (opts2) => {
19053
19240
  setCommandWizard(null);
19054
19241
  try {
@@ -19070,7 +19257,7 @@ ${lines.join("\n")}` }]);
19070
19257
  },
19071
19258
  [commandWizard, reloadCustomCommands, setEvents]
19072
19259
  );
19073
- const handleCommandDelete = useCallback2(
19260
+ const handleCommandDelete = useCallback3(
19074
19261
  async (cmd) => {
19075
19262
  setCommandToDelete(null);
19076
19263
  try {
@@ -19089,7 +19276,7 @@ ${lines.join("\n")}` }]);
19089
19276
  },
19090
19277
  [reloadCustomCommands, setEvents]
19091
19278
  );
19092
- const processMessage = useCallback2(
19279
+ const processMessage = useCallback3(
19093
19280
  async (text, displayText, opts2) => {
19094
19281
  if (!cfg) return;
19095
19282
  let trimmed = text.trim();
@@ -19475,7 +19662,7 @@ ${lines.join("\n")}` }]);
19475
19662
  if (shouldCompact({ messages: messagesRef.current })) {
19476
19663
  if (compiledContextRef.current) {
19477
19664
  const store = artifactStoreRef.current;
19478
- const result = compactMessages({
19665
+ const result = compactMessagesViaArtifacts({
19479
19666
  messages: messagesRef.current,
19480
19667
  state: sessionStateRef.current,
19481
19668
  store
@@ -19495,7 +19682,7 @@ ${lines.join("\n")}` }]);
19495
19682
  }
19496
19683
  } else {
19497
19684
  try {
19498
- const result = await compactMessages2({
19685
+ const result = await summarizeMessagesViaLlm({
19499
19686
  accountId: cfg.accountId,
19500
19687
  apiToken: cfg.apiToken,
19501
19688
  model: cfg.model,
@@ -19618,7 +19805,7 @@ ${lines.join("\n")}` }]);
19618
19805
  processMessage(next.full, next.display, { queuedKey: next.key });
19619
19806
  }
19620
19807
  }, [busy, queue, processMessage]);
19621
- const submit = useCallback2(
19808
+ const submit = useCallback3(
19622
19809
  (full, display) => {
19623
19810
  const trimmedFull = full.trim();
19624
19811
  if (!trimmedFull) return;
@@ -19819,7 +20006,7 @@ ${lines.join("\n")}` }]);
19819
20006
  ] }),
19820
20007
  /* @__PURE__ */ jsx24(Text23, { color: theme.info.color, children: commandToDelete.filepath }),
19821
20008
  /* @__PURE__ */ jsx24(Box22, { marginTop: 1, children: /* @__PURE__ */ jsx24(
19822
- SelectInput11,
20009
+ SelectInput10,
19823
20010
  {
19824
20011
  items: [
19825
20012
  { label: "Yes, delete", value: "yes", key: "yes" },
@@ -19860,6 +20047,9 @@ ${lines.join("\n")}` }]);
19860
20047
  perm.resolve(d);
19861
20048
  permResolveRef.current = null;
19862
20049
  setPerm(null);
20050
+ },
20051
+ onFeedback: (text) => {
20052
+ submitRef.current(text);
19863
20053
  }
19864
20054
  }
19865
20055
  ) : limitModal ? /* @__PURE__ */ jsx24(
@@ -20008,8 +20198,8 @@ var init_app = __esm({
20008
20198
  init_loop();
20009
20199
  init_supervisor();
20010
20200
  init_system_prompt();
20011
- init_compact();
20012
- init_compaction();
20201
+ init_llm_summarize();
20202
+ init_artifact_compaction();
20013
20203
  init_session_state();
20014
20204
  init_executor();
20015
20205
  init_manager3();
@@ -20033,7 +20223,7 @@ var init_app = __esm({
20033
20223
  init_config();
20034
20224
  init_worker_client();
20035
20225
  init_session_store();
20036
- init_tui_deploy();
20226
+ init_deploy();
20037
20227
  init_tui_auth();
20038
20228
  init_remote_dashboard();
20039
20229
  init_mode();
@@ -20434,6 +20624,11 @@ async function runPrintMode(opts2) {
20434
20624
  process.exitCode = 42;
20435
20625
  return;
20436
20626
  }
20627
+ if (err instanceof AgentLoopError) {
20628
+ process.stderr.write("\n\x1B[33m[Agent loop detected \u2014 exiting with code 43]\x1B[0m\n");
20629
+ process.exitCode = 43;
20630
+ return;
20631
+ }
20437
20632
  if (err instanceof KimiApiError) {
20438
20633
  process.stderr.write(`
20439
20634
  \x1B[31mError: ${humanizeCloudflareError(err)}\x1B[0m