@ringko-ai/rkh 0.1.0 → 0.2.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.
Files changed (2) hide show
  1. package/bin/rkh.mjs +893 -463
  2. package/package.json +1 -1
package/bin/rkh.mjs CHANGED
@@ -893,7 +893,8 @@ var init_paths = __esm(() => {
893
893
  });
894
894
 
895
895
  // packages/config/src/config.ts
896
- import { chmodSync, mkdirSync, readFileSync, writeFileSync } from "fs";
896
+ import { randomUUID as randomUUID2 } from "crypto";
897
+ import { chmodSync, closeSync, existsSync, fsyncSync, mkdirSync, openSync, readFileSync, realpathSync, renameSync, rmSync, writeFileSync } from "fs";
897
898
  import { dirname as dirname2 } from "path";
898
899
  function isRecord(value) {
899
900
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -945,6 +946,26 @@ function writeJson(path, value) {
945
946
  } catch {}
946
947
  return path;
947
948
  }
949
+ function saveConfigFile(config, path) {
950
+ const data = `${JSON.stringify(config, null, 2)}
951
+ `;
952
+ const target = existsSync(path) ? realpathSync(path) : path;
953
+ const temporary = `${target}.${randomUUID2()}.tmp`;
954
+ mkdirSync(dirname2(target), { recursive: true });
955
+ const descriptor = openSync(temporary, "wx", 384);
956
+ try {
957
+ try {
958
+ writeFileSync(descriptor, data, "utf8");
959
+ fsyncSync(descriptor);
960
+ } finally {
961
+ closeSync(descriptor);
962
+ }
963
+ renameSync(temporary, target);
964
+ } finally {
965
+ rmSync(temporary, { force: true });
966
+ }
967
+ return path;
968
+ }
948
969
  function saveConfig(config, env = process.env) {
949
970
  const { providers, model, small_model, mode, ...rest } = config;
950
971
  const settings = { ...rest };
@@ -1084,8 +1105,8 @@ var init_config = __esm(() => {
1084
1105
  });
1085
1106
 
1086
1107
  // packages/config/src/auth.ts
1087
- import { randomUUID as randomUUID2 } from "crypto";
1088
- import { chmodSync as chmodSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, renameSync, rmSync } from "fs";
1108
+ import { randomUUID as randomUUID3 } from "crypto";
1109
+ import { chmodSync as chmodSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, renameSync as renameSync2, rmSync as rmSync2 } from "fs";
1089
1110
  import { dirname as dirname3 } from "path";
1090
1111
  function isRecord2(value) {
1091
1112
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -1193,13 +1214,13 @@ function loadAuth(env = process.env) {
1193
1214
  function writeState(state, env) {
1194
1215
  const path = authPath(env);
1195
1216
  mkdirSync2(dirname3(path), { recursive: true, mode: 448 });
1196
- const temporary = `${path}.${randomUUID2()}.tmp`;
1217
+ const temporary = `${path}.${randomUUID3()}.tmp`;
1197
1218
  try {
1198
1219
  writeFileSync2(temporary, `${JSON.stringify(state, null, 2)}
1199
1220
  `, { flag: "wx", mode: 384 });
1200
- renameSync(temporary, path);
1221
+ renameSync2(temporary, path);
1201
1222
  } finally {
1202
- rmSync(temporary, { force: true });
1223
+ rmSync2(temporary, { force: true });
1203
1224
  }
1204
1225
  try {
1205
1226
  chmodSync2(path, 384);
@@ -1231,9 +1252,9 @@ function setOAuthAccount(domain, account, env = process.env) {
1231
1252
  const domainState = state.oauth[domain] ??= { accounts: [] };
1232
1253
  const index = domainState.accounts.findIndex((entry) => entry.id === account.id);
1233
1254
  if (index === -1)
1234
- domainState.accounts.push({ ...account, uuid: account.uuid ?? randomUUID2() });
1255
+ domainState.accounts.push({ ...account, uuid: account.uuid ?? randomUUID3() });
1235
1256
  else
1236
- domainState.accounts[index] = { ...account, uuid: domainState.accounts[index].uuid ?? account.uuid ?? randomUUID2() };
1257
+ domainState.accounts[index] = { ...account, uuid: domainState.accounts[index].uuid ?? account.uuid ?? randomUUID3() };
1237
1258
  domainState.defaultAccountId ??= account.id;
1238
1259
  writeState(state, env);
1239
1260
  }
@@ -2195,7 +2216,7 @@ var init_proxy = __esm(() => {
2195
2216
  });
2196
2217
 
2197
2218
  // packages/config/src/skills.ts
2198
- import { closeSync, openSync, readSync, mkdirSync as mkdirSync6, readdirSync, rmSync as rmSync2, statSync as statSync2, writeFileSync as writeFileSync6 } from "fs";
2219
+ import { closeSync as closeSync2, openSync as openSync2, readSync, mkdirSync as mkdirSync6, readdirSync, rmSync as rmSync3, statSync as statSync2, writeFileSync as writeFileSync6 } from "fs";
2199
2220
  import { isAbsolute, join as join2, relative, resolve as resolve2 } from "path";
2200
2221
  function parseSkillFrontmatter(text) {
2201
2222
  const match = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/.exec(text);
@@ -2247,13 +2268,13 @@ function discoverSkills(options = {}) {
2247
2268
  }
2248
2269
  let text;
2249
2270
  try {
2250
- const descriptor = openSync(skillFile, "r");
2271
+ const descriptor = openSync2(skillFile, "r");
2251
2272
  try {
2252
2273
  const buffer = Buffer.alloc(SKILL_METADATA_BYTES);
2253
2274
  const bytes = readSync(descriptor, buffer, 0, buffer.length, 0);
2254
2275
  text = buffer.subarray(0, bytes).toString("utf8");
2255
2276
  } finally {
2256
- closeSync(descriptor);
2277
+ closeSync2(descriptor);
2257
2278
  }
2258
2279
  } catch {
2259
2280
  continue;
@@ -2299,7 +2320,7 @@ function removeSkill(dir, env = process.env, cwd = process.cwd()) {
2299
2320
  } catch {
2300
2321
  return false;
2301
2322
  }
2302
- rmSync2(target, { recursive: true, force: true });
2323
+ rmSync3(target, { recursive: true, force: true });
2303
2324
  return true;
2304
2325
  }
2305
2326
  var SKILL_FILE_NAME = "SKILL.md", SKILL_METADATA_BYTES, SINGLE_SEGMENT;
@@ -2310,7 +2331,7 @@ var init_skills = __esm(() => {
2310
2331
  });
2311
2332
 
2312
2333
  // packages/config/src/mcp.ts
2313
- import { chmodSync as chmodSync6, existsSync, mkdirSync as mkdirSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync7 } from "fs";
2334
+ import { chmodSync as chmodSync6, existsSync as existsSync2, mkdirSync as mkdirSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync7 } from "fs";
2314
2335
  import { dirname as dirname7, join as join3 } from "path";
2315
2336
  function isRecord6(value) {
2316
2337
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -2404,7 +2425,7 @@ function saveProjectMcpServers(cwd, servers, env = process.env) {
2404
2425
  throw new Error("No project root found; cannot save project MCP configuration.");
2405
2426
  const dotMcp = join3(root, ".mcp.json");
2406
2427
  const ringkoJson = join3(root, "ringko.json");
2407
- const useRingkoJson = !existsSync(dotMcp);
2428
+ const useRingkoJson = !existsSync2(dotMcp);
2408
2429
  const target = useRingkoJson ? ringkoJson : dotMcp;
2409
2430
  let existing = {};
2410
2431
  if (useRingkoJson) {
@@ -2496,7 +2517,7 @@ function configuredModelIds(config) {
2496
2517
  }
2497
2518
 
2498
2519
  // packages/config/src/diagnostics.ts
2499
- import { appendFileSync, mkdirSync as mkdirSync8, renameSync as renameSync2, statSync as statSync4 } from "fs";
2520
+ import { appendFileSync, mkdirSync as mkdirSync8, renameSync as renameSync3, statSync as statSync4 } from "fs";
2500
2521
  import { join as join5 } from "path";
2501
2522
  function diagnosticLogPath() {
2502
2523
  return join5(ringkoRoot(), "logs", "diagnostics.jsonl");
@@ -2514,7 +2535,7 @@ function writeDiagnostic(source, message) {
2514
2535
  throw error;
2515
2536
  }
2516
2537
  if (size >= MAX_LOG_BYTES)
2517
- renameSync2(path, `${path}.previous`);
2538
+ renameSync3(path, `${path}.previous`);
2518
2539
  const text = message.slice(0, MAX_MESSAGE_LENGTH).replace(/(Bearer\s+)[^\s"']+/gi, "$1[redacted]").replace(/((?:api[_-]?key|access[_-]?token|refresh[_-]?token|password|secret)\s*["']?\s*[:=]\s*["']?)[^\s,"'}]+/gi, "$1[redacted]");
2519
2540
  appendFileSync(path, `${JSON.stringify({ timestamp: new Date().toISOString(), source: source.slice(0, 256), message: text, truncated: message.length > MAX_MESSAGE_LENGTH })}
2520
2541
  `, { mode: 384 });
@@ -2712,7 +2733,7 @@ function parseHeaderOnly(text) {
2712
2733
  var init_format = () => {};
2713
2734
 
2714
2735
  // packages/session/src/lock.ts
2715
- import { closeSync as closeSync2, openSync as openSync2, readFileSync as readFileSync9, unlinkSync, writeSync } from "fs";
2736
+ import { closeSync as closeSync3, openSync as openSync3, readFileSync as readFileSync9, unlinkSync, writeSync } from "fs";
2716
2737
  function readOwnerPid(path) {
2717
2738
  try {
2718
2739
  const parsed = JSON.parse(readFileSync9(path, "utf8"));
@@ -2735,9 +2756,9 @@ function isAlive(pid) {
2735
2756
  function acquireLock(path) {
2736
2757
  for (let attempt = 0;attempt < 2; attempt += 1) {
2737
2758
  try {
2738
- const fd = openSync2(path, "wx");
2759
+ const fd = openSync3(path, "wx");
2739
2760
  writeSync(fd, JSON.stringify({ pid: process.pid, time: Date.now() }));
2740
- closeSync2(fd);
2761
+ closeSync3(fd);
2741
2762
  return {
2742
2763
  release() {
2743
2764
  try {
@@ -2764,13 +2785,13 @@ var init_lock = () => {};
2764
2785
 
2765
2786
  // packages/session/src/store.ts
2766
2787
  import {
2767
- closeSync as closeSync3,
2768
- fsyncSync,
2788
+ closeSync as closeSync4,
2789
+ fsyncSync as fsyncSync2,
2769
2790
  mkdirSync as mkdirSync9,
2770
- openSync as openSync3,
2791
+ openSync as openSync4,
2771
2792
  readdirSync as readdirSync2,
2772
2793
  readFileSync as readFileSync10,
2773
- rmSync as rmSync3,
2794
+ rmSync as rmSync4,
2774
2795
  statSync as statSync5,
2775
2796
  writeSync as writeSync2
2776
2797
  } from "fs";
@@ -2831,7 +2852,7 @@ class SessionStore {
2831
2852
  return false;
2832
2853
  const lock = acquireLock(sessionLockPath(dir));
2833
2854
  try {
2834
- rmSync3(dir, { recursive: true, force: true });
2855
+ rmSync4(dir, { recursive: true, force: true });
2835
2856
  } finally {
2836
2857
  lock.release();
2837
2858
  }
@@ -2929,15 +2950,15 @@ class SessionHandle {
2929
2950
  mkdirSync9(this.dir, { recursive: true, mode: 448 });
2930
2951
  this.lock = acquireLock(sessionLockPath(this.dir));
2931
2952
  try {
2932
- this.fd = openSync3(this.path, "a");
2953
+ this.fd = openSync4(this.path, "a");
2933
2954
  if (!fileExists(this.path) || statSync5(this.path).size === 0) {
2934
2955
  writeSync2(this.fd, serializeHeader(this.header));
2935
- fsyncSync(this.fd);
2956
+ fsyncSync2(this.fd);
2936
2957
  }
2937
2958
  } catch (error) {
2938
2959
  try {
2939
2960
  if (this.fd !== undefined)
2940
- closeSync3(this.fd);
2961
+ closeSync4(this.fd);
2941
2962
  } finally {
2942
2963
  this.fd = undefined;
2943
2964
  this.lock.release();
@@ -2984,16 +3005,16 @@ class SessionHandle {
2984
3005
  if (!this.materialized) {
2985
3006
  mkdirSync9(this.dir, { recursive: true, mode: 448 });
2986
3007
  this.lock = acquireLock(sessionLockPath(this.dir));
2987
- this.fd = openSync3(this.path, "a");
3008
+ this.fd = openSync4(this.path, "a");
2988
3009
  writeSync2(this.fd, serializeHeader(this.header));
2989
3010
  this.materialized = true;
2990
3011
  }
2991
3012
  if (this.fd === undefined)
2992
- this.fd = openSync3(this.path, "a");
3013
+ this.fd = openSync4(this.path, "a");
2993
3014
  for (const line of this.buffer)
2994
3015
  writeSync2(this.fd, line);
2995
3016
  this.buffer.length = 0;
2996
- fsyncSync(this.fd);
3017
+ fsyncSync2(this.fd);
2997
3018
  } catch (error) {
2998
3019
  this.writeFailure = error;
2999
3020
  throw error;
@@ -3014,7 +3035,7 @@ class SessionHandle {
3014
3035
  }
3015
3036
  try {
3016
3037
  if (this.fd !== undefined)
3017
- closeSync3(this.fd);
3038
+ closeSync4(this.fd);
3018
3039
  } catch (error) {
3019
3040
  errors.push(error);
3020
3041
  }
@@ -4009,7 +4030,7 @@ var init_src4 = __esm(() => {
4009
4030
  });
4010
4031
 
4011
4032
  // packages/sdk/src/task.ts
4012
- import { randomUUID as randomUUID3 } from "crypto";
4033
+ import { randomUUID as randomUUID4 } from "crypto";
4013
4034
  function parseTask(value) {
4014
4035
  if (!value || typeof value !== "object" || Array.isArray(value))
4015
4036
  throw new TypeError("Expected a task object.");
@@ -4075,7 +4096,7 @@ class TaskManager {
4075
4096
  throw new Error("Task budget exhausted for this run.");
4076
4097
  this.active++;
4077
4098
  this.launched++;
4078
- const taskId = id ?? randomUUID3();
4099
+ const taskId = id ?? randomUUID4();
4079
4100
  const controller = new AbortController;
4080
4101
  const parentAbort = () => controller.abort(context.signal?.reason);
4081
4102
  context.signal?.addEventListener("abort", parentAbort, { once: true });
@@ -5237,7 +5258,7 @@ var init_src6 = __esm(() => {
5237
5258
  });
5238
5259
 
5239
5260
  // packages/tools/src/ask.ts
5240
- import { randomUUID as randomUUID4 } from "crypto";
5261
+ import { randomUUID as randomUUID5 } from "crypto";
5241
5262
  function parseOption(value, where) {
5242
5263
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
5243
5264
  throw new TypeError(`${where} must be an object.`);
@@ -5371,7 +5392,7 @@ class AskManager {
5371
5392
  context?.signal?.throwIfAborted();
5372
5393
  if (this.queue.length >= ASK_LIMITS.questions)
5373
5394
  throw new Error("Too many pending questions.");
5374
- const id = randomUUID4();
5395
+ const id = randomUUID5();
5375
5396
  const cancel = () => this.finish(id);
5376
5397
  const timer = setTimeout(cancel, 300000);
5377
5398
  const pending = { id, input, resolve, reject, cleanup: () => {
@@ -6191,6 +6212,219 @@ var init_todo = __esm(() => {
6191
6212
  TODO_LIMITS = Object.freeze({ items: 100, characters: 2048 });
6192
6213
  });
6193
6214
 
6215
+ // packages/tools/src/tree.ts
6216
+ import { lstat, opendir, realpath as realpath2 } from "fs/promises";
6217
+ import { isAbsolute as isAbsolute3, join as join9, relative as relative3, sep as sep2 } from "path";
6218
+ function parseTree(value) {
6219
+ if (!value || typeof value !== "object" || Array.isArray(value))
6220
+ throw new TypeError("Expected a tree input object.");
6221
+ const data = value;
6222
+ if (Object.keys(data).some((key) => !["path", "max_depth", "max_entries", "directories_only", "include_hidden", "exclude"].includes(key)))
6223
+ throw new TypeError("Unexpected tree input field.");
6224
+ const input = {};
6225
+ if (data.path !== undefined) {
6226
+ if (typeof data.path !== "string" || !data.path.trim() || data.path.includes("\x00") || data.path.length > TREE_LIMITS.pathCharacters)
6227
+ throw new TypeError("Invalid tree path.");
6228
+ input.path = data.path;
6229
+ }
6230
+ for (const [key, minimum, maximum] of [["max_depth", 0, TREE_LIMITS.maxDepth], ["max_entries", 1, TREE_LIMITS.maxEntries]]) {
6231
+ const value = data[key];
6232
+ if (value !== undefined) {
6233
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < minimum || value > maximum)
6234
+ throw new TypeError(`${key} must be an integer from ${minimum} to ${maximum}.`);
6235
+ input[key] = value;
6236
+ }
6237
+ }
6238
+ for (const key of ["directories_only", "include_hidden"]) {
6239
+ if (data[key] !== undefined) {
6240
+ if (typeof data[key] !== "boolean")
6241
+ throw new TypeError(`${key} must be boolean.`);
6242
+ input[key] = data[key];
6243
+ }
6244
+ }
6245
+ if (data.exclude !== undefined) {
6246
+ if (!Array.isArray(data.exclude) || data.exclude.length > TREE_LIMITS.excludeNames || data.exclude.some((name) => typeof name !== "string" || !name || name.length > TREE_LIMITS.nameCharacters || name === "." || name === ".." || /[\\/\0]/.test(name)))
6247
+ throw new TypeError(`exclude must contain at most ${TREE_LIMITS.excludeNames} nonempty entry names without path separators.`);
6248
+ input.exclude = data.exclude;
6249
+ }
6250
+ return input;
6251
+ }
6252
+ function contained(root, path) {
6253
+ const child = relative3(root, path);
6254
+ return child === "" || child !== ".." && !child.startsWith(`..${sep2}`) && !isAbsolute3(child);
6255
+ }
6256
+ function label(value) {
6257
+ return JSON.stringify(value).slice(1, -1);
6258
+ }
6259
+ function errorCode(error) {
6260
+ const code = error?.code;
6261
+ return typeof code === "string" && /^[A-Z0-9_]+$/.test(code) ? code : "DIRECTORY_CHANGED";
6262
+ }
6263
+ function compareNames(a, b) {
6264
+ return Number(b.directory) - Number(a.directory) || (a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
6265
+ }
6266
+ function createTreeTool(workspace) {
6267
+ return defineTool({
6268
+ name: "tree",
6269
+ taskAccess: "read",
6270
+ description: "Show a directory tree using native filesystem APIs, not a shell or system tree command. Use this tool for directory structure instead of shell. Defaults: workspace root, depth 3, 500 entries; skips hidden entries and common dependency/build directories. Symlinks are shown but not traversed. Outside-workspace targets require approval. exclude replaces the default list with exact entry names.",
6271
+ inputSchema: {
6272
+ type: "object",
6273
+ properties: {
6274
+ path: { type: "string" },
6275
+ max_depth: { type: "integer", minimum: 0, maximum: TREE_LIMITS.maxDepth },
6276
+ max_entries: { type: "integer", minimum: 1, maximum: TREE_LIMITS.maxEntries },
6277
+ directories_only: { type: "boolean" },
6278
+ include_hidden: { type: "boolean" },
6279
+ exclude: { type: "array", maxItems: TREE_LIMITS.excludeNames, items: { type: "string", minLength: 1, maxLength: TREE_LIMITS.nameCharacters } }
6280
+ },
6281
+ additionalProperties: false
6282
+ },
6283
+ parseInput: parseTree,
6284
+ async assessRisk(input) {
6285
+ const target = await resolveWriteTarget(workspace, input.path ?? ".");
6286
+ return { kind: target.insideWorkspace ? "workspace_file" : "external_file", reason: `List directory tree ${target.insideWorkspace ? target.relative || "." : target.absolute}.`, target: target.absolute };
6287
+ },
6288
+ async execute(input, context) {
6289
+ context?.signal?.throwIfAborted();
6290
+ const target = await resolveWriteTarget(workspace, input.path ?? ".");
6291
+ if (context?.approvedTarget && context.approvedTarget !== target.absolute)
6292
+ throw new Error("Tree target changed after approval; retry the call.");
6293
+ const rootInfo = await lstat(target.absolute);
6294
+ if (!rootInfo.isDirectory() || rootInfo.isSymbolicLink())
6295
+ throw new TypeError("tree path must resolve to a directory.");
6296
+ const shown = target.insideWorkspace ? target.relative || "." : target.absolute.split(sep2).join("/");
6297
+ const lines = [label(shown)];
6298
+ const entries = [];
6299
+ const reasons = new Set;
6300
+ const depthLimit = input.max_depth ?? TREE_LIMITS.defaultDepth;
6301
+ const entryLimit = input.max_entries ?? TREE_LIMITS.defaultEntries;
6302
+ const exclusions = new Set((input.exclude ?? TREE_DEFAULT_EXCLUDES).map((name) => process.platform === "win32" ? name.toLowerCase() : name));
6303
+ let scanned = 0;
6304
+ let characters = JSON.stringify(shown).length * 2;
6305
+ let stopped = false;
6306
+ const list = async (path) => {
6307
+ context?.signal?.throwIfAborted();
6308
+ const before = await lstat(path, { bigint: true });
6309
+ const canonical = await realpath2(path);
6310
+ if (!before.isDirectory() || before.isSymbolicLink() || !contained(target.absolute, canonical) || relative3(path, canonical) !== "")
6311
+ throw new Error("Tree directory changed before traversal.");
6312
+ const directory = await opendir(path);
6313
+ const children = [];
6314
+ try {
6315
+ for (;; ) {
6316
+ context?.signal?.throwIfAborted();
6317
+ if (scanned >= TREE_LIMITS.scannedEntries) {
6318
+ reasons.add("scan_limit");
6319
+ break;
6320
+ }
6321
+ const child = await directory.read();
6322
+ if (!child)
6323
+ break;
6324
+ scanned++;
6325
+ if (!input.include_hidden && child.name.startsWith(".") || exclusions.has(process.platform === "win32" ? child.name.toLowerCase() : child.name))
6326
+ continue;
6327
+ children.push({ name: child.name, directory: child.isDirectory() && !child.isSymbolicLink(), symlink: child.isSymbolicLink() });
6328
+ }
6329
+ } finally {
6330
+ await directory.close();
6331
+ }
6332
+ const after = await lstat(path, { bigint: true });
6333
+ if (after.isSymbolicLink() || before.dev !== after.dev || before.ino !== after.ino || relative3(canonical, await realpath2(path)) !== "")
6334
+ throw new Error("Tree directory changed during traversal.");
6335
+ return children.sort(compareNames);
6336
+ };
6337
+ const walk = async (path, display, prefix, depth) => {
6338
+ if (depth >= depthLimit) {
6339
+ reasons.add("max_depth");
6340
+ return;
6341
+ }
6342
+ const candidates = await list(path);
6343
+ const children = input.directories_only ? candidates.filter((child) => child.directory || child.symlink) : candidates;
6344
+ for (let index = 0;index < children.length; index++) {
6345
+ context?.signal?.throwIfAborted();
6346
+ if (entries.length >= entryLimit) {
6347
+ reasons.add("max_entries");
6348
+ stopped = true;
6349
+ return;
6350
+ }
6351
+ const child = children[index];
6352
+ const absolute = join9(path, child.name);
6353
+ const childPath = display ? `${display}/${child.name}` : child.name;
6354
+ const entry = { path: childPath, type: "other", depth: depth + 1 };
6355
+ try {
6356
+ const info = await lstat(absolute);
6357
+ entry.type = info.isSymbolicLink() ? "symlink" : info.isDirectory() ? "directory" : info.isFile() ? "file" : "other";
6358
+ } catch (error) {
6359
+ entry.error = errorCode(error);
6360
+ reasons.add("io_error");
6361
+ }
6362
+ if (input.directories_only && entry.type !== "directory" && entry.type !== "symlink" && !entry.error)
6363
+ continue;
6364
+ const last = index === children.length - 1;
6365
+ const suffix = entry.type === "directory" ? "/" : entry.type === "symlink" ? " [symlink; not followed]" : "";
6366
+ const line = `${prefix}${last ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 "}${label(child.name)}${suffix}${entry.error ? ` [${entry.error}]` : ""}`;
6367
+ const cost = JSON.stringify(line).length + JSON.stringify(entry).length + TREE_LIMITS.entryOverhead;
6368
+ if (characters + cost > TREE_LIMITS.outputCharacters - TREE_LIMITS.footerCharacters) {
6369
+ reasons.add("output_limit");
6370
+ stopped = true;
6371
+ return;
6372
+ }
6373
+ characters += cost;
6374
+ entries.push(entry);
6375
+ lines.push(line);
6376
+ const lineIndex = lines.length - 1;
6377
+ if (entry.type === "directory") {
6378
+ if (depth + 1 >= depthLimit) {
6379
+ entry.children_truncated = true;
6380
+ reasons.add("max_depth");
6381
+ lines[lineIndex] += " [depth limit]";
6382
+ } else if (scanned < TREE_LIMITS.scannedEntries) {
6383
+ try {
6384
+ await walk(absolute, childPath, `${prefix}${last ? " " : "\u2502 "}`, depth + 1);
6385
+ } catch (error) {
6386
+ context?.signal?.throwIfAborted();
6387
+ entry.error = errorCode(error);
6388
+ entry.children_truncated = true;
6389
+ reasons.add("io_error");
6390
+ lines[lineIndex] += ` [${entry.error}]`;
6391
+ }
6392
+ if (stopped)
6393
+ entry.children_truncated = true;
6394
+ } else
6395
+ entry.children_truncated = true;
6396
+ }
6397
+ if (stopped)
6398
+ return;
6399
+ }
6400
+ };
6401
+ await walk(target.absolute, "", "", 0);
6402
+ context?.signal?.throwIfAborted();
6403
+ if (reasons.size)
6404
+ lines.push(`\u2026 [truncated: ${[...reasons].join(", ")}]`);
6405
+ return {
6406
+ path: shown,
6407
+ tree: lines.join(`
6408
+ `),
6409
+ entries,
6410
+ directories: entries.filter((entry) => entry.type === "directory").length,
6411
+ files: entries.filter((entry) => entry.type === "file").length,
6412
+ symlinks: entries.filter((entry) => entry.type === "symlink").length,
6413
+ other: entries.filter((entry) => entry.type === "other").length,
6414
+ truncated: reasons.size > 0,
6415
+ ...reasons.size ? { truncation_reasons: [...reasons] } : {}
6416
+ };
6417
+ }
6418
+ });
6419
+ }
6420
+ var TREE_LIMITS, TREE_DEFAULT_EXCLUDES;
6421
+ var init_tree = __esm(() => {
6422
+ init_src();
6423
+ init_workspace();
6424
+ TREE_LIMITS = Object.freeze({ defaultDepth: 3, maxDepth: 16, defaultEntries: 500, maxEntries: 2000, scannedEntries: 20000, outputCharacters: 131072, footerCharacters: 160, entryOverhead: 160, excludeNames: 64, nameCharacters: 255, pathCharacters: 32768 });
6425
+ TREE_DEFAULT_EXCLUDES = [".git", "node_modules", "dist", "build", "coverage", "target", ".next", ".cache", ".venv", "venv", "__pycache__"];
6426
+ });
6427
+
6194
6428
  // node_modules/.pnpm/entities@7.0.1/node_modules/entities/dist/esm/decode-codepoint.js
6195
6429
  function replaceCodePoint(codePoint) {
6196
6430
  var _a;
@@ -23856,14 +24090,14 @@ function process2(parentNode) {
23856
24090
  } else if (node.nodeType === 1) {
23857
24091
  replacement = replacementForNode.call(self2, node);
23858
24092
  }
23859
- return join9(output, replacement);
24093
+ return join10(output, replacement);
23860
24094
  }, "");
23861
24095
  }
23862
24096
  function postProcess(output) {
23863
24097
  var self2 = this;
23864
24098
  this.rules.forEach(function(rule) {
23865
24099
  if (typeof rule.append === "function") {
23866
- output = join9(output, rule.append(self2.options));
24100
+ output = join10(output, rule.append(self2.options));
23867
24101
  }
23868
24102
  });
23869
24103
  return output.replace(/^[\t\r\n]+/, "").replace(/[\t\r\n\s]+$/, "");
@@ -23876,7 +24110,7 @@ function replacementForNode(node) {
23876
24110
  content = content.trim();
23877
24111
  return whitespace.leading + rule.replacement(content, node, this.options) + whitespace.trailing;
23878
24112
  }
23879
- function join9(output, replacement) {
24113
+ function join10(output, replacement) {
23880
24114
  var s1 = trimTrailingNewlines(output);
23881
24115
  var s2 = trimLeadingNewlines(replacement);
23882
24116
  var nls = Math.max(output.length - s1.length, replacement.length - s2.length);
@@ -24605,6 +24839,7 @@ function registerWorkspaceTools(registry, options) {
24605
24839
  registry.register(createEditTool(workspace, tracker));
24606
24840
  registry.register(createGlobTool(workspace));
24607
24841
  registry.register(createGrepTool(workspace));
24842
+ registry.register(createTreeTool(workspace));
24608
24843
  return workspace;
24609
24844
  }
24610
24845
  function registerNetworkTools(registry, options = {}) {
@@ -24630,6 +24865,7 @@ var init_src7 = __esm(() => {
24630
24865
  init_read();
24631
24866
  init_shell();
24632
24867
  init_todo();
24868
+ init_tree();
24633
24869
  init_webfetch();
24634
24870
  init_websearch();
24635
24871
  init_write();
@@ -24725,7 +24961,7 @@ var init_src8 = __esm(() => {
24725
24961
 
24726
24962
  // packages/sdk/src/skills.ts
24727
24963
  import { open } from "fs/promises";
24728
- import { join as join10 } from "path";
24964
+ import { join as join11 } from "path";
24729
24965
  function registerRuntimeSkills(registry, workspace) {
24730
24966
  const skills = discoverSkills({ cwd: workspace }).slice(0, MAX_SKILLS);
24731
24967
  if (skills.length === 0)
@@ -24747,7 +24983,7 @@ function registerRuntimeSkills(registry, workspace) {
24747
24983
  const skill = skills.find((skill) => skill.name === input.name);
24748
24984
  if (!skill)
24749
24985
  throw new Error("Skill is no longer available.");
24750
- const file = await open(join10(skill.dir, SKILL_FILE_NAME), "r");
24986
+ const file = await open(join11(skill.dir, SKILL_FILE_NAME), "r");
24751
24987
  try {
24752
24988
  const stat = await file.stat();
24753
24989
  if (!stat.isFile() || stat.size > MAX_SKILL_BYTES)
@@ -24762,7 +24998,7 @@ function registerRuntimeSkills(registry, workspace) {
24762
24998
  }
24763
24999
  if (total > MAX_SKILL_BYTES)
24764
25000
  throw new Error("Skill exceeds 64 KiB.");
24765
- return `Instructions from: ${join10(skill.dir, SKILL_FILE_NAME)}
25001
+ return `Instructions from: ${join11(skill.dir, SKILL_FILE_NAME)}
24766
25002
  ${buffer.subarray(0, total).toString("utf8")}`;
24767
25003
  } finally {
24768
25004
  await file.close();
@@ -24778,9 +25014,9 @@ var init_skills2 = __esm(() => {
24778
25014
  });
24779
25015
 
24780
25016
  // packages/sdk/src/permissions.ts
24781
- import { createHash as createHash2, randomUUID as randomUUID5 } from "crypto";
24782
- import { closeSync as closeSync4, existsSync as existsSync2, fstatSync, mkdirSync as mkdirSync11, openSync as openSync4, readSync as readSync2, renameSync as renameSync3, unlinkSync as unlinkSync2, writeFileSync as writeFileSync9 } from "fs";
24783
- import { join as join11, resolve as resolve5 } from "path";
25017
+ import { createHash as createHash2, randomUUID as randomUUID6 } from "crypto";
25018
+ import { closeSync as closeSync5, existsSync as existsSync3, fstatSync, mkdirSync as mkdirSync11, openSync as openSync5, readSync as readSync2, renameSync as renameSync4, unlinkSync as unlinkSync2, writeFileSync as writeFileSync9 } from "fs";
25019
+ import { join as join12, resolve as resolve5 } from "path";
24784
25020
  function validateRules(value) {
24785
25021
  if (!Array.isArray(value) || value.length > MAX_RULES)
24786
25022
  throw new TypeError("Invalid permission rules.");
@@ -24796,12 +25032,12 @@ class PermissionManager {
24796
25032
  sessions = new Map;
24797
25033
  constructor(workspace) {
24798
25034
  const key = createHash2("sha256").update(resolve5(workspace)).digest("hex");
24799
- this.path = join11(ringkoRoot(), "permissions", `${key}.json`);
25035
+ this.path = join12(ringkoRoot(), "permissions", `${key}.json`);
24800
25036
  }
24801
25037
  saved() {
24802
- if (!existsSync2(this.path))
25038
+ if (!existsSync3(this.path))
24803
25039
  return [];
24804
- const descriptor = openSync4(this.path, "r");
25040
+ const descriptor = openSync5(this.path, "r");
24805
25041
  const buffer = Buffer.alloc(MAX_FILE_BYTES2 + 1);
24806
25042
  let size = 0;
24807
25043
  try {
@@ -24814,7 +25050,7 @@ class PermissionManager {
24814
25050
  size += count;
24815
25051
  }
24816
25052
  } finally {
24817
- closeSync4(descriptor);
25053
+ closeSync5(descriptor);
24818
25054
  }
24819
25055
  if (size > MAX_FILE_BYTES2)
24820
25056
  throw new Error("Permission file exceeds 256 KiB.");
@@ -24843,10 +25079,10 @@ class PermissionManager {
24843
25079
  this.sessions.clear();
24844
25080
  }
24845
25081
  updateSaved(change) {
24846
- mkdirSync11(join11(ringkoRoot(), "permissions"), { recursive: true, mode: 448 });
25082
+ mkdirSync11(join12(ringkoRoot(), "permissions"), { recursive: true, mode: 448 });
24847
25083
  let lock;
24848
25084
  try {
24849
- lock = openSync4(`${this.path}.lock`, "wx", 384);
25085
+ lock = openSync5(`${this.path}.lock`, "wx", 384);
24850
25086
  } catch {
24851
25087
  throw new Error(`Permission rules are locked; retry or remove the stale lock after confirming no writer is active: ${this.path}.lock`);
24852
25088
  }
@@ -24858,17 +25094,17 @@ class PermissionManager {
24858
25094
  const data = JSON.stringify({ version: 1, rules: next });
24859
25095
  if (Buffer.byteLength(data) > MAX_FILE_BYTES2)
24860
25096
  throw new Error("Permission rules exceed 256 KiB.");
24861
- const temporary = `${this.path}.${randomUUID5()}.tmp`;
25097
+ const temporary = `${this.path}.${randomUUID6()}.tmp`;
24862
25098
  try {
24863
25099
  writeFileSync9(temporary, data, { flag: "wx", mode: 384 });
24864
- renameSync3(temporary, this.path);
25100
+ renameSync4(temporary, this.path);
24865
25101
  } finally {
24866
- if (existsSync2(temporary))
25102
+ if (existsSync3(temporary))
24867
25103
  unlinkSync2(temporary);
24868
25104
  }
24869
25105
  return true;
24870
25106
  } finally {
24871
- closeSync4(lock);
25107
+ closeSync5(lock);
24872
25108
  unlinkSync2(`${this.path}.lock`);
24873
25109
  }
24874
25110
  }
@@ -81677,7 +81913,7 @@ var init_github_copilot = __esm(() => {
81677
81913
  });
81678
81914
 
81679
81915
  // packages/providers/src/openai/oauth.ts
81680
- import { randomUUID as randomUUID6 } from "crypto";
81916
+ import { randomUUID as randomUUID7 } from "crypto";
81681
81917
  function describeError(error) {
81682
81918
  return error instanceof Error ? error : new Error(String(error));
81683
81919
  }
@@ -81717,7 +81953,7 @@ function withCodexStore(body) {
81717
81953
  }
81718
81954
  function createOpenAiOauthFetch(accountId) {
81719
81955
  let pending = null;
81720
- const sessionId = randomUUID6();
81956
+ const sessionId = randomUUID7();
81721
81957
  const send = async (input, init) => {
81722
81958
  applyProxyEnv();
81723
81959
  const account = getOAuthAccount(OPENAI_OAUTH_DOMAIN, accountId);
@@ -86060,7 +86296,7 @@ var defaultColumns = 80, defaultRows = 24, exec2 = (command, arguments_, { shell
86060
86296
  };
86061
86297
  var init_terminal_size = () => {};
86062
86298
 
86063
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/utils.js
86299
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/utils.js
86064
86300
  var getWindowSize = (stdout) => {
86065
86301
  const { columns, rows } = stdout;
86066
86302
  if (columns && rows) {
@@ -96810,7 +97046,7 @@ var init_widest_line = __esm(() => {
96810
97046
  init_string_width();
96811
97047
  });
96812
97048
 
96813
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/measure-text.js
97049
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/measure-text.js
96814
97050
  var cache, measureText = (text) => {
96815
97051
  if (text.length === 0) {
96816
97052
  return {
@@ -97784,7 +98020,7 @@ var init_cli_truncate = __esm(() => {
97784
98020
  validPositions = new Set(["start", "middle", "end"]);
97785
98021
  });
97786
98022
 
97787
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/wrap-text.js
98023
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/wrap-text.js
97788
98024
  var cache2, wrapText = (text, maxWidth, wrapType) => {
97789
98025
  const cacheKey = text + String(maxWidth) + String(wrapType);
97790
98026
  const cachedText = cache2[cacheKey];
@@ -97825,7 +98061,7 @@ var init_wrap_text = __esm(() => {
97825
98061
  wrap_text_default = wrapText;
97826
98062
  });
97827
98063
 
97828
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/ansi-tokenizer.js
98064
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/ansi-tokenizer.js
97829
98065
  var bellCharacter = "\x07", escapeCharacter = "\x1B", stringTerminatorCharacter = "\x9C", csiCharacter = "\x9B", oscCharacter = "\x9D", dcsCharacter = "\x90", pmCharacter = "\x9E", apcCharacter = "\x9F", sosCharacter = "\x98", isCsiParameterCharacter2 = (character) => {
97830
98066
  const codePoint = character.codePointAt(0);
97831
98067
  return codePoint !== undefined && codePoint >= 48 && codePoint <= 63;
@@ -98110,7 +98346,7 @@ var bellCharacter = "\x07", escapeCharacter = "\x1B", stringTerminatorCharacter
98110
98346
  return tokens;
98111
98347
  };
98112
98348
 
98113
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/sanitize-ansi.js
98349
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/sanitize-ansi.js
98114
98350
  var sgrParametersRegex, sanitizeAnsi = (text) => {
98115
98351
  if (!hasAnsiControlCharacters(text)) {
98116
98352
  return text;
@@ -98132,7 +98368,7 @@ var init_sanitize_ansi = __esm(() => {
98132
98368
  sanitize_ansi_default = sanitizeAnsi;
98133
98369
  });
98134
98370
 
98135
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/squash-text-nodes.js
98371
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/squash-text-nodes.js
98136
98372
  var squashTextNodes = (node) => {
98137
98373
  let text = "";
98138
98374
  for (let index = 0;index < node.childNodes.length; index++) {
@@ -98160,7 +98396,7 @@ var init_squash_text_nodes = __esm(() => {
98160
98396
  squash_text_nodes_default = squashTextNodes;
98161
98397
  });
98162
98398
 
98163
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/dom.js
98399
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/dom.js
98164
98400
  var createNode = (nodeName) => {
98165
98401
  const node = {
98166
98402
  nodeName,
@@ -98287,7 +98523,7 @@ var init_dom = __esm(async () => {
98287
98523
  await init_src13();
98288
98524
  });
98289
98525
 
98290
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/styles.js
98526
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/styles.js
98291
98527
  var positionEdges, applyPositionStyles = (node, style) => {
98292
98528
  if ("position" in style) {
98293
98529
  let positionType = src_default.POSITION_TYPE_RELATIVE;
@@ -98569,7 +98805,7 @@ var init_styles = __esm(async () => {
98569
98805
  styles_default = styles2;
98570
98806
  });
98571
98807
 
98572
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/devtools-window-polyfill.js
98808
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/devtools-window-polyfill.js
98573
98809
  import ws from "ws";
98574
98810
  var customGlobal;
98575
98811
  var init_devtools_window_polyfill = __esm(() => {
@@ -114722,7 +114958,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
114722
114958
  });
114723
114959
  });
114724
114960
 
114725
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/devtools.js
114961
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/devtools.js
114726
114962
  import WebSocket2 from "ws";
114727
114963
  var import_react_devtools_core, isDevToolsReachable = async () => new Promise((resolve) => {
114728
114964
  const socket = new WebSocket2("ws://localhost:8097");
@@ -114756,7 +114992,7 @@ $ npx react-devtools
114756
114992
  }
114757
114993
  });
114758
114994
 
114759
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/reconciler.js
114995
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/reconciler.js
114760
114996
  import process5 from "process";
114761
114997
  async function loadPackageJson() {
114762
114998
  const fs = await import("fs");
@@ -115061,7 +115297,7 @@ function indentString(string, count = 1, options = {}) {
115061
115297
  return string.replace(regex, indent.repeat(count));
115062
115298
  }
115063
115299
 
115064
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/get-max-width.js
115300
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/get-max-width.js
115065
115301
  var getMaxWidth = (yogaNode) => {
115066
115302
  return yogaNode.getComputedWidth() - yogaNode.getComputedPadding(src_default.EDGE_LEFT) - yogaNode.getComputedPadding(src_default.EDGE_RIGHT) - yogaNode.getComputedBorder(src_default.EDGE_LEFT) - yogaNode.getComputedBorder(src_default.EDGE_RIGHT);
115067
115303
  }, get_max_width_default;
@@ -115653,7 +115889,7 @@ var init_source = __esm(() => {
115653
115889
  source_default = chalk;
115654
115890
  });
115655
115891
 
115656
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/colorize.js
115892
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/colorize.js
115657
115893
  var rgbRegex, ansiRegex2, isNamedColor = (color) => {
115658
115894
  return color in source_default;
115659
115895
  }, colorize = (str, color, type) => {
@@ -115697,7 +115933,7 @@ var init_colorize = __esm(() => {
115697
115933
  colorize_default = colorize;
115698
115934
  });
115699
115935
 
115700
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/render-border.js
115936
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/render-border.js
115701
115937
  var stylePiece = (segment, fg, bg, dim) => {
115702
115938
  let styled = colorize_default(segment, fg, "foreground");
115703
115939
  styled = colorize_default(styled, bg, "background");
@@ -115774,7 +116010,7 @@ var init_render_border = __esm(() => {
115774
116010
  render_border_default = renderBorder;
115775
116011
  });
115776
116012
 
115777
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/render-background.js
116013
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/render-background.js
115778
116014
  var renderBackground = (x, y, node, output) => {
115779
116015
  if (!node.style.backgroundColor) {
115780
116016
  return;
@@ -115800,7 +116036,7 @@ var init_render_background = __esm(() => {
115800
116036
  render_background_default = renderBackground;
115801
116037
  });
115802
116038
 
115803
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/render-node-to-output.js
116039
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/render-node-to-output.js
115804
116040
  var applyPaddingToText = (node, text) => {
115805
116041
  const yogaNode = node.childNodes[0]?.yogaNode;
115806
116042
  if (yogaNode) {
@@ -116247,7 +116483,7 @@ var init_build = __esm(() => {
116247
116483
  init_tokenize();
116248
116484
  });
116249
116485
 
116250
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/output.js
116486
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/output.js
116251
116487
  class OutputCaches {
116252
116488
  widths = new Map;
116253
116489
  blockWidths = new Map;
@@ -116444,7 +116680,7 @@ var init_output = __esm(() => {
116444
116680
  init_build();
116445
116681
  });
116446
116682
 
116447
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/renderer.js
116683
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/renderer.js
116448
116684
  var renderer = (node, isScreenReaderEnabled) => {
116449
116685
  if (node.yogaNode) {
116450
116686
  if (isScreenReaderEnabled) {
@@ -116503,7 +116739,7 @@ var init_renderer = __esm(async () => {
116503
116739
  renderer_default = renderer;
116504
116740
  });
116505
116741
 
116506
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/cursor-helpers.js
116742
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/cursor-helpers.js
116507
116743
  var showCursorEscape = "\x1B[?25h", hideCursorEscape = "\x1B[?25l", cursorPositionChanged = (a, b) => a?.x !== b?.x || a?.y !== b?.y, buildCursorSuffix = (visibleLineCount, cursorPosition) => {
116508
116744
  if (!cursorPosition) {
116509
116745
  return "";
@@ -116626,7 +116862,7 @@ var init_cli_cursor = __esm(() => {
116626
116862
  cli_cursor_default = cliCursor;
116627
116863
  });
116628
116864
 
116629
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/log-update.js
116865
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/log-update.js
116630
116866
  var visibleLineCount = (lines, str) => str.endsWith(`
116631
116867
  `) ? lines.length - 1 : lines.length, createStandard = (stream, { showCursor = false } = {}) => {
116632
116868
  let previousLineCount = 0;
@@ -116865,7 +117101,7 @@ var init_log_update = __esm(() => {
116865
117101
  log_update_default = logUpdate;
116866
117102
  });
116867
117103
 
116868
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/write-synchronized.js
117104
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/write-synchronized.js
116869
117105
  function shouldSynchronize(stream, interactive) {
116870
117106
  return "isTTY" in stream && stream.isTTY && (interactive ?? !is_in_ci_default);
116871
117107
  }
@@ -116874,14 +117110,14 @@ var init_write_synchronized = __esm(() => {
116874
117110
  init_is_in_ci();
116875
117111
  });
116876
117112
 
116877
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/instances.js
117113
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/instances.js
116878
117114
  var instances, instances_default;
116879
117115
  var init_instances = __esm(() => {
116880
117116
  instances = new WeakMap;
116881
117117
  instances_default = instances;
116882
117118
  });
116883
117119
 
116884
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/input-parser.js
117120
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/input-parser.js
116885
117121
  var escape2 = "\x1B", pasteStart = "\x1B[200~", pasteEnd = "\x1B[201~", isCsiParameterByte = (byte) => {
116886
117122
  return byte >= 48 && byte <= 63;
116887
117123
  }, isCsiIntermediateByte = (byte) => {
@@ -117053,7 +117289,7 @@ var escape2 = "\x1B", pasteStart = "\x1B[200~", pasteEnd = "\x1B[201~", isCsiPar
117053
117289
  };
117054
117290
  };
117055
117291
 
117056
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/components/AppContext.js
117292
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/components/AppContext.js
117057
117293
  var import_react2, noopSuspension, defaultValue, AppContext, AppContext_default;
117058
117294
  var init_AppContext = __esm(() => {
117059
117295
  import_react2 = __toESM(require_react(), 1);
@@ -117077,7 +117313,7 @@ var init_AppContext = __esm(() => {
117077
117313
  AppContext_default = AppContext;
117078
117314
  });
117079
117315
 
117080
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/components/StdinContext.js
117316
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/components/StdinContext.js
117081
117317
  import { EventEmitter } from "events";
117082
117318
  import process9 from "process";
117083
117319
  var import_react3, StdinContext, StdinContext_default;
@@ -117095,7 +117331,7 @@ var init_StdinContext = __esm(() => {
117095
117331
  StdinContext_default = StdinContext;
117096
117332
  });
117097
117333
 
117098
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/components/StdoutContext.js
117334
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/components/StdoutContext.js
117099
117335
  import process10 from "process";
117100
117336
  var import_react4, StdoutContext, StdoutContext_default;
117101
117337
  var init_StdoutContext = __esm(() => {
@@ -117108,7 +117344,7 @@ var init_StdoutContext = __esm(() => {
117108
117344
  StdoutContext_default = StdoutContext;
117109
117345
  });
117110
117346
 
117111
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/components/StderrContext.js
117347
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/components/StderrContext.js
117112
117348
  import process11 from "process";
117113
117349
  var import_react5, StderrContext, StderrContext_default;
117114
117350
  var init_StderrContext = __esm(() => {
@@ -117121,7 +117357,7 @@ var init_StderrContext = __esm(() => {
117121
117357
  StderrContext_default = StderrContext;
117122
117358
  });
117123
117359
 
117124
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/components/FocusContext.js
117360
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/components/FocusContext.js
117125
117361
  var import_react6, FocusContext, FocusContext_default;
117126
117362
  var init_FocusContext = __esm(() => {
117127
117363
  import_react6 = __toESM(require_react(), 1);
@@ -117141,7 +117377,7 @@ var init_FocusContext = __esm(() => {
117141
117377
  FocusContext_default = FocusContext;
117142
117378
  });
117143
117379
 
117144
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/components/AnimationContext.js
117380
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/components/AnimationContext.js
117145
117381
  var import_react7, animationContext, AnimationContext_default;
117146
117382
  var init_AnimationContext = __esm(() => {
117147
117383
  import_react7 = __toESM(require_react(), 1);
@@ -117158,7 +117394,7 @@ var init_AnimationContext = __esm(() => {
117158
117394
  AnimationContext_default = animationContext;
117159
117395
  });
117160
117396
 
117161
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/components/CursorContext.js
117397
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/components/CursorContext.js
117162
117398
  var import_react8, CursorContext, CursorContext_default;
117163
117399
  var init_CursorContext = __esm(() => {
117164
117400
  import_react8 = __toESM(require_react(), 1);
@@ -117454,7 +117690,7 @@ var init_dist13 = __esm(() => {
117454
117690
  dist_default3 = codeExcerpt;
117455
117691
  });
117456
117692
 
117457
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/components/AccessibilityContext.js
117693
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/components/AccessibilityContext.js
117458
117694
  var import_react9, accessibilityContext;
117459
117695
  var init_AccessibilityContext = __esm(() => {
117460
117696
  import_react9 = __toESM(require_react(), 1);
@@ -117463,14 +117699,14 @@ var init_AccessibilityContext = __esm(() => {
117463
117699
  });
117464
117700
  });
117465
117701
 
117466
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/components/BackgroundContext.js
117702
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/components/BackgroundContext.js
117467
117703
  var import_react10, backgroundContext;
117468
117704
  var init_BackgroundContext = __esm(() => {
117469
117705
  import_react10 = __toESM(require_react(), 1);
117470
117706
  backgroundContext = import_react10.createContext(undefined);
117471
117707
  });
117472
117708
 
117473
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/components/Box.js
117709
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/components/Box.js
117474
117710
  var import_react11, Box, Box_default;
117475
117711
  var init_Box = __esm(() => {
117476
117712
  init_AccessibilityContext();
@@ -117504,7 +117740,7 @@ var init_Box = __esm(() => {
117504
117740
  Box_default = Box;
117505
117741
  });
117506
117742
 
117507
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/components/Text.js
117743
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/components/Text.js
117508
117744
  function Text2({ color, backgroundColor, dimColor = false, bold = false, italic = false, underline = false, strikethrough = false, inverse = false, wrap = "wrap", children, "aria-label": ariaLabel, "aria-hidden": ariaHidden = false }) {
117509
117745
  const { isScreenReaderEnabled } = import_react12.useContext(accessibilityContext);
117510
117746
  const inheritedBackgroundColor = import_react12.useContext(backgroundContext);
@@ -117554,7 +117790,7 @@ var init_Text = __esm(() => {
117554
117790
  import_react12 = __toESM(require_react(), 1);
117555
117791
  });
117556
117792
 
117557
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/components/ErrorOverview.js
117793
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/components/ErrorOverview.js
117558
117794
  import * as fs2 from "fs";
117559
117795
  import { cwd } from "process";
117560
117796
  function ErrorOverview({ error }) {
@@ -117601,7 +117837,7 @@ var init_ErrorOverview = __esm(() => {
117601
117837
  });
117602
117838
  });
117603
117839
 
117604
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/components/ErrorBoundary.js
117840
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/components/ErrorBoundary.js
117605
117841
  var import_react14, ErrorBoundary;
117606
117842
  var init_ErrorBoundary = __esm(() => {
117607
117843
  init_ErrorOverview();
@@ -117626,7 +117862,7 @@ var init_ErrorBoundary = __esm(() => {
117626
117862
  };
117627
117863
  });
117628
117864
 
117629
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/components/App.js
117865
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/components/App.js
117630
117866
  import { EventEmitter as EventEmitter2 } from "events";
117631
117867
  import process12 from "process";
117632
117868
  function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, exitOnCtrlC, onExit, onWaitUntilRenderFlush, onSuspendTerminal, onRegisterInputControl, setCursorPosition, interactive, renderThrottleMs }) {
@@ -118120,7 +118356,7 @@ var init_App = __esm(() => {
118120
118356
  App_default = App;
118121
118357
  });
118122
118358
 
118123
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/kitty-keyboard.js
118359
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/kitty-keyboard.js
118124
118360
  function resolveFlags(flags) {
118125
118361
  let result = 0;
118126
118362
  for (const flag of flags) {
@@ -118149,7 +118385,7 @@ var init_kitty_keyboard = __esm(() => {
118149
118385
  };
118150
118386
  });
118151
118387
 
118152
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/ink.js
118388
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/ink.js
118153
118389
  import process13 from "process";
118154
118390
 
118155
118391
  class Ink {
@@ -118928,7 +119164,7 @@ var init_ink = __esm(async () => {
118928
119164
  isWindowsConsole = process13.platform === "win32";
118929
119165
  });
118930
119166
 
118931
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/render.js
119167
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/render.js
118932
119168
  import { Stream } from "stream";
118933
119169
  import process14 from "process";
118934
119170
  var render = (node, options) => {
@@ -118984,7 +119220,7 @@ var init_render = __esm(async () => {
118984
119220
  render_default = render;
118985
119221
  });
118986
119222
 
118987
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/render-to-string.js
119223
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/render-to-string.js
118988
119224
  var import_constants3;
118989
119225
  var init_render_to_string = __esm(async () => {
118990
119226
  await __promiseAll([
@@ -118996,33 +119232,33 @@ var init_render_to_string = __esm(async () => {
118996
119232
  import_constants3 = __toESM(require_constants(), 1);
118997
119233
  });
118998
119234
 
118999
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/components/Static.js
119235
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/components/Static.js
119000
119236
  var import_react17;
119001
119237
  var init_Static = __esm(() => {
119002
119238
  import_react17 = __toESM(require_react(), 1);
119003
119239
  });
119004
119240
 
119005
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/components/Transform.js
119241
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/components/Transform.js
119006
119242
  var import_react18;
119007
119243
  var init_Transform = __esm(() => {
119008
119244
  init_AccessibilityContext();
119009
119245
  import_react18 = __toESM(require_react(), 1);
119010
119246
  });
119011
119247
 
119012
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/components/Newline.js
119248
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/components/Newline.js
119013
119249
  var import_react19;
119014
119250
  var init_Newline = __esm(() => {
119015
119251
  import_react19 = __toESM(require_react(), 1);
119016
119252
  });
119017
119253
 
119018
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/components/Spacer.js
119254
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/components/Spacer.js
119019
119255
  var import_react20;
119020
119256
  var init_Spacer = __esm(() => {
119021
119257
  init_Box();
119022
119258
  import_react20 = __toESM(require_react(), 1);
119023
119259
  });
119024
119260
 
119025
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/parse-keypress.js
119261
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/parse-keypress.js
119026
119262
  function resolveEventType(value) {
119027
119263
  if (value === 3)
119028
119264
  return "release";
@@ -119438,14 +119674,14 @@ var init_parse_keypress = __esm(() => {
119438
119674
  parse_keypress_default = parseKeypress;
119439
119675
  });
119440
119676
 
119441
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/hooks/use-stdin.js
119677
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/hooks/use-stdin.js
119442
119678
  var import_react21, useStdinContext = () => import_react21.useContext(StdinContext_default);
119443
119679
  var init_use_stdin = __esm(() => {
119444
119680
  init_StdinContext();
119445
119681
  import_react21 = __toESM(require_react(), 1);
119446
119682
  });
119447
119683
 
119448
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/hooks/use-input.js
119684
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/hooks/use-input.js
119449
119685
  var import_react22, useInput = (inputHandler, options = {}) => {
119450
119686
  const { setRawMode, internal_exitOnCtrlC, internal_eventEmitter } = useStdinContext();
119451
119687
  import_react22.useEffect(() => {
@@ -119530,7 +119766,7 @@ var init_use_input = __esm(async () => {
119530
119766
  use_input_default = useInput;
119531
119767
  });
119532
119768
 
119533
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/hooks/use-paste.js
119769
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/hooks/use-paste.js
119534
119770
  var import_react23, usePaste = (handler, options = {}) => {
119535
119771
  const { setRawMode, setBracketedPasteMode, internal_eventEmitter } = useStdinContext();
119536
119772
  import_react23.useEffect(() => {
@@ -119566,7 +119802,7 @@ var init_use_paste = __esm(async () => {
119566
119802
  use_paste_default = usePaste;
119567
119803
  });
119568
119804
 
119569
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/hooks/use-app.js
119805
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/hooks/use-app.js
119570
119806
  var import_react24, useApp = () => import_react24.useContext(AppContext_default), use_app_default;
119571
119807
  var init_use_app = __esm(() => {
119572
119808
  init_AppContext();
@@ -119574,7 +119810,7 @@ var init_use_app = __esm(() => {
119574
119810
  use_app_default = useApp;
119575
119811
  });
119576
119812
 
119577
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/hooks/use-stdout.js
119813
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/hooks/use-stdout.js
119578
119814
  var import_react25, useStdout = () => import_react25.useContext(StdoutContext_default), use_stdout_default;
119579
119815
  var init_use_stdout = __esm(() => {
119580
119816
  init_StdoutContext();
@@ -119582,14 +119818,14 @@ var init_use_stdout = __esm(() => {
119582
119818
  use_stdout_default = useStdout;
119583
119819
  });
119584
119820
 
119585
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/hooks/use-stderr.js
119821
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/hooks/use-stderr.js
119586
119822
  var import_react26;
119587
119823
  var init_use_stderr = __esm(() => {
119588
119824
  init_StderrContext();
119589
119825
  import_react26 = __toESM(require_react(), 1);
119590
119826
  });
119591
119827
 
119592
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/hooks/use-focus.js
119828
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/hooks/use-focus.js
119593
119829
  var import_react27;
119594
119830
  var init_use_focus = __esm(() => {
119595
119831
  init_FocusContext();
@@ -119597,35 +119833,35 @@ var init_use_focus = __esm(() => {
119597
119833
  import_react27 = __toESM(require_react(), 1);
119598
119834
  });
119599
119835
 
119600
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/hooks/use-focus-manager.js
119836
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/hooks/use-focus-manager.js
119601
119837
  var import_react28;
119602
119838
  var init_use_focus_manager = __esm(() => {
119603
119839
  init_FocusContext();
119604
119840
  import_react28 = __toESM(require_react(), 1);
119605
119841
  });
119606
119842
 
119607
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/hooks/use-is-screen-reader-enabled.js
119843
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/hooks/use-is-screen-reader-enabled.js
119608
119844
  var import_react29;
119609
119845
  var init_use_is_screen_reader_enabled = __esm(() => {
119610
119846
  init_AccessibilityContext();
119611
119847
  import_react29 = __toESM(require_react(), 1);
119612
119848
  });
119613
119849
 
119614
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/hooks/use-cursor.js
119850
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/hooks/use-cursor.js
119615
119851
  var import_react30;
119616
119852
  var init_use_cursor = __esm(() => {
119617
119853
  init_CursorContext();
119618
119854
  import_react30 = __toESM(require_react(), 1);
119619
119855
  });
119620
119856
 
119621
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/hooks/use-animation.js
119857
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/hooks/use-animation.js
119622
119858
  var import_react31;
119623
119859
  var init_use_animation = __esm(() => {
119624
119860
  init_AnimationContext();
119625
119861
  import_react31 = __toESM(require_react(), 1);
119626
119862
  });
119627
119863
 
119628
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/hooks/use-window-size.js
119864
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/hooks/use-window-size.js
119629
119865
  var import_react32;
119630
119866
  var init_use_window_size = __esm(() => {
119631
119867
  init_utils();
@@ -119633,7 +119869,7 @@ var init_use_window_size = __esm(() => {
119633
119869
  import_react32 = __toESM(require_react(), 1);
119634
119870
  });
119635
119871
 
119636
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/hooks/use-box-metrics.js
119872
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/hooks/use-box-metrics.js
119637
119873
  var import_react33, emptyMetrics, findRootNode = (node) => {
119638
119874
  if (!node) {
119639
119875
  return;
@@ -119678,10 +119914,10 @@ var init_use_box_metrics = __esm(async () => {
119678
119914
  use_box_metrics_default = useBoxMetrics;
119679
119915
  });
119680
119916
 
119681
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/measure-element.js
119917
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/measure-element.js
119682
119918
  var init_measure_element = () => {};
119683
119919
 
119684
- // node_modules/.pnpm/ink@7.1.1_@types+react@19.3_70993b4e971952190401d8ef62a09bf2/node_modules/ink/build/index.js
119920
+ // node_modules/.pnpm/ink@7.1.1_@types+react@19.3.0_react-devtools-core@8.0.0_react@19.3.0/node_modules/ink/build/index.js
119685
119921
  var init_build2 = __esm(async () => {
119686
119922
  init_Box();
119687
119923
  init_Text();
@@ -119858,6 +120094,9 @@ function edit(state, action) {
119858
120094
  return { text: chars.join(""), cursor: start };
119859
120095
  }
119860
120096
  function editorLines(state, columns, maxRows) {
120097
+ return editorViewport(state, columns, maxRows).lines;
120098
+ }
120099
+ function editorViewport(state, columns, maxRows) {
119861
120100
  const width = Math.max(2, columns);
119862
120101
  const rows = [{ before: "", after: "" }];
119863
120102
  let row = 0;
@@ -119892,7 +120131,8 @@ function editorLines(state, columns, maxRows) {
119892
120131
  used += cells;
119893
120132
  }
119894
120133
  const start = Math.max(0, cursorRow - Math.max(1, maxRows) + 1);
119895
- return rows.slice(start, start + Math.max(1, maxRows));
120134
+ const lines = rows.slice(start, start + Math.max(1, maxRows));
120135
+ return { lines, above: start, below: Math.max(0, rows.length - start - lines.length) };
119896
120136
  }
119897
120137
  var INPUT_LIMIT = 65536, HISTORY_LIMIT = 100, segmenter5;
119898
120138
  var init_editor = __esm(() => {
@@ -119922,9 +120162,12 @@ var init_glyphs = __esm(() => {
119922
120162
  var theme, SPINNER_FRAMES;
119923
120163
  var init_theme = __esm(() => {
119924
120164
  theme = {
119925
- brand: "#ff7a1a",
120165
+ brand: "#e58c54",
119926
120166
  userBackground: "#303030",
119927
- tool: "cyan",
120167
+ userText: "#eeeeee",
120168
+ tool: "#b8b8b8",
120169
+ selected: "#383838",
120170
+ shell: "magenta",
119928
120171
  error: "red",
119929
120172
  success: "green",
119930
120173
  dim: "gray",
@@ -119935,6 +120178,22 @@ var init_theme = __esm(() => {
119935
120178
  SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
119936
120179
  });
119937
120180
 
120181
+ // packages/repl/src/terminal-layout.ts
120182
+ function terminalColumns(columns, windows = process.platform === "win32") {
120183
+ return Math.max(1, Math.floor(columns) - (windows ? 1 : 0));
120184
+ }
120185
+ function terminalLayout(rows, modal) {
120186
+ const height = Math.max(6, Math.floor(rows) - 1);
120187
+ const compact = height < 20;
120188
+ return {
120189
+ height,
120190
+ compact,
120191
+ todoRows: modal || height < 16 ? 0 : Math.min(5, Math.floor(height / 5)),
120192
+ jobRows: modal || height < 16 ? 0 : 2,
120193
+ inputRows: Math.max(1, Math.min(5, Math.floor(height / 5)))
120194
+ };
120195
+ }
120196
+
119938
120197
  // node_modules/.pnpm/react@19.3.0/node_modules/react/cjs/react-jsx-dev-runtime.development.js
119939
120198
  var require_react_jsx_dev_runtime_development = __commonJS(function(exports) {
119940
120199
  var React = __toESM(require_react());
@@ -120172,7 +120431,7 @@ function TodoPanel({ todos, maxRows = 5 }) {
120172
120431
  const { stdout } = use_stdout_default();
120173
120432
  if (todos.length === 0 || maxRows <= 0)
120174
120433
  return null;
120175
- const columns = stdout.columns ?? 80;
120434
+ const columns = terminalColumns(stdout.columns ?? 80);
120176
120435
  const padding = columns > 6 ? 1 : 0;
120177
120436
  const width = Math.max(1, columns - padding * 2);
120178
120437
  const completed = todos.filter((todo) => todo.status === "completed").length;
@@ -120243,7 +120502,7 @@ function formatElapsed(ms) {
120243
120502
  const hours = Math.floor(minutes / 60);
120244
120503
  return minutes % 60 === 0 ? `${hours}h` : `${hours}h ${minutes % 60}m`;
120245
120504
  }
120246
- function TaskTree({ tasks, selectedId, columns }) {
120505
+ function TaskTree({ tasks, selectedId, columns, maxRows = MAX_VISIBLE + 2 }) {
120247
120506
  const anyRunning = tasks.some((task) => task.status === "running");
120248
120507
  const [now, setNow] = import_react34.useState(() => Date.now());
120249
120508
  import_react34.useEffect(() => {
@@ -120255,8 +120514,14 @@ function TaskTree({ tasks, selectedId, columns }) {
120255
120514
  if (!tasks.length)
120256
120515
  return null;
120257
120516
  const selected = tasks.find((task) => task.id === selectedId);
120258
- const recent = tasks.slice(-MAX_VISIBLE);
120259
- const visible = selected && !recent.includes(selected) ? [selected, ...tasks.slice(-(MAX_VISIBLE - 1))] : recent;
120517
+ if (maxRows < 3)
120518
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text2, {
120519
+ color: theme.dim,
120520
+ children: fitTerminalLine(`${tasks.length} subagent${tasks.length === 1 ? "" : "s"} \xB7 ${selected ? selected.description : "main"} \xB7 Ctrl+G views`, columns)
120521
+ }, undefined, false, undefined, this);
120522
+ const count = Math.max(1, Math.min(MAX_VISIBLE, maxRows - 2));
120523
+ const recent = tasks.slice(-count);
120524
+ const visible = selected && !recent.includes(selected) ? [selected, ...count > 1 ? tasks.slice(-(count - 1)) : []] : recent;
120260
120525
  const width = Math.max(1, columns - 2);
120261
120526
  const mainViewed = selectedId === undefined;
120262
120527
  return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
@@ -120307,7 +120572,7 @@ function Banner({ modelLabel, workspace }) {
120307
120572
  children: /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text2, {
120308
120573
  color: theme.brand,
120309
120574
  bold: true,
120310
- children: fitTerminalLine(`RingKo \xB7 ${modelLabel} \xB7 ${workspace}`, stdout.columns ?? 80)
120575
+ children: fitTerminalLine(`RingKo \xB7 ${modelLabel} \xB7 ${workspace}`, terminalColumns(stdout.columns ?? 80))
120311
120576
  }, undefined, false, undefined, this)
120312
120577
  }, undefined, false, undefined, this);
120313
120578
  }
@@ -121940,6 +122205,8 @@ function toolResultSummary(item) {
121940
122205
  const parsed = JSON.parse(item.text);
121941
122206
  if (typeof parsed === "object" && parsed !== null) {
121942
122207
  const record = parsed;
122208
+ if (!item.failed && item.toolName === "tree" && typeof record.directories === "number" && typeof record.files === "number")
122209
+ return `${record.directories} ${record.directories === 1 ? "directory" : "directories"} \xB7 ${record.files} file${record.files === 1 ? "" : "s"}${record.truncated === true ? " (truncated)" : ""}`;
121943
122210
  if (typeof record.exitCode === "number" || record.exitCode === null)
121944
122211
  return `Exit ${record.exitCode ?? "unknown"}${record.timedOut === true ? " (timed out)" : ""}${record.truncated === true ? " (truncated)" : ""}`;
121945
122212
  if (item.failed)
@@ -121949,7 +122216,7 @@ function toolResultSummary(item) {
121949
122216
  if (Array.isArray(record.matches)) {
121950
122217
  const count = record.matches.length;
121951
122218
  const unit = item.toolName === "glob" ? "file" : "match";
121952
- return `${count} ${unit}${count === 1 ? "" : "s"}${truncated}`;
122219
+ return `${count} ${unit}${count === 1 ? "" : unit === "match" ? "es" : "s"}${truncated}`;
121953
122220
  }
121954
122221
  if (Array.isArray(record.files)) {
121955
122222
  const count = record.files.length;
@@ -121987,6 +122254,13 @@ function toolInputText(item) {
121987
122254
  }
121988
122255
  }
121989
122256
  function toolOutputText(item) {
122257
+ if (!item.failed && item.toolName === "tree") {
122258
+ try {
122259
+ const value = JSON.parse(item.text);
122260
+ if (value && typeof value === "object" && typeof value.tree === "string")
122261
+ return value.tree;
122262
+ } catch {}
122263
+ }
121990
122264
  if (item.toolName === "shell") {
121991
122265
  try {
121992
122266
  const value = JSON.parse(item.text);
@@ -122023,103 +122297,236 @@ var init_state = __esm(() => {
122023
122297
  QUIET_TOOLS = new Set(["glob", "grep"]);
122024
122298
  });
122025
122299
 
122300
+ // packages/repl/src/transcript-groups.ts
122301
+ function transcriptGroups(items) {
122302
+ const groups = [];
122303
+ for (const item of items) {
122304
+ const exploration = item.kind === "tool" && !item.failed && !item.incomplete && EXPLORATION_TOOLS.has(item.toolName ?? "");
122305
+ const previous = groups.at(-1);
122306
+ if (exploration && previous?.exploration)
122307
+ previous.items.push(item);
122308
+ else
122309
+ groups.push({ items: [item], exploration });
122310
+ }
122311
+ return groups;
122312
+ }
122313
+ function explorationLabel(items) {
122314
+ const reads = items.filter((item) => item.toolName === "read").length;
122315
+ const searches = items.filter((item) => item.toolName === "grep" || item.toolName === "glob").length;
122316
+ const lists = items.length - reads - searches;
122317
+ const counts = [[reads, "read"], [searches, "search"], [lists, "listing"]];
122318
+ const detail = counts.filter(([count]) => count > 0).map(([count, name]) => `${count} ${name}${count === 1 ? "" : name === "search" ? "es" : "s"}`).join(" \xB7 ");
122319
+ return `${items.some((item) => item.running) ? "Exploring" : "Explored"} \xB7 ${detail}`;
122320
+ }
122321
+ var EXPLORATION_TOOLS;
122322
+ var init_transcript_groups = __esm(() => {
122323
+ EXPLORATION_TOOLS = new Set(["read", "glob", "grep", "list", "tree"]);
122324
+ });
122325
+
122026
122326
  // packages/repl/src/transcript-layout.ts
122027
- function transcriptLines(items, columns, expandThinking, expandTools) {
122327
+ function wrapped(item, text, columns, options = {}) {
122328
+ const prefix = options.prefix ?? "";
122329
+ const continuation = options.continuation ?? prefix;
122330
+ const width = Math.max(1, columns - prefix.length);
122331
+ const source = options.markdown ? markdownToAnsi(text) : cleanTerminalText(text);
122332
+ let position = (options.section ?? 0) * (MARKDOWN_LIMITS.characters + 1);
122333
+ return wrapAnsi2(source, width, { hard: true, trim: false }).split(`
122334
+ `).map((line, index) => {
122335
+ const result = { text: `${index === 0 ? prefix : continuation}${line}`, kind: item.kind, failed: item.failed, heading: options.heading, running: item.running, itemId: item.id, position };
122336
+ position += Math.max(1, cleanTerminalText(line).length);
122337
+ return result;
122338
+ });
122339
+ }
122340
+ function renderBlock(item, columns, thinking, tools) {
122341
+ if (item.kind === "user")
122342
+ return wrapped(item, item.text.slice(0, MARKDOWN_LIMITS.characters) + (item.text.length > MARKDOWN_LIMITS.characters ? `
122343
+ [Prompt display truncated; full text retained in session]` : ""), columns, { prefix: "> ", continuation: " " });
122344
+ if (item.kind === "assistant")
122345
+ return wrapped(item, item.text, columns, { markdown: true, prefix: "\u25CF ", continuation: " " });
122346
+ if (item.kind === "notice")
122347
+ return wrapped(item, item.text, columns, { prefix: " " });
122348
+ if (item.kind === "thinking") {
122349
+ const title = wrapped(item, thinking ? "Thinking" : "Thinking \xB7 Ctrl+T to expand", columns, { prefix: " ", heading: true });
122350
+ return thinking ? [...title, ...wrapped(item, item.text.slice(0, MARKDOWN_LIMITS.characters), columns, { prefix: " ", section: 1 })] : title;
122351
+ }
122352
+ const target = toolCallSummary(item);
122353
+ const status = item.failed ? " \xB7 Failed" : item.incomplete ? " \xB7 Outcome unknown" : item.running ? " \xB7 Running" : "";
122354
+ const lines = wrapped(item, `${item.toolName ?? "tool"}${target ? ` (${target})` : ""}${status}`, columns, { prefix: "\u25CF ", continuation: " ", heading: true });
122355
+ lines.push(...wrapped(item, toolResultSummary(item) ?? "Done", columns, { prefix: " \u2514 ", continuation: " ", section: 1 }));
122356
+ if (tools) {
122357
+ const input = toolInputText(item);
122358
+ if (input !== undefined)
122359
+ lines.push(...wrapped(item, `Input:
122360
+ ${input}`, columns, { prefix: " ", section: 2 }));
122361
+ if (!item.running) {
122362
+ const output = toolOutputText(item);
122363
+ const preview = output.slice(0, TRANSCRIPT_LIMITS.toolPreview);
122364
+ lines.push(...wrapped(item, `Output:
122365
+ ${preview}${output.length > preview.length ? `
122366
+ [Display preview truncated; full output retained in session]` : ""}`, columns, { prefix: " ", section: 3 }));
122367
+ }
122368
+ }
122369
+ return lines;
122370
+ }
122371
+ function layout(items, columns, thinking, tools, render) {
122028
122372
  const lines = [];
122029
- const width = Math.max(1, columns);
122030
- const append = (item, text, heading = false) => {
122031
- for (const line of wrapAnsi2(cleanTerminalText(text), width, { hard: true, trim: false }).split(`
122032
- `))
122033
- lines.push({ text: line, kind: item.kind, failed: item.failed, heading });
122034
- };
122035
- const appendMarkdown = (item, text) => {
122036
- const rendered = markdownToAnsi(text);
122037
- for (const line of wrapAnsi2(rendered, width, { hard: true, trim: false }).split(`
122038
- `))
122039
- lines.push({ text: line, kind: item.kind, failed: item.failed });
122040
- };
122041
- for (const item of items) {
122042
- if (item.kind === "user") {
122043
- append(item, "");
122044
- append(item, `> ${item.text}`);
122045
- } else if (item.kind === "assistant")
122046
- appendMarkdown(item, item.text);
122047
- else if (item.kind === "notice")
122048
- append(item, item.text);
122049
- else if (item.kind === "thinking") {
122050
- append(item, expandThinking ? "Thinking" : "Thinking (Ctrl+T to expand)", true);
122051
- if (expandThinking)
122052
- append(item, item.text);
122373
+ const width = Math.max(1, Math.floor(columns));
122374
+ for (const group of transcriptGroups(items)) {
122375
+ const first = group.items[0];
122376
+ if (!first)
122377
+ continue;
122378
+ if (lines.length && (first.kind === "user" || first.kind === "tool" || first.kind === "assistant")) {
122379
+ lines.push({ text: "", kind: "notice", itemId: first.id, position: -1 });
122380
+ }
122381
+ if (group.exploration && group.items.length > 1 && !tools) {
122382
+ const active = group.items.find((item) => item.running);
122383
+ const last = active ?? group.items.at(-1);
122384
+ lines.push(...wrapped({ ...first, running: Boolean(active) }, explorationLabel(group.items), width, { prefix: "\u25CF ", heading: true }));
122385
+ lines.push(...wrapped(first, `${last.toolName}${toolCallSummary(last) ? ` (${toolCallSummary(last)})` : ""} \xB7 ${toolResultSummary(last) ?? "Done"}`, width, { prefix: " \u2514 ", continuation: " ", section: 1 }));
122053
122386
  } else {
122054
- append(item, "");
122055
- const target = toolCallSummary(item);
122056
- append(item, `${item.running ? "Running" : item.incomplete ? "Unknown" : item.failed ? "Failed" : "Completed"}: ${item.toolName ?? "tool"}${target ? ` (${target})` : ""}`, true);
122057
- append(item, ` ${toolResultSummary(item) ?? "Done"} \xB7 Ctrl+O ${expandTools ? "collapse" : "expand"}`);
122058
- if (expandTools) {
122059
- const detailWidth = Math.max(1, width - 2);
122060
- const input = toolInputText(item);
122061
- if (input !== undefined) {
122062
- append(item, " Input:");
122063
- for (const line of wrapAnsi2(cleanTerminalText(input), detailWidth, { hard: true, trim: false }).split(`
122064
- `))
122065
- append(item, ` ${line}`);
122066
- }
122067
- if (!item.running) {
122068
- append(item, " Output:");
122069
- for (const line of wrapAnsi2(cleanTerminalText(toolOutputText(item)), detailWidth, { hard: true, trim: false }).split(`
122070
- `))
122071
- append(item, ` ${line}`);
122072
- }
122073
- }
122074
- append(item, "");
122387
+ for (const item of group.items)
122388
+ lines.push(...render(item, width, thinking, tools));
122075
122389
  }
122076
122390
  }
122077
122391
  return lines;
122078
122392
  }
122393
+ function createTranscriptRenderer() {
122394
+ const cache = new Map;
122395
+ let characters = 0;
122396
+ const render = (item, columns, thinking, tools) => {
122397
+ const signature = [item.kind, item.text, item.toolName, item.running, item.incomplete, item.failed, toolCallSummary(item), tools ? toolInputText(item) : undefined, columns, thinking, tools];
122398
+ const previous = cache.get(item.id);
122399
+ if (previous && previous.signature.every((part, index) => part === signature[index])) {
122400
+ cache.delete(item.id);
122401
+ cache.set(item.id, previous);
122402
+ return previous.lines;
122403
+ }
122404
+ if (previous) {
122405
+ characters -= previous.size;
122406
+ cache.delete(item.id);
122407
+ }
122408
+ const lines = renderBlock(item, columns, thinking, tools);
122409
+ const size = signature.reduce((sum, part) => sum + (typeof part === "string" ? part.length : 0), 0) + lines.reduce((sum, line) => sum + line.text.length, 0);
122410
+ if (size <= TRANSCRIPT_LIMITS.cacheCharacters) {
122411
+ cache.set(item.id, { signature, lines, size });
122412
+ characters += size;
122413
+ while (cache.size > TRANSCRIPT_LIMITS.cacheEntries || characters > TRANSCRIPT_LIMITS.cacheCharacters) {
122414
+ const oldest = cache.keys().next().value;
122415
+ if (oldest === undefined)
122416
+ break;
122417
+ characters -= cache.get(oldest).size;
122418
+ cache.delete(oldest);
122419
+ }
122420
+ }
122421
+ return lines;
122422
+ };
122423
+ return (items, columns, thinking, tools) => layout(items, columns, thinking, tools, render);
122424
+ }
122425
+ var TRANSCRIPT_LIMITS;
122079
122426
  var init_transcript_layout = __esm(() => {
122080
122427
  init_wrap_ansi2();
122081
122428
  init_editor();
122082
122429
  init_markdown();
122083
122430
  init_state();
122431
+ init_transcript_groups();
122432
+ TRANSCRIPT_LIMITS = Object.freeze({ cacheEntries: 256, cacheCharacters: 2097152, toolPreview: 65536 });
122433
+ });
122434
+
122435
+ // packages/repl/src/transcript-viewport.ts
122436
+ function transcriptViewport(lines, rows, columns, offset, viewKey, previous) {
122437
+ const height = Math.max(0, Math.floor(rows));
122438
+ const sameView = previous?.viewKey === viewKey;
122439
+ const continuing = sameView && previous.offset === offset && offset > 0;
122440
+ const history = offset > 0 && lines.length > height;
122441
+ const available = Math.max(0, height - (history ? 1 : 0));
122442
+ const tailLine = lines.at(-1);
122443
+ const tail = tailLine ? `${tailLine.itemId}:${tailLine.position}:${tailLine.text}` : undefined;
122444
+ let end = Math.max(available, lines.length - Math.max(0, offset));
122445
+ if (continuing && previous.anchor) {
122446
+ let match = -1;
122447
+ for (let index = 0;index < lines.length; index++) {
122448
+ const line = lines[index];
122449
+ if (line.itemId === previous.anchor.itemId && line.position <= previous.anchor.position && line.position >= 0)
122450
+ match = index;
122451
+ }
122452
+ if (match >= 0)
122453
+ end = Math.max(0, match - previous.anchor.leading) + available;
122454
+ }
122455
+ end = Math.min(lines.length, Math.max(0, end));
122456
+ const actual = history ? Math.max(0, lines.length - end) : 0;
122457
+ if (!actual)
122458
+ end = lines.length;
122459
+ const count = actual ? available : height;
122460
+ const page = height ? lines.slice(Math.max(0, end - count), end) : [];
122461
+ const firstIndex = page.findIndex((line) => line.position >= 0);
122462
+ const first = page[firstIndex];
122463
+ return {
122464
+ offset: actual,
122465
+ page,
122466
+ anchor: actual && first ? { itemId: first.itemId, position: first.position, leading: firstIndex } : actual && sameView ? previous.anchor : undefined,
122467
+ pending: Boolean(actual && sameView && (previous.pending || previous.columns === columns && previous.tail !== tail)),
122468
+ tail,
122469
+ columns,
122470
+ viewKey
122471
+ };
122472
+ }
122473
+
122474
+ // packages/repl/src/chrome.ts
122475
+ function hintLine(hints, columns) {
122476
+ let line = "";
122477
+ for (const hint of hints) {
122478
+ const label = cleanTerminalText(hint).replace(/\s+/g, " ").trim();
122479
+ const next = line ? `${line} \xB7 ${label}` : label;
122480
+ if (stringWidth2(next) <= columns)
122481
+ line = next;
122482
+ }
122483
+ return line;
122484
+ }
122485
+ var init_chrome = __esm(() => {
122486
+ init_string_width2();
122487
+ init_editor();
122084
122488
  });
122085
122489
 
122086
122490
  // packages/repl/src/components/Transcript.tsx
122087
- function Transcript({ items, limit, expandThinking = false, expandTools = false, columns = 80, rows = 20, offset = 0, onOffset }) {
122088
- const lines = import_react35.useMemo(() => transcriptLines(limit === undefined ? items : items.slice(-limit), columns, expandThinking, expandTools), [items, limit, expandThinking, expandTools, columns]);
122089
- const height = Math.max(0, rows);
122090
- const contentHeight = Math.max(0, height - (offset > 0 ? 1 : 0));
122091
- const maximum = Math.max(0, lines.length - contentHeight);
122092
- const active = Math.min(offset, maximum);
122093
- import_react35.useEffect(() => {
122094
- if (offset !== active)
122095
- onOffset?.(active);
122096
- }, [offset, active, onOffset]);
122097
- const end = Math.max(0, lines.length - active);
122098
- const page = lines.slice(Math.max(0, end - contentHeight), end);
122491
+ function Transcript({ items, limit, expandThinking = false, expandTools = false, columns = 80, rows = 20, offset = 0, onOffset, viewKey = "main" }) {
122492
+ const render = import_react35.useMemo(() => createTranscriptRenderer(), [viewKey]);
122493
+ const lines = import_react35.useMemo(() => render(limit === undefined ? items : items.slice(-limit), columns, expandThinking, expandTools), [items, limit, expandThinking, expandTools, columns, render]);
122494
+ const tools = items.some((item) => item.kind === "tool");
122495
+ const previous = import_react35.useRef(undefined);
122496
+ const height = Math.max(0, rows - (tools && rows > 2 ? 1 : 0));
122497
+ const viewport = transcriptViewport(lines, height, columns, offset, viewKey, previous.current);
122498
+ import_react35.useLayoutEffect(() => {
122499
+ previous.current = viewport;
122500
+ if (offset !== viewport.offset)
122501
+ onOffset?.(viewport.offset);
122502
+ });
122099
122503
  return /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Box_default, {
122100
122504
  flexDirection: "column",
122101
122505
  flexShrink: 0,
122102
122506
  children: [
122103
- active > 0 && height > 0 ? /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text2, {
122104
- color: theme.dim,
122105
- children: [
122106
- "History \xB7 ",
122107
- active,
122108
- " rows above latest \xB7 PgDn to return"
122109
- ]
122110
- }, undefined, true, undefined, this) : null,
122111
- page.map((line, index) => /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text2, {
122507
+ viewport.offset > 0 && height > 0 ? /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text2, {
122508
+ color: viewport.pending ? theme.brand : theme.dim,
122509
+ children: fitTerminalLine(`${viewport.pending ? "New output \xB7 " : ""}History \xB7 PgDn to latest`, columns)
122510
+ }, undefined, false, undefined, this) : null,
122511
+ viewport.page.map((line, index) => /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text2, {
122112
122512
  bold: line.heading,
122113
122513
  backgroundColor: line.kind === "user" ? theme.userBackground : undefined,
122114
- color: line.failed ? theme.error : line.kind === "thinking" || line.kind === "notice" ? theme.dim : line.kind === "tool" && line.heading ? theme.tool : undefined,
122115
- children: line.text || " "
122116
- }, index, false, undefined, this))
122514
+ color: line.failed ? theme.error : line.kind === "user" ? theme.userText : line.kind === "thinking" || line.kind === "notice" ? theme.dim : line.running && line.heading ? theme.brand : line.kind === "tool" && line.heading ? theme.tool : undefined,
122515
+ children: line.kind === "user" ? line.text + " ".repeat(Math.max(0, columns - stringWidth2(line.text))) : line.text || " "
122516
+ }, index, false, undefined, this)),
122517
+ tools && rows > 2 ? /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text2, {
122518
+ color: theme.dim,
122519
+ children: hintLine([`Ctrl+O ${expandTools ? "collapse" : "expand"} tool details`, "Ctrl+T thinking"], columns)
122520
+ }, undefined, false, undefined, this) : null
122117
122521
  ]
122118
122522
  }, undefined, true, undefined, this);
122119
122523
  }
122120
122524
  var import_react35, jsx_dev_runtime4;
122121
122525
  var init_Transcript = __esm(async () => {
122526
+ init_string_width2();
122122
122527
  init_transcript_layout();
122528
+ init_editor();
122529
+ init_chrome();
122123
122530
  init_theme();
122124
122531
  await init_build2();
122125
122532
  import_react35 = __toESM(require_react(), 1);
@@ -122345,15 +122752,18 @@ function PromptInput({ running, editor, onEdit, history, onSubmit, onShortcut, o
122345
122752
  const [historyIndex, setHistoryIndex] = import_react37.useState(null);
122346
122753
  const [draft, setDraft] = import_react37.useState("");
122347
122754
  const [exitArmed, setExitArmed] = import_react37.useState(false);
122755
+ const [dismissed, setDismissed] = import_react37.useState();
122348
122756
  const lastInterrupt = import_react37.useRef(0);
122349
122757
  const value = editor.text;
122350
122758
  const maxSuggestions = Math.max(1, Math.min(MAX_SUGGESTIONS, Math.floor(((stdout.rows ?? 24) - 14) / 2)));
122351
- const width = Math.max(10, (stdout.columns ?? 80) - 6);
122352
- const suggestions = value.startsWith("/") && !/\s/.test(value) ? filterCommands(value.slice(1)).slice(0, maxSuggestions) : [];
122759
+ const columns = terminalColumns(stdout.columns ?? 80);
122760
+ const width = Math.max(1, columns - 2);
122761
+ const suggestions = value !== dismissed && value.startsWith("/") && !/\s/.test(value) ? filterCommands(value.slice(1)).slice(0, maxSuggestions) : [];
122353
122762
  const active = Math.min(selected, Math.max(0, suggestions.length - 1));
122354
122763
  const recent = history.slice(-HISTORY_LIMIT);
122355
122764
  function change(action) {
122356
122765
  onEdit(edit(editor, action));
122766
+ setDismissed(undefined);
122357
122767
  setSelected(0);
122358
122768
  }
122359
122769
  use_paste_default((text) => {
@@ -122400,7 +122810,9 @@ function PromptInput({ running, editor, onEdit, history, onSubmit, onShortcut, o
122400
122810
  return;
122401
122811
  }
122402
122812
  if (key.escape) {
122403
- if (running)
122813
+ if (suggestions.length)
122814
+ setDismissed(value);
122815
+ else if (running)
122404
122816
  onInterrupt();
122405
122817
  return;
122406
122818
  }
@@ -122477,7 +122889,13 @@ function PromptInput({ running, editor, onEdit, history, onSubmit, onShortcut, o
122477
122889
  else if (!key.meta && input)
122478
122890
  change({ type: "insert", text: input });
122479
122891
  });
122480
- const lines = editorLines(editor, Math.max(1, (stdout.columns ?? 80) - 4), Math.max(1, maxEditorLines));
122892
+ const viewport = editorViewport(editor, Math.max(1, columns - 4), Math.max(1, maxEditorLines));
122893
+ const shell = value.startsWith("!");
122894
+ const overflow = [viewport.above ? `\u2191 ${viewport.above} more` : "", viewport.below ? `\u2193 ${viewport.below} more` : ""].filter(Boolean).join(" \xB7 ");
122895
+ const border = shell ? theme.shell : theme.border;
122896
+ const borderLabel = [shell ? "Shell" : "", overflow].filter(Boolean).join(" \xB7 ");
122897
+ const caption = borderLabel ? fitTerminalLine(`\u2500\u2500 ${borderLabel}`, columns) : "";
122898
+ const hints = suggestions.length ? ["\u2191/\u2193 select", "Tab complete", "Enter run", "Esc close"] : running ? ["Esc interrupt", "Draft kept until idle", "Alt+Enter newline"] : shell ? ["Enter run shell", "Alt+Enter newline", "Ctrl+C clear"] : ["Enter send", "Alt+Enter newline", "/ commands", "Ctrl+L models", "Ctrl+C twice exits"];
122481
122899
  return /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Box_default, {
122482
122900
  flexDirection: "column",
122483
122901
  flexShrink: 0,
@@ -122485,50 +122903,47 @@ function PromptInput({ running, editor, onEdit, history, onSubmit, onShortcut, o
122485
122903
  suggestions.length ? /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Box_default, {
122486
122904
  flexDirection: "column",
122487
122905
  paddingX: 1,
122906
+ children: suggestions.map((command, index) => /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(import_react37.Fragment, {
122907
+ children: [
122908
+ index === 0 || commandGroup(suggestions[index - 1]?.name ?? "") !== commandGroup(command.name) ? /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text2, {
122909
+ color: theme.dim,
122910
+ bold: true,
122911
+ children: commandGroup(command.name)
122912
+ }, undefined, false, undefined, this) : null,
122913
+ /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Box_default, {
122914
+ children: [
122915
+ /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text2, {
122916
+ color: index === active ? theme.brand : undefined,
122917
+ bold: index === active,
122918
+ children: [
122919
+ "/",
122920
+ command.name
122921
+ ]
122922
+ }, undefined, true, undefined, this),
122923
+ /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text2, {
122924
+ color: theme.dim,
122925
+ children: [
122926
+ " ",
122927
+ truncate2(command.description, Math.max(1, width - command.name.length - 3))
122928
+ ]
122929
+ }, undefined, true, undefined, this)
122930
+ ]
122931
+ }, undefined, true, undefined, this)
122932
+ ]
122933
+ }, command.name, true, undefined, this))
122934
+ }, undefined, false, undefined, this) : null,
122935
+ /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text2, {
122936
+ color: border,
122488
122937
  children: [
122489
- suggestions.map((command, index) => /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(import_react37.Fragment, {
122490
- children: [
122491
- index === 0 || commandGroup(suggestions[index - 1]?.name ?? "") !== commandGroup(command.name) ? /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text2, {
122492
- color: theme.dim,
122493
- bold: true,
122494
- children: commandGroup(command.name)
122495
- }, undefined, false, undefined, this) : null,
122496
- /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Box_default, {
122497
- children: [
122498
- /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text2, {
122499
- color: index === active ? theme.brand : undefined,
122500
- bold: index === active,
122501
- children: [
122502
- "/",
122503
- command.name
122504
- ]
122505
- }, undefined, true, undefined, this),
122506
- /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text2, {
122507
- color: theme.dim,
122508
- children: [
122509
- " ",
122510
- truncate2(command.description, Math.max(1, width - command.name.length - 3))
122511
- ]
122512
- }, undefined, true, undefined, this)
122513
- ]
122514
- }, undefined, true, undefined, this)
122515
- ]
122516
- }, command.name, true, undefined, this)),
122517
- /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text2, {
122518
- color: theme.dim,
122519
- children: truncate2("Up/Down select \xB7 Tab complete \xB7 Enter run", width)
122520
- }, undefined, false, undefined, this)
122938
+ caption,
122939
+ "\u2500".repeat(Math.max(0, columns - stringWidth2(caption)))
122521
122940
  ]
122522
- }, undefined, true, undefined, this) : null,
122941
+ }, undefined, true, undefined, this),
122523
122942
  /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Box_default, {
122524
- borderStyle: "single",
122525
- borderLeft: false,
122526
- borderRight: false,
122527
- borderColor: running ? theme.permission : theme.brand,
122528
122943
  paddingX: 1,
122529
122944
  children: [
122530
122945
  /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text2, {
122531
- color: theme.brand,
122946
+ color: shell ? theme.shell : theme.brand,
122532
122947
  children: "> "
122533
122948
  }, undefined, false, undefined, this),
122534
122949
  /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Box_default, {
@@ -122542,10 +122957,10 @@ function PromptInput({ running, editor, onEdit, history, onSubmit, onShortcut, o
122542
122957
  }, undefined, false, undefined, this),
122543
122958
  /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text2, {
122544
122959
  color: theme.dim,
122545
- children: fitTerminalLine(running ? "Working \xB7 Esc interrupts" : "Message, /command or !shell command", Math.max(1, (stdout.columns ?? 80) - 5))
122960
+ children: fitTerminalLine(running ? "Working \xB7 Esc interrupts" : "Message, /command or !shell command", Math.max(1, columns - 5))
122546
122961
  }, undefined, false, undefined, this)
122547
122962
  ]
122548
- }, undefined, true, undefined, this) : lines.map((line, index) => /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text2, {
122963
+ }, undefined, true, undefined, this) : viewport.lines.map((line, index) => /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text2, {
122549
122964
  children: [
122550
122965
  line.before,
122551
122966
  line.cursor !== undefined ? /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text2, {
@@ -122558,20 +122973,26 @@ function PromptInput({ running, editor, onEdit, history, onSubmit, onShortcut, o
122558
122973
  }, undefined, false, undefined, this)
122559
122974
  ]
122560
122975
  }, undefined, true, undefined, this),
122976
+ /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text2, {
122977
+ color: border,
122978
+ children: "\u2500".repeat(columns)
122979
+ }, undefined, false, undefined, this),
122561
122980
  exitArmed ? /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text2, {
122562
122981
  color: theme.permission,
122563
122982
  children: truncate2("Press Ctrl+C again to exit", width)
122564
122983
  }, undefined, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text2, {
122565
122984
  color: theme.dim,
122566
- children: truncate2(`${running ? "Esc interrupt" : "Enter send"} \xB7 Alt+Enter newline \xB7 Up/Down history \xB7 Ctrl+C twice exits`, width)
122985
+ children: hintLine(hints, columns)
122567
122986
  }, undefined, false, undefined, this)
122568
122987
  ]
122569
122988
  }, undefined, true, undefined, this);
122570
122989
  }
122571
122990
  var import_react37, jsx_dev_runtime6, MAX_SUGGESTIONS = 6, MAX_EDITOR_LINES = 5, EXIT_CTRL_C_WINDOW_MS = 800;
122572
122991
  var init_PromptInput = __esm(async () => {
122992
+ init_string_width2();
122573
122993
  init_commands();
122574
122994
  init_editor();
122995
+ init_chrome();
122575
122996
  init_theme();
122576
122997
  init_state();
122577
122998
  await init_build2();
@@ -122581,16 +123002,19 @@ var init_PromptInput = __esm(async () => {
122581
123002
 
122582
123003
  // packages/repl/src/components/StatusBar.tsx
122583
123004
  import { homedir as homedir2 } from "os";
122584
- import { relative as relative3, isAbsolute as isAbsolute3 } from "path";
123005
+ import { relative as relative4, isAbsolute as isAbsolute4 } from "path";
122585
123006
  function formatCwd(path) {
122586
123007
  const home = homedir2();
122587
- const child = relative3(home, path);
122588
- if (home.length > 0 && !isAbsolute3(child) && child !== ".." && !child.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`))
123008
+ const child = relative4(home, path);
123009
+ if (home.length > 0 && !isAbsolute4(child) && child !== ".." && !child.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`))
122589
123010
  return child ? `~/${child}` : "~";
122590
123011
  return path;
122591
123012
  }
122592
123013
  function StatusBar({ modelLabel, workspace, title, columns = 80, compact = false, loop }) {
122593
123014
  const line1 = title ? `${formatCwd(workspace)} \u2022 ${title}` : formatCwd(workspace);
123015
+ const model = fitTerminalLine(modelLabel, Math.max(1, Math.floor(columns / 2)));
123016
+ const left = fitTerminalLine(line1, Math.max(1, columns - stringWidth2(model) - 2));
123017
+ const inline = !compact && columns >= 70;
122594
123018
  return /* @__PURE__ */ jsx_dev_runtime7.jsxDEV(Box_default, {
122595
123019
  flexDirection: "column",
122596
123020
  flexShrink: 0,
@@ -122599,30 +123023,70 @@ function StatusBar({ modelLabel, workspace, title, columns = 80, compact = false
122599
123023
  color: theme.permission,
122600
123024
  children: fitTerminalLine(loop, columns)
122601
123025
  }, undefined, false, undefined, this) : null,
122602
- /* @__PURE__ */ jsx_dev_runtime7.jsxDEV(Text2, {
123026
+ inline ? /* @__PURE__ */ jsx_dev_runtime7.jsxDEV(Text2, {
122603
123027
  color: theme.dim,
122604
- children: fitTerminalLine(`${modelLabel} \xB7 ${line1}`, columns)
122605
- }, undefined, false, undefined, this),
122606
- !compact && columns >= 60 ? /* @__PURE__ */ jsx_dev_runtime7.jsxDEV(Text2, {
123028
+ children: [
123029
+ left,
123030
+ " ".repeat(Math.max(1, columns - stringWidth2(left) - stringWidth2(model))),
123031
+ model
123032
+ ]
123033
+ }, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime7.jsxDEV(Text2, {
122607
123034
  color: theme.dim,
122608
- children: fitTerminalLine(HINTS, columns)
122609
- }, undefined, false, undefined, this) : null
123035
+ children: fitTerminalLine(`${modelLabel} \xB7 ${line1}`, columns)
123036
+ }, undefined, false, undefined, this)
122610
123037
  ]
122611
123038
  }, undefined, true, undefined, this);
122612
123039
  }
122613
- var jsx_dev_runtime7, HINTS = "Ctrl+L models \xB7 Ctrl+O tools \xB7 Ctrl+G agents \xB7 /shortcuts";
123040
+ var jsx_dev_runtime7;
122614
123041
  var init_StatusBar = __esm(async () => {
123042
+ init_string_width2();
122615
123043
  init_editor();
122616
123044
  init_theme();
122617
123045
  await init_build2();
122618
123046
  jsx_dev_runtime7 = __toESM(require_jsx_dev_runtime(), 1);
122619
123047
  });
122620
123048
 
123049
+ // packages/repl/src/components/Panel.tsx
123050
+ function Panel({ title, children, color = theme.brand }) {
123051
+ const { stdout } = use_stdout_default();
123052
+ const columns = terminalColumns(stdout.columns ?? 80);
123053
+ const width = Math.max(1, columns - 2);
123054
+ return /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Box_default, {
123055
+ flexDirection: "column",
123056
+ flexShrink: 0,
123057
+ children: [
123058
+ /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text2, {
123059
+ color,
123060
+ children: "\u2500".repeat(columns)
123061
+ }, undefined, false, undefined, this),
123062
+ /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Box_default, {
123063
+ flexDirection: "column",
123064
+ paddingX: columns > 2 ? 1 : 0,
123065
+ children: [
123066
+ /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text2, {
123067
+ bold: true,
123068
+ color,
123069
+ children: fitTerminalLine(title, width)
123070
+ }, undefined, false, undefined, this),
123071
+ children
123072
+ ]
123073
+ }, undefined, true, undefined, this)
123074
+ ]
123075
+ }, undefined, true, undefined, this);
123076
+ }
123077
+ var jsx_dev_runtime8;
123078
+ var init_Panel = __esm(async () => {
123079
+ init_editor();
123080
+ init_theme();
123081
+ await init_build2();
123082
+ jsx_dev_runtime8 = __toESM(require_jsx_dev_runtime(), 1);
123083
+ });
123084
+
122621
123085
  // packages/repl/src/components/ApprovalDialog.tsx
122622
123086
  function ApprovalDialog({ request, onAnswer }) {
122623
123087
  const { stdout } = use_stdout_default();
122624
123088
  const [offset, setOffset] = import_react38.useState(0);
122625
- const width = Math.max(1, (stdout.columns ?? 80) - 4);
123089
+ const width = Math.max(1, terminalColumns(stdout.columns ?? 80) - 4);
122626
123090
  const count = Math.max(1, Math.min(4, (stdout.rows ?? 24) - 10));
122627
123091
  const details = wrapAnsi2(cleanTerminalText(`${request.reason}${request.target ? `
122628
123092
  target: ${request.target}` : ""}`), width, { hard: true, trim: false }).split(`
@@ -122646,49 +123110,45 @@ target: ${request.target}` : ""}`), width, { hard: true, trim: false }).split(`
122646
123110
  else if (input === "n" || input === "N" || key.escape)
122647
123111
  onAnswer(false);
122648
123112
  });
122649
- return /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Box_default, {
122650
- flexDirection: "column",
122651
- borderStyle: "round",
122652
- borderColor: theme.permission,
122653
- paddingX: 1,
123113
+ return /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Panel, {
123114
+ title: `Approve ${request.toolName}?`,
123115
+ color: theme.permission,
122654
123116
  children: [
122655
- /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text2, {
122656
- color: theme.permission,
122657
- bold: true,
122658
- children: fitTerminalLine(`Approve ${request.toolName}?`, width)
122659
- }, undefined, false, undefined, this),
122660
- /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text2, {
123117
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text2, {
122661
123118
  color: theme.dim,
122662
123119
  children: fitTerminalLine(`${request.riskKind} \xB7 ${request.riskLevel}`, width)
122663
123120
  }, undefined, false, undefined, this),
122664
- details.slice(start, start + count).map((line, index) => /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text2, {
123121
+ details.slice(start, start + count).map((line, index) => /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text2, {
122665
123122
  children: line
122666
123123
  }, index, false, undefined, this)),
122667
- request.remember ? /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text2, {
123124
+ request.remember ? /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text2, {
122668
123125
  color: theme.dim,
122669
123126
  children: fitTerminalLine("s allow for session \xB7 a save rule (same tool and target)", width)
122670
123127
  }, undefined, false, undefined, this) : null,
122671
- /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text2, {
123128
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text2, {
122672
123129
  color: theme.dim,
122673
- children: fitTerminalLine(`y allow once \xB7 n reject${details.length > count ? " \xB7 PgUp/PgDn details" : ""}`, width)
123130
+ children: fitTerminalLine(`Enter/y allow once \xB7 n/Esc reject${details.length > count ? " \xB7 PgUp/PgDn details" : ""}`, width)
122674
123131
  }, undefined, false, undefined, this)
122675
123132
  ]
122676
123133
  }, undefined, true, undefined, this);
122677
123134
  }
122678
- var import_react38, jsx_dev_runtime8;
123135
+ var import_react38, jsx_dev_runtime9;
122679
123136
  var init_ApprovalDialog = __esm(async () => {
122680
123137
  init_wrap_ansi2();
122681
123138
  init_theme();
122682
123139
  init_editor();
122683
- await init_build2();
123140
+ await __promiseAll([
123141
+ init_build2(),
123142
+ init_Panel()
123143
+ ]);
122684
123144
  import_react38 = __toESM(require_react(), 1);
122685
- jsx_dev_runtime8 = __toESM(require_jsx_dev_runtime(), 1);
123145
+ jsx_dev_runtime9 = __toESM(require_jsx_dev_runtime(), 1);
122686
123146
  });
122687
123147
 
122688
123148
  // packages/repl/src/components/AskDialog.tsx
122689
123149
  function AskDialog({ input, onAnswer, onCancel }) {
122690
123150
  const { stdout } = use_stdout_default();
122691
- const width = Math.max(1, (stdout.columns ?? 80) - 4);
123151
+ const width = Math.max(1, terminalColumns(stdout.columns ?? 80) - 4);
122692
123152
  const optionCount = Math.max(1, Math.min(6, (stdout.rows ?? 24) - 12));
122693
123153
  const [index, setIndex] = import_react39.useState(0);
122694
123154
  const [cursor, setCursor] = import_react39.useState(0);
@@ -122817,71 +123277,59 @@ function AskDialog({ input, onAnswer, onCancel }) {
122817
123277
  advance();
122818
123278
  });
122819
123279
  if (reviewing)
122820
- return /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
122821
- flexDirection: "column",
122822
- borderStyle: "round",
122823
- borderColor: theme.brand,
122824
- paddingX: 1,
123280
+ return /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Panel, {
123281
+ title: "Review answers",
122825
123282
  children: [
122826
- /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text2, {
122827
- bold: true,
122828
- color: theme.brand,
122829
- children: "Review answers"
122830
- }, undefined, false, undefined, this),
122831
- detailLines.slice(detailStart, detailStart + visibleCount).map((line, row) => /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text2, {
123283
+ detailLines.slice(detailStart, detailStart + visibleCount).map((line, row) => /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text2, {
122832
123284
  children: line
122833
123285
  }, row, false, undefined, this)),
122834
- /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text2, {
123286
+ /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text2, {
122835
123287
  color: theme.dim,
122836
- children: fitTerminalLine("Enter submit \xB7 Left edit \xB7 PgUp/PgDn details \xB7 Esc cancel", width)
123288
+ children: hintLine(["Enter submit", "Esc cancel", "Left edit", "PgUp/PgDn details"], width)
122837
123289
  }, undefined, false, undefined, this)
122838
123290
  ]
122839
123291
  }, undefined, true, undefined, this);
122840
- return /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
122841
- flexDirection: "column",
122842
- borderStyle: "round",
122843
- borderColor: theme.brand,
122844
- paddingX: 1,
123292
+ return /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Panel, {
123293
+ title: `Question ${index + 1}/${input.questions.length}${question.header ? ` \xB7 ${question.header}` : ""}`,
122845
123294
  children: [
122846
- /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text2, {
122847
- bold: true,
122848
- color: theme.brand,
122849
- children: fitTerminalLine(`Question ${index + 1}/${input.questions.length}${question.header ? ` \xB7 ${question.header}` : ""}`, width)
122850
- }, undefined, false, undefined, this),
122851
- detailLines.slice(detailStart, detailStart + visibleCount).map((line, row) => /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text2, {
123295
+ detailLines.slice(detailStart, detailStart + visibleCount).map((line, row) => /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text2, {
122852
123296
  children: line
122853
123297
  }, row, false, undefined, this)),
122854
123298
  options.slice(optionStart, optionStart + optionCount).map((option, row) => {
122855
123299
  const optionIndex = optionStart + row;
122856
- return /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text2, {
123300
+ return /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text2, {
122857
123301
  color: !editing && optionIndex === cursor ? theme.brand : undefined,
122858
123302
  children: fitTerminalLine(`${optionIndex === cursor && !editing ? ">" : " "} ${draft.selected.includes(option.label) ? "[x]" : "[ ]"} ${option.label}${option.description ? ` \u2014 ${option.description}` : ""}`, width)
122859
123303
  }, option.label, false, undefined, this);
122860
123304
  }),
122861
- /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text2, {
123305
+ /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text2, {
122862
123306
  color: editing || cursor === options.length ? theme.brand : theme.dim,
122863
123307
  children: fitTerminalLine(`${!editing && cursor === options.length ? ">" : " "} Custom: ${draft.custom || (editing ? "Type your answer" : "Enter/Tab to type")}`, width)
122864
123308
  }, undefined, false, undefined, this),
122865
- feedback ? /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text2, {
123309
+ feedback ? /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text2, {
122866
123310
  color: theme.brand,
122867
123311
  children: fitTerminalLine(feedback, width)
122868
123312
  }, undefined, false, undefined, this) : null,
122869
- /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text2, {
123313
+ /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text2, {
122870
123314
  color: theme.dim,
122871
- children: fitTerminalLine("Up/Down \xB7 Space select \xB7 Enter next \xB7 Tab custom \xB7 PgUp/PgDn details \xB7 Esc", width)
123315
+ children: hintLine([...question.multiSelect ? ["Space toggle"] : [], "Enter next", "Esc cancel", "\u2191/\u2193 select", "Tab custom", "PgUp/PgDn details"], width)
122872
123316
  }, undefined, false, undefined, this)
122873
123317
  ]
122874
123318
  }, undefined, true, undefined, this);
122875
123319
  }
122876
- var import_react39, jsx_dev_runtime9, emptyDraft = () => ({ selected: [], custom: "" });
123320
+ var import_react39, jsx_dev_runtime10, emptyDraft = () => ({ selected: [], custom: "" });
122877
123321
  var init_AskDialog = __esm(async () => {
122878
123322
  init_wrap_ansi2();
122879
123323
  init_src7();
122880
123324
  init_editor();
122881
123325
  init_theme();
122882
- await init_build2();
123326
+ init_chrome();
123327
+ await __promiseAll([
123328
+ init_build2(),
123329
+ init_Panel()
123330
+ ]);
122883
123331
  import_react39 = __toESM(require_react(), 1);
122884
- jsx_dev_runtime9 = __toESM(require_jsx_dev_runtime(), 1);
123332
+ jsx_dev_runtime10 = __toESM(require_jsx_dev_runtime(), 1);
122885
123333
  });
122886
123334
 
122887
123335
  // packages/repl/src/clipboard.ts
@@ -122919,9 +123367,9 @@ var init_clipboard = () => {};
122919
123367
  // packages/repl/src/components/AuthDialog.tsx
122920
123368
  function AuthDialog({ auth, onCopied, onClose }) {
122921
123369
  const { stdout } = use_stdout_default();
122922
- const width = Math.max(1, (stdout.columns ?? 80) - 4);
123370
+ const width = Math.max(1, terminalColumns(stdout.columns ?? 80) - 4);
122923
123371
  use_input_default((input, key) => {
122924
- if (key.escape) {
123372
+ if (key.escape || key.ctrl && input === "c") {
122925
123373
  onClose();
122926
123374
  return;
122927
123375
  }
@@ -122936,37 +123384,31 @@ function AuthDialog({ auth, onCopied, onClose }) {
122936
123384
  }
122937
123385
  }
122938
123386
  });
122939
- return /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
122940
- flexDirection: "column",
122941
- borderStyle: "round",
122942
- borderColor: theme.permission,
122943
- paddingX: 1,
123387
+ return /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Panel, {
123388
+ title: auth.title,
123389
+ color: theme.permission,
122944
123390
  children: [
122945
- /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text2, {
122946
- bold: true,
122947
- children: fitTerminalLine(auth.title, width)
122948
- }, undefined, false, undefined, this),
122949
- /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text2, {
123391
+ /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text2, {
122950
123392
  color: theme.brand,
122951
123393
  children: fitTerminalLine(auth.url, width)
122952
123394
  }, undefined, false, undefined, this),
122953
- auth.instructions ? /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text2, {
123395
+ auth.instructions ? /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text2, {
122954
123396
  color: theme.dim,
122955
123397
  children: fitTerminalLine(auth.instructions, width)
122956
123398
  }, undefined, false, undefined, this) : null,
122957
- /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text2, {
123399
+ /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text2, {
122958
123400
  color: theme.dim,
122959
123401
  children: "waiting for authorization\u2026"
122960
123402
  }, undefined, false, undefined, this),
122961
- /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text2, {
123403
+ /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text2, {
122962
123404
  children: [
122963
123405
  "c ",
122964
- /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text2, {
123406
+ /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text2, {
122965
123407
  color: theme.dim,
122966
123408
  children: "copy"
122967
123409
  }, undefined, false, undefined, this),
122968
123410
  " \xB7 esc ",
122969
- /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text2, {
123411
+ /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text2, {
122970
123412
  color: theme.dim,
122971
123413
  children: "hide"
122972
123414
  }, undefined, false, undefined, this)
@@ -122975,23 +123417,27 @@ function AuthDialog({ auth, onCopied, onClose }) {
122975
123417
  ]
122976
123418
  }, undefined, true, undefined, this);
122977
123419
  }
122978
- var jsx_dev_runtime10, CODE_PATTERN;
123420
+ var jsx_dev_runtime11, CODE_PATTERN;
122979
123421
  var init_AuthDialog = __esm(async () => {
122980
123422
  init_clipboard();
122981
123423
  init_theme();
122982
123424
  init_editor();
122983
- await init_build2();
122984
- jsx_dev_runtime10 = __toESM(require_jsx_dev_runtime(), 1);
123425
+ await __promiseAll([
123426
+ init_build2(),
123427
+ init_Panel()
123428
+ ]);
123429
+ jsx_dev_runtime11 = __toESM(require_jsx_dev_runtime(), 1);
122985
123430
  CODE_PATTERN = /[A-Z0-9]{4}-[A-Z0-9]{4,5}/;
122986
123431
  });
122987
123432
 
122988
123433
  // packages/repl/src/components/RenameInput.tsx
122989
123434
  function RenameInput({ initial, onSubmit, onCancel }) {
122990
123435
  const { stdout } = use_stdout_default();
122991
- const width = Math.max(1, (stdout.columns ?? 80) - 4);
123436
+ const width = Math.max(1, terminalColumns(stdout.columns ?? 80) - 4);
122992
123437
  const [editor, setEditor] = import_react40.useState({ text: initial, cursor: graphemes(initial).length });
123438
+ use_paste_default((text) => setEditor((previous) => edit(previous, { type: "insert", text: text.replace(/[\r\n]+/g, " ") })));
122993
123439
  use_input_default((input, key) => {
122994
- if (key.escape) {
123440
+ if (key.escape || key.ctrl && input === "c") {
122995
123441
  onCancel();
122996
123442
  return;
122997
123443
  }
@@ -123035,45 +123481,40 @@ function RenameInput({ initial, onSubmit, onCancel }) {
123035
123481
  setEditor(edit(editor, { type: "insert", text: input }));
123036
123482
  });
123037
123483
  const lines = editorLines(editor, width, 1);
123038
- return /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
123039
- flexDirection: "column",
123040
- borderStyle: "round",
123041
- borderColor: theme.brand,
123042
- paddingX: 1,
123484
+ return /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Panel, {
123485
+ title: "Rename session",
123043
123486
  children: [
123044
- /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text2, {
123045
- bold: true,
123046
- color: theme.brand,
123047
- children: fitTerminalLine("Rename session", width)
123048
- }, undefined, false, undefined, this),
123049
- lines.map((line, index) => /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text2, {
123487
+ lines.map((line, index) => /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text2, {
123050
123488
  children: [
123051
- /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text2, {
123489
+ /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text2, {
123052
123490
  color: theme.brand,
123053
123491
  children: "> "
123054
123492
  }, undefined, false, undefined, this),
123055
123493
  line.before,
123056
- line.cursor !== undefined ? /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text2, {
123494
+ line.cursor !== undefined ? /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text2, {
123057
123495
  inverse: true,
123058
123496
  children: line.cursor
123059
123497
  }, undefined, false, undefined, this) : null,
123060
123498
  line.after
123061
123499
  ]
123062
123500
  }, index, true, undefined, this)),
123063
- /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Text2, {
123501
+ /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text2, {
123064
123502
  color: theme.dim,
123065
123503
  children: fitTerminalLine("Enter save \xB7 Esc cancel", width)
123066
123504
  }, undefined, false, undefined, this)
123067
123505
  ]
123068
123506
  }, undefined, true, undefined, this);
123069
123507
  }
123070
- var import_react40, jsx_dev_runtime11;
123508
+ var import_react40, jsx_dev_runtime12;
123071
123509
  var init_RenameInput = __esm(async () => {
123072
123510
  init_editor();
123073
123511
  init_theme();
123074
- await init_build2();
123512
+ await __promiseAll([
123513
+ init_build2(),
123514
+ init_Panel()
123515
+ ]);
123075
123516
  import_react40 = __toESM(require_react(), 1);
123076
- jsx_dev_runtime11 = __toESM(require_jsx_dev_runtime(), 1);
123517
+ jsx_dev_runtime12 = __toESM(require_jsx_dev_runtime(), 1);
123077
123518
  });
123078
123519
 
123079
123520
  // packages/repl/src/selection.ts
@@ -123108,7 +123549,7 @@ function Selector({ title, items, onSelect, onCancel, actions }) {
123108
123549
  const count = Math.max(1, Math.min(8, Math.floor(((stdout.rows ?? 24) - 14) / 2)));
123109
123550
  const start = Math.max(0, Math.min(active - Math.floor(count / 2), filtered.length - count));
123110
123551
  const visible = filtered.slice(start, start + count);
123111
- const width = Math.max(10, (stdout.columns ?? 80) - 10);
123552
+ const width = Math.max(1, terminalColumns(stdout.columns ?? 80) - 2);
123112
123553
  function search(input) {
123113
123554
  setQuery((value) => (value + cleanTerminalText(input.slice(0, 1024)).replace(/\n/g, " ")).slice(0, 256));
123114
123555
  setIndex(0);
@@ -123151,49 +123592,29 @@ function Selector({ title, items, onSelect, onCancel, actions }) {
123151
123592
  search(input);
123152
123593
  }
123153
123594
  });
123154
- return /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
123155
- flexDirection: "column",
123156
- borderStyle: "round",
123157
- borderColor: theme.brand,
123158
- paddingX: 1,
123159
- flexShrink: 0,
123595
+ return /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Panel, {
123596
+ title: `${title} \xB7 ${filtered.length} options`,
123160
123597
  children: [
123161
- /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
123162
- justifyContent: "space-between",
123163
- children: [
123164
- /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text2, {
123165
- bold: true,
123166
- children: title
123167
- }, undefined, false, undefined, this),
123168
- /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text2, {
123169
- color: theme.dim,
123170
- children: [
123171
- filtered.length,
123172
- " options"
123173
- ]
123174
- }, undefined, true, undefined, this)
123175
- ]
123176
- }, undefined, true, undefined, this),
123177
- /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text2, {
123598
+ /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text2, {
123178
123599
  color: query ? undefined : theme.dim,
123179
123600
  children: fitTerminalLine(`Search: ${query || "type to filter"}`, width)
123180
123601
  }, undefined, false, undefined, this),
123181
- visible.length === 0 ? /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text2, {
123602
+ visible.length === 0 ? /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text2, {
123182
123603
  color: theme.dim,
123183
123604
  children: "No matches. Backspace to edit; Esc to return."
123184
123605
  }, undefined, false, undefined, this) : null,
123185
123606
  visible.map((item, row) => {
123186
123607
  const selected = start + row === active;
123187
- return /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(import_react41.Fragment, {
123608
+ return /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(import_react41.Fragment, {
123188
123609
  children: [
123189
- item.group && (row === 0 || visible[row - 1]?.group !== item.group) ? /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text2, {
123610
+ item.group && (row === 0 || visible[row - 1]?.group !== item.group) ? /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text2, {
123190
123611
  bold: true,
123191
123612
  color: theme.dim,
123192
123613
  children: fitTerminalLine(cleanTerminalText(item.group), width)
123193
123614
  }, undefined, false, undefined, this) : null,
123194
- /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text2, {
123615
+ /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text2, {
123195
123616
  color: selected ? theme.brand : undefined,
123196
- backgroundColor: selected ? theme.userBackground : undefined,
123617
+ backgroundColor: selected ? theme.selected : undefined,
123197
123618
  bold: selected,
123198
123619
  children: [
123199
123620
  selected ? "> " : " ",
@@ -123204,24 +123625,28 @@ function Selector({ title, items, onSelect, onCancel, actions }) {
123204
123625
  ]
123205
123626
  }, item.value, true, undefined, this);
123206
123627
  }),
123207
- filtered[active]?.description ? /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text2, {
123628
+ filtered[active]?.description ? /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text2, {
123208
123629
  color: theme.dim,
123209
123630
  children: fitTerminalLine(cleanTerminalText(filtered[active].description ?? ""), width)
123210
123631
  }, undefined, false, undefined, this) : null,
123211
- /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text2, {
123632
+ /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text2, {
123212
123633
  color: theme.dim,
123213
- children: fitTerminalLine(`${filtered.length ? `${active + 1}/${filtered.length} \xB7 ` : ""}Up/Down \xB7 Enter select${actions?.length ? ` \xB7 ${actions.map((action) => action.label).join(" \xB7 ")}` : ""} \xB7 Esc back`, width)
123634
+ children: hintLine(["Enter select", "Esc back", "\u2191/\u2193", ...(actions ?? []).map((action) => action.label), ...filtered.length ? [`${active + 1}/${filtered.length}`] : []], width)
123214
123635
  }, undefined, false, undefined, this)
123215
123636
  ]
123216
123637
  }, undefined, true, undefined, this);
123217
123638
  }
123218
- var import_react41, jsx_dev_runtime12;
123639
+ var import_react41, jsx_dev_runtime13;
123219
123640
  var init_Selector = __esm(async () => {
123220
123641
  init_editor();
123221
123642
  init_theme();
123222
- await init_build2();
123643
+ init_chrome();
123644
+ await __promiseAll([
123645
+ init_build2(),
123646
+ init_Panel()
123647
+ ]);
123223
123648
  import_react41 = __toESM(require_react(), 1);
123224
- jsx_dev_runtime12 = __toESM(require_jsx_dev_runtime(), 1);
123649
+ jsx_dev_runtime13 = __toESM(require_jsx_dev_runtime(), 1);
123225
123650
  });
123226
123651
 
123227
123652
  // packages/repl/src/local-shell.ts
@@ -123237,19 +123662,6 @@ var init_local_shell = __esm(() => {
123237
123662
  init_src7();
123238
123663
  });
123239
123664
 
123240
- // packages/repl/src/terminal-layout.ts
123241
- function terminalLayout(rows, modal) {
123242
- const height = Math.max(6, Math.floor(rows) - 1);
123243
- const compact = height < 20;
123244
- return {
123245
- height,
123246
- compact,
123247
- todoRows: modal || height < 16 ? 0 : Math.min(5, Math.floor(height / 5)),
123248
- jobRows: modal || height < 16 ? 0 : 2,
123249
- inputRows: Math.max(1, Math.min(5, Math.floor(height / 5)))
123250
- };
123251
- }
123252
-
123253
123665
  // packages/repl/src/subagent-view.ts
123254
123666
  function bounded2(text) {
123255
123667
  return text.length > MAX_EVENT_CHARACTERS ? `${text.slice(0, MAX_EVENT_CHARACTERS)}
@@ -123305,6 +123717,9 @@ var init_subagent_view = __esm(() => {
123305
123717
  });
123306
123718
 
123307
123719
  // packages/repl/src/backend-state.ts
123720
+ function stableItems(items) {
123721
+ return items.map((item, index) => ({ ...item, id: -(index + 1) }));
123722
+ }
123308
123723
  function snapshotItems(snapshot) {
123309
123724
  const pending = new Set(toolLogEntries(snapshot.events).filter((call) => call.status === "pending").map((call) => call.callId));
123310
123725
  const items = messagesToItems(snapshot.messages, snapshot.events).map((item) => snapshot.busy && item.toolCallId && pending.has(item.toolCallId) ? { ...item, running: true, incomplete: false, text: "" } : item);
@@ -123312,12 +123727,15 @@ function snapshotItems(snapshot) {
123312
123727
  items.push({ id: nextId(), kind: "thinking", text: snapshot.partial.reasoning });
123313
123728
  if (snapshot.partial?.content)
123314
123729
  items.push({ id: nextId(), kind: "assistant", text: snapshot.partial.content, running: true });
123315
- return items;
123730
+ if (snapshot.error)
123731
+ items.push({ id: nextId(), kind: "assistant", text: `Request failed: ${snapshot.error.split(" | ")[0]}`, failed: true });
123732
+ return stableItems(items);
123316
123733
  }
123317
123734
  function snapshotTasks(snapshot) {
123318
123735
  return restoreTaskViews(snapshot.events).map((view) => {
123319
123736
  const task = snapshot.tasks.find((task) => task.taskId === view.id);
123320
- return !snapshot.busy && view.status === "running" ? { ...view, status: "cancelled", reason: task?.reason ?? "No active backend run." } : view;
123737
+ const stable = { ...view, items: stableItems(view.items) };
123738
+ return !snapshot.busy && view.status === "running" ? { ...stable, status: "cancelled", reason: task?.reason ?? "No active backend run." } : stable;
123321
123739
  });
123322
123740
  }
123323
123741
  var init_backend_state = __esm(() => {
@@ -123349,9 +123767,9 @@ function Repl(props) {
123349
123767
  const { exit } = use_app_default();
123350
123768
  const { createModel, workspace, onSession, backend } = props;
123351
123769
  const { stdout } = use_stdout_default();
123352
- const [size, setSize] = import_react42.useState({ columns: stdout.columns ?? 80, rows: stdout.rows ?? 24 });
123770
+ const [size, setSize] = import_react42.useState({ columns: terminalColumns(stdout.columns ?? 80), rows: stdout.rows ?? 24 });
123353
123771
  import_react42.useEffect(() => {
123354
- const update = () => setSize({ columns: stdout.columns ?? 80, rows: stdout.rows ?? 24 });
123772
+ const update = () => setSize({ columns: terminalColumns(stdout.columns ?? 80), rows: stdout.rows ?? 24 });
123355
123773
  stdout.on("resize", update);
123356
123774
  return () => {
123357
123775
  stdout.off("resize", update);
@@ -124670,21 +125088,22 @@ function Repl(props) {
124670
125088
  const layout = terminalLayout(size.rows, modal);
124671
125089
  const selectedTask = taskViews.find((task) => task.id === viewedTaskId);
124672
125090
  const visibleItems = selectedTask?.items ?? items;
124673
- return /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Box_default, {
125091
+ return /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
124674
125092
  flexDirection: "column",
124675
125093
  width: size.columns,
124676
125094
  height: layout.height,
124677
125095
  children: [
124678
- !sessionStarted ? /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Banner, {
125096
+ !sessionStarted ? /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Banner, {
124679
125097
  modelLabel: modelLabelText,
124680
125098
  workspace
124681
125099
  }, undefined, false, undefined, this) : null,
124682
- !modal && taskViews.length > 0 ? /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(TaskTree, {
125100
+ !modal && taskViews.length > 0 ? /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(TaskTree, {
124683
125101
  tasks: taskViews,
124684
125102
  selectedId: selectedTask?.id,
124685
- columns: size.columns
125103
+ columns: size.columns,
125104
+ maxRows: layout.compact ? 1 : Math.min(6, Math.floor(layout.height / 6) + 1)
124686
125105
  }, undefined, false, undefined, this) : null,
124687
- /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Box_default, {
125106
+ /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
124688
125107
  ref: transcriptBox,
124689
125108
  flexDirection: "column",
124690
125109
  flexGrow: 1,
@@ -124693,7 +125112,8 @@ function Repl(props) {
124693
125112
  justifyContent: !sessionStarted ? "flex-start" : "flex-end",
124694
125113
  overflowY: "hidden",
124695
125114
  children: [
124696
- /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Transcript, {
125115
+ /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Transcript, {
125116
+ viewKey: `${sessionId ?? "new"}:${viewedTaskId ?? "main"}`,
124697
125117
  items: visibleItems,
124698
125118
  expandThinking,
124699
125119
  expandTools,
@@ -124702,22 +125122,22 @@ function Repl(props) {
124702
125122
  offset: scrollOffset,
124703
125123
  onOffset: setScrollOffset
124704
125124
  }, undefined, false, undefined, this),
124705
- !sessionStarted ? /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Box_default, {
125125
+ !sessionStarted ? /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
124706
125126
  flexDirection: "column",
124707
125127
  paddingX: 2,
124708
125128
  marginTop: 1,
124709
125129
  marginBottom: 1,
124710
125130
  children: [
124711
- /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text2, {
125131
+ /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text2, {
124712
125132
  bold: true,
124713
125133
  color: theme.brand,
124714
125134
  children: "What would you like to work on?"
124715
125135
  }, undefined, false, undefined, this),
124716
- /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text2, {
125136
+ /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text2, {
124717
125137
  color: theme.dim,
124718
125138
  children: "/connect providers \xB7 /model models \xB7 /resume sessions"
124719
125139
  }, undefined, false, undefined, this),
124720
- /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text2, {
125140
+ /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text2, {
124721
125141
  color: theme.dim,
124722
125142
  children: "Ctrl+L models \xB7 Shift+Tab effort \xB7 /shortcuts keyboard help"
124723
125143
  }, undefined, false, undefined, this)
@@ -124725,52 +125145,52 @@ function Repl(props) {
124725
125145
  }, undefined, true, undefined, this) : null
124726
125146
  ]
124727
125147
  }, undefined, true, undefined, this),
124728
- running ? /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Spinner, {}, undefined, false, undefined, this) : null,
124729
- switching ? /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Spinner, {
125148
+ running ? /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Spinner, {}, undefined, false, undefined, this) : null,
125149
+ switching ? /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Spinner, {
124730
125150
  label: "Applying changes"
124731
125151
  }, undefined, false, undefined, this) : null,
124732
- /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(TodoPanel, {
125152
+ /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(TodoPanel, {
124733
125153
  todos,
124734
125154
  maxRows: layout.todoRows
124735
125155
  }, undefined, false, undefined, this),
124736
- layout.jobRows > 0 && jobs.some((job) => job.status === "running") ? /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Box_default, {
125156
+ layout.jobRows > 0 && jobs.some((job) => job.status === "running") ? /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Box_default, {
124737
125157
  flexDirection: "column",
124738
125158
  paddingX: 1,
124739
125159
  flexShrink: 0,
124740
125160
  children: [
124741
- jobs.filter((job) => job.status === "running").slice(-1).map((job) => /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text2, {
125161
+ jobs.filter((job) => job.status === "running").slice(-1).map((job) => /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text2, {
124742
125162
  color: theme.dim,
124743
125163
  children: fitTerminalLine(`${job.kind} ${job.jobId.slice(0, 8)} \xB7 ${job.background ? "background" : "foreground"} \xB7 ${job.description}`, size.columns - 2)
124744
125164
  }, job.jobId, false, undefined, this)),
124745
- /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text2, {
125165
+ /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Text2, {
124746
125166
  color: theme.dim,
124747
125167
  children: fitTerminalLine("Ctrl+B move foreground job to background", size.columns - 2)
124748
125168
  }, undefined, false, undefined, this)
124749
125169
  ]
124750
125170
  }, undefined, true, undefined, this) : null,
124751
- pending ? /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(ApprovalDialog, {
125171
+ pending ? /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(ApprovalDialog, {
124752
125172
  request: pending.request,
124753
125173
  onAnswer: answer
124754
125174
  }, undefined, false, undefined, this) : null,
124755
- pending ? null : question?.input ? /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(AskDialog, {
125175
+ pending ? null : question?.input ? /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(AskDialog, {
124756
125176
  input: question.input,
124757
125177
  onAnswer: (output) => backend ? void backend.request("/api/ask", { id: question.id, output }).catch(reportRemote) : askRef.current?.respond(question.id, output),
124758
125178
  onCancel: () => backend ? void backend.request("/api/ask", { id: question.id, cancel: true }).catch(reportRemote) : askRef.current?.respond(question.id)
124759
- }, question.id, false, undefined, this) : authBox ? /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(AuthDialog, {
125179
+ }, question.id, false, undefined, this) : authBox ? /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(AuthDialog, {
124760
125180
  auth: authBox,
124761
125181
  onCopied: (label) => print(`${label} copied to clipboard.`),
124762
125182
  onClose: () => setAuthBox(null)
124763
- }, undefined, false, undefined, this) : renameTarget ? /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(RenameInput, {
125183
+ }, undefined, false, undefined, this) : renameTarget ? /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(RenameInput, {
124764
125184
  initial: renameTarget.title,
124765
125185
  onSubmit: applyRename,
124766
125186
  onCancel: () => setRenameTarget(null)
124767
- }, undefined, false, undefined, this) : picker ? /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Selector, {
125187
+ }, undefined, false, undefined, this) : picker ? /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(Selector, {
124768
125188
  title: picker.title,
124769
125189
  items: picker.items,
124770
125190
  onSelect: picker.onSelect,
124771
125191
  onCancel: () => setPicker(null),
124772
125192
  actions: picker.actions
124773
- }, undefined, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(PromptInput, {
125193
+ }, undefined, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(PromptInput, {
124774
125194
  maxEditorLines: layout.inputRows,
124775
125195
  running: running || switching,
124776
125196
  editor,
@@ -124780,7 +125200,7 @@ function Repl(props) {
124780
125200
  onShortcut: handleShortcut,
124781
125201
  onInterrupt: interrupt
124782
125202
  }, undefined, false, undefined, this),
124783
- /* @__PURE__ */ jsx_dev_runtime13.jsxDEV(StatusBar, {
125203
+ /* @__PURE__ */ jsx_dev_runtime14.jsxDEV(StatusBar, {
124784
125204
  modelLabel: thinking === "off" ? `${modelLabelText} \u2022 thinking off` : `${modelLabelText} \u2022 ${thinking}`,
124785
125205
  workspace,
124786
125206
  title: selectedTask ? `Subagent: ${selectedTask.description}` : title,
@@ -124791,7 +125211,7 @@ function Repl(props) {
124791
125211
  ]
124792
125212
  }, undefined, true, undefined, this);
124793
125213
  }
124794
- var import_react42, jsx_dev_runtime13;
125214
+ var import_react42, jsx_dev_runtime14;
124795
125215
  var init_app = __esm(async () => {
124796
125216
  init_src5();
124797
125217
  init_src7();
@@ -124827,7 +125247,7 @@ var init_app = __esm(async () => {
124827
125247
  init_Selector()
124828
125248
  ]);
124829
125249
  import_react42 = __toESM(require_react(), 1);
124830
- jsx_dev_runtime13 = __toESM(require_jsx_dev_runtime(), 1);
125250
+ jsx_dev_runtime14 = __toESM(require_jsx_dev_runtime(), 1);
124831
125251
  });
124832
125252
 
124833
125253
  // packages/repl/src/diagnostics.ts
@@ -124939,8 +125359,8 @@ var init_model = __esm(() => {
124939
125359
  // packages/app/src/workspace-review.ts
124940
125360
  import { execFile } from "child_process";
124941
125361
  import { constants as constants2 } from "fs";
124942
- import { lstat, open as open3, opendir, realpath as realpath2 } from "fs/promises";
124943
- import { isAbsolute as isAbsolute4, join as join13, relative as relative4, resolve as resolve10, sep as sep2 } from "path";
125362
+ import { lstat as lstat2, open as open3, opendir as opendir2, realpath as realpath3 } from "fs/promises";
125363
+ import { isAbsolute as isAbsolute5, join as join14, relative as relative5, resolve as resolve10, sep as sep3 } from "path";
124944
125364
  import { promisify } from "util";
124945
125365
 
124946
125366
  class WorkspaceReview {
@@ -124949,29 +125369,29 @@ class WorkspaceReview {
124949
125369
  this.root = root;
124950
125370
  }
124951
125371
  async target(path) {
124952
- if (typeof path !== "string" || path.length > REVIEW_LIMITS.path || path.includes("\x00") || isAbsolute4(path) || path.split(/[\\/]/).some((part) => part === ".." || part.includes(":")))
125372
+ if (typeof path !== "string" || path.length > REVIEW_LIMITS.path || path.includes("\x00") || isAbsolute5(path) || path.split(/[\\/]/).some((part) => part === ".." || part.includes(":")))
124953
125373
  throw new Error("Invalid workspace-relative path.");
124954
- const root = await realpath2(this.root);
125374
+ const root = await realpath3(this.root);
124955
125375
  const candidate = resolve10(root, path || ".");
124956
- const rel = relative4(root, candidate);
124957
- if (isAbsolute4(rel) || rel === ".." || rel.startsWith(`..${sep2}`))
125376
+ const rel = relative5(root, candidate);
125377
+ if (isAbsolute5(rel) || rel === ".." || rel.startsWith(`..${sep3}`))
124958
125378
  throw new Error("Path is outside the workspace.");
124959
125379
  let current = root;
124960
- for (const part of rel.split(sep2).filter(Boolean)) {
124961
- current = join13(current, part);
124962
- if ((await lstat(current)).isSymbolicLink())
125380
+ for (const part of rel.split(sep3).filter(Boolean)) {
125381
+ current = join14(current, part);
125382
+ if ((await lstat2(current)).isSymbolicLink())
124963
125383
  throw new Error("Links cannot be opened in the workspace viewer.");
124964
125384
  }
124965
- const target = await realpath2(candidate);
124966
- const canonical = relative4(root, target);
124967
- if (isAbsolute4(canonical) || canonical === ".." || canonical.startsWith(`..${sep2}`))
125385
+ const target = await realpath3(candidate);
125386
+ const canonical = relative5(root, target);
125387
+ if (isAbsolute5(canonical) || canonical === ".." || canonical.startsWith(`..${sep3}`))
124968
125388
  throw new Error("Path is outside the workspace.");
124969
125389
  return { root, target };
124970
125390
  }
124971
125391
  async list(path = "") {
124972
125392
  const { target } = await this.target(path);
124973
125393
  const entries = [];
124974
- for await (const item of await opendir(target)) {
125394
+ for await (const item of await opendir2(target)) {
124975
125395
  if (!item.isSymbolicLink() && item.name !== ".git" && (item.isFile() || item.isDirectory()))
124976
125396
  entries.push(item);
124977
125397
  if (entries.length > REVIEW_LIMITS.entries)
@@ -125009,10 +125429,10 @@ var init_workspace_review = __esm(() => {
125009
125429
  });
125010
125430
 
125011
125431
  // packages/app/src/services/sync.ts
125012
- import { randomUUID as randomUUID7 } from "crypto";
125432
+ import { randomUUID as randomUUID8 } from "crypto";
125013
125433
 
125014
125434
  class SyncManager {
125015
- instance = randomUUID7();
125435
+ instance = randomUUID8();
125016
125436
  revision = 0;
125017
125437
  subscribers = new Set;
125018
125438
  publish(kind, sessionId) {
@@ -125141,11 +125561,11 @@ var init_runs = __esm(() => {
125141
125561
  });
125142
125562
 
125143
125563
  // packages/app/src/server.ts
125144
- import { randomUUID as randomUUID8 } from "crypto";
125145
- import { existsSync as existsSync4, mkdirSync as mkdirSync12, readdirSync as readdirSync3, statSync as statSync6 } from "fs";
125564
+ import { randomUUID as randomUUID9 } from "crypto";
125565
+ import { existsSync as existsSync5, mkdirSync as mkdirSync12, readdirSync as readdirSync3, statSync as statSync6 } from "fs";
125146
125566
  import { readFile as readFile4 } from "fs/promises";
125147
125567
  import { homedir as homedir3 } from "os";
125148
- import { basename as basename3, dirname as dirname11, extname, join as join14, relative as relative5, resolve as resolve11, sep as sep3 } from "path";
125568
+ import { basename as basename3, dirname as dirname11, extname, join as join15, relative as relative6, resolve as resolve11, sep as sep4 } from "path";
125149
125569
  function json3(data, status = 200) {
125150
125570
  return new Response(JSON.stringify(data), {
125151
125571
  status,
@@ -125195,7 +125615,7 @@ function startServer(options = {}) {
125195
125615
  const port = options.port ?? (Number.isInteger(configuredPort) && configuredPort > 0 ? configuredPort : DEFAULT_PORT);
125196
125616
  let workspace = resolve11(options.workspace ?? process.cwd());
125197
125617
  const bundledWebuiDir = resolve11(import.meta.dir, "../webui");
125198
- const webuiDir = resolve11(options.webuiDir ?? process.env.RINGKO_WEBUI_DIR ?? (existsSync4(join14(DEFAULT_WEBUI_DIR, "index.html")) ? DEFAULT_WEBUI_DIR : existsSync4(join14(bundledWebuiDir, "index.html")) ? bundledWebuiDir : join14(dirname11(process.execPath), "webui")));
125618
+ const webuiDir = resolve11(options.webuiDir ?? process.env.RINGKO_WEBUI_DIR ?? (existsSync5(join15(DEFAULT_WEBUI_DIR, "index.html")) ? DEFAULT_WEBUI_DIR : existsSync5(join15(bundledWebuiDir, "index.html")) ? bundledWebuiDir : join15(dirname11(process.execPath), "webui")));
125199
125619
  let store = new SessionStore({ cwd: workspace });
125200
125620
  const approvals = new Map;
125201
125621
  const questions = new Map;
@@ -125347,7 +125767,7 @@ function startServer(options = {}) {
125347
125767
  }
125348
125768
  const existing = projects.projects.find((entry) => resolve11(entry.path) === target);
125349
125769
  if (!existing) {
125350
- const id = `proj-${randomUUID8().slice(0, 8)}`;
125770
+ const id = `proj-${randomUUID9().slice(0, 8)}`;
125351
125771
  const name = typeof body?.name === "string" && body.name.trim().length > 0 ? body.name.trim() : basename3(target);
125352
125772
  projects = { projects: [...projects.projects, { id, name, path: target }], ...projects.current ? { current: projects.current } : {} };
125353
125773
  if (!projects.current) {
@@ -125382,11 +125802,11 @@ function startServer(options = {}) {
125382
125802
  const code = error.code;
125383
125803
  return json3({ error: code === "ENOENT" ? "Directory not found." : "Cannot read this directory." }, 400);
125384
125804
  }
125385
- const entries = dirents.filter((entry) => entry.isDirectory()).map((entry) => ({ name: entry.name, path: join14(target, entry.name), hidden: entry.name.startsWith(".") })).sort((a, b) => a.name.localeCompare(b.name));
125805
+ const entries = dirents.filter((entry) => entry.isDirectory()).map((entry) => ({ name: entry.name, path: join15(target, entry.name), hidden: entry.name.startsWith(".") })).sort((a, b) => a.name.localeCompare(b.name));
125386
125806
  return json3({
125387
125807
  path: target,
125388
125808
  home,
125389
- separator: sep3,
125809
+ separator: sep4,
125390
125810
  crumbs: crumbsFor(target),
125391
125811
  entries: entries.slice(0, LIST_LIMIT),
125392
125812
  truncated: entries.length > LIST_LIMIT
@@ -125401,7 +125821,7 @@ function startServer(options = {}) {
125401
125821
  if (name.trim().length === 0 || name.includes("/") || name.includes("\\")) {
125402
125822
  return json3({ error: "name must be a single folder name." }, 400);
125403
125823
  }
125404
- const target = join14(resolve11(parent), name);
125824
+ const target = join15(resolve11(parent), name);
125405
125825
  try {
125406
125826
  mkdirSync12(target, { recursive: false });
125407
125827
  } catch (error) {
@@ -125508,7 +125928,7 @@ function startServer(options = {}) {
125508
125928
  const url = typeof body?.url === "string" ? body.url.trim() : "";
125509
125929
  if (name.length === 0 || url.length === 0)
125510
125930
  return json3({ error: "name and url are required." }, 400);
125511
- const id = randomUUID8();
125931
+ const id = randomUUID9();
125512
125932
  oauthFlows.set(id, { status: "pending", createdAt: now });
125513
125933
  let resolveIssued;
125514
125934
  const issued = new Promise((resolve) => {
@@ -125691,13 +126111,13 @@ function startServer(options = {}) {
125691
126111
  return json3({ error: `Unsupported OAuth domain "${domain}".` }, 400);
125692
126112
  if ([...oauthFlows.values()].filter((flow) => flow.status === "pending").length >= 4 || oauthFlows.size >= 64)
125693
126113
  return json3({ error: "Too many sign-in attempts. Finish an existing attempt or retry later." }, 429);
125694
- const id = randomUUID8();
126114
+ const id = randomUUID9();
125695
126115
  oauthFlows.set(id, { status: "pending", createdAt: now });
125696
126116
  let resolveIssued;
125697
126117
  const onCode = (url, code) => resolveIssued?.({ url, code });
125698
126118
  const login = kind === "openai" ? loginOpenAiDevice(onCode) : kind === "copilot" ? loginGitHubCopilot(onCode) : kind === "anthropic" ? loginAnthropic((url) => onCode(url, "")) : loginXaiDevice(onCode);
125699
126119
  const outcome = login.then((credential) => {
125700
- const accountId = credential.accountId ?? credential.login ?? randomUUID8();
126120
+ const accountId = credential.accountId ?? credential.login ?? randomUUID9();
125701
126121
  setOAuthAccount(domain, { id: accountId, credential, authenticatedAt: Date.now() });
125702
126122
  oauthFlows.set(id, { status: "success", createdAt: now });
125703
126123
  return;
@@ -125798,6 +126218,12 @@ function startServer(options = {}) {
125798
126218
  return json3({ error: "Could not fork session." }, 500);
125799
126219
  }
125800
126220
  }
126221
+ function persistSettings(config) {
126222
+ if (options.configPath)
126223
+ saveConfigFile(config, options.configPath);
126224
+ else
126225
+ saveSettings(config);
126226
+ }
125801
126227
  async function handleSetAccess(request) {
125802
126228
  const body = await readJson(request);
125803
126229
  const permission = body?.permission ?? body?.mode;
@@ -125807,7 +126233,7 @@ function startServer(options = {}) {
125807
126233
  const config = readConfig();
125808
126234
  if (typeof config === "string")
125809
126235
  return json3({ error: config }, 500);
125810
- saveSettings({ ...config, permission, mode: permission });
126236
+ persistSettings({ ...config, permission, mode: permission });
125811
126237
  return await handleInfo();
125812
126238
  }
125813
126239
  async function handleSetMode(request) {
@@ -125818,7 +126244,7 @@ function startServer(options = {}) {
125818
126244
  const config = readConfig();
125819
126245
  if (typeof config === "string")
125820
126246
  return json3({ error: config }, 500);
125821
- saveSettings({ ...config, workflow });
126247
+ persistSettings({ ...config, workflow });
125822
126248
  return await handleInfo();
125823
126249
  }
125824
126250
  async function handleUpload(request) {
@@ -125831,13 +126257,13 @@ function startServer(options = {}) {
125831
126257
  const files = form.getAll("file").filter((value) => value instanceof File);
125832
126258
  if (files.length === 0)
125833
126259
  return json3({ error: "no files." }, 400);
125834
- const dir = join14(workspace, ".ringko", "uploads");
126260
+ const dir = join15(workspace, ".ringko", "uploads");
125835
126261
  mkdirSync12(dir, { recursive: true });
125836
126262
  const saved = [];
125837
126263
  for (const file of files) {
125838
126264
  const safe = file.name.replace(/[^A-Za-z0-9._-]/g, "_");
125839
126265
  const stored = `${Date.now()}-${safe}`;
125840
- await Bun.write(join14(dir, stored), file);
126266
+ await Bun.write(join15(dir, stored), file);
125841
126267
  saved.push({ name: file.name, path: `.ringko/uploads/${stored}` });
125842
126268
  }
125843
126269
  return json3({ files: saved });
@@ -125851,7 +126277,7 @@ function startServer(options = {}) {
125851
126277
  const config = readConfig();
125852
126278
  if (typeof config === "string")
125853
126279
  return json3({ error: config }, 500);
125854
- saveSettings({ ...config, thinking: level });
126280
+ persistSettings({ ...config, thinking: level });
125855
126281
  return await handleInfo();
125856
126282
  }
125857
126283
  async function handleSetUi(request) {
@@ -125864,7 +126290,7 @@ function startServer(options = {}) {
125864
126290
  next.expandThinking = body.expandThinking;
125865
126291
  if (typeof body?.expandTools === "boolean")
125866
126292
  next.expandTools = body.expandTools;
125867
- saveSettings(next);
126293
+ persistSettings(next);
125868
126294
  return await handleInfo();
125869
126295
  }
125870
126296
  async function handleCompact(request) {
@@ -125928,7 +126354,10 @@ function startServer(options = {}) {
125928
126354
  if (!(provider.models ?? []).some((entry) => entry.id === modelId)) {
125929
126355
  return json3({ error: `unknown model "${modelId}" for provider "${providerName}".` }, 400);
125930
126356
  }
125931
- saveProviders({ ...loadProviders(), model: target });
126357
+ if (options.configPath)
126358
+ saveConfigFile({ ...config, model: target }, options.configPath);
126359
+ else
126360
+ saveProviders({ ...loadProviders(), model: target });
125932
126361
  return await handleInfo();
125933
126362
  }
125934
126363
  function sessionTitleView(events) {
@@ -126174,7 +126603,7 @@ function startServer(options = {}) {
126174
126603
  } catch {
126175
126604
  return json3({ error: "Unknown or locked session." }, 404);
126176
126605
  }
126177
- const call = { id: randomUUID8(), name: "shell", arguments: { command: body.command } };
126606
+ const call = { id: randomUUID9(), name: "shell", arguments: { command: body.command } };
126178
126607
  const abort = beginRun(session, () => {
126179
126608
  session.appendEvent("run/started", { kind: "shell" });
126180
126609
  recordUserMessage(session, `!${body.command}`);
@@ -126320,7 +126749,7 @@ Attached files (read them if relevant): ${attachments.join(", ")}` : raw;
126320
126749
  ...config.compaction ? { compaction: config.compaction } : {},
126321
126750
  ...isAccessMode(config.permission) ? { accessMode: config.permission } : isAccessMode(config.mode) ? { accessMode: config.mode } : {},
126322
126751
  requestApproval: async (approval) => {
126323
- const id = randomUUID8();
126752
+ const id = randomUUID9();
126324
126753
  send("approval", { id, toolName: approval.toolName, riskLevel: approval.riskLevel, riskKind: approval.riskKind, reason: approval.reason, target: approval.target ?? null });
126325
126754
  return await new Promise((resolveApproval) => {
126326
126755
  const approvalSignal = approval.signal ?? abort.signal;
@@ -126486,16 +126915,16 @@ Attached files (read them if relevant): ${attachments.join(", ")}` : raw;
126486
126915
  }
126487
126916
  async function serveStatic(pathname) {
126488
126917
  const rel = pathname === "/" ? "index.html" : pathname.replace(/^\/+/, "");
126489
- const target = resolve11(join14(webuiDir, rel));
126490
- const withinRoot = relative5(webuiDir, target);
126918
+ const target = resolve11(join15(webuiDir, rel));
126919
+ const withinRoot = relative6(webuiDir, target);
126491
126920
  if (withinRoot.startsWith("..") || withinRoot.includes(".."))
126492
126921
  return json3({ error: "not found" }, 404);
126493
126922
  let file = target;
126494
126923
  try {
126495
126924
  if (statSync6(file).isDirectory())
126496
- file = join14(file, "index.html");
126925
+ file = join15(file, "index.html");
126497
126926
  } catch {
126498
- file = join14(webuiDir, "index.html");
126927
+ file = join15(webuiDir, "index.html");
126499
126928
  }
126500
126929
  try {
126501
126930
  const bytes = await readFile4(file);
@@ -126538,7 +126967,7 @@ Attached files (read them if relevant): ${attachments.join(", ")}` : raw;
126538
126967
  const nodePath = Bun.which("node");
126539
126968
  if (!nodePath)
126540
126969
  throw new Error("Interactive terminals require Node.js in PATH.");
126541
- const bridgePath = join14(import.meta.dir, "terminal-bridge.mjs");
126970
+ const bridgePath = join15(import.meta.dir, "terminal-bridge.mjs");
126542
126971
  const child = Bun.spawn([nodePath, bridgePath], {
126543
126972
  cwd,
126544
126973
  env: { ...process.env },
@@ -126658,7 +127087,7 @@ Attached files (read them if relevant): ${attachments.join(", ")}` : raw;
126658
127087
  } catch (cause) {
126659
127088
  return json3({ error: cause instanceof Error ? cause.message : "Could not start a terminal." }, 500);
126660
127089
  }
126661
- const id = randomUUID8();
127090
+ const id = randomUUID9();
126662
127091
  const session = { terminal, exited: false, pendingOutput: "" };
126663
127092
  terminalSessions.set(id, session);
126664
127093
  terminal.onData((data) => {
@@ -127130,12 +127559,12 @@ import { resolve as resolve8 } from "path";
127130
127559
 
127131
127560
  // packages/client/src/local.ts
127132
127561
  import { createHash as createHash3 } from "crypto";
127133
- import { realpathSync } from "fs";
127562
+ import { realpathSync as realpathSync2 } from "fs";
127134
127563
  import { resolve as resolve7 } from "path";
127135
127564
  var SERVICE_PORT_BASE = 22000;
127136
127565
  var SERVICE_PORT_RANGE = 20000;
127137
127566
  function canonicalWorkspace(workspace) {
127138
- return realpathSync(resolve7(workspace));
127567
+ return realpathSync2(resolve7(workspace));
127139
127568
  }
127140
127569
  function sharedPort(workspace, configPath) {
127141
127570
  const path = canonicalWorkspace(workspace);
@@ -127144,6 +127573,7 @@ function sharedPort(workspace, configPath) {
127144
127573
  const key = `${normalized}\x00${process.platform === "win32" ? config.toLowerCase() : config}`;
127145
127574
  return SERVICE_PORT_BASE + createHash3("sha256").update(key).digest().readUInt32BE(0) % SERVICE_PORT_RANGE;
127146
127575
  }
127576
+
127147
127577
  // packages/tui/src/backend.ts
127148
127578
  var START_TIMEOUT_MS = 15000;
127149
127579
  var PROBE_TIMEOUT_MS = 1000;
@@ -127213,7 +127643,7 @@ init_src3();
127213
127643
  // packages/tui/src/provider.ts
127214
127644
  init_loader();
127215
127645
  // packages/tui/package.json
127216
- var version2 = "0.1.0";
127646
+ var version2 = "0.2.0";
127217
127647
 
127218
127648
  // packages/tui/src/cli.ts
127219
127649
  var VERSION8 = version2;